/** * returns all models for the given area/user * * @param $id_game int * @param $id_zarea int * @param $id_user int * @return array - array(int id_unit => ModelInGameLandUnit) */ public static function getUnitsByIdZAreaUser($id_game, $id_zarea, $id_user) { $output = array(); $iter = ModelLandUnit::iterator(); while ($iter->hasNext()) { $landUnit = $iter->next(); $id_unit = (int) $landUnit->getId(); $output[$id_unit] = self::getModelByIdZAreaUserUnit($id_game, $id_zarea, $id_user, $id_unit); } return $output; }
private function validateNewProductionMove($round, $id_zarea, array $units) { // 1. check if zarea belongs to user $gameArea = ModelGameArea::getGameArea($this->id_game, $id_zarea); if ($this->id_user !== $gameArea->getIdUser()) { throw new ControllerException('Unable to create production move. Area doesn\'t belong to the current user.'); } // 2. check if user has enough res left // 2.a check cost of previous productions $current_costs = 0; $moves = ModelProductionMove::iterator($this->id_user, $this->id_game, $round); while ($moves->hasNext()) { /* @var $move ModelProductionMove */ $move = $moves->next(); $current_costs += $move->getCost(); } // 2.b get available res $current_production = UserViewHelper::getCurrentProductionForUserInGame($this->id_user, $this->id_game); // 2.c get cost of new move $new_cost = 0; $unit_iter = ModelLandUnit::iterator(); while ($unit_iter->hasNext()) { /* @var $unit ModelLandUnit */ $unit = $unit_iter->next(); $id_unit = (int) $unit->getId(); if (!isset($units[$id_unit]) || $units[$id_unit] <= 0) { continue; } $new_cost += (int) $unit->getPrice() * $units[$id_unit]; } if ($current_production['sum'] - $current_costs < $new_cost) { throw new ControllerException('Insufficient funds!'); } }
private function handleInput(array &$data) { if (empty($_POST)) { return; } $controller = new LandMoveController(ModelUser::getCurrentUser()->getId(), ModelGame::getCurrentGame()->getId()); // fixating land move if (isset($_POST['fixate_land_move'])) { $controller->finishMove(); return; } // deleting land move if (isset($_POST['delete'])) { try { $controller->deleteLandMove(intval($_POST['delete'])); $data['status'] = array('message' => 'Landzug gelöscht.'); } catch (NullPointerException $ex) { $data['errors'] = array('message' => $ex->getMessage()); } catch (ControllerException $ex) { $data['errors'] = array('message' => $ex->getMessage()); } finally { return; } } // creating new land move if (isset($_POST['newmove'])) { try { if (!isset($_POST['start']) || !isset($_POST['destination'])) { $data['errors'] = array('message' => 'Missing parameter!'); return; } $units = array(); $iter = ModelLandUnit::iterator(); while ($iter->hasNext()) { /* @var $unit ModelLandUnit */ $unit = $iter->next(); $abbr = $unit->getAbbreviation(); $id_unit = $unit->getId(); $units[$id_unit] = isset($_POST[$abbr]) ? intval($_POST[$abbr]) : 0; } $controller->createLandMove(intval($_POST['start']), intval($_POST['destination']), $units); $data['status'] = array('message' => 'Landzug erstellt.'); } catch (NullPointerException $ex) { $data['errors'] = array('message' => $ex->getMessage()); } catch (ControllerException $ex) { $data['errors'] = array('message' => $ex->getMessage()); } } }
/** * creates land move for user * * @param $id_user int * @param $id_game int * @param $round int * @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 ModelException * @return ModelLandMove */ public static function createLandMove($id_user, $id_game, $round, $steps, $units) { SQLCommands::init(intval($id_game)); // CREATE MOVE $query = 'create_move'; $dict = array(); $dict[':id_user'] = intval($id_user); $dict[':id_phase'] = PHASE_LANDMOVE; $dict[':round'] = $round; DataSource::Singleton()->epp($query, $dict); $id_move = DataSource::getInstance()->getLastInsertId(); try { // INSERT MOVE STEPS $x = 0; foreach ($steps as $step => $id_zarea) { ++$x; ModelGameArea::getGameArea((int) $id_game, (int) $id_zarea); if (!isset($steps[$x])) { throw new ModelException('Cannot create landmove, steps not consistent.'); } $query = 'insert_area_for_move'; $dict = array(); $dict[':id_move'] = intval($id_move); $dict[':step'] = intval($step); $dict[':id_zarea'] = intval($id_zarea); DataSource::Singleton()->epp($query, $dict); } $id_zarea_start = (int) $steps[1]; // INSERT UNITS foreach ($units as $id_unit => $count) { ModelLandUnit::getModelById($id_unit); $zUnit = ModelInGameLandUnit::getModelByIdZAreaUserUnit((int) $id_game, $id_zarea_start, (int) $id_user, (int) $id_unit); $query = 'insert_land_units_for_move'; $dict = array(); $dict[':id_zunit'] = $zUnit->getId(); $dict[':id_move'] = intval($id_move); $dict[':count'] = intval($count); DataSource::Singleton()->epp($query, $dict); } } catch (ModelException $ex) { self::flagMoveDeleted(); throw $ex; } catch (NullPointerException $ex) { self::flagMoveDeleted(); throw $ex; } return self::$moves[$id_game][$id_move] = new ModelLandMove((int) $id_user, (int) $id_game, PHASE_LANDMOVE, (int) $id_move, (int) $round, false, $steps, $units); }
/** * 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 showNewMove(array &$data) { $areasViewData = array(); $areas = ModelArea::iterator(TYPE_LAND); while ($areas->hasNext()) { /* @var $area ModelArea */ $area = $areas->next(); $zArea = ModelGameArea::getGameAreaForArea(ModelGame::getCurrentGame()->getId(), $area->getId()); $areaViewData = array(); $areaViewData['id_zarea'] = $zArea->getId(); $areaViewData['number'] = $area->getNumber(); $areaViewData['name'] = $area->getName(); if ($zArea->getIdUser() === ModelUser::getCurrentUser()->getId()) { $areasViewData[] = $areaViewData; } } $data['areas'] = $areasViewData; $unitsViewData = array(); $unit_iter = ModelLandUnit::iterator(); while ($unit_iter->hasNext()) { /* @var $unit ModelLandUnit */ $unit = $unit_iter->next(); $unitsViewData[] = array('id' => $unit->getId(), 'name' => $unit->getName()); } $data['units'] = $unitsViewData; }
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; } }
public function run(array &$data) { $game = ModelGame::getCurrentGame(); $id_game = $game->getId(); SQLCommands::init($id_game); // running game (or newly started but countries are already picked) if ($game->getStatus() === GAME_STATUS_RUNNING || $game->getStatus() === GAME_STATUS_STARTED && $game->getIdPhase() === PHASE_SETSHIPS) { $query = 'get_map_for_running_game'; } else { if ($game->getStatus() === GAME_STATUS_STARTED && $game->getIdPhase() === PHASE_SELECTSTART) { $query = 'get_map_for_new_game'; } else { throw new MapException('invalid game selected: ' . $id_game); } } $result = DataSource::getInstance()->epp($query); $countryData = array(); foreach ($result as $country) { // newly started game countries have to be picked -> no landunits/ships available if (array_key_exists('countrySelectOption', $country)) { $countryData[] = $country; continue; } // running game (or newly started but countries are already picked) // check landunits $unitCount = 0; $id_user = (int) $country['id_user']; if ($id_user <= 0) { $id_user = NEUTRAL_COUNTRY; } $units = ModelInGameLandUnit::getUnitsByIdZAreaUser($id_game, (int) $country['id'], $id_user); $unitsViewData = array(); /* @var $unit ModelInGameLandUnit */ foreach ($units as $unit) { $unitCount += $unit->getCount(); $landUnit = ModelLandUnit::getModelById($unit->getIdUnit()); $unitViewData = array('name' => $landUnit->getName(), 'count' => $unit->getCount()); $unitsViewData[] = $unitViewData; } if ($unitCount > 0) { $country['units'] = $unitsViewData; } $country['unitCount'] = $unitCount; // check ships $shipCount = 0; $shipViewData = array(); if ((int) $country['area_type'] === TYPE_LAND) { $ships = ModelInGameShip::getShipsInPort($id_game, (int) $country['id_zarea']); } else { $ships = ModelInGameShip::getShipsInAreaNotInPort($id_game, (int) $country['id_zarea']); } while ($ships->hasNext()) { /* @var $ship ModelInGameShip */ $ship = $ships->next(); $id_ship_owner = $ship->getIdUser(); if (!isset($shipViewData[$id_ship_owner])) { $shipViewData[$id_ship_owner] = array('username' => ModelUser::getUser($id_ship_owner)->getLogin(), 'ships' => array()); } $shipType = ModelShip::getModelById($ship->getIdUnit()); $currShipViewData = array('name' => $ship->getName(), 'type' => $shipType->getName(), 'diveStatus' => $ship->getDiveStatus(), 'experience' => $ship->getExperience()); if ((int) $country['area_type'] === TYPE_LAND) { $portToArea = ModelGameArea::getGameArea($id_game, $ship->getIdZArea()); $currShipViewData['port'] = $portToArea->getName(); $currShipViewData['portNumber'] = $portToArea->getNumber(); } $shipViewData[$id_ship_owner]['ships'][] = $currShipViewData; ++$shipCount; } if ($shipCount > 0) { $country['ships'] = $shipViewData; } $country['shipCount'] = $shipCount; $countryData[] = $country; } $data['countryData'] = $countryData; return $data; }
/** * @throws NullPointerException * @return int total cost of this production move (all units) */ public function getCost() { $costsSum = 0; $unit_iter = ModelLandUnit::iterator(); while ($unit_iter->hasNext()) { /* @var $unit ModelLandUnit */ $unit = $unit_iter->next(); $id_unit = (int) $unit->getId(); if (!isset($this->units[$id_unit]) || $this->units[$id_unit] <= 0) { continue; } $costsSum += (int) $unit->getPrice() * $this->units[$id_unit]; } return $costsSum; }
/** * run the game logic * * @throws LogicException * @return void */ public function run() { if (!$this->checkIfValid()) { throw new LogicException('Game ' . $this->id_game . ' not valid for processing.'); } $this->startProcessing(); try { // run through moves for each user $iter = ModelSelectStartMove::iterator($this->id_game); while ($iter->hasNext()) { // areas to select for user $selectStartMove = $iter->next(); $regions_selected = $selectStartMove->getRegions(); // array(int option_number => array(int id_zarea)) $id_user = $selectStartMove->getIdUser(); /* @var $iigi ModelIsInGameInfo */ $iigi = ModelIsInGameInfo::getIsInGameInfo($id_user, $this->id_game); $id_set = $iigi->getIdStartingSet(); foreach ($regions_selected as $option_number => $areas) { $regions = ModelStartRegion::getRegionsForSetAndOption($id_set, $option_number); // array(int id_area => ModelStartRegion) foreach ($areas as $id_zarea) { $gameArea = ModelGameArea::getGameArea($this->id_game, $id_zarea); $id_area = $gameArea->getIdArea(); /* @var $region ModelStartRegion */ $region = $regions[$id_area]; $id_option = $region->getIdOptionType(); $unit_count = ModelOptionType::getOptionType($id_option)->getUnits(); // set user for game area $gameArea->setIdUser($id_user); // create units for user $iterUnits = ModelLandUnit::iterator(); while ($iterUnits->hasNext()) { $landUnit = $iterUnits->next(); $id_unit = $landUnit->getId(); $inGameLandUnit = ModelInGameLandUnit::getModelByIdZAreaUserUnit($this->id_game, $id_zarea, $id_user, $id_unit); $inGameLandUnit->setCount($unit_count); } } } } // add units to all empty game-areas $iter = ModelGameArea::iterator(NEUTRAL_COUNTRY, $this->id_game); while ($iter->hasNext()) { /* @var $gameArea ModelGameArea */ $gameArea = $iter->next(); if ($gameArea->getIdType() !== TYPE_LAND) { continue; } $count = $gameArea->getProductivity(); if ($gameArea->getIdResource() === RESOURCE_OIL) { ++$count; } $iterUnits = ModelLandUnit::iterator(); while ($iterUnits->hasNext()) { $landUnit = $iterUnits->next(); $id_unit = $landUnit->getId(); $inGameLandUnit = ModelInGameLandUnit::getModelByIdZAreaUserUnit($this->id_game, $gameArea->getId(), NEUTRAL_COUNTRY, $id_unit); $inGameLandUnit->setCount($count); } } $this->finishProcessing(); } catch (\Exception $ex) { $this->logger->fatal($ex); $this->rollback(); } }
/** * 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 validateMove($id_move, $round, $steps, $units) { /* * check if user owns the start country and if start area is land area */ $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 user owns destination area */ if (ModelGameArea::getGameArea($this->id_game, end($steps))->getIdUser() !== $this->id_user) { throw new ControllerException('destination country isn\'t owned by this user.'); } /* * 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 = false; $units_left = false; $landUnitsIterator = ModelLandUnit::iterator(); while ($landUnitsIterator->hasNext()) { /* @var $landUnit ModelTroopsMove */ $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; } } $movesIterator = ModelTroopsMove::iterator($this->id_user, $this->id_game, $round); while ($movesIterator->hasNext()) { /* @var $troopsMove ModelTroopsMove */ $troopsMove = $movesIterator->next(); if ($troopsMove->getId() === $id_move) { continue; // only subtract units from other moves } $move_steps = $troopsMove->getSteps(); $zTargetArea = ModelGameArea::getGameArea($this->id_game, end($move_steps)); $zStartArea = ModelGameArea::getGameArea($this->id_game, reset($move_steps)); if ($zStartArea->getId() === $id_start_area) { $move_units = $troopsMove->getUnits(); foreach ($move_units as $id_unit => $count) { $area_units[$id_unit] -= $count; } } else { if ($zTargetArea->getId() === $id_start_area) { $move_units = $troopsMove->getUnits(); foreach ($move_units as $id_unit => $count) { if ($count > 0) { $units_incoming = true; } } } } } 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; if ($count - $count_leaving > 0) { $units_left = true; } } if (!$units_incoming && !$units_left) { 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; 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 (!$this->checkPossibleRoute($id_start_area, $id_target_area, $type)) { throw new ControllerException('Unable to find route between the 2 countries.'); } return true; }