Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Failed Conditions
Push — main ( 2c9538...02418a )
by Dan
38s queued 18s
created

SmrGame::isGameType()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
use Smr\Database;
4
use Smr\Epoch;
5
use Smr\Exceptions\GameNotFound;
6
use Smr\Race;
7
8
class SmrGame {
9
10
	/** @var array<int, self> */
11
	protected static array $CACHE_GAMES = [];
12
13
	protected Database $db;
14
15
	protected string $name;
16
	protected string $description;
17
	protected int $joinTime;
18
	protected int $startTime;
19
	protected int $endTime;
20
	protected int $maxPlayers;
21
	protected int $maxTurns;
22
	protected int $startTurnHours;
23
	protected int $gameTypeID;
24
	protected int $creditsNeeded;
25
	protected float $gameSpeed;
26
	protected bool $enabled;
27
	protected bool $ignoreStats;
28
	protected int $allianceMaxPlayers;
29
	protected int $allianceMaxVets;
30
	protected int $startingCredits;
31
32
	protected int $totalPlayers;
33
	/** @var array<int> */
34
	protected array $playableRaceIDs;
35
36
	protected bool $hasChanged = false;
37
	protected bool $isNew = false;
38
39
	public const GAME_TYPE_DEFAULT = 0;
40
	public const GAME_TYPE_HUNTER_WARS = 3;
41
	public const GAME_TYPE_SEMI_WARS = 4;
42
	public const GAME_TYPE_DRAFT = 5;
43
	public const GAME_TYPE_FFA = 6;
44
	public const GAME_TYPE_NEWBIE = 7;
45
	public const GAME_TYPES = [
46
		self::GAME_TYPE_DEFAULT => 'Default',
47
		self::GAME_TYPE_HUNTER_WARS => 'Hunter Wars',
48
		self::GAME_TYPE_SEMI_WARS => 'Semi Wars',
49
		self::GAME_TYPE_DRAFT => 'Draft',
50
		self::GAME_TYPE_FFA => 'FFA',
51
		self::GAME_TYPE_NEWBIE => 'Newbie',
52
	];
53
54
	/**
55
	 * Attempts to construct the game to determine if it exists.
56
	 */
57
	public static function gameExists(int $gameID): bool {
58
		try {
59
			self::getGame($gameID);
60
			return true;
61
		} catch (GameNotFound) {
62
			return false;
63
		}
64
	}
65
66
	public static function getGame(int $gameID, bool $forceUpdate = false): self {
67
		if ($forceUpdate || !isset(self::$CACHE_GAMES[$gameID])) {
68
			self::$CACHE_GAMES[$gameID] = new self($gameID);
69
		}
70
		return self::$CACHE_GAMES[$gameID];
71
	}
72
73
	public static function clearCache(): void {
74
		self::$CACHE_GAMES = [];
75
	}
76
77
	public static function saveGames(): void {
78
		foreach (self::$CACHE_GAMES as $game) {
79
			$game->save();
80
		}
81
	}
82
83
	public static function createGame(int $gameID): self {
84
		if (!isset(self::$CACHE_GAMES[$gameID])) {
85
			self::$CACHE_GAMES[$gameID] = new self($gameID, true);
86
		}
87
		return self::$CACHE_GAMES[$gameID];
88
	}
89
90
	protected function __construct(
91
		protected readonly int $gameID,
92
		bool $create = false
93
	) {
94
		$this->db = Database::getInstance();
95
96
		$dbResult = $this->db->read('SELECT * FROM game WHERE game_id = ' . $this->db->escapeNumber($gameID));
97
		if ($dbResult->hasRecord()) {
98
			$dbRecord = $dbResult->record();
99
			$this->name = $dbRecord->getString('game_name');
100
			$this->description = $dbRecord->getString('game_description');
101
			$this->joinTime = $dbRecord->getInt('join_time');
102
			$this->startTime = $dbRecord->getInt('start_time');
103
			$this->endTime = $dbRecord->getInt('end_time');
104
			$this->maxPlayers = $dbRecord->getInt('max_players');
105
			$this->maxTurns = $dbRecord->getInt('max_turns');
106
			$this->startTurnHours = $dbRecord->getInt('start_turns');
107
			$this->gameTypeID = $dbRecord->getInt('game_type');
108
			$this->creditsNeeded = $dbRecord->getInt('credits_needed');
109
			$this->gameSpeed = $dbRecord->getFloat('game_speed');
110
			$this->enabled = $dbRecord->getBoolean('enabled');
111
			$this->ignoreStats = $dbRecord->getBoolean('ignore_stats');
112
			$this->allianceMaxPlayers = $dbRecord->getInt('alliance_max_players');
113
			$this->allianceMaxVets = $dbRecord->getInt('alliance_max_vets');
114
			$this->startingCredits = $dbRecord->getInt('starting_credits');
115
		} elseif ($create === true) {
116
			$this->isNew = true;
117
		} else {
118
			throw new GameNotFound('No such game: ' . $gameID);
119
		}
120
	}
121
122
	public function save(): void {
123
		if ($this->isNew) {
124
			$this->db->insert('game', [
125
				'game_id' => $this->db->escapeNumber($this->getGameID()),
126
				'game_name' => $this->db->escapeString($this->getName()),
127
				'game_description' => $this->db->escapeString($this->getDescription()),
128
				'join_time' => $this->db->escapeNumber($this->getJoinTime()),
129
				'start_time' => $this->db->escapeNumber($this->getStartTime()),
130
				'end_time' => $this->db->escapeNumber($this->getEndTime()),
131
				'max_players' => $this->db->escapeNumber($this->getMaxPlayers()),
132
				'max_turns' => $this->db->escapeNumber($this->getMaxTurns()),
133
				'start_turns' => $this->db->escapeNumber($this->getStartTurnHours()),
134
				'game_type' => $this->db->escapeNumber($this->gameTypeID),
135
				'credits_needed' => $this->db->escapeNumber($this->getCreditsNeeded()),
136
				'game_speed' => $this->db->escapeNumber($this->getGameSpeed()),
137
				'enabled' => $this->db->escapeBoolean($this->isEnabled()),
138
				'ignore_stats' => $this->db->escapeBoolean($this->isIgnoreStats()),
139
				'alliance_max_players' => $this->db->escapeNumber($this->getAllianceMaxPlayers()),
140
				'alliance_max_vets' => $this->db->escapeNumber($this->getAllianceMaxVets()),
141
				'starting_credits' => $this->db->escapeNumber($this->getStartingCredits()),
142
			]);
143
		} elseif ($this->hasChanged) {
144
			$this->db->write('UPDATE game SET game_name = ' . $this->db->escapeString($this->getName()) .
145
										', game_description = ' . $this->db->escapeString($this->getDescription()) .
146
										', join_time = ' . $this->db->escapeNumber($this->getJoinTime()) .
147
										', start_time = ' . $this->db->escapeNumber($this->getStartTime()) .
148
										', end_time = ' . $this->db->escapeNumber($this->getEndTime()) .
149
										', max_players = ' . $this->db->escapeNumber($this->getMaxPlayers()) .
150
										', max_turns = ' . $this->db->escapeNumber($this->getMaxTurns()) .
151
										', start_turns = ' . $this->db->escapeNumber($this->getStartTurnHours()) .
152
										', game_type = ' . $this->db->escapeNumber($this->gameTypeID) .
153
										', credits_needed = ' . $this->db->escapeNumber($this->getCreditsNeeded()) .
154
										', game_speed = ' . $this->db->escapeNumber($this->getGameSpeed()) .
155
										', enabled = ' . $this->db->escapeBoolean($this->isEnabled()) .
156
										', ignore_stats = ' . $this->db->escapeBoolean($this->isIgnoreStats()) .
157
										', alliance_max_players = ' . $this->db->escapeNumber($this->getAllianceMaxPlayers()) .
158
										', alliance_max_vets = ' . $this->db->escapeNumber($this->getAllianceMaxVets()) .
159
										', starting_credits = ' . $this->db->escapeNumber($this->getStartingCredits()) .
160
									' WHERE game_id = ' . $this->db->escapeNumber($this->getGameID()));
161
		}
162
		$this->isNew = false;
163
		$this->hasChanged = false;
164
	}
165
166
	public function getGameID(): int {
167
		return $this->gameID;
168
	}
169
170
	public function getName(): string {
171
		return $this->name;
172
	}
173
174
	public function setName(string $name): void {
175
		if (!$this->isNew && $this->name === $name) {
176
			return;
177
		}
178
		$this->name = $name;
179
		$this->hasChanged = true;
180
	}
181
182
	public function getDescription(): string {
183
		return $this->description;
184
	}
185
186
	public function setDescription(string $description): void {
187
		if (!$this->isNew && $this->description === $description) {
188
			return;
189
		}
190
		$this->description = $description;
191
		$this->hasChanged = true;
192
	}
193
194
	public function hasStarted(): bool {
195
		return Epoch::time() >= $this->getStartTime();
196
	}
197
198
	/**
199
	 * Returns the epoch time when the game starts,
200
	 * i.e. when players can move, turns are gained, etc.
201
	 */
202
	public function getStartTime(): int {
203
		return $this->startTime;
204
	}
205
206
	public function setStartTime(int $startTime): void {
207
		if (!$this->isNew && $this->startTime === $startTime) {
208
			return;
209
		}
210
		$this->startTime = $startTime;
211
		$this->hasChanged = true;
212
	}
213
214
	/**
215
	 * Returns the epoch time when players can begin to join the game.
216
	 */
217
	public function getJoinTime(): int {
218
		return $this->joinTime;
219
	}
220
221
	public function setJoinTime(int $joinTime): void {
222
		if (!$this->isNew && $this->joinTime === $joinTime) {
223
			return;
224
		}
225
		$this->joinTime = $joinTime;
226
		$this->hasChanged = true;
227
	}
228
229
	public function hasEnded(): bool {
230
		return $this->getEndTime() < Epoch::time();
231
	}
232
233
	/**
234
	 * Returns the epoch time when the game ends.
235
	 */
236
	public function getEndTime(): int {
237
		return $this->endTime;
238
	}
239
240
	public function setEndTime(int $endTime): void {
241
		if (!$this->isNew && $this->endTime === $endTime) {
242
			return;
243
		}
244
		$this->endTime = $endTime;
245
		$this->hasChanged = true;
246
	}
247
248
	public function getMaxPlayers(): int {
249
		return $this->maxPlayers;
250
	}
251
252
	public function setMaxPlayers(int $maxPlayers): void {
253
		if (!$this->isNew && $this->maxPlayers === $maxPlayers) {
254
			return;
255
		}
256
		$this->maxPlayers = $maxPlayers;
257
		$this->hasChanged = true;
258
	}
259
260
	public function getMaxTurns(): int {
261
		return $this->maxTurns;
262
	}
263
264
	public function setMaxTurns(int $int): void {
265
		if (!$this->isNew && $this->maxTurns === $int) {
266
			return;
267
		}
268
		$this->maxTurns = $int;
269
		$this->hasChanged = true;
270
	}
271
272
	public function getStartTurnHours(): int {
273
		return $this->startTurnHours;
274
	}
275
276
	public function setStartTurnHours(int $int): void {
277
		if (!$this->isNew && $this->startTurnHours === $int) {
278
			return;
279
		}
280
		$this->startTurnHours = $int;
281
		$this->hasChanged = true;
282
	}
283
284
	public function isGameType(int $gameTypeID): bool {
285
		return $this->gameTypeID === $gameTypeID;
286
	}
287
288
	public function getGameType(): string {
289
		return self::GAME_TYPES[$this->gameTypeID];
290
	}
291
292
	public function setGameTypeID(int $gameTypeID): void {
293
		if (!$this->isNew && $this->gameTypeID === $gameTypeID) {
294
			return;
295
		}
296
		$this->gameTypeID = $gameTypeID;
297
		$this->hasChanged = true;
298
	}
299
300
	public function getCreditsNeeded(): int {
301
		return $this->creditsNeeded;
302
	}
303
304
	public function setCreditsNeeded(int $creditsNeeded): void {
305
		if (!$this->isNew && $this->creditsNeeded === $creditsNeeded) {
306
			return;
307
		}
308
		$this->creditsNeeded = $creditsNeeded;
309
		$this->hasChanged = true;
310
	}
311
312
	public function getGameSpeed(): float {
313
		return $this->gameSpeed;
314
	}
315
316
	public function setGameSpeed(float $gameSpeed): void {
317
		if (!$this->isNew && $this->gameSpeed === $gameSpeed) {
318
			return;
319
		}
320
		$this->gameSpeed = $gameSpeed;
321
		$this->hasChanged = true;
322
	}
323
324
	public function isEnabled(): bool {
325
		return $this->enabled;
326
	}
327
328
	public function setEnabled(bool $bool): void {
329
		if (!$this->isNew && $this->enabled === $bool) {
330
			return;
331
		}
332
		$this->enabled = $bool;
333
		$this->hasChanged = true;
334
	}
335
336
	public function isIgnoreStats(): bool {
337
		return $this->ignoreStats;
338
	}
339
340
	public function setIgnoreStats(bool $bool): void {
341
		if (!$this->isNew && $this->ignoreStats === $bool) {
342
			return;
343
		}
344
		$this->ignoreStats = $bool;
345
		$this->hasChanged = true;
346
	}
347
348
	public function getAllianceMaxPlayers(): int {
349
		return $this->allianceMaxPlayers;
350
	}
351
352
	public function setAllianceMaxPlayers(int $int): void {
353
		if (!$this->isNew && $this->allianceMaxPlayers === $int) {
354
			return;
355
		}
356
		$this->allianceMaxPlayers = $int;
357
		$this->hasChanged = true;
358
	}
359
360
	public function getAllianceMaxVets(): int {
361
		return $this->allianceMaxVets;
362
	}
363
364
	public function setAllianceMaxVets(int $int): void {
365
		if (!$this->isNew && $this->allianceMaxVets === $int) {
366
			return;
367
		}
368
		$this->allianceMaxVets = $int;
369
		$this->hasChanged = true;
370
	}
371
372
	public function getStartingCredits(): int {
373
		return $this->startingCredits;
374
	}
375
376
	public function setStartingCredits(int $int): void {
377
		if (!$this->isNew && $this->startingCredits === $int) {
378
			return;
379
		}
380
		$this->startingCredits = $int;
381
		$this->hasChanged = true;
382
	}
383
384
	public function getTotalPlayers(): int {
385
		if (!isset($this->totalPlayers)) {
386
			$dbResult = $this->db->read('SELECT count(*) FROM player WHERE game_id = ' . $this->db->escapeNumber($this->getGameID()));
387
			$this->totalPlayers = $dbResult->record()->getInt('count(*)');
388
		}
389
		return $this->totalPlayers;
390
	}
391
392
	/**
393
	 * @return array<int, \SmrGalaxy>
394
	 */
395
	public function getGalaxies(): array {
396
		return SmrGalaxy::getGameGalaxies($this->gameID);
397
	}
398
399
	public function getNumberOfGalaxies(): int {
400
		return count($this->getGalaxies());
401
	}
402
403
	public function equals(self $otherGame): bool {
404
		return $otherGame->getGameID() == $this->getGameID();
405
	}
406
407
	// Convenience function for printing the game name with id
408
	public function getDisplayName(): string {
409
		return $this->getName() . ' (' . $this->getGameID() . ')';
410
	}
411
412
	/**
413
	 * Set the starting political relations between races.
414
	 */
415
	public function setStartingRelations(int $relations): void {
416
		if ($relations < MIN_GLOBAL_RELATIONS || $relations > MAX_GLOBAL_RELATIONS) {
417
			throw new Exception('Invalid relations: ' . $relations);
418
		}
419
		foreach (Race::getAllIDs() as $raceID1) {
420
			foreach (Race::getAllIDs() as $raceID2) {
421
				if ($raceID1 == $raceID2) {
422
					// Max relations for a race with itself
423
					$amount = MAX_GLOBAL_RELATIONS;
424
				} elseif ($raceID1 == RACE_NEUTRAL || $raceID2 == RACE_NEUTRAL) {
425
					$amount = 0; //0 relations with neutral
426
				} else {
427
					$amount = $relations;
428
				}
429
				$this->db->replace('race_has_relation', [
430
					'game_id' => $this->db->escapeNumber($this->getGameID()),
431
					'race_id_1' => $this->db->escapeNumber($raceID1),
432
					'race_id_2' => $this->db->escapeNumber($raceID2),
433
					'relation' => $this->db->escapeNumber($amount),
434
				]);
435
			}
436
		}
437
	}
438
439
	/**
440
	 * Get the list of playable Race IDs based on which Racial HQ's
441
	 * are locations in this game.
442
	 *
443
	 * @return array<int>
444
	 */
445
	public function getPlayableRaceIDs(): array {
446
		if (!isset($this->playableRaceIDs)) {
447
			// Get a unique set of HQ's available in game
448
			$dbResult = $this->db->read('SELECT DISTINCT location_type_id
449
				FROM location
450
				WHERE location_type_id > ' . $this->db->escapeNumber(UNDERGROUND) . '
451
					AND location_type_id < ' . $this->db->escapeNumber(FED) . '
452
					AND game_id = ' . $this->db->escapeNumber($this->getGameID()) . '
453
				ORDER BY location_type_id');
454
			$this->playableRaceIDs = [];
455
			foreach ($dbResult->records() as $dbRecord) {
456
				$this->playableRaceIDs[] = $dbRecord->getInt('location_type_id') - GOVERNMENT;
457
			}
458
		}
459
		return $this->playableRaceIDs;
460
	}
461
462
	/**
463
	 * Returns the time (in seconds) until restricted ships are unlocked.
464
	 */
465
	public function timeUntilShipUnlock(): int {
466
		return $this->getStartTime() + TIME_FOR_RAIDER_UNLOCK - Epoch::time();
467
	}
468
469
}
470