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

Issues (412)

src/lib/Default/SmrEnhancedWeaponEvent.php (1 issue)

Labels
Severity
1
<?php declare(strict_types=1);
2
3
use Smr\Database;
4
use Smr\DatabaseRecord;
5
use Smr\Epoch;
6
7
/**
8
 * Defines enhanced weapon sale events for weapon shops.
9
 */
10
class SmrEnhancedWeaponEvent {
11
12
	protected const GRACE_PERIOD = 3600; // 1 hour
13
	protected const DURATION = 21600; // 6 hours
14
15
	protected readonly SmrWeapon $weapon;
16
17
	/**
18
	 * Return all the valid events for the given location in a sector.
19
	 *
20
	 * @return array<self>
21
	 */
22
	public static function getShopEvents(int $gameID, int $sectorID, int $locationID): array {
23
		$events = [];
24
		$db = Database::getInstance();
25
		$dbResult = $db->read('SELECT * FROM location_sells_special WHERE sector_id = ' . $db->escapeNumber($sectorID) . ' AND location_type_id = ' . $db->escapeNumber($locationID) . ' AND game_id = ' . $db->escapeNumber($gameID) . ' AND expires > ' . $db->escapeNumber(Epoch::time()));
26
		foreach ($dbResult->records() as $dbRecord) {
27
			$events[] = self::getEventFromDatabase($dbRecord);
28
		}
29
		return $events;
30
	}
31
32
	/**
33
	 * Get the most recent event.
34
	 *
35
	 * This function also does the work of cleaning up expired events and
36
	 * creating new ones when necessary.
37
	 */
38
	public static function getLatestEvent(int $gameID): self {
39
		// First, remove any expired events from the database
40
		$db = Database::getInstance();
41
		$db->write('DELETE FROM location_sells_special WHERE expires < ' . $db->escapeNumber(Epoch::time()));
42
43
		// Next, check if an existing event can be advertised
44
		$db = Database::getInstance();
45
		$dbResult = $db->read('SELECT * FROM location_sells_special WHERE game_id = ' . $db->escapeNumber($gameID) . ' ORDER BY expires DESC LIMIT 1');
46
		if ($dbResult->hasRecord()) {
47
			$event = self::getEventFromDatabase($dbResult->record());
48
			// Don't advertise if the event expires within one GRACE_PERIOD
49
			if (Epoch::time() < $event->getExpireTime() - self::GRACE_PERIOD) {
50
				return $event;
51
			}
52
		}
53
54
		// Otherwise, create a new event
55
		return self::createEvent($gameID);
56
	}
57
58
	/**
59
	 * Create a new event.
60
	 *
61
	 * Events are generated randomly across all weapon types available in the
62
	 * game, and then randomly across locations that offer that weapon type.
63
	 */
64
	private static function createEvent(int $gameID): self {
65
		// First, randomly select a weapon type to enhance
66
		$weaponTypeID = array_rand(SmrWeaponType::getAllSoldWeaponTypes($gameID));
67
68
		$db = Database::getInstance();
69
		$dbResult = $db->read('SELECT location_type_id, sector_id FROM location JOIN location_sells_weapons USING (location_type_id) WHERE game_id = ' . $db->escapeNumber($gameID) . ' AND weapon_type_id = ' . $db->escapeNumber($weaponTypeID) . ' ORDER BY RAND() LIMIT 1');
70
		$dbRecord = $dbResult->record();
71
		$locationTypeID = $dbRecord->getInt('location_type_id');
72
		$sectorID = $dbRecord->getInt('sector_id');
73
74
		$expires = Epoch::time() + self::DURATION;
75
76
		// Determine which bonuses the weapon should have
77
		$random = rand(1, 100);
78
		if ($random <= 40) {
79
			$bonusAccuracy = false;
80
			$bonusDamage = true;
81
		} elseif ($random <= 80) {
82
			$bonusAccuracy = true;
83
			$bonusDamage = false;
84
		} else {
85
			$bonusAccuracy = true;
86
			$bonusDamage = true;
87
		}
88
89
		// We replace instead of insert in the very unlikely case that we have
90
		// selected the same configuration twice in a row.
91
		$db->replace('location_sells_special', [
92
			'game_id' => $db->escapeNumber($gameID),
93
			'sector_id' => $db->escapeNumber($sectorID),
94
			'location_type_id' => $db->escapeNumber($locationTypeID),
95
			'weapon_type_id' => $db->escapeNumber($weaponTypeID),
96
			'expires' => $db->escapeNumber($expires),
97
			'bonus_accuracy' => $db->escapeBoolean($bonusAccuracy),
98
			'bonus_damage' => $db->escapeBoolean($bonusDamage),
99
		]);
100
101
		return new self($gameID, $weaponTypeID, $locationTypeID, $sectorID, $expires, $bonusAccuracy, $bonusDamage);
102
	}
103
104
	/**
105
	 * Convenience function to instantiate an event from a query result.
106
	 */
107
	private static function getEventFromDatabase(DatabaseRecord $dbRecord): self {
108
		return new self(
109
			$dbRecord->getInt('game_id'),
110
			$dbRecord->getInt('weapon_type_id'),
111
			$dbRecord->getInt('location_type_id'),
112
			$dbRecord->getInt('sector_id'),
113
			$dbRecord->getInt('expires'),
114
			$dbRecord->getBoolean('bonus_accuracy'),
115
			$dbRecord->getBoolean('bonus_damage'),
116
		);
117
	}
118
119
	protected function __construct(
120
		protected readonly int $gameID,
121
		protected readonly int $weaponTypeID,
122
		protected readonly int $locationTypeID,
123
		protected readonly int $sectorID,
124
		protected readonly int $expires,
125
		bool $bonusAccuracy,
126
		bool $bonusDamage
127
	) {
128
		$this->weapon = SmrWeapon::getWeapon($weaponTypeID);
0 ignored issues
show
The property weapon is declared read-only in SmrEnhancedWeaponEvent.
Loading history...
129
		$this->weapon->setBonusDamage($bonusDamage);
130
		$this->weapon->setBonusAccuracy($bonusAccuracy);
131
	}
132
133
	public function getSectorID(): int {
134
		return $this->sectorID;
135
	}
136
137
	public function getExpireTime(): int {
138
		return $this->expires;
139
	}
140
141
	public function getWeapon(): SmrWeapon {
142
		return $this->weapon;
143
	}
144
145
	/**
146
	 * Returns the amount of time left in the event as a percent of the
147
	 * total duration of the event.
148
	 */
149
	public function getDurationRemainingPercent(): float {
150
		return max(0, min(100, ($this->expires - Epoch::time()) / self::DURATION * 100));
151
	}
152
153
}
154