mirror of
https://github.com/Shadowss/TravianZ.git
synced 2026-06-28 16:44:24 +00:00
70f911996d
Fixed hero stacking deff bonus % if multiple heroes are reinforcing same village, now the deff bonus will apply only to the units that came with the hero.
794 lines
34 KiB
PHP
Executable File
794 lines
34 KiB
PHP
Executable File
<?php
|
|
|
|
#################################################################################
|
|
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
|
## --------------------------------------------------------------------------- ##
|
|
## Project: TravianZ ##
|
|
## Version: 22.06.2015 ##
|
|
## Filename Battle.php ##
|
|
## Developed by: Dzoki & Dixie ##
|
|
## Fixed by: Shadow ##
|
|
## Thanks to: Akakori, Elmar & Kirilloid ##
|
|
## Reworked and Fix by: ronix ##
|
|
## Fixed by: InCube - double troops ##
|
|
## License: TravianZ Project ##
|
|
## Copyright: TravianZ (c) 2010-2015. All rights reserved. ##
|
|
## URLs: http://travian.shadowss.ro ##
|
|
## Source code: https://github.com/Shadowss/TravianZ ##
|
|
## ##
|
|
#################################################################################
|
|
|
|
|
|
class Battle {
|
|
|
|
/**
|
|
*
|
|
* @author Kirilloid --> https://github.com/kirilloid/travian/blob/master/src/model/base/combat.ts
|
|
* @var double The number of attacking catapults: 1 = 100%, 0 = 0%
|
|
*
|
|
*/
|
|
|
|
private $sigma;
|
|
|
|
public function __construct(){
|
|
|
|
$this->sigma = function($x) { return ($x > 1 ? 2 - $x ** -1.5 : $x ** 1.5) / 2; };
|
|
|
|
}
|
|
|
|
public function procSim($post) {
|
|
global $form;
|
|
|
|
// receive form and process
|
|
if(isset($post['a1_v']) && (isset($post['a2_v1']) || isset($post['a2_v2']) || isset($post['a2_v3']) || isset($post['a2_v4']) || isset($post['a2_v5']))){
|
|
$_POST['mytribe'] = $post['a1_v'];
|
|
|
|
$target = [];
|
|
if(isset($post['a2_v1'])) array_push($target, 1);
|
|
if(isset($post['a2_v2'])) array_push($target, 2);
|
|
if(isset($post['a2_v3'])) array_push($target, 3);
|
|
if(isset($post['a2_v4'])) array_push($target, 4);
|
|
if(isset($post['a2_v5'])) array_push($target, 5);
|
|
|
|
$_POST['target'] = $target;
|
|
if(isset($post['h_off_bonus'])){
|
|
if(intval($post['h_off_bonus']) > 20) $post['h_off_bonus'] = 20;
|
|
}
|
|
else $post['h_off_bonus'] = 0;
|
|
|
|
if(isset($post['h_def_bonus'])){
|
|
if(intval($post['h_def_bonus']) > 20) $post['h_def_bonus'] = 20;
|
|
}
|
|
else $post['h_def_bonus'] = 0;
|
|
|
|
$sum = 0;
|
|
for($i = 1; $i <= 10; $i++) $sum += (!empty($post['a1_'.$i]) ? $post['a1_'.$i] : 0);
|
|
|
|
if($sum > 0){
|
|
$post['palast'] = intval($post['palast']);
|
|
if($post['palast'] > 20) $post['palast'] = 20;
|
|
|
|
for($i = 1; $i <= 5; $i++){
|
|
if(isset($post['wall'.$i])){
|
|
$post['wall'.$i] = intval($post['wall'.$i]);
|
|
if($post['wall'.$i] > 20) $post['wall'.$i] = 20;
|
|
elseif($post['wall'.$i] < 0) $post['wall'.$i] = 0;
|
|
$post['walllevel'] = $post['wall'.$i];
|
|
}
|
|
}
|
|
|
|
$post['tribe'] = $target[0];
|
|
$_POST['result'] = $this->simulate($post);
|
|
$newWallLevel = $_POST['result'][7];
|
|
$oldWallLevel = $_POST['result'][8];
|
|
|
|
//If the wall level is reduce, we have to re-do the whole battle
|
|
if($newWallLevel != $oldWallLevel){
|
|
$post['walllevel'] = $newWallLevel;
|
|
$_POST['result'] = $this->simulate($post);
|
|
|
|
//Reset the datas
|
|
$_POST['result'][7] = $newWallLevel;
|
|
$_POST['result'][8] = $post['walllevel'] = $oldWallLevel;
|
|
}
|
|
|
|
$form->valuearray = $post;
|
|
}
|
|
}
|
|
}
|
|
|
|
private function getBattleHero($uid) {
|
|
global $database;
|
|
$heroarray = $database->getHero($uid);
|
|
|
|
if (!count($heroarray)) return ['heroid' => 0, 'unit' =>'','atk' => 0,'di' => 0,'dc' => 0,'ob' => 0,'db' => 0,'health' => 0];
|
|
|
|
$herodata = $GLOBALS["h".$heroarray[0]['unit']];
|
|
if(!isset($heroarray['health'])) $heroarray['health'] = 0;
|
|
$h_atk = $herodata['atk'] + ($heroarray[0]['attack'] * $herodata['atkp']);
|
|
$h_di = $herodata['di'] + 5 * floor($heroarray[0]['defence'] * $herodata['dip'] / 5);
|
|
$h_dc = $herodata['dc'] + 5 * floor($heroarray[0]['defence'] * $herodata['dcp'] / 5);
|
|
$h_ob = 1 + 0.010 * ($heroarray[0]['attackbonus'] / 5);
|
|
$h_db = 1 + 0.010 * ($heroarray[0]['defencebonus'] / 5);
|
|
|
|
return ['heroid' => (int) $heroarray[0]['heroid'], 'unit' => $heroarray[0]['unit'], 'atk' => $h_atk, 'di' => $h_di, 'dc' => $h_dc, 'ob' => $h_ob, 'db' => $h_db, 'health' => $heroarray['health']];
|
|
}
|
|
|
|
private function getBattleHeroSim($attbonus) {
|
|
$h_atk = 0;
|
|
$h_ob = 1 + 0.010 * $attbonus;
|
|
|
|
return ['unit' => 16,'atk' => $h_atk,'ob' => $h_ob];
|
|
}
|
|
|
|
private function simulate($post) {
|
|
//set the arrays with attacking and defending units
|
|
$attacker = ['u1' => 0, 'u2' => 0, 'u3' => 0, 'u4' => 0, 'u5' => 0, 'u6' => 0, 'u7' => 0, 'u8' => 0, 'u9' => 0, 'u10' => 0, 'u11' => 0, 'u12' => 0, 'u13' => 0, 'u14' => 0, 'u15' => 0, 'u16' => 0, 'u17' => 0, 'u18' => 0, 'u19' => 0, 'u20' => 0, 'u21' => 0, 'u22' => 0, 'u23' => 0, 'u24' => 0,
|
|
'u25' => 0, 'u26' => 0, 'u27' => 0, 'u28' => 0, 'u29' => 0, 'u30' => 0, 'u31' => 0, 'u32' => 0, 'u33' => 0, 'u34' => 0, 'u35' => 0, 'u36' => 0, 'u37' => 0, 'u38' => 0, 'u39' => 0, 'u40' => 0, 'u41' => 0, 'u42' => 0, 'u43' => 0, 'u44' => 0, 'u45' => 0, 'u46' => 0, 'u47' => 0, 'u48' => 0,
|
|
'u49' => 0, 'u50' => 0];
|
|
$start = ($post['a1_v'] - 1) * 10 + 1;
|
|
$offhero = intval($post['h_off_bonus']);
|
|
$hero_strenght = intval($post['h_off']);
|
|
$deffhero = intval($post['h_def_bonus']);
|
|
for($i = $start, $index = 1; $i <= $start + 9; $i++, $index++) {
|
|
if(isset($post['a1_'.$index]) && !empty($post['a1_'.$index])) {
|
|
$attacker['u'.$i] = $post['a1_'.$index];
|
|
}
|
|
else $attacker['u'.$i] = 0;
|
|
|
|
if($index <=8 && isset($post['f1_'.$index]) && !empty($post['f1_'.$index])) {
|
|
${'att_ab'.$index} = $post['f1_'.$index];
|
|
}
|
|
else ${'att_ab'.$index} = 0;
|
|
}
|
|
|
|
$defender = [];
|
|
$defscout = 0;
|
|
//fix by ronix
|
|
for($i = 1;$i <= 50; $i++) {
|
|
if(isset($post['a2_'.$i]) && !empty($post['a2_'.$i])) {
|
|
$defender['u'.$i] = $post['a2_'.$i];
|
|
$def_ab[$i] = $post['f2_'.$i];
|
|
if($i == 4 || $i == 14 || $i == 23 || $i == 44){
|
|
$defscout += $defender['u'.$i];
|
|
}
|
|
|
|
}
|
|
else {
|
|
$defender['u'.$i] = 0;
|
|
$def_ab[$i] = 0;
|
|
}
|
|
}
|
|
|
|
$deftribe = $post['tribe'];
|
|
$wall = 0;
|
|
|
|
if(empty($post['kata'])) $post['kata'] = 0;
|
|
|
|
// check scout
|
|
|
|
$scout = 1;
|
|
for($i = $start; $i <= $start + 9 ; $i++) {
|
|
if($i == 4 || $i == 14 || $i == 23 || $i == 44){
|
|
}else{
|
|
if($attacker['u'.$i] > 0) {
|
|
$scout = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
$walllevel = $post['walllevel'];
|
|
$wall = $walllevel;
|
|
$palast = $post['palast'];
|
|
|
|
if($scout == 1 && $defscout == 0) $walllevel = $wall = $palast = 0;
|
|
|
|
if($scout == 1) $palast = 0; //no def point palace and residence when scout
|
|
|
|
if(!$scout) return $this->calculateBattle($attacker,$defender,$wall,$post['a1_v'],$deftribe,$palast,$post['ew1'],$post['ew2'],$post['ktyp']+3,$def_ab,$att_ab1,$att_ab2,$att_ab3,$att_ab4,$att_ab5,$att_ab6,$att_ab7,$att_ab8,$post['kata'],$post['stonemason'],$walllevel,$offhero,$post['h_off'],$deffhero,0,0,0,0,0);
|
|
else return $this->calculateBattle($attacker,$defender,$wall,$post['a1_v'],$deftribe,$palast,$post['ew1'],$post['ew2'],1,$def_ab,$att_ab1,$att_ab2,$att_ab3,$att_ab4,$att_ab5,$att_ab6,$att_ab7,$att_ab8,$post['kata'],$post['stonemason'],$walllevel,0,0,0,0,0,0,0,0);
|
|
|
|
}
|
|
|
|
public function getTypeLevel($tid,$vid) {
|
|
global $village,$database;
|
|
|
|
$keyholder = [];
|
|
$resourcearray = $database->getResourceLevel($vid);
|
|
|
|
foreach(array_keys($resourcearray, $tid) as $key) {
|
|
if(strpos($key,'t')) {
|
|
$key = preg_replace("/[^0-9]/", '', $key);
|
|
array_push($keyholder, $key);
|
|
}
|
|
}
|
|
|
|
$element = count($keyholder);
|
|
if($element >= 2) {
|
|
if($tid <= 4) {
|
|
$temparray = [];
|
|
for($i = 0; $i <= $element - 1; $i++){
|
|
array_push($temparray, $resourcearray['f'.$keyholder[$i]]);
|
|
}
|
|
foreach ($temparray as $key => $val) {
|
|
if ($val == max($temparray))
|
|
$target = $key;
|
|
}
|
|
}
|
|
else {
|
|
$target = 0;
|
|
for($i=1;$i<=$element-1;$i++) {
|
|
if($resourcearray['f'.$keyholder[$i]] > $resourcearray['f'.$keyholder[$target]]) {
|
|
$target = $i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if($element == 1) $target = 0;
|
|
else return 0;
|
|
|
|
|
|
if(!empty($keyholder[$target])) return $resourcearray['f'.$keyholder[$target]];
|
|
else return 0;
|
|
}
|
|
|
|
//1 raid 0 normal
|
|
function calculateBattle($Attacker, $Defender, $def_wall, $att_tribe, $def_tribe, $residence, $attpop, $defpop, $type, $def_ab, $att_ab1, $att_ab2, $att_ab3, $att_ab4, $att_ab5, $att_ab6, $att_ab7, $att_ab8, $tblevel, $stonemason, $walllevel, $offhero, $hero_strenght, $deffhero, $AttackerID, $DefenderID, $AttackerWref, $DefenderWref, $conqureby, $defReinforcements = null) {
|
|
global $bid34, $bid35, $database;
|
|
|
|
// Define the array, with the units
|
|
$calvary = [4, 5, 6, 15, 16, 23, 24, 25, 26, 45, 46];
|
|
$catapult = [8, 18, 28, 48];
|
|
$rams = [7, 17, 27, 47];
|
|
$catp = $ram = 0;
|
|
|
|
// Array to return the result of the calculation back
|
|
$result = [];
|
|
$involve = 0;
|
|
$winner = false;
|
|
|
|
// at 0 all partial results
|
|
|
|
//cap = Cavalry attack points
|
|
//ap = Infantry attack points
|
|
//cdp = Cavalry attack points
|
|
//dp = Infantry defense points
|
|
//rap = Result attack points
|
|
//rdp = Result defense points
|
|
//detected = Detected or not by defender spies
|
|
$cap = $ap = $dp = $cdp = $rap = $rdp = 0;
|
|
$detected = false;
|
|
|
|
//Get involved artifacts
|
|
$attacker_artefact = $database->getArtifactsValueInfluence($AttackerID, $AttackerWref, 3, 1, false);
|
|
$defender_artefact = $database->getArtifactsValueInfluence($DefenderID, $DefenderWref, 3, 1, false);
|
|
$strongerbuildings = $database->getArtifactsValueInfluence($DefenderID, $DefenderWref, 1, 1, false);
|
|
$isWWVillage = $database->getVillageField($DefenderWref, 'natar');
|
|
|
|
if(isset($Attacker['uhero']) && $Attacker['uhero'] > 0){
|
|
$atkhero = $this->getBattleHero($AttackerID);
|
|
}
|
|
if(isset($Defender['hero']) && $Defender['hero'] > 0){
|
|
$defenderhero = $this->getBattleHero($DefenderID);
|
|
}
|
|
//own defender units
|
|
if ($type == 1) {
|
|
$datadefScout = $this->getDataDefScout($Defender, $def_ab, $defender_artefact);
|
|
$dp += $datadefScout['dp'];
|
|
$cdp += $datadefScout['cdp'];
|
|
$involve = $datadefScout['involve'];
|
|
if(!$detected && $datadefScout['detect']) $detected = $datadefScout['detect'];
|
|
}else{
|
|
$datadef = $this->getDataDef($Defender, $def_ab);
|
|
$own_dp = $datadef['dp'];
|
|
$own_cdp = $datadef['cdp'];
|
|
$involve = $datadef['involve'];
|
|
if(isset($Defender['hero']) && $Defender['hero'] != 0){
|
|
$units['Def_unit']['hero'] = $Defender['hero'];
|
|
$own_cdp += $defenderhero['dc'];
|
|
$own_dp += $defenderhero['di'];
|
|
$own_dp *= $defenderhero['db'];
|
|
$own_cdp *= $defenderhero['db'];
|
|
}
|
|
$dp += $own_dp;
|
|
$cdp += $own_cdp;
|
|
}
|
|
$DefendersAll = (!is_null($defReinforcements) ? $database->getEnforceVillage($DefenderWref, 0) : $defReinforcements);
|
|
|
|
if(!empty($DefendersAll) && $DefenderWref > 0){
|
|
// preload village IDs
|
|
$vilIDs = [];
|
|
foreach($DefendersAll as $defenders) {
|
|
$vilIDs[$defenders['from']] = true;
|
|
$vilIDs[$defenders['to']] = true;
|
|
}
|
|
$vilIDs = array_keys($vilIDs);
|
|
$database->getABTech($vilIDs);
|
|
|
|
foreach($DefendersAll as $defenders) {
|
|
for ($i = 1; $i <= 50; $i++) $def_ab[$i] = 0;
|
|
$fromvillage = $defenders['from'];
|
|
|
|
$userdataCache[$fromvillage] = $database->getUserArray($database->getVillageField($fromvillage, "owner"), 1);
|
|
|
|
$enforcetribe = $userdataCache[$fromvillage]["tribe"];
|
|
$ud=($enforcetribe - 1) * 10;
|
|
if($defenders['from'] > 0) { //don't check nature tribe
|
|
$armory = $database->getABTech($defenders['from']); // Armory level every village enforcement
|
|
$def_ab[$ud + 1] = $armory['a1'];
|
|
$def_ab[$ud + 2] = $armory['a2'];
|
|
$def_ab[$ud + 3] = $armory['a3'];
|
|
$def_ab[$ud + 4] = $armory['a4'];
|
|
$def_ab[$ud + 5] = $armory['a5'];
|
|
$def_ab[$ud + 6] = $armory['a6'];
|
|
$def_ab[$ud + 7] = $armory['a7'];
|
|
$def_ab[$ud + 8] = $armory['a8'];
|
|
}
|
|
if ($type == 1) {
|
|
$datadefScout = $this->getDataDefScout($defenders, $def_ab, $defender_artefact);
|
|
$dp += $datadefScout['dp'];
|
|
$cdp += $datadefScout['cdp'];
|
|
$involve = $datadefScout['involve'];
|
|
if(!$detected && $datadefScout['detect']) $detected = $datadefScout['detect'];
|
|
}else{
|
|
$datadef = $this->getDataDef($defenders, $def_ab);
|
|
$reinf_dp = $datadef['dp'];
|
|
$reinf_cdp = $datadef['cdp'];
|
|
$involve += $datadef['involve'];
|
|
$reinfowner = $database->getVillageField($fromvillage, "owner");
|
|
$defhero = $this->getBattleHero($reinfowner);
|
|
|
|
|
|
if($defenders['hero'] != 0 && $type != 1){
|
|
$reinf_cdp += $defhero['dc'];
|
|
$reinf_dp += $defhero['di'];
|
|
$reinf_dp *= $defhero['db'];
|
|
$reinf_cdp *= $defhero['db'];
|
|
}
|
|
$dp += $reinf_dp;
|
|
$cdp += $reinf_cdp;
|
|
}
|
|
}
|
|
}
|
|
// Calculate the total number of points Attacker
|
|
$start = ($att_tribe - 1) * 10 + 1;
|
|
$end = $att_tribe * 10;
|
|
|
|
if($att_tribe == 3) $abcount = 3;
|
|
else $abcount = 4;
|
|
|
|
if($type == 1) {//scout
|
|
for($i = $start;$i <= $end; $i++) {
|
|
global ${'u'.$i};
|
|
$j = $i - $start + 1;
|
|
if($Attacker['u'.$i] > 0 && ($i == 4 || $i == 14 || $i == 23 || $i == 44)){
|
|
if(${'att_ab'.$abcount} > 0) {
|
|
$ap += round(35 + (35 + 300 * ${'u'.$i}['pop'] / 7) * (pow(1.007, ${'att_ab'.$abcount}) - 1), 4) * $Attacker['u'.$i];
|
|
}
|
|
else $ap += $Attacker['u'.$i] * 35;
|
|
}
|
|
$involve += $Attacker['u'.$i];
|
|
$units['Att_unit'][$i] = $Attacker['u'.$i];
|
|
|
|
}
|
|
$ap *= $attacker_artefact;
|
|
|
|
}else{ //type=3 normal 4=raid
|
|
$abcount = 1;
|
|
for($i = $start; $i <= $end; $i++) {
|
|
global ${'u'.$i};
|
|
$j = $i - $start + 1;
|
|
if($abcount <= 8 && ${'att_ab'.$abcount} > 0) {
|
|
if(in_array($i,$calvary)) {
|
|
$cap += round(${'u'.$i}['atk'] + (${'u'.$i}['atk'] + 300 * ${'u'.$i}['pop'] / 7) * (pow(1.007, ${'att_ab'.$abcount}) - 1), 4) * (int) $Attacker['u'.$i];
|
|
}else{
|
|
$ap += round(${'u'.$i}['atk'] + (${'u'.$i}['atk'] + 300 * ${'u'.$i}['pop'] / 7) * (pow(1.007, ${'att_ab'.$abcount}) - 1), 4) * (int) $Attacker['u'.$i];
|
|
}
|
|
}else{
|
|
if(in_array($i,$calvary)) $cap += (int) $Attacker['u'.$i]*${'u'.$i}['atk'];
|
|
else $ap += (int) $Attacker['u'.$i]*${'u'.$i}['atk'];
|
|
}
|
|
|
|
$abcount += 1;
|
|
|
|
// Points catapult the attacker
|
|
if(in_array($i, $catapult)) $catp += (int) $Attacker['u'.$i];
|
|
|
|
// Points of the Rams attacker
|
|
if(in_array($i, $rams)) $ram += (int) $Attacker['u'.$i];
|
|
|
|
$involve += (int) $Attacker['u'.$i];
|
|
$units['Att_unit'][$i] = (int) $Attacker['u'.$i];
|
|
}
|
|
if (isset($Attacker['uhero']) && $Attacker['uhero'] != 0){
|
|
$units['Att_unit']['hero'] = $Attacker['uhero'];
|
|
$ap *= $atkhero['ob'];
|
|
$cap *= $atkhero['ob'];
|
|
$ap += $atkhero['atk'];
|
|
}
|
|
|
|
if ($offhero > 0 || $hero_strenght > 0) {
|
|
$atkhero= $this->getBattleHeroSim($offhero);
|
|
$ap *= $atkhero['ob'];
|
|
$cap *= $atkhero['ob'];
|
|
$ap += $hero_strenght;
|
|
}
|
|
if ($deffhero > 0) {
|
|
$dfdhero = $this->getBattleHeroSim($deffhero);
|
|
$dp *= $dfdhero['ob'];
|
|
$cdp *= $dfdhero['ob'];
|
|
}
|
|
}
|
|
// Formula for calculating the bonus defensive wall and Residence
|
|
|
|
if($def_wall > 0) {
|
|
// Set the factor calculation for the "wall" as the type of the civilization
|
|
// Factor = 1030 Wall Roman
|
|
// Factor = 1020 Wall Teuton
|
|
// Factor = 1025 Wall Goul
|
|
$factor = ($def_tribe == 1)? 1.030 : (($def_tribe == 2)? 1.020 : 1.025);
|
|
$wallMultiplier = round(pow($factor, $def_wall), 3);
|
|
// Defense infantry = Infantry * Wall (%)
|
|
// Defense calvary calvary = * Wall (%)
|
|
if ($dp > 0 || $cdp > 0){
|
|
if($type == 1) {
|
|
$dp *= $wallMultiplier;
|
|
$dp += 10;
|
|
}else{
|
|
$dp *= $wallMultiplier;
|
|
$cdp *= $wallMultiplier;
|
|
|
|
// Calculation of the Basic defense bonus "Residence"
|
|
$dp += (2 * (pow($residence, 2)) + 10) * $wallMultiplier;
|
|
$cdp += (2 * (pow($residence, 2)) + 10) * $wallMultiplier;
|
|
}
|
|
}else{
|
|
$dp = 10 * $wallMultiplier * $def_wall;
|
|
// Defense calvary calvary = * Wall (%)
|
|
$cdp = 10 * $wallMultiplier * $def_wall;
|
|
if($type != 1){
|
|
// Calculation of the Basic defense bonus "Residence"
|
|
$dp += (2 * (pow($residence, 2)) + 10) * $wallMultiplier;
|
|
$cdp += (2 * (pow($residence, 2)) + 10) * $wallMultiplier;
|
|
}else{
|
|
$dp += 10;
|
|
$cdp = 0;
|
|
}
|
|
}
|
|
}elseif($type != 1) {
|
|
|
|
// Calculation of the Basic defense bonus "Residence"
|
|
$dp += (2 * (pow($residence, 2)) + 10);
|
|
$cdp += (2 * (pow($residence, 2)) + 10);
|
|
}
|
|
|
|
// Formula for calculating Attacking Points (Infantry & Cavalry)
|
|
if($AttackerWref != 0){
|
|
$rap = round(($ap + $cap) + (($ap + $cap) / 100 * (isset($bid35[$this->getTypeLevel(35, $AttackerWref)]) ? $bid35[$this->getTypeLevel(35, $AttackerWref)]['attri'] : 0)));
|
|
}
|
|
else $rap = round($ap + $cap);
|
|
|
|
// Formula for calculating Defensive Points
|
|
if ($rap == 0) $rdp = round(($dp) + ($cdp));
|
|
else $rdp = round(round($cap / $rap, 4) * ($cdp) + round($ap / $rap, 4) * ($dp));
|
|
|
|
// The Winner is....:
|
|
$result['Attack_points'] = $rap;
|
|
$result['Defend_points'] = $rdp;
|
|
$winner = ($rap > $rdp);
|
|
|
|
// Formula for calculating the Morale bonus
|
|
// WW villages aren't affected by this bonus
|
|
if($attpop > $defpop && !$isWWVillage) {
|
|
$moralbonus = 1 / round(max(0.667, pow($defpop / $attpop, 0.2 * min(1, $rap / ($rdp > 0 ? $rdp : 1)))), 3);
|
|
}
|
|
else $moralbonus = 1.0;
|
|
|
|
if($involve >= 1000 && $type != 1) $Mfactor = 2 * round((1.8592 - pow($involve, 0.015)), 4);
|
|
else $Mfactor = 1.5;
|
|
|
|
if ($Mfactor < 1.2578) $Mfactor = 1.2578;
|
|
elseif ($Mfactor > 1.5) $Mfactor = 1.5;
|
|
|
|
// Formula for calculating losses
|
|
// $type = 1 Scout, 2 Enforcement
|
|
// $type = 3 Normal, 4 Raid
|
|
if($type == 1){
|
|
$holder = pow((($rdp * $moralbonus) / $rap), $Mfactor);
|
|
if($holder > 1) $holder = 1;
|
|
if ($rdp > $rap) $holder = 1;
|
|
|
|
//Birds of Prey cannot die when scouting
|
|
//Spies cannot die if the attacked village has no defending spies
|
|
//Attacker result
|
|
$result[1] = ($att_tribe == 5 || !$detected) ? 0 : $holder;
|
|
|
|
//Defender result
|
|
$result[2] = 0;
|
|
}else if($type == 4) {
|
|
$holder = ($winner) ? pow((($rdp * $moralbonus) / $rap), $Mfactor) : pow(($rap / ($rdp * $moralbonus)), $Mfactor);
|
|
$holder = $holder / (1 + $holder);
|
|
//Attacker result
|
|
$result[1] = $winner ? $holder : 1 - $holder;
|
|
//Defender result
|
|
$result[2] = $winner ? 1 - $holder : $holder;
|
|
$ram -= round($ram * $result[1] / 100);
|
|
$catp -= round($catp * $result[1] / 100);
|
|
}else if($type == 3){
|
|
|
|
// Attacker
|
|
$result[1] = ($winner) ? pow((($rdp * $moralbonus) / $rap), $Mfactor) : 1;
|
|
|
|
if ($result[1] > 1){
|
|
$result[1] = 1;
|
|
$winner = false;
|
|
$result['Winner'] = "defender";
|
|
}
|
|
|
|
// Defender
|
|
$result[2] = (!$winner) ? pow(($rap / ($rdp * $moralbonus)), $Mfactor) : 1;
|
|
|
|
if ($result[1] == 1) $result[2] = pow(($rap / ($rdp * $moralbonus)), $Mfactor);
|
|
|
|
if ($result[2] > 1) {
|
|
$result[2] = 1;
|
|
$result['Winner'] = "attacker";
|
|
$winner = true;
|
|
}
|
|
|
|
// If attacked with "Hero"
|
|
$ku = ($att_tribe - 1) * 10 + 9;
|
|
$kings = (int) $Attacker['u'.$ku];
|
|
|
|
$aviables = $kings - round($kings * (int) $result[1]);
|
|
if ($aviables > 0){
|
|
switch($aviables){
|
|
case 1: $fealthy = rand(20, 30); break;
|
|
case 2: $fealthy = rand(40, 60); break;
|
|
case 3: $fealthy = rand(60, 80); break;
|
|
case 4: $fealthy = rand(80, 100); break;
|
|
default: $fealthy = 100; break;
|
|
}
|
|
$result['hero_fealthy'] = $fealthy;
|
|
}
|
|
|
|
$ram -= ($winner) ? round($ram * $result[1] / 100) : round($ram * $result[2] / 100);
|
|
$catp -= ($winner) ? round($catp * $result[1] / 100) : round($catp * $result[2] / 100);
|
|
}
|
|
|
|
if($catp > 0 && $tblevel != 0) {
|
|
|
|
//Catapults blacksmith upgrades
|
|
$upgrades = round(200 * pow(1.0205, $att_ab8)) / 200;
|
|
|
|
//Buildings durability
|
|
$durability = ($stonemason > 0 ? $bid34[$stonemason]['attri'] / 100 : 1);
|
|
|
|
//Calculates the catapults morale bonus
|
|
$catpMoraleBonus = min(max(($attpop / ($defpop > 0 ? $defpop : 1)) ** 0.3, 1), 3);
|
|
|
|
//New level of the building (only for warsim.php)
|
|
$catapultsDamage = $this->calculateCatapultsDamage($catp, $upgrades, $durability, $rap / $rdp, $strongerbuildings, $catpMoraleBonus);
|
|
$result[3] = $this->calculateNewBuildingLevel($tblevel, $catapultsDamage);
|
|
$result[4] = $tblevel;
|
|
|
|
//Results for Automation.php
|
|
$result['catapults']['upgrades'] = $upgrades;
|
|
$result['catapults']['durability'] = $durability;
|
|
$result['catapults']['attackDefenseRatio'] = $rap / $rdp;
|
|
$result['catapults']['strongerBuildings'] = $strongerbuildings;
|
|
$result['catapults']['moraleBonus'] = $catpMoraleBonus;
|
|
}
|
|
|
|
if($ram > 0 && $walllevel != 0) {
|
|
|
|
//Rams blacksmith upgrades
|
|
$upgrades = round(200 * pow(1.0205, $att_ab7)) / 200;
|
|
|
|
//Building durability
|
|
$durability = ($stonemason > 0 ? $bid34[$stonemason]['attri'] / 100 : 1);
|
|
|
|
// New level of the building (only for warsim.php)
|
|
$ramsDamage = $this->calculateCatapultsDamage($ram, $upgrades, $durability, $rap / $rdp, $strongerbuildings, 1);
|
|
$result[7] = $this->calculateNewBuildingLevel($walllevel, $ramsDamage);
|
|
$result[8] = $walllevel;
|
|
|
|
// Results for Automation.php
|
|
$result['rams']['upgrades'] = $upgrades;
|
|
$result['rams']['durability'] = $durability;
|
|
$result['rams']['attackDefenseRatio'] = $rap / $rdp;
|
|
$result['rams']['strongerBuildings'] = $strongerbuildings;
|
|
$result['rams']['moraleBonus'] = 1;
|
|
}
|
|
|
|
$result[6] = pow($rap / ($rdp * $moralbonus > 0 ? $rdp * $moralbonus : 1), $Mfactor);
|
|
$result['moralBonus'] = $moralbonus;
|
|
|
|
$total_att_units = count($units['Att_unit']);
|
|
$start = intval(($att_tribe - 1) * 10 + 1);
|
|
$end = intval($att_tribe * 10);
|
|
|
|
for($i = $start; $i <= $end; $i++){
|
|
$y = $i - (($att_tribe - 1) * 10);
|
|
$result['casualties_attacker'][$y] = round($result[1] * $units['Att_unit'][$i]);
|
|
}
|
|
|
|
if (isset($units['Att_unit']['hero']) && $units['Att_unit']['hero'] >0){
|
|
|
|
$_result = mysqli_query($database->dblink,"select heroid, health from " . TB_PREFIX . "hero where `dead`='0' and `heroid`=".(int) $atkhero['heroid']);
|
|
$fdb = mysqli_fetch_array($_result);
|
|
$hero_id = (int) $fdb['heroid'];
|
|
$hero_health = $fdb['health'];
|
|
$damage_health = round(100 * $result[1]);
|
|
|
|
if ($hero_health <= $damage_health || $damage_health > 90){
|
|
//hero die
|
|
$result['casualties_attacker'][11] = 1;
|
|
mysqli_query($database->dblink,"update " . TB_PREFIX . "hero set `dead` = 1, `health` = 0 where `heroid`=".(int) $hero_id);
|
|
}else{
|
|
mysqli_query($database->dblink,"update " . TB_PREFIX . "hero set `health`=`health`-".(int) $damage_health." where `heroid`=".(int) $hero_id);
|
|
}
|
|
}
|
|
unset($_result, $fdb, $hero_id, $hero_health, $damage_health);
|
|
|
|
|
|
if (isset($units['Def_unit']['hero']) && $units['Def_unit']['hero'] >0){
|
|
|
|
$_result = mysqli_query($database->dblink,"select heroid, health from " . TB_PREFIX . "hero where `dead`='0' and `heroid`=".(int) $defenderhero['heroid']);
|
|
$fdb = mysqli_fetch_array($_result);
|
|
$hero_id = (int) $fdb['heroid'];
|
|
$hero_health = $fdb['health'];
|
|
$damage_health = round(100 * $result[2]);
|
|
if ($hero_health <= $damage_health || $damage_health > 90){
|
|
//hero die
|
|
$result['deadherodef'] = 1;
|
|
mysqli_query($database->dblink,"update " . TB_PREFIX . "hero set `dead` = 1, `health` = 0 where `heroid`=".(int) $hero_id);
|
|
}else{
|
|
$result['deadherodef'] = 0;
|
|
mysqli_query($database->dblink,"update " . TB_PREFIX . "hero set `health`=`health`-".(int) $damage_health." where `heroid`=".(int) $hero_id);
|
|
}
|
|
}
|
|
unset($_result, $fdb, $hero_id, $hero_health, $damage_health);
|
|
|
|
if(!empty($DefendersAll)){
|
|
$battleHeroesCache = [];
|
|
foreach($DefendersAll as $defenders) {
|
|
if($defenders['hero'] > 0) {
|
|
$battleHeroesCache[$defenders['from']] = $this->getBattleHero($database->getVillageField($defenders['from'],"owner"));
|
|
$heroarraydefender = $battleHeroesCache[$defenders['from']];
|
|
$_result = mysqli_query($database->dblink,"select heroid, health from " . TB_PREFIX . "hero where `dead`='0' and `heroid`=".(int) $heroarraydefender['heroid']);
|
|
$fdb = mysqli_fetch_array($_result);
|
|
$hero_id = (int) $fdb['heroid'];
|
|
$hero_health = $fdb['health'];
|
|
$damage_health = round(100 * $result[2]);
|
|
if ($hero_health <= $damage_health || $damage_health > 90){
|
|
//hero die
|
|
$result['deadheroref'][$defenders['id']] = 1;
|
|
mysqli_query($database->dblink,"update " . TB_PREFIX . "hero set `dead` = 1, `health` = 0 where `heroid`=".(int) $hero_id);
|
|
}else{
|
|
$result['deadheroref'][$defenders['id']] = 0;
|
|
mysqli_query($database->dblink,"update " . TB_PREFIX . "hero set `health`=`health`-".(int) $damage_health." where `heroid`=".(int) $hero_id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
unset($_result, $fdb, $hero_id, $hero_health, $damage_health);
|
|
|
|
|
|
// Work out bounty
|
|
$start = ($att_tribe - 1) * 10 + 1;
|
|
$end = ($att_tribe * 10);
|
|
|
|
$max_bounty = 0;
|
|
|
|
for($i = $start; $i <= $end; $i++) {
|
|
$j = $i - $start + 1;
|
|
$y = $i -(($att_tribe - 1) * 10);
|
|
|
|
$max_bounty += ((int) $Attacker['u'.$i] - (int) $result['casualties_attacker'][$y]) * (int) ${'u'.$i}['cap'];
|
|
}
|
|
|
|
$result['bounty'] = $max_bounty;
|
|
return $result;
|
|
}
|
|
|
|
public function getDataDefScout($defenders, $def_ab, $defender_artefact) {
|
|
$abcount = 1;
|
|
$invol = $dp = $cdp = 0;
|
|
$detected = false;
|
|
|
|
for($y = 4; $y <= 50; $y++) {
|
|
if($y == 4 || $y == 14 || $y == 23 || $y == 44){
|
|
global ${'u'.$y};
|
|
|
|
if($defenders['u'.$y] > 0 && $def_ab[$y] > 0){
|
|
$dp += round(20 + (20 + 300 * ${'u'.$y}['pop'] / 7) * (pow(1.007, $def_ab[$y]) - 1), 4) * $defenders['u'.$y] * $defender_artefact;
|
|
$detected = true;
|
|
}else{
|
|
if($defenders['u'.$y] > 0){
|
|
$dp += $defenders['u'.$y] * 20 * $defender_artefact;
|
|
$detected = true;
|
|
}
|
|
}
|
|
|
|
$invol += $defenders['u'.$y]; //total troops
|
|
$units['Def_unit'][$y] = $defenders['u'.$y];
|
|
}
|
|
}
|
|
|
|
$datadef['dp'] = $dp;
|
|
$datadef['cdp'] = $cdp;
|
|
$datadef['detect'] = $detected;
|
|
$datadef['involve'] = $invol;
|
|
return $datadef;
|
|
}
|
|
|
|
public function getDataDef($defenders,$def_ab) {
|
|
$dp = $cdp = $invol = 0;
|
|
for($y = 1;$y <= 50; $y++) {
|
|
global ${'u'.$y};
|
|
if ($defenders['u'.$y] > 0) {
|
|
if (!isset($def_ab[$y])) {
|
|
$def_ab[$y] = 0;
|
|
}
|
|
if ($def_ab[$y] > 0) {
|
|
$dp += round(${'u'.$y}['di'] + (${'u'.$y}['di'] + 300 * ${'u'.$y}['pop'] / 7) * (pow(1.007, $def_ab[$y]) - 1), 4) * $defenders['u'.$y];
|
|
$cdp += round(${'u'.$y}['dc'] + (${'u'.$y}['dc'] + 300 * ${'u'.$y}['pop'] / 7) * (pow(1.007, $def_ab[$y]) - 1), 4) * $defenders['u'.$y];
|
|
}else{
|
|
$dp += $defenders['u'.$y] * ${'u'.$y}['di'];
|
|
$cdp += $defenders['u'.$y] * ${'u'.$y}['dc'];
|
|
}
|
|
|
|
}
|
|
$invol += $defenders['u'.$y]; //total troops
|
|
$units['Def_unit'][$y] = $defenders['u'.$y];
|
|
}
|
|
$datadef['dp'] = $dp;
|
|
$datadef['cdp'] = $cdp;
|
|
$datadef['involve'] = $invol;
|
|
return $datadef;
|
|
}
|
|
|
|
/**
|
|
* @author Kirilloid --> https://github.com/kirilloid/travian/blob/master/src/model/base/combat.ts
|
|
*
|
|
* Calculates the new building level, after damaging it
|
|
*
|
|
* @param int $oldLevel The old building level
|
|
* @param float $damage The damage done by catapults
|
|
* @return int Returns the new building level
|
|
*/
|
|
|
|
public function calculateNewBuildingLevel($oldLevel, $damage){
|
|
$damage -= 0.5;
|
|
if ($damage < 0) return $oldLevel;
|
|
|
|
while ($damage >= $oldLevel && $oldLevel) $damage -= $oldLevel--;
|
|
|
|
return $oldLevel;
|
|
}
|
|
|
|
/**
|
|
* @author Kirilloid --> https://github.com/kirilloid/travian/blob/master/src/model/base/combat.ts
|
|
*
|
|
* Calculates the damage done by catapults
|
|
*
|
|
* @param int $catapultsQuantity The quantity of catapults which take part in the attack
|
|
* @param double $catapultsUpgrade The catapults upgrade multiplier, affected by the cataputls level in the blacksmith
|
|
* @param double $durability The building durability, affected by the stonemason's lodge
|
|
* @param double $ADRatio The attack points / defensive points ratio
|
|
* @param double $strongerBuildings The artifacts multiplier, which strengthens the building, affected by durability artifacts
|
|
* @param double $moraleBonus The defender morale bonus
|
|
* @return double Returns the damage done by catapults
|
|
*/
|
|
|
|
public function calculateCatapultsDamage($catapultsQuantity, $catapultsUpgrade, $durability, $ADRatio, $strongerBuildings, $moraleBonus){
|
|
$catapultsEfficiency = floor($catapultsQuantity / ($durability * $strongerBuildings));
|
|
return 4 * ($this->sigma)($ADRatio) * $catapultsEfficiency * $catapultsUpgrade / $moraleBonus;
|
|
}
|
|
};
|
|
|
|
$battle = new Battle;
|
|
?>
|