$min) { return true; } } else { if ($var > $min && $var <= $max) { return true; } } return false; } /** * Бонус 1 очко выше 10: +5% профильного урона. * Штраф 1 очко ниже 10: -10% профильного урона. * @param int $stat * @return int */ private function statDamageModificator(int $stat): int { $bonus = ($stat - self::BASE_STAT) * 5; if ($bonus < 0) { $bonus *= 2; } return $bonus; } /** * Бонус 1 очко выше 10: +1% шанса крита. * Штраф 1 очко ниже 10: -2% шанса крита. * @param int $stat * @return int */ private function statCriticalsModificator(int $stat): int { $bonus = ($stat - self::BASE_STAT); if ($bonus < 0) { $bonus *= 2; } return $bonus; } /** * Рассчёт типа удара в зависимости от параметров. * Значения проверок смещаются в зависимости от разницы двух параметров. * @param int $player_accuracy * @param int $enemy_evasion * @param int $player_criticals * @return string */ protected function attack(int $player_accuracy, int $enemy_evasion, int $player_criticals): string { $result = ''; $d100 = mt_rand(0, 100); $mf = $player_accuracy - $enemy_evasion; if ($this->rangeCheck($d100, min(1, 0 - $mf), 15 - $mf)) { $result = 'selfharm'; } if ($this->rangeCheck($d100, min(1, 16 - $mf), 50 - $mf)) { $result = 'miss'; } if ($this->rangeCheck($d100, 51 - $mf, 100 - $mf - $player_criticals)) { $result = 'hit'; } if ($this->rangeCheck($d100, 101 - $mf - $player_criticals)) { $result = 'crit'; } return $result; } /** * Рассчёт базового урона до применения модификаторов. * Если урон меньше равно нулю, получается удар в 20% от минималки. * Учитывая удар кулака 1-2, значения прибавляются к $min и $max в формуле. * @param int $min минимальный урон * @param int $max максимальный урон * @param int $enemyDefence защита противника * @return int */ protected function baseDamage(int $min, int $max, int $enemyDefence): int { return max(mt_rand(1 + $min, 2 + $max) - $enemyDefence, intval(round((1 + $min) * (20 / 100)))); } /** * @param object $attacker [str,dex,intu,accuracy,crit,min_dmg,max_dmg] * @param object $defender [evasion,defence] * @param int $type тип удара: ближний бой (1), дальний бой (2). * @return object */ public function hit(object $attacker, object $defender, int $type): object { $result = (object)[]; $attackType = $this->attack($attacker->accuracy, $defender->evasion, $attacker->criticals + $this->statCriticalsModificator($attacker->intuition)); if ($attackType === 'miss') { $result->damage = 0; $result->attackType = $attackType; return $result; } $damage = $this->baseDamage($attacker->min_damage, $attacker->max_damage, $defender->defence); $critDamageMultiplier = $attackType === 'crit' ? 2 : 1; if ($type === 1) { $damage = $damage * ($this->statDamageModificator($attacker->strength) / 100); } if ($type === 2) { $damage = $damage * ($this->statDamageModificator($attacker->dexterity) / 100); } $damage = $damage * $critDamageMultiplier; $result->damage = $damage; $result->attackType = $attackType; return $result; } }