$dragons = array(
'-- Нет --' => array(),
'Great Dragon' => array(
'4' => array('melee' => 459, 'ranged' => 459, 'def' => 459, 'hp' => 45947, 'speed' => 750, 'range' => 1500),
'5' => array('melee' => 747, 'ranged' => 747, 'def' => 747, 'hp' => 74743, 'speed' => 750, 'range' => 1500),
'6' => array('melee' => 1055, 'ranged' => 1055, 'def' => 1055, 'hp' => 105560, 'speed' => 750, 'range' => 1500),
'7' => array('melee' => 1379, 'ranged' => 1379, 'def' => 1379, 'hp' => 137972, 'speed' => 750, 'range' => 1500),
'8' => array('melee' => 1717, 'ranged' => 1717, 'def' => 1717, 'hp' => 171716, 'speed' => 750, 'range' => 1500),
'9' => array('melee' => 2066, 'ranged' => 2066, 'def' => 2066, 'hp' => 206608, 'speed' => 750, 'range' => 1500),
'10' => array('melee' => 2425, 'ranged' => 2425, 'def' => 2425, 'hp' => 242514, 'speed' => 750, 'range' => 1500)),
'Stone Dragon' => array(
'4' => array('melee' => 1836, 'ranged' => 1378, 'def' => 2754, 'hp' => 183788, 'speed' => 650, 'range' => 1700),
'5' => array('melee' => 2988, 'ranged' => 2242, 'def' => 4482, 'hp' => 298972, 'speed' => 650, 'range' => 1700),
'6' => array('melee' => 4220, 'ranged' => 3164, 'def' => 6330, 'hp' => 422240, 'speed' => 650, 'range' => 1700),
'7' => array('melee' => 5516, 'ranged' => 4138, 'def' => 8274, 'hp' => 551888, 'speed' => 650, 'range' => 1700),
'8' => array('melee' => 6868, 'ranged' => 5152, 'def' => 10302, 'hp' => 686864, 'speed' => 650, 'range' => 1700),
'9' => array('melee' => 8264, 'ranged' => 6198, 'def' => 12396, 'hp' => 826432, 'speed' => 650, 'range' => 1700),
'10' => array('melee' => 9700, 'ranged' => 7276, 'def' => 14550, 'hp' => 970056, 'speed' => 650, 'range' => 1700)),
);
$bs = array(
1 => array('melee' => 1, 'ranged' => 0, 'def' => 10, 'hp' => 45, 'speed' => 100, 'range' => 0, 'name' => 'Porter'),
2 => array('melee' => 10, 'ranged' => 0, 'def' => 10, 'hp' => 75, 'speed' => 200, 'range' => 0, 'name' => 'Conscript'),
3 => array('melee' => 5, 'ranged' => 0, 'def' => 5, 'hp' => 10, 'speed' => 3000, 'range' => 0, 'name' => 'Spy'),
4 => array('melee' => 40, 'ranged' => 0, 'def' => 40, 'hp' => 150, 'speed' => 300, 'range' => 0, 'name' => 'Halberdsmen'),
5 => array('melee' => 70, 'ranged' => 0, 'def' => 45, 'hp' => 225, 'speed' => 275, 'range' => 0, 'name' => 'Minotaur'),
6 => array('melee' => 5, 'ranged' => 80, 'def' => 30, 'hp' => 75, 'speed' => 250, 'range' => 1200, 'name' => 'Longbowmen'),
7 => array('melee' => 150, 'ranged' => 0, 'def' => 60, 'hp' => 300, 'speed' => 1000, 'range' => 0, 'name' => 'Swift strike dragon'),
8 => array('melee' => 300, 'ranged' => 0, 'def' => 300, 'hp' => 1500, 'speed' => 750, 'range' => 0, 'name' => 'Battle dragon'),
9 => array('melee' => 5, 'ranged' => 0, 'def' => 200, 'hp' => 750, 'speed' => 150, 'range' => 0, 'name' => 'Armored transport'),
10 => array('melee' => 1000, 'ranged' => 0, 'def' => 400, 'hp' => 4000, 'speed' => 120, 'range' => 0, 'name' => 'Giant'),
11 => array('melee' => 20, 'ranged' => 1200, 'def' => 30, 'hp' => 1500, 'speed' => 50, 'range' => 1500, 'name' => 'Fire Mirror'),
12 => array('melee' => 150, 'ranged' => 0, 'def' => 400, 'hp' => 850, 'speed' => 1000, 'range' => 0, 'name' => 'Pack Dragon'),
13 => array('melee' => 1600, 'ranged' => 800, 'def' => 300, 'hp' => 3000, 'speed' => 500, 'range' => 600, 'name' => 'Fangtooth'),
14 => array('melee' => 650, 'ranged' => 0, 'def' => 900, 'hp' => 15000, 'speed' => 350, 'range' => 0, 'name' => 'Granite Ogre'),
15 => array('melee' => 500, 'ranged' => 2000, 'def' => 150, 'hp' => 1000, 'speed' => 400, 'range' => 1600, 'name' => 'Lava Jaw'),
16 => array('melee' => 700, 'ranged' => 0, 'def' => 200, 'hp' => 2850, 'speed' => 1350, 'range' => 0, 'name' => 'Banshee'),
17 => array('melee' => 1000, 'ranged' => 0, 'def' => 500, 'hp' => 3000, 'speed' => 450, 'range' => 0, 'name' => 'Soul Reaper'),
18 => array('melee' => 900, 'ranged' => 800, 'def' => 225, 'hp' => 3500, 'speed' => 300, 'range' => 700, 'name' => 'Venom Dweller'),
19 => array('melee' => 1500, 'ranged' => 0, 'def' => 200, 'hp' => 5500, 'speed' => 200, 'range' => 0, 'name' => 'Frost Giant'),
20 => array('melee' => 5000, 'ranged' => 0, 'def' => 1500, 'hp' => 7500, 'speed' => 50, 'range' => 0, 'name' => 'Petrified Titan'),
21 => array('melee' => 600, 'ranged' => 400, 'def' => 600, 'hp' => 2000, 'speed' => 1000, 'range' => 1200, 'name' => 'Sand Strider'),
);
$wall_koef = 1.05;
?>
if ($_POST['action'] == 'calc') {
//чтение данных
$att = array(
'f' => array(),
's' => array(),
);
$def = array(
'f' => array(),
's' => array(),
'w' => 0
);
//научка
for($k = 1; $k < 7; $k ++) {
if (!empty($_POST['s' . $k])) {
$value = _num_read('s' . $k);
$att['s'][$k] = $value;
}
if (!empty($_POST['sc' . $k])) {
$value = _num_read('sc' . $k);
$def['s'][$k] = $value;
}
}
//стена
$def['w'] = _num_read('wall') * $wall_koef; //модификатор защиты стенки
$maxRange = 0;
//драконы
if ($_POST['da'] != '-- Нет --' && isset($dragons[$_POST['da']]) && $_POST['da_lev'] + 0 >= 8 && $_POST['da_lev'] + 0 <= 10) {
$att['f'][0] = $dragons[$_POST['da']][$_POST['da_lev'] + 0];
$att['f'][0]['amount'] = 1;
$att['f'][0]['name'] = $_POST['da'];
$maxRange = $att['f'][0]['range'];
}
if ($_POST['dd'] != '-- Нет --' && isset($dragons[$_POST['dd']]) && $_POST['dd_lev'] + 0 >= 8 && $_POST['dd_lev'] + 0 <= 10) {
$def['f'][0] = $dragons[$_POST['dd']][$_POST['dd_lev'] + 0];
$def['f'][0]['amount'] = 1;
$def['f'][0]['name'] = $_POST['dd'];
// $maxRange = max($def['f'][0]['range'], $maxRange);
}
//отряды
for($k = 1; $k < 22; $k ++) {
if (!empty($_POST['p' . $k])) {
$value = _num_read('p' . $k);
if ($value > 0) {
$att['f'][$k] = $bs[$k];
$att['f'][$k]['amount'] = $value;
$att['f'][$k]['range'] *= 1 + $att['s'][1] * 0.05; //WC
$att['f'][$k]['ranged'] *= 1 + $att['s'][2] * 0.05; //MET
$att['f'][$k]['melee'] *= 1 + $att['s'][2] * 0.05; //MET
$att['f'][$k]['def'] *= 1 + $att['s'][2] * 0.05; //MET
$att['f'][$k]['hp'] *= 1 + $att['s'][3] * 0.05; //MED
$att['f'][$k]['speed'] *= 1 + $att['s'][5] * 0.05 //RD
+ ($k == 7 || $k == 8 ? $att['s'][4] * 0.05 : 0); //DRAG
if ($maxRange < $att['f'][$k]['range']) $maxRange = $att['f'][$k]['range'];
}
}
if (!empty($_POST['r' . $k])) {
$value = _num_read('r' . $k);
if ($value > 0) {
$def['f'][$k] = $bs[$k];
$def['f'][$k]['amount'] = $value;
$def['f'][$k]['range'] *= 1 + $def['s'][1] * 0.05; //WC
$def['f'][$k]['ranged'] *= 1 + $def['s'][2] * 0.05; //MET
$def['f'][$k]['melee'] *= 1 + $def['s'][2] * 0.05; //MET
$def['f'][$k]['def'] *= 1 + $def['s'][2] * 0.05; //MET
$def['f'][$k]['hp'] *= 1 + $def['s'][3] * 0.05; //MED
$def['f'][$k]['speed'] *= 1 + $def['s'][5] * 0.05 //RD
+ ($k == 7 || $k == 8 ? $def['s'][4] * 0.05 : 0); //DRAG
// if ($maxRange < $def['f'][$k]['range']) $maxRange = $def['f'][$k]['range'];
}
}
}
$len = rand(350, 500) + $maxRange; //вообще то от 325 до 550
//расчет раундов и вывод информации по итерациям
$DOA = new DAO_calc($att, $def, $len);
echo "Обратите внимание, что некоторые детали боя зависят от случайных факторов (от генератора случаных чисел - RNG).
Потому стоит несколько раз прогонять одни и те же данные через расчет, чтобы поглядеть возможные варианты исхода боя.
Перед боем (Before fight)
";
echo $DOA->show();
while ($DOA -> iteration()) {
echo "Раунд (Round) № " . $DOA->n_inter . '
';
echo $DOA->show();
}
}
function _num_read($name) {
if (!empty($_POST[$name])) {
return floor(abs($_POST[$name] + 0));
}
return 0;
}
/* класс для расчета раундов боя */
class DAO_calc {
var $att, $def;
var $n_inter = 0;
function DAO_calc($att, $def, $range) {
uasort($att['f'], 'DAO_calc::speed_buble');
$this->att = $att;
uasort($def['f'], 'DAO_calc::speed_buble');
$this->def = $def;
foreach($this->att['f'] as $k => $v) {
$this->att['f'][$k]['pos'] = 0;
//общее число хитов и брони
$this->att['f'][$k]['hp-amount'] = $v['amount'] * $v['hp'];
$this->att['f'][$k]['arm-amount'] = $v['amount'] * $v['def'];
}
foreach($this->def['f'] as $k => $v) {
$this->def['f'][$k]['pos'] = $range;
//общее число хитов и брони
$this->def['f'][$k]['hp-amount'] = $v['amount'] * $v['hp'];
$this->def['f'][$k]['arm-amount'] = $v['amount'] * $v['def'];
}
}
//расстояние и описание группы войск - рассчитаем потенц. опасность
function danger_rating($distance, $bg) {
if ($distance > 0 && $bg['ranged'] > 0) {
return $bg['ranged'] * $bg['amount'];
} else {
return $bg['melee'] * $bg['amount'];
}
}
/* выбрать ближайшего врага со строны защиты */
function select_def($att_ind) {
$z = &$this->att[$att_ind];
$pos = 1000000;
$danger = 0;
$t = -1;
foreach($this->def['f'] as $ek => $ev) {
$new_danger = $this->danger_rating($ev['pos'] - $z['pos'], $ev);
if ($pos > $ev['pos'] || ($pos == $ev['pos'] && $new_danger > $danger) ) {
$pos = $ev['pos'];
$danger = $new_danger;
$t = $ek;
}
}
return $t;
}
/* выбрать ближайшего врага со строны атаккера */
function select_att($def_ind) {
$z = &$this->def[$def_ind];
$pos = -100;
$danger = 0;
$t = -1;
foreach($this->att['f'] as $ek => $ev) {
$new_danger = $this->danger_rating($z['pos'] - $ev['pos'], $ev);
if ($pos < $ev['pos'] || ($pos == $ev['pos'] && $new_danger > $danger) ) {
$pos = $ev['pos'];
$danger = $new_danger;
$t = $ek;
}
}
return $t;
}
/* вывод таблицы раунда */
function show() {
$as = '
| ATTeff | HP | DEF | Amount | Pos |
';
foreach ($this->att['f'] as $k => $v) {
if (!$v['amount']) {
$as .= "{$v['name']} | | " . floor($v['pos']) . " |
";
unset($this->att['f'][$k]);
} else {
if ($v['f']) {
$class = 'wounded';
$this->att['f'][$k]['f'] = 0;
} else
$class = '';
$as .= "{$v['name']} | " . round($v['attack'], 2) . " | " . floor($v['hp-amount'] / $v['amount']) . " | " . floor($v['arm-amount'] / $v['amount']). " | " . floor($v['amount']) . " | " . floor($v['pos']) . " |
";
}
}
$as .= '
';
$ds = '
| ATTeff | HP | DEF | Amount | Pos |
';
foreach ($this->def['f'] as $k => $v) {
if (!$v['amount']) {
$ds .= "{$v['name']} | | " . floor($v['pos']) . " |
";
unset($this->def['f'][$k]);
} else {
if ($v['f']) {
$class = 'wounded';
$this->def['f'][$k]['f'] = 0;
} else
$class = '';
$ds .= "{$v['name']} | " . round($v['attack'] ,2) . " | " . floor($v['hp-amount'] / $v['amount']) . " | " . floor($v['arm-amount'] / $v['amount']). " | " . floor($v['amount']) . " | " . floor($v['pos']) . " |
";
}
}
$ds .= '
';
return "";
}
function iteration() {
//остались ли ещё воины
$n = 0;
foreach($this->att['f'] as $k => $v) {
$n += $this->att['f'][$k]['amount'];
}
if (!$n) return false;
$n = 0;
foreach($this->def['f'] as $k => $v) {
$n += $this->def['f'][$k]['amount'];
}
if (!$n) return false;
$this->n_inter ++;
if ($this->n_inter > 50) return false; //ограничение по числу расчетных раундов
//ход атакующего
foreach($this->att['f'] as $k => $v) {
//ближайший враг
$t = $this->select_def($k);
$defer = &$this->def['f'][$t];
if ($t == -1) return true; //враг не обнаружен - но итерация полноценная, поэтому вернем true
$pos = $defer['pos'];
//движение
if ($pos > $v['pos'] + $v['range']) {
$new_pos = min($v['pos'] + $v['speed'], $pos - $v['range']);
if ($new_pos > $v['pos']) {
$this->att['f'][$k]['pos'] = $new_pos;
$v['pos'] = $new_pos;
}
}
if ($v['pos'] < $pos && $v['pos'] + $v['range'] >= $pos) {
//атака ranged
$attack = $v['ranged'];
} else if ($v['pos'] == $pos) {
//атака melee
$attack = $v['melee'];
} else
continue;
$attack -= $this->def['w'];
$this->att['f'][$k]['attack'] = $attack;
if ($attack <= 0) continue;
$dem = $attack * $v['amount'];
$defer['f'] = 1;
$amount = $defer['amount'];
$arm = $defer['arm-amount'];
$hp = $defer['hp-amount'];
//коэф неопред
$min = 0.5;
$max = $attack / ($attack + $defer['def']);
$dem = $dem * 0.5 + $dem * $max * mt_rand() / mt_getrandmax();
//особенности
if ($k == 18 && $t == 14) $dem *= 2; //venom dveller атакует granite ogre с удвоенным уроном
if ($k == 19 && $t == 15) $dem /= 2; //lava jaw получает в два раза меньший урон от frost giant
//варианты стычки
if ($dem >= $arm + $hp) {
$defer['amount'] = 0; //сдохли
} else if ($dem <= $arm) {
// $this->def['f'][$t]['def'] = ($arm - $dem) / $amount; //ослабление брони (чисто для индикации)
$defer['arm-amount'] -= $dem;
} else {
// $this->def['f'][$t]['def'] = 0
$dem -= $defer['arm-amount'];
$defer['arm-amount'] = 0; //броня выбита
$defer['hp-amount'] -= $dem;
$defer['amount'] = ceil($defer['hp-amount'] / $defer['hp']);
}
}
//ход обороняющегося
foreach($this->def['f'] as $k => $v) {
if (!$v['amount']) continue;
//ближайший враг
$t = $this->select_att($k);
$ataker = &$this->att['f'][$t];
if ($t == -1) return true; //враг не обнаружен - но итерация полноценная, поэтому вернем true
$pos = $ataker['pos'];
//движение
if ($pos < $v['pos'] - $v['range']) {
$new_pos = max($v['pos'] - $v['speed'], $pos + $v['range']);
if ($new_pos < $v['pos']) {
$this->def['f'][$k]['pos'] = $new_pos;
$v['pos'] = $new_pos;
}
}
if ($v['pos'] > $pos && $v['pos'] - $v['range'] <= $pos) {
//атака ranged
$attack = $v['ranged'];
} else if ($v['pos'] == $pos) {
//атака melee
$attack = $v['melee'];
} else
continue;
$this->def['f'][$k]['attack'] = $attack;
$dem = $attack * $v['amount'];
$ataker['f'] = 1;
$amount = $ataker['amount'];
$arm = $ataker['arm-amount'];
$hp = $ataker['hp-amount'];
//коэф неопред
$min = 0.5;
$max = $attack / ($attack + $ataker['def']);
$dem = $dem * 0.5 + $dem * $max * mt_rand() / mt_getrandmax();
//особенности
if ($k == 18 && $t == 14) $dem *= 2; //venom dveller атакует granite ogre с удвоенным уроном
if ($k == 19 && $t == 15) $dem /= 2; //lava jaw получает в два раза меньший урон от frost giant
//варианты стычки
if ($dem >= $arm + $hp) {
$ataker['amount'] = 0; //сдохли
} else if ($dem <= $arm) {
// $this->att['f'][$t]['def'] = ($arm - $dem) / $amount; //ослабление брони
$ataker['arm-amount'] -= $dem;
} else {
// $this->att['f'][$t]['def'] = 0
$dem -= $ataker['arm-amount'];
$ataker['arm-amount'] = 0; //броня выбита
$ataker['hp-amount'] -= $dem;
$ataker['amount'] = ceil($ataker['hp-amount'] / $ataker['hp']);
}
}
return true;
}
static function speed_buble($a, $b) {
if ($a['speed'] == $b['speed']) {
return 0;
}
return ($a['speed'] > $b['speed']) ? -1 : 1; //с большей скоротью объекты всплвывают вверх
}
}