We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.
| Total Complexity | 66 | 
| Total Lines | 346 | 
| Duplicated Lines | 0 % | 
| Changes | 3 | ||
| Bugs | 0 | Features | 0 | 
Complex classes like SmrWeapon often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use SmrWeapon, and based on these observations, apply Extract Interface, too.
| 1 | <?php declare(strict_types=1);  | 
            ||
| 6 | class SmrWeapon extends AbstractSmrCombatWeapon { | 
            ||
| 7 | |||
| 8 | const BONUS_DAMAGE = 1.05; // multiplicative bonus  | 
            ||
| 9 | const BONUS_ACCURACY = 3; // additive bonus  | 
            ||
| 10 | |||
| 11 | protected int $weaponTypeID;  | 
            ||
| 12 | protected SmrWeaponType $weaponType;  | 
            ||
| 13 | protected bool $bonusAccuracy = false; // default  | 
            ||
| 14 | protected bool $bonusDamage = false; // default  | 
            ||
| 15 | protected $damageRollover = false; // fixed for all SmrWeapons  | 
            ||
| 16 | |||
| 17 | 	public static function getWeapon(int $weaponTypeID, SmrMySqlDatabase $db = null) : SmrWeapon { | 
            ||
| 19 | }  | 
            ||
| 20 | |||
| 21 | 	protected function __construct(int $weaponTypeID, SmrMySqlDatabase $db = null) { | 
            ||
| 22 | $this->weaponType = SmrWeaponType::getWeaponType($weaponTypeID, $db);  | 
            ||
| 23 | $this->weaponTypeID = $weaponTypeID;  | 
            ||
| 24 | $this->name = $this->weaponType->getName();  | 
            ||
| 25 | $this->raceID = $this->weaponType->getRaceID();  | 
            ||
| 26 | }  | 
            ||
| 27 | |||
| 28 | 	public function hasBonusAccuracy() : bool { | 
            ||
| 29 | return $this->bonusAccuracy;  | 
            ||
| 30 | }  | 
            ||
| 31 | |||
| 32 | 	public function setBonusAccuracy(bool $bonusAccuracy) { | 
            ||
| 33 | $this->bonusAccuracy = $bonusAccuracy;  | 
            ||
| 34 | }  | 
            ||
| 35 | |||
| 36 | 	public function hasBonusDamage() : bool { | 
            ||
| 37 | return $this->bonusDamage;  | 
            ||
| 38 | }  | 
            ||
| 39 | |||
| 40 | 	public function setBonusDamage(bool $bonusDamage) { | 
            ||
| 41 | $this->bonusDamage = $bonusDamage;  | 
            ||
| 42 | }  | 
            ||
| 43 | |||
| 44 | 	private function hasEnhancements() : bool { | 
            ||
| 45 | return $this->getNumberOfEnhancements() > 0;  | 
            ||
| 46 | }  | 
            ||
| 47 | |||
| 48 | 	private function getNumberOfEnhancements() : int { | 
            ||
| 49 | return (int)$this->bonusAccuracy + (int)$this->bonusDamage;  | 
            ||
| 50 | }  | 
            ||
| 51 | |||
| 52 | /**  | 
            ||
| 53 | * (Override) Return weapon name suitable for HTML display.  | 
            ||
| 54 | * The name is displayed in green with pluses if enhancements are present.  | 
            ||
| 55 | */  | 
            ||
| 56 | 	public function getName() : string { | 
            ||
| 57 | 		if ($this->hasEnhancements()) { | 
            ||
| 58 | 			return '<span class="green">' . $this->name . str_repeat('+', $this->getNumberOfEnhancements()) . '</span>'; | 
            ||
| 59 | }  | 
            ||
| 60 | return $this->name;  | 
            ||
| 61 | }  | 
            ||
| 62 | |||
| 63 | /**  | 
            ||
| 64 | * (Override) Return the weapon base accuracy.  | 
            ||
| 65 | */  | 
            ||
| 66 | 	public function getBaseAccuracy() : int { | 
            ||
| 67 | 		if ($this->bonusAccuracy) { | 
            ||
| 68 | return $this->weaponType->getAccuracy() + self::BONUS_ACCURACY;  | 
            ||
| 69 | }  | 
            ||
| 70 | return $this->weaponType->getAccuracy();  | 
            ||
| 71 | }  | 
            ||
| 72 | |||
| 73 | /**  | 
            ||
| 74 | * (Override) Return the weapon shield damage.  | 
            ||
| 75 | */  | 
            ||
| 76 | 	public function getShieldDamage() : int { | 
            ||
| 77 | 		if ($this->bonusDamage) { | 
            ||
| 78 | return IFloor($this->weaponType->getShieldDamage() * self::BONUS_DAMAGE);  | 
            ||
| 79 | }  | 
            ||
| 80 | return $this->weaponType->getShieldDamage();  | 
            ||
| 81 | }  | 
            ||
| 82 | |||
| 83 | /**  | 
            ||
| 84 | * (Override) Return the weapon armour damage.  | 
            ||
| 85 | */  | 
            ||
| 86 | 	public function getArmourDamage() : int { | 
            ||
| 87 | 		if ($this->bonusDamage) { | 
            ||
| 88 | return IFloor($this->weaponType->getArmourDamage() * self::BONUS_DAMAGE);  | 
            ||
| 89 | }  | 
            ||
| 90 | return $this->weaponType->getArmourDamage();  | 
            ||
| 91 | }  | 
            ||
| 92 | |||
| 93 | /**  | 
            ||
| 94 | * (Override) Return the max weapon damage possible in a single round.  | 
            ||
| 95 | */  | 
            ||
| 96 | 	public function getMaxDamage() : int { | 
            ||
| 97 | return max($this->getShieldDamage(), $this->getArmourDamage());  | 
            ||
| 98 | }  | 
            ||
| 99 | |||
| 100 | 	public function getBuyHREF(SmrLocation $location) { | 
            ||
| 101 | 		$container = create_container('shop_weapon_processing.php'); | 
            ||
| 102 | $container['LocationID'] = $location->getTypeID();  | 
            ||
| 103 | $container['Weapon'] = $this;  | 
            ||
| 104 | return SmrSession::getNewHREF($container);  | 
            ||
| 105 | }  | 
            ||
| 106 | |||
| 107 | 	public function getSellHREF(SmrLocation $location, $orderID) { | 
            ||
| 108 | 		$container = create_container('shop_weapon_processing.php'); | 
            ||
| 109 | $container['LocationID'] = $location->getTypeID();  | 
            ||
| 110 | $container['Weapon'] = $this;  | 
            ||
| 111 | $container['OrderID'] = $orderID;  | 
            ||
| 112 | return SmrSession::getNewHREF($container);  | 
            ||
| 113 | }  | 
            ||
| 114 | |||
| 115 | 	public function getWeaponTypeID() { | 
            ||
| 116 | return $this->weaponTypeID;  | 
            ||
| 117 | }  | 
            ||
| 118 | |||
| 119 | /**  | 
            ||
| 120 | * Weapon cost is increased by 100% for each enhancement present  | 
            ||
| 121 | */  | 
            ||
| 122 | 	public function getCost() { | 
            ||
| 123 | return $this->weaponType->getCost() * (1 + $this->getNumberOfEnhancements());  | 
            ||
| 124 | }  | 
            ||
| 125 | |||
| 126 | 	public function getPowerLevel() { | 
            ||
| 127 | return $this->weaponType->getPowerLevel();  | 
            ||
| 128 | }  | 
            ||
| 129 | |||
| 130 | 	public function getBuyerRestriction() { | 
            ||
| 131 | return $this->weaponType->getBuyerRestriction();  | 
            ||
| 132 | }  | 
            ||
| 133 | |||
| 134 | 	protected function getWeightedRandomForPlayer(AbstractSmrPlayer $player) { | 
            ||
| 135 | return WeightedRandom::getWeightedRandomForPlayer($player, 'Weapon', $this->getWeaponTypeID());  | 
            ||
| 136 | }  | 
            ||
| 137 | |||
| 138 | /**  | 
            ||
| 139 | * Given $weaponAccuracy as a percent, decide if the weapon hits.  | 
            ||
| 140 | */  | 
            ||
| 141 | 	protected function checkHit(AbstractSmrPlayer $player, $weaponAccuracy) : bool { | 
            ||
| 142 | // Skip weighting factor for absolute hits/misses.  | 
            ||
| 143 | 		if ($weaponAccuracy >= 100) { | 
            ||
| 144 | return true;  | 
            ||
| 145 | 		} elseif ($weaponAccuracy <= 0) { | 
            ||
| 146 | return false;  | 
            ||
| 147 | }  | 
            ||
| 148 | return $this->getWeightedRandomForPlayer($player)->flipWeightedCoin($weaponAccuracy);  | 
            ||
| 149 | }  | 
            ||
| 150 | |||
| 151 | 	public static function getPlayerLevelAccuracyMod(AbstractSmrPlayer $player) { | 
            ||
| 152 | return ($player->getLevelID() * $player->getLevelID() / 60 + $player->getLevelID() / 2 + 2) / 100;  | 
            ||
| 153 | }  | 
            ||
| 154 | |||
| 155 | 	public function getModifiedAccuracy(AbstractSmrPlayer $weaponPlayer) { | 
            ||
| 156 | $modifiedAccuracy = $this->getBaseAccuracy();  | 
            ||
| 157 | $modifiedAccuracy += $this->getBaseAccuracy() * self::getPlayerLevelAccuracyMod($weaponPlayer);  | 
            ||
| 158 | return $modifiedAccuracy;  | 
            ||
| 159 | }  | 
            ||
| 160 | |||
| 161 | 	public function getModifiedAccuracyAgainstForces(AbstractSmrPlayer $weaponPlayer, SmrForce $forces) { | 
            ||
| 
                                                                                                    
                        
                         | 
                |||
| 162 | $modifiedAccuracy = $this->getModifiedAccuracy($weaponPlayer);  | 
            ||
| 163 | return $modifiedAccuracy;  | 
            ||
| 164 | }  | 
            ||
| 165 | |||
| 166 | 	public function getModifiedAccuracyAgainstPort(AbstractSmrPlayer $weaponPlayer, SmrPort $port) { | 
            ||
| 167 | $modifiedAccuracy = $this->getModifiedAccuracy($weaponPlayer);  | 
            ||
| 168 | $modifiedAccuracy -= $this->getBaseAccuracy() * $port->getLevel() / 50;  | 
            ||
| 169 | return $modifiedAccuracy;  | 
            ||
| 170 | }  | 
            ||
| 171 | |||
| 172 | 	public function getModifiedAccuracyAgainstPlanet(AbstractSmrPlayer $weaponPlayer, SmrPlanet $planet) { | 
            ||
| 173 | $modifiedAccuracy = $this->getModifiedAccuracy($weaponPlayer);  | 
            ||
| 174 | $modifiedAccuracy -= $this->getBaseAccuracy() * $planet->getLevel() / 350;  | 
            ||
| 175 | return $modifiedAccuracy;  | 
            ||
| 176 | }  | 
            ||
| 177 | |||
| 178 | 	public function getModifiedAccuracyAgainstPlayer(AbstractSmrPlayer $weaponPlayer, AbstractSmrPlayer $targetPlayer) { | 
            ||
| 179 | $modifiedAccuracy = $this->getModifiedAccuracy($weaponPlayer);  | 
            ||
| 180 | $modifiedAccuracy -= $this->getBaseAccuracy() * self::getPlayerLevelAccuracyMod($targetPlayer) / 2;  | 
            ||
| 181 | |||
| 182 | $weaponShip = $weaponPlayer->getShip();  | 
            ||
| 183 | $targetShip = $targetPlayer->getShip();  | 
            ||
| 184 | $mrDiff = $targetShip->getMR() - $weaponShip->getMR();  | 
            ||
| 185 | 		if ($mrDiff > 0) { | 
            ||
| 186 | $modifiedAccuracy -= $this->getBaseAccuracy() * ($mrDiff / MR_FACTOR) / 100;  | 
            ||
| 187 | }  | 
            ||
| 188 | |||
| 189 | return $modifiedAccuracy;  | 
            ||
| 190 | }  | 
            ||
| 191 | |||
| 192 | 	public function getModifiedPortAccuracy(SmrPort $port) { | 
            ||
| 193 | $modifiedAccuracy = $this->getBaseAccuracy();  | 
            ||
| 194 | return $modifiedAccuracy;  | 
            ||
| 195 | }  | 
            ||
| 196 | |||
| 197 | 	public function getModifiedPortAccuracyAgainstPlayer(SmrPort $port, AbstractSmrPlayer $targetPlayer) { | 
            ||
| 198 | $modifiedAccuracy = $this->getModifiedPortAccuracy($port);  | 
            ||
| 199 | $modifiedAccuracy -= $this->getBaseAccuracy() * self::getPlayerLevelAccuracyMod($targetPlayer);  | 
            ||
| 200 | return $modifiedAccuracy;  | 
            ||
| 201 | }  | 
            ||
| 202 | |||
| 203 | 	public function getModifiedPlanetAccuracy(SmrPlanet $planet) { | 
            ||
| 204 | $modifiedAccuracy = $this->getBaseAccuracy();  | 
            ||
| 205 | 		if ($this->getWeaponTypeID() == WEAPON_PLANET_TURRET) { | 
            ||
| 206 | $modifiedAccuracy += $planet->getLevel() / 2;  | 
            ||
| 207 | 		} else { | 
            ||
| 208 | $modifiedAccuracy += $planet->getAccuracyBonus();  | 
            ||
| 209 | }  | 
            ||
| 210 | return $modifiedAccuracy;  | 
            ||
| 211 | }  | 
            ||
| 212 | |||
| 213 | 	public function getModifiedPlanetAccuracyAgainstPlayer(SmrPlanet $planet, AbstractSmrPlayer $targetPlayer) { | 
            ||
| 214 | $modifiedAccuracy = $this->getModifiedPlanetAccuracy($planet);  | 
            ||
| 215 | $modifiedAccuracy -= $this->getBaseAccuracy() * self::getPlayerLevelAccuracyMod($targetPlayer);  | 
            ||
| 216 | return $modifiedAccuracy;  | 
            ||
| 217 | }  | 
            ||
| 218 | |||
| 219 | 	public function &getModifiedDamage() { | 
            ||
| 220 | $damage = $this->getDamage();  | 
            ||
| 221 | return $damage;  | 
            ||
| 222 | }  | 
            ||
| 223 | |||
| 224 | 	public function &getModifiedDamageAgainstForces(AbstractSmrPlayer $weaponPlayer, SmrForce $forces) { | 
            ||
| 225 | 		if (!$this->canShootForces()) { | 
            ||
| 226 | // If we can't shoot forces then just return a damageless array and don't waste resources calculated any damage mods.  | 
            ||
| 227 | 			return array('MaxDamage' => 0, 'Shield' => 0, 'Armour' => 0, 'Rollover' => $this->isDamageRollover()); | 
            ||
| 228 | }  | 
            ||
| 229 | $damage =& $this->getModifiedDamage();  | 
            ||
| 230 | return $damage;  | 
            ||
| 231 | }  | 
            ||
| 232 | |||
| 233 | 	public function &getModifiedDamageAgainstPort(AbstractSmrPlayer $weaponPlayer, SmrPort $port) { | 
            ||
| 234 | 		if (!$this->canShootPorts()) { | 
            ||
| 235 | // If we can't shoot forces then just return a damageless array and don't waste resources calculated any damage mods.  | 
            ||
| 236 | 			return array('MaxDamage' => 0, 'Shield' => 0, 'Armour' => 0, 'Rollover' => $this->isDamageRollover()); | 
            ||
| 237 | }  | 
            ||
| 238 | $damage =& $this->getModifiedDamage();  | 
            ||
| 239 | return $damage;  | 
            ||
| 240 | }  | 
            ||
| 241 | |||
| 242 | 	public function &getModifiedDamageAgainstPlanet(AbstractSmrPlayer $weaponPlayer, SmrPlanet $planet) { | 
            ||
| 255 | }  | 
            ||
| 256 | |||
| 257 | 	public function &getModifiedForceDamageAgainstPlayer(SmrForce $forces, AbstractSmrPlayer $targetPlayer) { | 
            ||
| 258 | 		$return = array('MaxDamage' => 0, 'Shield' => 0, 'Armour' => 0, 'Rollover' => $this->isDamageRollover()); | 
            ||
| 259 | return $return;  | 
            ||
| 260 | }  | 
            ||
| 261 | |||
| 262 | 	public function &getModifiedDamageAgainstPlayer(AbstractSmrPlayer $weaponPlayer, AbstractSmrPlayer $targetPlayer) { | 
            ||
| 263 | 		if (!$this->canShootTraders()) { // If we can't shoot traders then just return a damageless array and don't waste resources calculating any damage mods. | 
            ||
| 264 | 			$return = array('MaxDamage' => 0, 'Shield' => 0, 'Armour' => 0, 'Rollover' => $this->isDamageRollover()); | 
            ||
| 265 | return $return;  | 
            ||
| 266 | }  | 
            ||
| 267 | $damage =& $this->getModifiedDamage();  | 
            ||
| 268 | return $damage;  | 
            ||
| 269 | }  | 
            ||
| 270 | |||
| 271 | 	public function &getModifiedPortDamageAgainstPlayer(SmrPort $port, AbstractSmrPlayer $targetPlayer) { | 
            ||
| 272 | 		if (!$this->canShootTraders()) { // If we can't shoot traders then just return a damageless array and don't waste resources calculating any damage mods. | 
            ||
| 273 | 			$return = array('MaxDamage' => 0, 'Shield' => 0, 'Armour' => 0, 'Rollover' => $this->isDamageRollover()); | 
            ||
| 274 | return $return;  | 
            ||
| 275 | }  | 
            ||
| 276 | $damage = $this->getDamage();  | 
            ||
| 277 | return $damage;  | 
            ||
| 278 | }  | 
            ||
| 279 | |||
| 280 | 	public function &getModifiedPlanetDamageAgainstPlayer(SmrPlanet $planet, AbstractSmrPlayer $targetPlayer) { | 
            ||
| 281 | 		if (!$this->canShootTraders()) { // If we can't shoot traders then just return a damageless array and don't waste resources calculating any damage mods. | 
            ||
| 282 | 			$return = array('MaxDamage' => 0, 'Shield' => 0, 'Armour' => 0, 'Rollover' => $this->isDamageRollover()); | 
            ||
| 283 | return $return;  | 
            ||
| 284 | }  | 
            ||
| 285 | $damage = $this->getDamage();  | 
            ||
| 286 | return $damage;  | 
            ||
| 287 | }  | 
            ||
| 288 | |||
| 289 | 	public function &shootForces(AbstractSmrPlayer $weaponPlayer, SmrForce $forces) { | 
            ||
| 290 | 		$return = array('Weapon' => $this, 'TargetForces' => $forces, 'Hit' => false); | 
            ||
| 291 | $modifiedAccuracy = $this->getModifiedAccuracyAgainstForces($weaponPlayer, $forces);  | 
            ||
| 292 | 		if ($this->checkHit($weaponPlayer, $modifiedAccuracy)) { | 
            ||
| 293 | $return['Hit'] = true;  | 
            ||
| 294 | return $this->doPlayerDamageToForce($return, $weaponPlayer, $forces);  | 
            ||
| 295 | }  | 
            ||
| 296 | return $return;  | 
            ||
| 297 | }  | 
            ||
| 298 | |||
| 299 | 	public function &shootPort(AbstractSmrPlayer $weaponPlayer, SmrPort $port) { | 
            ||
| 300 | 		$return = array('Weapon' => $this, 'TargetPort' => $port, 'Hit' => false); | 
            ||
| 301 | $modifiedAccuracy = $this->getModifiedAccuracyAgainstPort($weaponPlayer, $port);  | 
            ||
| 302 | 		if ($this->checkHit($weaponPlayer, $modifiedAccuracy)) { | 
            ||
| 303 | $return['Hit'] = true;  | 
            ||
| 304 | return $this->doPlayerDamageToPort($return, $weaponPlayer, $port);  | 
            ||
| 305 | }  | 
            ||
| 306 | return $return;  | 
            ||
| 307 | }  | 
            ||
| 308 | |||
| 309 | 	public function &shootPlanet(AbstractSmrPlayer $weaponPlayer, SmrPlanet $planet, $delayed) { | 
            ||
| 310 | 		$return = array('Weapon' => $this, 'TargetPlanet' => $planet, 'Hit' => false); | 
            ||
| 311 | $modifiedAccuracy = $this->getModifiedAccuracyAgainstPlanet($weaponPlayer, $planet);  | 
            ||
| 312 | 		if ($this->checkHit($weaponPlayer, $modifiedAccuracy)) { | 
            ||
| 313 | $return['Hit'] = true;  | 
            ||
| 314 | return $this->doPlayerDamageToPlanet($return, $weaponPlayer, $planet, $delayed);  | 
            ||
| 315 | }  | 
            ||
| 316 | return $return;  | 
            ||
| 317 | }  | 
            ||
| 318 | |||
| 319 | 	public function &shootPlayer(AbstractSmrPlayer $weaponPlayer, AbstractSmrPlayer $targetPlayer) { | 
            ||
| 320 | 		$return = array('Weapon' => $this, 'TargetPlayer' => $targetPlayer, 'Hit' => false); | 
            ||
| 321 | $modifiedAccuracy = $this->getModifiedAccuracyAgainstPlayer($weaponPlayer, $targetPlayer);  | 
            ||
| 322 | 		if ($this->checkHit($weaponPlayer, $modifiedAccuracy)) { | 
            ||
| 323 | $return['Hit'] = true;  | 
            ||
| 324 | return $this->doPlayerDamageToPlayer($return, $weaponPlayer, $targetPlayer);  | 
            ||
| 325 | }  | 
            ||
| 326 | return $return;  | 
            ||
| 327 | }  | 
            ||
| 328 | |||
| 329 | 	public function &shootPlayerAsForce(SmrForce $forces, AbstractSmrPlayer $targetPlayer) { | 
            ||
| 330 | 		$return = array('Weapon' => $this, 'TargetPlayer' => $targetPlayer, 'Hit' => false); | 
            ||
| 331 | return $return;  | 
            ||
| 332 | }  | 
            ||
| 333 | |||
| 334 | 	public function &shootPlayerAsPort(SmrPort $port, AbstractSmrPlayer $targetPlayer) { | 
            ||
| 335 | 		$return = array('Weapon' => $this, 'TargetPlayer' => $targetPlayer, 'Hit' => false); | 
            ||
| 336 | $modifiedAccuracy = $this->getModifiedPortAccuracyAgainstPlayer($port, $targetPlayer);  | 
            ||
| 337 | 		if ($this->checkHit($targetPlayer, $modifiedAccuracy)) { | 
            ||
| 338 | $return['Hit'] = true;  | 
            ||
| 339 | return $this->doPortDamageToPlayer($return, $port, $targetPlayer);  | 
            ||
| 340 | }  | 
            ||
| 341 | return $return;  | 
            ||
| 342 | }  | 
            ||
| 343 | |||
| 344 | 	public function &shootPlayerAsPlanet(SmrPlanet $planet, AbstractSmrPlayer $targetPlayer) { | 
            ||
| 352 | }  | 
            ||
| 353 | |||
| 354 | }  | 
            ||
| 355 | 
This check looks for parameters that have been defined for a function or method, but which are not used in the method body.