Merge remote-tracking branch 'origin/dev-arena' into dev-arena

This commit is contained in:
lopar 2022-02-12 20:17:51 +02:00
commit 1bf7a40fe9

View File

@ -0,0 +1,127 @@
<?php
namespace Battles\Fight;
class PhysicalDamage
{
const BASE_STAT = 10;
private function rangeCheck(int $var, int $min, int $max = null): bool
{
if (is_null($max)) {
if ($var > $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;
}
}