public function setCombatIndex($defenderId)
 {
     $combatLog = "";
     /* @var JagCore $battle */
     $battle = Battle::getBattle();
     $scenario = $battle->scenario;
     $combats = $battle->combatRules->combats->{$defenderId};
     $combats->dieShift = 0;
     $attackingForceId = $battle->force->attackingForceId;
     $attackingForceName = preg_replace("/ /", "-", Battle::$forceName[$attackingForceId]);
     $defendingForceId = $battle->force->defendingForceId;
     $defendingForceName = preg_replace("/ /", "-", Battle::$forceName[$defendingForceId]);
     if (count((array) $combats->attackers) == 0) {
         $combats->index = null;
         $combats->attackStrength = null;
         $combats->defenseStrength = null;
         $combats->terrainCombatEffect = null;
         return;
     }
     $defenders = $combats->defenders;
     $isFrozenSwamp = $isTown = $isHill = $isForest = $isSwamp = $attackerIsSunkenRoad = $isRedoubt = $isElevated = false;
     foreach ($defenders as $defId => $defender) {
         $hexagon = $battle->force->units[$defId]->hexagon;
         $hexpart = new Hexpart();
         $hexpart->setXYwithNameAndType($hexagon->name, HEXAGON_CENTER);
         $isTown |= $battle->terrain->terrainIs($hexpart, 'town');
         $isHill |= $battle->terrain->terrainIs($hexpart, 'hill');
         $isForest |= $battle->terrain->terrainIs($hexpart, 'forest');
         $isSwamp |= $battle->terrain->terrainIs($hexpart, 'swamp');
         if ($battle->terrain->terrainIs($hexpart, 'frozenswamp')) {
             if ($battle->terrain->getDefenderTerrainCombatEffect($hexagon)) {
                 $isFrozenSwamp |= true;
             }
         }
         if ($battle->terrain->terrainIs($hexpart, 'elevation1')) {
             $isElevated = 1;
         }
         if ($battle->terrain->terrainIs($hexpart, 'elevation2')) {
             $isElevated = 2;
         }
     }
     $isClear = true;
     if ($isTown || $isForest || $isHill || $isSwamp || $isFrozenSwamp) {
         $isClear = false;
     }
     $attackers = $combats->attackers;
     $attackStrength = 0;
     $attackersCav = false;
     $combinedArms = ['infantry' => 0, 'artillery' => 0, 'cavalry' => 0];
     $arnold = $morgan = false;
     $combatLog .= "<br><span class='{$attackingForceName} combatants'>Attackers</span><br>";
     $attackStrengths = "";
     foreach ($attackers as $attackerId => $attacker) {
         $terrainReason = "";
         $unit = $battle->force->units[$attackerId];
         $unitStrength = $unit->strength;
         if ($unit->class === "wagon") {
             $unitStrength = 0;
         }
         if (!empty($scenario->americanRevolution) && $unit->class === "hq") {
             $combatLog .= "&nbsp;&nbsp;<br><span class='crtDetailComment'>Arnold was here</span>&nbsp;&nbsp;<br>";
             $arnold = true;
         }
         if ($unit->name === "morgan") {
             $combatLog .= "&nbsp;&nbsp;<br><span class='crtDetailComment'>Morgan was here</span>&nbsp;&nbsp;<br>";
             $morgan = true;
         }
         $hexagon = $unit->hexagon;
         $hexpart = new Hexpart();
         $hexpart->setXYwithNameAndType($hexagon->name, HEXAGON_CENTER);
         $attackerIsSwamp = false;
         if (empty($scenario->wimpySwamps)) {
             $attackerIsSwamp = $battle->terrain->terrainIs($hexpart, 'swamp');
         }
         $attackerIsFrozenSwamp = $battle->terrain->terrainIs($hexpart, 'frozenswamp');
         $attackerIsSunkenRoad = $battle->terrain->terrainIs($hexpart, 'sunkenroad');
         if ($attackerIsSwamp) {
             $terrainReason .= "attacker is in swamp ";
         }
         if ($attackerIsSunkenRoad) {
             $terrainReason .= "attacker is in sunken road ";
         }
         if ($attackerIsFrozenSwamp) {
             $terrainReason .= "attacker is frozen swamp ";
         }
         if ($isFrozenSwamp) {
             $terrainReason .= "Frozen Swamp ";
         }
         $attackerIsElevated = false;
         if ($battle->terrain->terrainIs($hexpart, 'elevation1')) {
             $attackerIsElevated = 1;
         }
         if ($battle->terrain->terrainIs($hexpart, 'elevation2')) {
             $attackerIsElevated = 2;
         }
         $attackUpHill = false;
         if ($isElevated && $isElevated > $attackerIsElevated) {
             /* Special case for elevation 2 and attack no elevated, can be from be behind */
             if ($isElevated == 2 && $attackerIsElevated === false) {
                 if ($battle->combatRules->thisAttackAcrossTwoType($defId, $attackerId, "elevation1")) {
                     $terrainReason .= "attack uphill ";
                     $attackUpHill = true;
                 }
             } else {
                 $terrainReason .= "attack uphill ";
                 $attackUpHill = true;
             }
         }
         $acrossRiver = false;
         foreach ($defenders as $defId => $defender) {
             if ($battle->combatRules->thisAttackAcrossRiver($defId, $attackerId)) {
                 $terrainReason .= "attack across river or wadi";
                 $acrossRiver = true;
             }
         }
         $acrossRedoubt = false;
         foreach ($defenders as $defId => $defender) {
             $isRedoubt = false;
             $hexagon = $battle->force->units[$defId]->hexagon;
             $hexpart = new Hexpart();
             $hexpart->setXYwithNameAndType($hexagon->name, HEXAGON_CENTER);
             $isRedoubt |= $battle->terrain->terrainIs($hexpart, 'redoubt');
             if ($isRedoubt && $battle->combatRules->thisAttackAcrossType($defId, $attackerId, "redoubt")) {
                 $acrossRedoubt = true;
                 $terrainReason .= "across redoubt ";
             }
         }
         if ($unit->class == "hq") {
             $combatLog .= "{$unitStrength} HQ Leardership";
         }
         if ($unit->class == "infantry") {
             $combinedArms[$battle->force->units[$attackerId]->class]++;
             $combatLog .= "{$unitStrength} Infantry";
             if (!empty($scenario->jagersdorfCombat)) {
                 if ($unit->nationality == "Prussian" && $isClear && !$acrossRiver) {
                     $unitStrength++;
                     $combatLog .= "&nbsp;&nbsp;<br><span class='crtDetailComment'>+1 for attack into clear</span>&nbsp;&nbsp;<br>";
                 }
                 if ($unit->nationality == "Russian" && ($isTown || $isForest) && !$acrossRiver) {
                     $unitStrength++;
                     $combatLog .= "&nbsp;&nbsp;<br><span class='crtDetailComment'>+1 for attack into town or forest</span>&nbsp;&nbsp;<br>";
                 }
             }
             if (!empty($scenario->americanRevolution)) {
                 if ($unit->forceId == LOYALIST_FORCE && $isClear && !$acrossRiver) {
                     if ($unit->name !== "sharpshooter") {
                         $unitStrength++;
                         $combatLog .= "&nbsp;&nbsp;<br><span class='crtDetailComment'>+1 for attack into clear</span>&nbsp;&nbsp;<br>";
                     }
                 }
             }
             if (($unit->nationality == "Beluchi" || $unit->nationality == "Sikh") && ($isTown || $isForest) && !$acrossRiver) {
                 $unitStrength++;
                 $combatLog .= "+1 for attack into town or forest<br>";
             }
             if ($isSwamp || $isFrozenSwamp || $attackerIsFrozenSwamp || $attackerIsSwamp || $acrossRiver || $attackerIsSunkenRoad || $acrossRedoubt || $attackUpHill) {
                 if (!$terrainReason) {
                     $terrainReason = " terrain ";
                 }
                 if (($attackUpHill || $isFrozenSwamp || $attackerIsFrozenSwamp) && !($isSwamp || $attackerIsSwamp || $acrossRiver || $attackerIsSunkenRoad || $acrossRedoubt)) {
                     //                        $unitStrength *= .75;
                     //                        $combats->dieShift = -1;
                     $unitStrength -= 1;
                     $combatLog .= "<span class='crtDetailComment'>unit strength -1  for {$terrainReason}</span>&nbsp;&nbsp;<br>";
                 } else {
                     if (empty($scenario->weakRedoubts)) {
                         $unitStrength /= 2;
                         $combatLog .= "&nbsp;&nbsp;<br><span class='crtDetailComment'>attack halved&nbsp;&nbsp;<br>{$terrainReason}</span>&nbsp;&nbsp;<br>";
                     }
                 }
             }
             $combatLog .= " {$unitStrength}<br>";
         }
         if ($unit->class == "cavalry") {
             $combatLog .= "{$unitStrength} Cavalry";
             $attackersCav = true;
             if ($attackerIsSwamp || $acrossRiver || !$isClear || $attackerIsSunkenRoad || $acrossRedoubt) {
                 if (!$terrainReason) {
                     $terrainReason = " terrain ";
                 }
                 $combatLog .= "&nbsp;&nbsp;<br><span class='crtDetailComment'>loses combined arms bonus&nbsp;&nbsp;<br>";
                 $unitStrength /= 2;
                 $combatLog .= "attack halved&nbsp;&nbsp;<br>{$terrainReason}</span>&nbsp;&nbsp;<br>";
             } elseif ($attackUpHill || $attackerIsFrozenSwamp) {
                 //                    $unitStrength *= .75;
                 //                    $combats->dieShift = -1;
                 $unitStrength -= 1;
                 $combatLog .= "&nbsp;&nbsp;<br><span class='crtDetailComment'>unit strength -1 for {$terrainReason}</span>&nbsp;&nbsp;<br>";
                 if ($unit->nationality != "Beluchi" && $unit->nationality != "Sikh") {
                     $combinedArms[$battle->force->units[$attackerId]->class]++;
                 } else {
                     $combatLog .= "&nbsp;&nbsp;<br><span class='crtDetailComment'>no combined arms bonus for " . $unit->nationality . " cavalry</span>&nbsp;&nbsp;<br>";
                 }
             } else {
                 if (!empty($scenario->angloCavBonus) && $unit->nationality == "AngloAllied") {
                     $unitStrength++;
                     $combatLog .= "&nbsp;&nbsp;<br><span class='crtDetailComment'>+1 for attack into clear</span>&nbsp;&nbsp;<br>";
                 }
                 if ($unit->nationality != "Beluchi" && $unit->nationality != "Sikh") {
                     $combinedArms[$battle->force->units[$attackerId]->class]++;
                 } else {
                     $combatLog .= "&nbsp;&nbsp;<br><span class='crtDetailComment'>no combined arms bonus for " . $unit->nationality . " cavalry</span>&nbsp;&nbsp;<br>";
                 }
             }
             $combatLog .= " {$unitStrength}<br>";
         }
         if ($unit->class == "artillery" || $unit->class == "horseartillery") {
             $combatLog .= "{$unitStrength} " . ucfirst($unit->class);
             if ($isSwamp || $acrossRedoubt || $attackUpHill || $isFrozenSwamp || $attackerIsFrozenSwamp) {
                 if ($attackUpHill || $isFrozenSwamp || $attackerIsFrozenSwamp) {
                     //                        $unitStrength *= .75;
                     //                        $combats->dieShift = -1;
                     $unitStrength -= 1;
                     $combatLog .= "&nbsp;&nbsp;<br><span class='crtDetailComment'>unit strength -1 for {$terrainReason}</span>&nbsp&nbsp;<br>";
                 } else {
                     $unitStrength /= 2;
                     $combatLog .= "&nbsp;&nbsp;<br><span class='crtDetailComment'>attacker halved for {$terrainReason}</span>&nbsp;&nbsp;<br>";
                 }
                 if (!$terrainReason) {
                     $terrainReason = " terrain ";
                 }
             }
             $class = $unit->class;
             if ($class == 'horseartillery') {
                 $class = 'artillery';
             }
             if ($unit->nationality != "Beluchi") {
                 $combinedArms[$class]++;
             } else {
                 $combatLog .= "&nbsp;&nbsp;<br><span class='crtDetailComment'>no combined arms bonus for Beluchi</span>&nbsp&nbsp;<br>";
             }
             $combatLog .= " {$unitStrength}<br>";
         }
         if ($attackStrengths) {
             $attackStrengths .= " + {$unitStrength}";
         } else {
             $attackStrengths = $unitStrength;
         }
         $attackStrength += $unitStrength;
     }
     $combatLog .= "{$attackStrengths} = {$attackStrength}<br>";
     $defenseStrength = 0;
     $defenseStrengths = '';
     $defendersAllCav = true;
     $combatLog .= "<br><span class='{$defendingForceName} combatants'>Defenders</span><br>";
     foreach ($defenders as $defId => $defender) {
         $unit = $battle->force->units[$defId];
         $class = $unit->class;
         $unitDefense = $unit->defStrength;
         $combatLog .= " {$unitDefense} " . $unit->class;
         /* set to true to disable for not scenario->doubleArt */
         $clearHex = false;
         $artInNonTown = false;
         $notClearHex = false;
         $hexagon = $unit->hexagon;
         $hexpart = new Hexpart();
         $hexpart->setXYwithNameAndType($hexagon->name, HEXAGON_CENTER);
         $isTown = $battle->terrain->terrainIs($hexpart, 'town');
         $isHill = $battle->terrain->terrainIs($hexpart, 'hill');
         $isForest = $battle->terrain->terrainIs($hexpart, 'forest');
         $isSwamp = $battle->terrain->terrainIs($hexpart, 'swamp');
         $notClearHex = false;
         if ($isTown || $isForest || $isHill || $isSwamp) {
             $notClearHex = true;
         }
         $clearHex = !$notClearHex;
         if (($unit->class == 'artillery' || $unit->class == 'horseartillery') && !$isTown) {
             $combatLog .= "&nbsp;&nbsp;<br><span class='crtDetailComment'>doubled for defending in non town</span>&nbsp;&nbsp;<br>";
             $artInNonTown = true;
         }
         if ($unit->class != 'cavalry') {
             $defendersAllCav = false;
         }
         if (!empty($scenario->jagersdorfCombat)) {
             if ($unit->forceId == PRUSSIAN_FORCE && $class == "infantry" && $isClear) {
                 $unitDefense += 1;
                 $combatLog .= "&nbsp;&nbsp;<br><span class='crtDetailComment'>+1 for defending in clear 1</span><br>";
             }
             if ($unit->forceId == RUSSIAN_FORCE && $class == "infantry" && ($isTown || $isForest)) {
                 $unitDefense += 1;
                 $combatLog .= "&nbsp;&nbsp;<br><span class='crtDetailComment'>+1 for defending in town or forest</span><br>";
             }
         }
         if (!empty($scenario->americanRevolution)) {
             if ($unit->forceId == LOYALIST_FORCE && $class == "infantry" && $isClear) {
                 if ($unit->name !== "sharpshooter") {
                     $unitDefense += 1;
                     $combatLog .= "&nbsp;&nbsp;<br><span class='crtDetailComment'>+1 for defending in clear</span><br>";
                 }
             }
             if ($unit->forceId == REBEL_FORCE && $class == "infantry" && (!$isClear || $battle->combatRules->allAreAttackingThisAcrossRiver($defId))) {
                 $unitDefense += 1;
                 $combatLog .= "&nbsp;&nbsp;<br><span class='crtDetailComment'>+1 for defending in town or forest</span><br>";
             }
         }
         if (($unit->nationality == "Beluchi" || $unit->nationality == "Sikh") && $class == "infantry" && ($isTown || $isForest)) {
             $unitDefense++;
             $combatLog .= "&nbsp;&nbsp;<br><span class='crtDetailComment'>+1 in town or forest</span><br>";
         }
         $defMultiplier = 1;
         if ($isTown && $class !== 'cavalry' || $artInNonTown || $isHill) {
             $defMultiplier = 2.0;
             if ($isTown && $class !== 'cavalry' || $isHill) {
                 $defMultiplier = 2;
                 $combatLog .= "&nbsp;&nbsp;<br><span class='crtDetailComment'>2x for terrain</span><br>";
             }
         }
         $combatLog .= " " . $unitDefense * $defMultiplier . "<br>";
         if ($defenseStrengths) {
             $defenseStrengths .= " + " . $unitDefense * $defMultiplier;
         } else {
             $defenseStrengths = $unitDefense * $defMultiplier;
         }
         $defenseStrength += $unitDefense * $defMultiplier;
     }
     $combatLog .= "{$defenseStrengths} = {$defenseStrength}<br><br>";
     $armsShift = 0;
     $combinedLog = '';
     if ($attackStrength >= $defenseStrength) {
         foreach ($combinedArms as $key => $arms) {
             if ($arms > 0) {
                 if ($combinedLog) {
                     $combinedLog .= " + {$key}";
                 } else {
                     $combinedLog .= "{$key}";
                 }
                 $armsShift++;
             }
         }
         $armsShift--;
     }
     if ($armsShift) {
         $combatLog .= "Combined Arms Bonus<br> {$combinedLog}<br>Column Shift +{$armsShift}<br><br>";
     }
     if ($armsShift < 0) {
         $armsShift = 0;
     }
     $combatIndex = $this->getCombatIndex($attackStrength, $defenseStrength);
     /* Do this before terrain effects */
     $combatIndex += $armsShift;
     if ($morgan || $arnold) {
         $combatIndex++;
     }
     if ($combatIndex >= $this->maxCombatIndex) {
         $combatIndex = $this->maxCombatIndex;
     }
     //        $terrainCombatEffect = $battle->combatRules->getDefenderTerrainCombatEffect($defenderId);
     //        $combatIndex -= $terrainCombatEffect;
     $combats->attackStrength = $attackStrength;
     $combats->defenseStrength = $defenseStrength;
     $combats->terrainCombatEffect = $armsShift;
     if ($combats->pinCRT !== false) {
         $pinIndex = $combats->pinCRT;
         if ($combatIndex > $pinIndex) {
             $combatLog .= "<br>Pinned to {$this->combatResultsHeader[$pinIndex]} ";
         } else {
             $combats->pinCRT = false;
         }
     }
     $combats->index = $combatIndex;
     $combats->useAlt = false;
     if ($defendersAllCav && !$attackersCav) {
         $combats->useAlt = true;
         $combats->useDetermined = false;
         $combatLog .= "using cavalry table ";
     }
     $combats->combatLog = $combatLog;
 }
 public function postCombatResults($args)
 {
     list($defenderId, $attackers, $combatResults, $dieRoll) = $args;
     $b = Battle::getBattle();
     $cr = $b->combatRules;
     $f = $b->force;
     foreach ($attackers as $attackId => $v) {
         $unit = $f->units[$attackId];
         $hexagon = $unit->hexagon;
         $hexpart = new Hexpart();
         $hexpart->setXYwithNameAndType($hexagon->name, HEXAGON_CENTER);
         if ($b->terrain->terrainIs($hexpart, 'town') || $b->terrain->terrainIs($hexpart, 'forest')) {
             $cr->sighted($hexagon->name);
         }
     }
 }
 public function setCombatIndex($defenderId)
 {
     $combatLog = "";
     $battle = Battle::getBattle();
     $scenario = $battle->scenario;
     $combats = $battle->combatRules->combats->{$defenderId};
     if (count((array) $combats->attackers) == 0) {
         $combats->index = null;
         $combats->attackStrength = null;
         $combats->defenseStrength = null;
         $combats->terrainCombatEffect = null;
         return;
     }
     $defenders = $combats->defenders;
     $isCrest = $isCavalry = $isTown = $isHill = $isForest = $isSwamp = $attackerIsSunkenRoad = $isRedoubt = $isElevated = false;
     $combats->index = [];
     foreach ($defenders as $defId => $defender) {
         $defUnit = $battle->force->units[$defId];
         $hexagon = $defUnit->hexagon;
         if ($defUnit->class === 'cavalry') {
             $isCavalry = true;
         }
         $hexpart = new Hexpart();
         $hexpart->setXYwithNameAndType($hexagon->name, HEXAGON_CENTER);
         $isTown |= $battle->terrain->terrainIs($hexpart, 'town');
         $isForest |= $battle->terrain->terrainIs($hexpart, 'forest');
         if ($battle->terrain->terrainIs($hexpart, 'elevation')) {
             $isElevated = 1;
         }
         if ($battle->terrain->terrainIs($hexpart, 'elevation2')) {
             $isElevated = 2;
         }
         $defenseStrength = $defUnit->defenseStrength;
     }
     $isClear = true;
     if ($isTown || $isForest || $isHill || $isSwamp) {
         $isClear = false;
     }
     $attackers = $combats->attackers;
     $attackStrength = 0;
     $attackersCav = false;
     $combinedArms = array();
     $combatLog .= "<br>";
     foreach ($attackers as $attackerId => $attacker) {
         $terrainReason = "";
         $unit = $battle->force->units[$attackerId];
         $unitStrength = $unit->strength;
         $hexagon = $unit->hexagon;
         $hexpart = new Hexpart();
         $hexpart->setXYwithNameAndType($hexagon->name, HEXAGON_CENTER);
         $los = new Los();
         $los->setOrigin($battle->force->getUnitHexagon($attackerId));
         $los->setEndPoint($battle->force->getUnitHexagon($defenderId));
         $range = $los->getRange();
         $hexParts = $los->getlosList();
         $targetHex = array_pop($hexParts);
         $targetHexSide = array_pop($hexParts);
         if ($battle->terrain->terrainIs($targetHexSide, "crest")) {
             $isCrest = true;
         }
         $combatLog .= $unit->strength . " " . $unit->class . " = " . $unit->strength . "<br>";
         if ($range == 1) {
             $isCloseAssault = false;
             if ($unit->weapons === ModernTacticalUnit::SM_WEAPONS) {
                 if ($defenderId !== false) {
                     $defUnit = $battle->force->units[$defenderId];
                     if ($defUnit->target === ModernTacticalUnit::HARD_TARGET) {
                         $isCloseAssault = true;
                     }
                 }
             }
             if (!$isCloseAssault) {
                 $unitStrength *= 2;
                 $combatLog .= "range 1, doubled = {$unitStrength}<br>";
             } else {
                 $combatLog .= "close assult no range attenuation = {$unitStrength}<br>";
             }
         }
         if ($range >= 4 && $range <= 5) {
             $unitStrength -= 1;
             $combatLog .= " -1 range attentuation = {$unitStrength}<br>";
         }
         if ($range >= 6 && $range <= 8) {
             $unitStrength -= 2;
             $combatLog .= " -2 range attentuation = {$unitStrength}<br>";
         }
         if ($range >= 9 && $range <= 10) {
             $unitStrength -= 3;
             $combatLog .= " -3 range attentuation = {$unitStrength}<br>";
         }
         if ($range >= 11) {
             $unitStrength -= 6;
             $combatLog .= "-6 range attentuation = {$unitStrength}<br>";
         }
         $attackerIsElevated = false;
         if ($battle->terrain->terrainIs($hexpart, 'elevation')) {
             $attackerIsElevated = 1;
         }
         if ($battle->terrain->terrainIs($hexpart, 'elevation2')) {
             $attackerIsElevated = 2;
         }
         $unitStrength -= $defenseStrength;
         $combatLog .= " - {$defenseStrength} defender = {$unitStrength}<br>";
         if ($isForest) {
             $unitStrength--;
             $combatLog .= " in forest - 1 = <span class='fixed-width' >{$unitStrength}</span><br>";
         }
         if ($isTown) {
             $unitStrength -= 2;
             $combatLog .= " in town - 2 = <span class='fixed-width' >{$unitStrength}</span><br>";
         }
         if ($isCrest) {
             $unitStrength -= 1;
             $combatLog .= " in crest - 1 = <span class='fixed-width' >{$unitStrength}</span><br>";
         }
         $combatLog .= "final = {$unitStrength}<br><br>";
         $combats->index[] = $unitStrength;
     }
     $combats->combatLog = $combatLog;
 }
Example #4
0
 function moveIsInto($hexagon, $name)
 {
     $hexpart = new Hexpart();
     $hexpart->setXYwithNameAndType($hexagon->name, HEXAGON_CENTER);
     $moveIsInto = false;
     if ($this->terrainIs($hexpart, $name) == true) {
         $moveIsInto = true;
     }
     return $moveIsInto;
 }
 public function setCombatIndex($defenderId)
 {
     $combatLog = "";
     /* @var JagCore $battle */
     $battle = Battle::getBattle();
     $scenario = $battle->scenario;
     $combats = $battle->combatRules->combats->{$defenderId};
     if (count((array) $combats->attackers) == 0) {
         $combats->index = null;
         $combats->attackStrength = null;
         $combats->defenseStrength = null;
         $combats->terrainCombatEffect = null;
         return;
     }
     $defenders = $combats->defenders;
     $isCavalry = $isTown = $isHill = $isForest = $isSwamp = $attackerIsSunkenRoad = $isRedoubt = $isElevated = false;
     foreach ($defenders as $defId => $defender) {
         $defUnit = $battle->force->units[$defId];
         $hexagon = $defUnit->hexagon;
         if ($defUnit->class === 'cavalry') {
             $isCavalry = true;
         }
         $hexpart = new Hexpart();
         $hexpart->setXYwithNameAndType($hexagon->name, HEXAGON_CENTER);
         $isTown |= $battle->terrain->terrainIs($hexpart, 'town');
         $isForest |= $battle->terrain->terrainIs($hexpart, 'forest');
         if ($battle->terrain->terrainIs($hexpart, 'elevation')) {
             $isElevated = 1;
         }
         if ($battle->terrain->terrainIs($hexpart, 'elevation2')) {
             $isElevated = 2;
         }
     }
     $isClear = true;
     if ($isTown || $isForest || $isHill || $isSwamp) {
         $isClear = false;
     }
     $attackers = $combats->attackers;
     $attackStrength = 0;
     $attackersCav = false;
     $combinedArms = array();
     $combatLog .= "Attackers<br>";
     foreach ($attackers as $attackerId => $attacker) {
         $terrainReason = "";
         $unit = $battle->force->units[$attackerId];
         $unitStrength = $unit->strength;
         $hexagon = $unit->hexagon;
         $hexpart = new Hexpart();
         $hexpart->setXYwithNameAndType($hexagon->name, HEXAGON_CENTER);
         $los = new Los();
         $los->setOrigin($battle->force->getUnitHexagon($attackerId));
         $los->setEndPoint($battle->force->getUnitHexagon($defenderId));
         $range = $los->getRange();
         $combatLog .= $unit->strength . " " . $unit->class . " ";
         if ($isCavalry) {
             $combatLog .= "defender is cavalry, doubled ";
             $unitStrength *= 2;
         }
         if ($unit->class === "infantry" && $range == 1) {
             $combatLog .= "infantry at range 1, doubled ";
             $unitStrength *= 2;
         }
         if ($unit->class === "mg" && $range <= 3) {
             $combatLog .= "machine gun at range 3 or less, doubled ";
             $unitStrength *= 2;
         }
         if ($isTown || $isForest) {
             if ($range > 1) {
                 $combatLog .= "using observation fire, halved ";
                 $unitStrength /= 2;
             }
         }
         $attackerIsElevated = false;
         if ($battle->terrain->terrainIs($hexpart, 'elevation')) {
             $attackerIsElevated = 1;
         }
         if ($battle->terrain->terrainIs($hexpart, 'elevation2')) {
             $attackerIsElevated = 2;
         }
         $combatLog .= "<br>";
         $attackStrength += $unitStrength;
     }
     $combatLog .= " = {$attackStrength}<br>Defenders<br>";
     $defenseStrength = 0;
     foreach ($defenders as $defId => $defender) {
         $unitStrength = 2;
         $terrain = '';
         $unit = $battle->force->units[$defId];
         $class = $unit->class;
         $clearHex = false;
         $notClearHex = false;
         $hexagon = $unit->hexagon;
         $hexpart = new Hexpart();
         $hexpart->setXYwithNameAndType($hexagon->name, HEXAGON_CENTER);
         $isTown = $battle->terrain->terrainIs($hexpart, 'town');
         //            $isHill = $battle->terrain->terrainIs($hexpart, 'hill');
         $isForest = $battle->terrain->terrainIs($hexpart, 'forest');
         $isSwamp = $battle->terrain->terrainIs($hexpart, 'swamp');
         $terran = "";
         if ($attackerIsElevated < $isElevated) {
             $unitStrength = 4;
             $terrain = "uphill ";
         }
         if ($isTown) {
             $terrain = "in town ";
             $unitStrength = 8;
         }
         if ($isForest) {
             $terrain = "in forest ";
             $unitStrength = 5;
         }
         if ($unit->isImproved) {
             $unitStrength *= 2;
             $terrain .= "Improved ";
         }
         $combatLog .= "{$unitStrength} " . $unit->class . " {$terrain}";
         $defenseStrength += $unitStrength;
         $combatLog .= "<br>";
     }
     $combatLog .= " = {$defenseStrength}";
     $combatIndex = $this->getCombatIndex($attackStrength, $defenseStrength);
     /* Do this before terrain effects */
     if ($combatIndex >= $this->maxCombatIndex) {
         $combatIndex = $this->maxCombatIndex;
     }
     //        $terrainCombatEffect = $battle->combatRules->getDefenderTerrainCombatEffect($defenderId);
     //        $combatIndex -= $terrainCombatEffect;
     $combats->attackStrength = $attackStrength;
     $combats->defenseStrength = $defenseStrength;
     $combats->terrainCombatEffect = 0;
     //
     //        if($combats->pinCRT !== false){
     //            $pinIndex = $combats->pinCRT;
     //            if($combatIndex > $pinIndex){
     //                $combatLog .= "<br>Pinned to {$this->combatResultsHeader[$pinIndex]} ";
     //            }else{
     //                $combats->pinCRT = false;
     //            }
     //        }
     $combats->index = $combatIndex;
     $combats->useAlt = false;
     $combats->combatLog = $combatLog;
 }
 public function setCombatIndex($defenderId)
 {
     /* @var Jagersdorf $battle */
     $battle = Battle::getBattle();
     $combats = $battle->combatRules->combats->{$defenderId};
     $hexagon = $battle->force->units[$defenderId]->hexagon;
     $hexpart = new Hexpart();
     $hexpart->setXYwithNameAndType($hexagon->name, HEXAGON_CENTER);
     if (count((array) $combats->attackers) == 0) {
         $combats->index = null;
         $combats->attackStrength = null;
         $combats->defenseStrength = null;
         $combats->terrainCombatEffect = null;
         return;
     }
     $isClear = $battle->terrain->terrainIs($hexpart, 'clear');
     $isTown = $battle->terrain->terrainIs($hexpart, 'town');
     $isHill = $battle->terrain->terrainIs($hexpart, 'hill');
     $isForest = $battle->terrain->terrainIs($hexpart, 'forest');
     $defenders = $combats->defenders;
     $attackers = $combats->attackers;
     $attackStrength = 0;
     $attackersCav = false;
     $combinedArms = ['infantry' => 0, 'artillery' => 0, 'cavalry' => 0];
     foreach ($attackers as $attackerId => $attacker) {
         $unit = $battle->force->units[$attackerId];
         $unitStrength = $unit->strength;
         if ($unit->class == "infantry") {
             //                if($unit->forceId == PRUSSIAN_FORCE && $isClear){
             //                    $unitStrength++;
             //                }
             //                if($unit->forceId == RUSSIAN_FORCE && ($isTown || $isForest)){
             //                    $unitStrength++;
             //                }
             if ($battle->combatRules->thisAttackAcrossRiver($defenderId, $attackerId)) {
                 $unitStrength /= 2;
             }
         }
         if ($unit->class == "cavalry") {
             $attackersCav = true;
             if ($battle->combatRules->thisAttackAcrossRiver($defenderId, $attackerId) || !$isClear) {
                 $unitStrength /= 2;
             }
         }
         $attackStrength += $unitStrength;
     }
     //        $attackStrength = $battle->force->getAttackerStrength($combats->attackers);
     $defenseStrength = 0;
     $defendersAllCav = true;
     foreach ($defenders as $defId => $defender) {
         $unit = $battle->force->units[$defId];
         $class = $unit->class;
         $unitDefense = $unit->defStrength;
         if ($unit->class != 'cavalry') {
             $defendersAllCav = false;
         }
         //            if($unit->forceId == PRUSSIAN_FORCE && $class == "infantry" && $isClear){
         //                $unitDefense += 1;
         //            }
         //            if($unit->forceId == RUSSIAN_FORCE  && $class == "infantry" && ($isTown || $isForest)){
         //                $unitDefense += 1;
         //            }
         $defenseStrength += $unitDefense * ($isTown && $class != 'cavalry' || $isHill ? 2 : 1);
     }
     if ($attackStrength >= $defenseStrength) {
         foreach ($combats->attackers as $attackerId => $attacker) {
             $combinedArms[$battle->force->units[$attackerId]->class]++;
         }
         if (!$isClear) {
             unset($combinedArms['cavalry']);
         }
     }
     $armsShift = 0;
     if ($attackStrength >= $defenseStrength) {
         foreach ($combinedArms as $arms) {
             if ($arms > 0) {
                 $armsShift++;
             }
         }
         $armsShift--;
     }
     if ($armsShift < 0) {
         $armsShift = 0;
     }
     $combatIndex = $this->getCombatIndex($attackStrength, $defenseStrength);
     /* Do this before terrain effects */
     $combatIndex += $armsShift;
     if ($combatIndex >= $this->maxCombatIndex) {
         $combatIndex = $this->maxCombatIndex;
     }
     //        $terrainCombatEffect = $battle->combatRules->getDefenderTerrainCombatEffect($defenderId);
     //        $combatIndex -= $terrainCombatEffect;
     $combats->attackStrength = $attackStrength;
     $combats->defenseStrength = $defenseStrength;
     $combats->terrainCombatEffect = $armsShift;
     $combats->index = $combatIndex;
     $combats->useAlt = false;
     if ($defendersAllCav && !$attackersCav) {
         $combats->useAlt = true;
     }
 }
 function setCombatIndex($defenderId)
 {
     $combatLog = "";
     $battle = Battle::getBattle();
     $combatRules = $battle->combatRules;
     $terrain = $battle->terrain;
     $combats = $battle->combatRules->combats->{$defenderId};
     /* @var Force $force */
     $force = $battle->force;
     $hexagon = $battle->force->units[$defenderId]->hexagon;
     $hexpart = new Hexpart();
     $hexpart->setXYwithNameAndType($hexagon->name, HEXAGON_CENTER);
     if (count((array) $combats->attackers) == 0) {
         $combats->index = null;
         $combats->attackStrength = null;
         $combats->defenseStrength = null;
         $combats->terrainCombatEffect = null;
         return;
     }
     $defenders = $combats->defenders;
     $attackStrength = 0;
     //        $attackStrength = $this->force->getAttackerStrength($combats->attackers);
     $defenseStrength = 0;
     $defMarsh = false;
     $defArt = false;
     $combatLog .= "<br>Defenders<br> ";
     foreach ($defenders as $defId => $defender) {
         $unit = $battle->force->units[$defId];
         $unitStr = $unit->defStrength;
         $combatLog .= $unit->class . " {$unitStr}";
         $unit = $force->units[$defId];
         $unitHex = $unit->hexagon;
         if ($unit->class == "artillery") {
             $defArt = true;
         }
         if ($terrain->terrainIsHex($unitHex->name, "rough") || $terrain->terrainIsHex($unitHex->name, "hills")) {
             $unitStr *= 2;
             $combatLog .= " 2x rough {$unitStr}";
         }
         if ($terrain->terrainIsHex($unitHex->name, "marsh")) {
             $defMarsh = true;
             if ($unit->class == "inf" || $unit->class == "cavalry") {
                 $unitStr *= 2;
                 $combatLog .= " 2x marsh {$unitStr}";
             }
         }
         $combatLog .= "<br>";
         $defenseStrength += $unitStr;
     }
     $defHex = $unitHex;
     $combatLog .= "Total {$defenseStrength}<br>";
     $combatLog .= "<br>Attackers<br>";
     foreach ($combats->attackers as $id => $v) {
         $unit = $force->units[$id];
         $unitStr = $unit->strength;
         $combatLog .= $unit->class . " " . $unit->strength;
         if ($unit->class != 'artillery' && $terrain->terrainIsHexSide($defHex->name, $unit->hexagon->name, "blocked")) {
             $unitStr = 0;
         }
         if ($unit->class != 'artillery' && ($terrain->terrainIsHexSide($defHex->name, $unit->hexagon->name, "river") || $terrain->terrainIsHexSide($defHex->name, $unit->hexagon->name, "ford"))) {
             $unitStr /= 2;
         }
         if ($defMarsh && $force->units[$id]->class == 'mech') {
             $unitStr /= 2;
             $combatLog .= " mech into marsh halved {$unitStr}";
         }
         if ($defArt && $force->units[$id]->class != 'artillery') {
             $unitStr *= 2;
         }
         $combatLog .= "<br>";
         $attackStrength += $unitStr;
     }
     $combatLog .= "Total {$attackStrength}<br><br>";
     $terrainCombatEffect = 0;
     $combatIndex = $this->getCombatIndex($attackStrength, $defenseStrength);
     /* Do this before terrain effects */
     if ($combatIndex >= $this->maxCombatIndex) {
         $combatIndex = $this->maxCombatIndex;
     }
     $combatIndex -= $terrainCombatEffect;
     $combats->attackStrength = $attackStrength;
     $combats->defenseStrength = $defenseStrength;
     $combats->terrainCombatEffect = $terrainCombatEffect;
     $combats->index = $combatIndex;
     $combats->combatLog = $combatLog;
     //    $this->force->storeCombatIndex($defenderId, $combatIndex);
 }
 function setupCombat($id, $shift = false)
 {
     $battle = Battle::getBattle();
     $victory = $battle->victory;
     $unit = $battle->force->units[$id];
     $cd = $this->currentDefender;
     if ($this->force->unitIsEnemy($id) == true) {
         $isHidden = false;
         $hexagon = $battle->force->units[$id]->hexagon;
         $hexpart = new Hexpart();
         $hexpart->setXYwithNameAndType($hexagon->name, HEXAGON_CENTER);
         $isHidden |= $battle->terrain->terrainIs($hexpart, 'town');
         $isHidden |= $battle->terrain->terrainIs($hexpart, 'forest');
         if ($isHidden && !$battle->force->unitIsAdjacent($id) && !$this->isSighted($hexagon->name, $id)) {
             return false;
         }
         //            $this->sighted($hexagon->name);
         // defender is already in combatRules, so make it currently selected
         //            if(isset($this->defenders->$id)){
         //                $id = $this->defenders->$id;
         //            }
         $combats = isset($this->combats->{$id}) ? $this->combats->{$id} : [];
         $combatId = $id;
         if (isset($this->defenders->{$id})) {
             $combatId = $this->defenders->{$id};
             //                $cd = $this->defenders->$id;
             $combats = $this->combats->{$combatId};
         }
         if ($combats) {
             //            if(count($this->combats->$this->currnetDefender->attackers) == 0){
             //                unset($this->currnetDefender[$id]);
             //            }
             if ($this->currentDefender === false) {
                 $this->currentDefender = $this->defenders->{$id};
             } else {
                 if ($shift) {
                     if (isset($this->defenders->{$id})) {
                         if ($combatId === $this->currentDefender) {
                             foreach ($combats->attackers as $attackerId => $attacker) {
                                 $this->force->undoAttackerSetup($attackerId);
                                 unset($this->attackers->{$attackerId});
                                 $victory->postUnsetAttacker($this->units[$attackerId]);
                             }
                             foreach ($combats->defenders as $defenderId => $defender) {
                                 $unit = $this->force->getUnit($defenderId);
                                 $unit->setStatus(STATUS_READY);
                                 unset($this->defenders->{$defenderId});
                                 $victory->postUnsetDefender($unit);
                             }
                             unset($this->combats->{$combatId});
                             $this->currentDefender = false;
                         } else {
                             $this->currentDefender = $combatId;
                         }
                     }
                 } else {
                     if ($combatId === $this->currentDefender) {
                         $this->currentDefender = false;
                     } else {
                         $this->currentDefender = $combatId;
                     }
                 }
             }
         } else {
             if ($shift) {
                 if ($this->currentDefender !== false) {
                     foreach ($this->combats->{$this->currentDefender}->attackers as $attackerId => $attacker) {
                         $this->force->undoAttackerSetup($attackerId);
                         unset($this->attackers->{$attackerId});
                         unset($this->combats->{$cd}->attackers->{$attackerId});
                         unset($this->combats->{$cd}->thetas->{$attackerId});
                         $victory->postUnsetAttacker($this->units[$attackerId]);
                     }
                     $this->defenders->{$id} = $this->currentDefender;
                 } else {
                     $this->currentDefender = $id;
                     $this->defenders->{$id} = $id;
                 }
             } else {
                 $mapHex = $battle->mapData->getHex($unit->hexagon->getName());
                 $forces = $mapHex->getForces($unit->forceId);
                 $this->currentDefender = $id;
                 foreach ($forces as $force) {
                     if ($this->force->units[$force]->class !== "air" && ($battle->gameRules->phase == RED_AIR_COMBAT_PHASE || $battle->gameRules->phase == BLUE_AIR_COMBAT_PHASE)) {
                         continue;
                     }
                     $this->defenders->{$force} = $id;
                     if ($force != $id) {
                         $cd = $this->currentDefender;
                         $this->force->setupDefender($force);
                         if (!$this->combats) {
                             $this->combats = new stdClass();
                         }
                         if (!$this->combats->{$cd}) {
                             $this->combats->{$cd} = new Combat();
                         }
                         $this->combats->{$cd}->defenders->{$force} = $id;
                     }
                 }
             }
             $cd = $this->currentDefender;
             //                $this->defenders->{$this->currentDefender} = $id;
             $this->force->setupDefender($id);
             if (!$this->combats) {
                 $this->combats = new stdClass();
             }
             if (empty($this->combats->{$cd})) {
                 $this->combats->{$cd} = new Combat();
             }
             $this->combats->{$cd}->defenders->{$id} = $id;
             //                $victory->postSetDefender($this->force->units[$id]);
         }
     } else {
         if ($this->currentDefender !== false && $this->force->units[$id]->status != STATUS_UNAVAIL_THIS_PHASE) {
             if (isset($this->combats->{$cd}->attackers->{$id}) && $this->attackers->{$id} === $cd) {
                 $this->force->undoAttackerSetup($id);
                 unset($this->attackers->{$id});
                 unset($this->combats->{$cd}->attackers->{$id});
                 unset($this->combats->{$cd}->thetas->{$id});
                 $victory->postUnsetAttacker($this->force->units[$id]);
                 $this->crt->setCombatIndex($cd);
             } else {
                 $good = true;
                 foreach ($this->combats->{$this->currentDefender}->defenders as $defenderId => $defender) {
                     $los = new Los();
                     $los->setOrigin($this->force->getUnitHexagon($id));
                     $los->setEndPoint($this->force->getUnitHexagon($defenderId));
                     $range = $los->getRange();
                     if ($range > $unit->getRange($id)) {
                         $good = false;
                         break;
                     }
                     if ($range > 1) {
                         $good = $this->checkBlocked($los, $id);
                         if ($good) {
                             $isHidden = false;
                             $hexagon = $this->force->getUnitHexagon($defenderId);
                             $hexpart = new Hexpart();
                             $hexpart->setXYwithNameAndType($hexagon->name, HEXAGON_CENTER);
                             $isHidden |= $battle->terrain->terrainIs($hexpart, 'town');
                             $isHidden |= $battle->terrain->terrainIs($hexpart, 'forest');
                             if ($isHidden && !$this->isSighted($hexagon->name, $cd)) {
                                 /* confirm observer is in los too */
                                 $bad = true;
                                 $adjacentUnits = $this->force->getAdjacentUnits($defenderId);
                                 $observerLos = new Los();
                                 $observerLos->setOrigin($this->force->getUnitHexagon($id));
                                 foreach ($adjacentUnits as $adjacentUnitId => $v) {
                                     $observerLos->setEndPoint($this->force->getUnitHexagon($adjacentUnitId));
                                     if ($this->checkBlocked($observerLos, $adjacentUnitId)) {
                                         $bad = false;
                                         break;
                                     }
                                 }
                                 if ($bad) {
                                     $good = false;
                                 }
                             }
                         }
                     }
                     if ($range == 1) {
                         if ($this->terrain->terrainIsHexSide($this->force->getUnitHexagon($id)->name, $this->force->getUnitHexagon($defenderId)->name, "blocked") && !($unit->class === "artillery" || $unit->class === "horseartillery")) {
                             $good = false;
                         }
                     }
                     if (method_exists($unit, "checkLos")) {
                         if ($unit->checkLos($los, $defenderId) === false) {
                             $good = false;
                         }
                     }
                 }
                 if ($good) {
                     foreach ($this->combats->{$this->currentDefender}->defenders as $defenderId => $defender) {
                         $los = new Los();
                         $los->setOrigin($this->force->getUnitHexagon($id));
                         $los->setEndPoint($this->force->getUnitHexagon($defenderId));
                         $range = $los->getRange();
                         $bearing = $los->getBearing();
                         if ($range <= $unit->getRange($id)) {
                             $this->force->setupAttacker($id, $range);
                             if (isset($this->attackers->{$id}) && $this->attackers->{$id} !== $cd) {
                                 /* move unit to other attack */
                                 $oldCd = $this->attackers->{$id};
                                 unset($this->combats->{$oldCd}->attackers->{$id});
                                 unset($this->combats->{$oldCd}->thetas->{$id});
                                 $this->crt->setCombatIndex($oldCd);
                                 $this->checkBombardment($oldCd);
                             }
                             $this->attackers->{$id} = $cd;
                             $this->combats->{$cd}->attackers->{$id} = $bearing;
                             $this->combats->{$cd}->defenders->{$defenderId} = $bearing;
                             if (empty($this->combats->{$cd}->thetas->{$id})) {
                                 $this->combats->{$cd}->thetas->{$id} = new stdClass();
                             }
                             $this->combats->{$cd}->thetas->{$id}->{$defenderId} = $bearing;
                             $victory->postSetDefender($this->force->units[$defenderId]);
                             $this->crt->setCombatIndex($cd);
                         }
                     }
                     $victory->postSetAttacker($this->force->units[$id]);
                 }
             }
             $this->checkBombardment();
         }
     }
     $this->cleanUpAttacklessDefenders();
 }