private function showMoves(array &$data) { // add unit description $units = ModelLandUnit::iterator(); $unitsViewData = array(); while ($units->hasNext()) { /* @var $unit ModelLandUnit */ $unit = $units->next(); $unitsViewData[] = array('id' => $unit->getId(), 'abbreviation' => $unit->getAbbreviation(), 'name' => $unit->getName()); } $data['units'] = $unitsViewData; // show moves $game = ModelGame::getCurrentGame(); $id_game = $game->getId(); $round = $game->getRound(); $phase = $game->getIdPhase(); if ($phase > PHASE_LANDMOVE) { ++$round; } $moves = ModelLandMove::iterator(ModelUser::getCurrentUser()->getId(), $id_game, $round); $movesViewData = array(); while ($moves->hasNext()) { /* @var $move ModelLandMove */ $move = $moves->next(); $moveViewData = array(); $moveViewData['id'] = $move->getIdMove(); $steps = $move->getSteps(); $zArea = ModelGameArea::getGameArea((int) $id_game, (int) array_shift($steps)); $area = ModelArea::getArea((int) $zArea->getIdArea()); $moveViewData['startArea'] = array('number' => $area->getNumber(), 'name' => $area->getName()); $zArea = ModelGameArea::getGameArea((int) $id_game, (int) array_pop($steps)); $area = ModelArea::getArea($zArea->getIdArea()); $moveViewData['destinationArea'] = array('number' => $area->getNumber(), 'name' => $area->getName()); $units = $move->getUnits(); $unit_iter = ModelLandUnit::iterator(); $unitsViewData = array(); while ($unit_iter->hasNext()) { /* @var $unit ModelLandUnit */ $unit = $unit_iter->next(); $id_unit = (int) $unit->getId(); $unitsViewData[] = array('id' => $id_unit, 'count' => isset($units[$id_unit]) ? $units[$id_unit] : 0); } $moveViewData['units'] = $unitsViewData; $movesViewData[] = $moveViewData; } $data['moves'] = $movesViewData; }
/** * checks if this move is valid, throws exception if not valid * * @param int $id_move * @param int $round * @param $steps array(int step_nr => int id_zarea) -> step_nr counting from 1 to x * @param $units array(int id_unit => count) * @throws NullPointerException * @throws ControllerException * @return boolean */ private function validateLandMove($id_move, $round, $steps, $units) { $attacks = array(); /* * check if user owns the start country */ $id_start_area = $steps[1]; $zArea = ModelGameArea::getGameArea($this->id_game, $id_start_area); if ($zArea->getIdUser() !== $this->id_user) { throw new ControllerException('Start country isn\'t owned by this user.'); } /* * check if start area is land area */ if ($zArea->getIdType() !== TYPE_LAND) { throw new ControllerException('Start area not a country.'); } /* * check if enough units are left in the country -> iterate over all moves (except this), substract outgoing * check if there are any incoming units * count number of attacks */ $ingameLandUnits = ModelInGameLandUnit::getUnitsByIdZAreaUser($this->id_game, $id_start_area, $this->id_user); //array(int id_unit => ModelInGameLandUnit) $area_units = array(); $units_incoming = 0; $landUnitsIterator = ModelLandUnit::iterator(); while ($landUnitsIterator->hasNext()) { /* @var $landUnit ModelLandMove */ $landUnit = $landUnitsIterator->next(); $id_unit = (int) $landUnit->getId(); if (isset($ingameLandUnits[$id_unit])) { /* @var $ingameLandUnit ModelInGameLandUnit */ $ingameLandUnit = $ingameLandUnits[$id_unit]; $area_units[$id_unit] = $ingameLandUnit->getCount(); } else { $area_units[$id_unit] = 0; } } $landMovesIterator = ModelLandMove::iterator($this->id_user, $this->id_game, $round); while ($landMovesIterator->hasNext()) { /* @var $landMove ModelLandMove */ $landMove = $landMovesIterator->next(); if ($landMove->getId() === $id_move) { continue; // only subtract units from other moves } $move_steps = $landMove->getSteps(); $zTargetArea = ModelGameArea::getGameArea($this->id_game, end($move_steps)); $zStartArea = ModelGameArea::getGameArea($this->id_game, reset($move_steps)); // check if this is an attack if ($zTargetArea->getIdUser() !== $this->id_user && !in_array($zTargetArea->getId(), $attacks)) { $attacks[] = $zTargetArea->getId(); } if ($zStartArea->getId() === $id_start_area) { $move_units = $landMove->getUnits(); foreach ($move_units as $id_unit => $count) { $area_units[$id_unit] -= $count; } } else { if ($zTargetArea->getId() === $id_start_area) { $move_units = $landMove->getUnits(); foreach ($move_units as $id_unit => $count) { $units_incoming += $count; } } } } $total_units_left = $units_incoming; foreach ($area_units as $id_unit => $count) { if (isset($units[$id_unit]) && $units[$id_unit] > $count) { throw new ControllerException('Invalid move, not enough units in area.'); } $count_leaving = isset($units[$id_unit]) ? $units[$id_unit] : 0; $total_units_left += $count - $count_leaving; } if ($total_units_left <= 0) { throw new ControllerException('Can\'t leave country empty.'); } /* * check if target area is reachable -> 2 cases: type land or type aircraft movement */ $id_target_area = (int) end($steps); $type = TYPE_AIR; $speed = 99999; foreach ($units as $id_unit => $count) { if ($count <= 0) { continue; } /* @var $landUnit ModelLandUnit */ $landUnit = ModelLandUnit::getModelById((int) $id_unit); if ($landUnit->getIdType() < $type) { $type = $landUnit->getIdType(); } if ($landUnit->getSpeed() < $speed) { $speed = $landUnit->getSpeed(); } } if (!$this->checkPossibleRoute($id_start_area, $id_target_area, $type, $speed)) { throw new ControllerException('Unable to find route between the 2 countries.'); } /* * check if target area is enemy area, only MAX_LAND_ATTACKS attacks per round */ $zTargetArea = ModelGameArea::getGameArea($this->id_game, $id_target_area); if ($zTargetArea->getIdUser() !== $this->id_user) { // move is an attack if (!in_array($zTargetArea->getId(), $attacks)) { $attacks[] = $zTargetArea->getId(); } if (count($attacks) > MAX_LAND_ATTACKS) { throw new ControllerException('Unable to start any more attacks! Only ' . MAX_LAND_ATTACKS . ' per round allowed.'); } } /* * check if target area is land area */ if ($zTargetArea->getIdType() != TYPE_LAND) { throw new ControllerException('Destination not a country.'); } return true; }
private function executeAttack($id_target_area, array $moves) { // 0. init empty arrays for attacker/defender units $units_attacker = array(); $units_defender = array(); // 1. get units for defender $target_area = ModelGameArea::getGameArea($this->id_game, $id_target_area); $id_defender = $target_area->getIdUser(); $iter = ModelLandUnit::iterator(); while ($iter->hasNext()) { /* @var ModelLandUnit $unit */ $unit = $iter->next(); $units_attacker[$unit->getId()] = 0; $landUnit_defender = ModelInGameLandUnit::getModelByIdZAreaUserUnit($this->id_game, $id_target_area, $id_defender, $unit->getId()); $units_defender[$unit->getId()] = $landUnit_defender->getCount(); } // 2. add up all units for attacker (multiple moves possible, check already finished moves from NML-fights) // 2.a subtract units from originating country $id_attacker = 0; foreach ($moves as $id_move) { $move = ModelLandMove::getLandMove($this->id_game, $id_move); $id_user = $move->getIdUser(); $id_attacker = $id_user; $steps = $move->getSteps(); $from = reset($steps); $units = $move->getUnits(); foreach ($units as $id_unit => $count) { $landUnit_from = ModelInGameLandUnit::getModelByIdZAreaUserUnit($this->id_game, $from, $id_user, $id_unit); $landUnit_from->addCount($count * -1); $units_attacker[$id_unit] += $count; } } // 3. calculate winner and remaining units $attacker_wins = $this->calculateFight($units_attacker, $units_defender); // 3.a update defender units $iter = ModelLandUnit::iterator(); while ($iter->hasNext()) { /* @var ModelLandUnit $unit */ $unit = $iter->next(); $landUnit_defender = ModelInGameLandUnit::getModelByIdZAreaUserUnit($this->id_game, $id_target_area, $id_defender, $unit->getId()); $landUnit_defender->setCount($units_defender[$unit->getId()]); } // 4. update target country units (and user if attacker won) if ($attacker_wins) { // 4.a update attacker units $iter = ModelLandUnit::iterator(); while ($iter->hasNext()) { /* @var ModelLandUnit $unit */ $unit = $iter->next(); $landUnit_attacker = ModelInGameLandUnit::getModelByIdZAreaUserUnit($this->id_game, $id_target_area, $id_attacker, $unit->getId()); $landUnit_attacker->setCount($units_attacker[$unit->getId()]); } // 4.b update country owner $area = ModelGameArea::getGameArea($this->id_game, $id_target_area); $area->setIdUser($id_attacker); // 4.c check ships // TODO : implement ship takeover or ship destruction } // 4. flag all moves as finished foreach ($moves as $id_move) { $this->finished_moves[] = $id_move; } }