diff --git a/classes/Battles/Fight/PhysicalDamage.php b/classes/Battles/Fight/PhysicalDamage.php new file mode 100644 index 0000000..b67e7e9 --- /dev/null +++ b/classes/Battles/Fight/PhysicalDamage.php @@ -0,0 +1,127 @@ + $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; + } +} \ No newline at end of file