diff --git a/assets/gpack/travian_default/lang/en/compact.css b/assets/gpack/travian_default/lang/en/compact.css index 878cdecd..72cb8e09 100644 --- a/assets/gpack/travian_default/lang/en/compact.css +++ b/assets/gpack/travian_default/lang/en/compact.css @@ -102,7 +102,7 @@ div.messages { padding: 43px 25px 0; width: 502px; } -div.a2b { +div.gid16 { padding: 43px 25px 0; width: 502px; } @@ -5527,44 +5527,44 @@ div.quest div#qstd table.altquest td.ra { div.quest div#qstd table.altquest td.desc { text-align: left; } -div.a2b table th, div.a2b table td { +div.gid16 table th, div.gid16 table td { padding: 2px 7px; } -div.a2b table#troops { +div.gid16 table#troops { background-color: #FFFFFF; border: 1px dashed #C0C0C0; } -div.a2b table#troops td.column-first { +div.gid16 table#troops td.column-first { padding-left: 8px; } -div.a2b table#troops td.column-last { +div.gid16 table#troops td.column-last { padding-right: 8px; } -div.a2b table#troops td.line-first { +div.gid16 table#troops td.line-first { padding-top: 8px; } -div.a2b table#troops td.line-last { +div.gid16 table#troops td.line-last { padding-bottom: 8px; } -div.a2b table#troops td.large { +div.gid16 table#troops td.large { width: 26%; } -div.a2b table#troops td.regular { +div.gid16 table#troops td.regular { width: 25%; } -div.a2b table#troops td.small { +div.gid16 table#troops td.small { width: 23%; } -div.a2b table#troops img { +div.gid16 table#troops img { bottom: 3px; margin-right: 2px; position: relative; vertical-align: bottom; } -div.a2b table#troops input.text { +div.gid16 table#troops input.text { width: 30px; } -div.a2b table#troops input.disabled { +div.gid16 table#troops input.disabled { background-color: #EEEEEE; border-color: #AAAAAA; } @@ -5593,7 +5593,7 @@ body.presto div.gid16 table#coords td.sel input.radio { * + html div.gid16 table#coords td.sel input.radio { top: -2px; } -div.gid16 table#coords td.vil *, div.a2b table#coords td.target * { +div.gid16 table#coords td.vil *, div.gid16 table#coords td.target * { float: left; margin-right: 10px; } @@ -5606,46 +5606,46 @@ div.gid16 table#coords td.target input.text { div.gid16 table#short_info { background-color: #FFFFFF; } -div.a2b table#short_info th { +div.gid16 table#short_info th { padding-left: 0; width: 15%; } -div.a2b table.troop_details tbody th { +div.gid16 table.troop_details tbody th { width: 20%; } -div.a2b table.troop_details tbody.units td { +div.gid16 table.troop_details tbody.units td { padding: 2px; text-align: center; width: 7.2%; } -div.a2b table.troop_details tbody.units input.text { +div.gid16 table.troop_details tbody.units input.text { width: 73%; } -div.a2b table.troop_details tbody.options input.radio { +div.gid16 table.troop_details tbody.options input.radio { margin-right: 2px; position: relative; top: 2px; } -body.presto div.a2b table.troop_details tbody.options input.radio { +body.presto div.gid16 table.troop_details tbody.options input.radio { top: 0; } -body.ie6 div.a2b table.troop_details tbody.options input.radio, body.ie7 div.a2b table.troop_details tbody.options input.radio { +body.ie6 div.gid16 table.troop_details tbody.options input.radio, body.ie7 div.gid16 table.troop_details tbody.options input.radio { top: -2px; } -div.a2b table.troop_details tbody.cata select.dropdown { +div.gid16 table.troop_details tbody.cata select.dropdown { margin: 1px 0; } -div.a2b table.troop_details tbody.infos th, div.a2b table.troop_details tbody.infos td { +div.gid16 table.troop_details tbody.infos th, div.gid16 table.troop_details tbody.infos td { background-color: #F5F5F5; } -div.a2b table.troop_details tbody.infos div { +div.gid16 table.troop_details tbody.infos div { text-align: center; width: 49%; } -div.a2b table.troop_details tbody.infos div.in { +div.gid16 table.troop_details tbody.infos div.in { float: left; } -div.a2b table.troop_details tbody.infos div.at { +div.gid16 table.troop_details tbody.infos div.at { float: right; } div.cropfinder table#croplist th, div.cropfinder table#croplist td { @@ -6532,16 +6532,16 @@ div.quest div.rew p.ta_aw { div.quest div#qstd span.org { font-style: normal; } -div.a2b p.error { +div.gid16 p.error { font-weight: bold; } -div.a2b span.info { +div.gid16 span.info { font-size: 11px; } -div.a2b table#troops td { +div.gid16 table#troops td { font-size: 11px; } -div.a2b table#troops span.none { +div.gid16 table#troops span.none { font-weight: bold; } div.gid16 table#coords td.or { diff --git a/sql_updates.txt b/sql_updates.txt index 9694be1d..ee890e0c 100644 --- a/sql_updates.txt +++ b/sql_updates.txt @@ -1,3 +1,12 @@ +-- 19.09.2018 added a column, an index, changed 15 columns default value and 14 columns attribute +ALTER TABLE `s1_a2b` ADD `from` INT(11) NOT NULL AFTER `ckey`; +ALTER TABLE `s1_a2b` CHANGE `id` `id` INT(11) NOT NULL AUTO_INCREMENT, CHANGE `ckey` `ckey` VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '0', CHANGE `from` `from` INT(11) NOT NULL DEFAULT '0', CHANGE `to` `to` INT(11) NOT NULL DEFAULT '0', CHANGE `u1` `u1` INT(11) NOT NULL DEFAULT '0', CHANGE `u2` `u2` INT(11) NOT NULL DEFAULT '0', CHANGE `u3` `u3` INT(11) NOT NULL DEFAULT '0', CHANGE `u4` `u4` INT(11) NOT NULL DEFAULT '0', CHANGE `u5` `u5` INT(11) NOT NULL DEFAULT '0', CHANGE `u6` `u6` INT(11) NOT NULL DEFAULT '0', CHANGE `u7` `u7` INT(11) NOT NULL DEFAULT '0', CHANGE `u8` `u8` INT(11) NOT NULL DEFAULT '0', CHANGE `u9` `u9` INT(11) NOT NULL DEFAULT '0', CHANGE `u10` `u10` INT(11) NOT NULL DEFAULT '0', CHANGE `u11` `u11` INT(11) NOT NULL DEFAULT '0', CHANGE `type` `type` SMALLINT(1) NOT NULL DEFAULT '0'; +ALTER TABLE `s1_a2b` ADD INDEX `from` (`from`); + +-- 18.09.2018 dropped a column and changed a column name +ALTER TABLE `s1_a2b` DROP `time_check`; +ALTER TABLE `s1_a2b` CHANGE `to_vid` `to` INT(11) NULL DEFAULT NULL; + -- 14.09.2018 changed a column name ALTER TABLE `s1_wdata` CHANGE `oasistype` `oasestype` TINYINT(2) NULL DEFAULT NULL; diff --git a/src/Data/Buildings/RallyPoint.php b/src/Data/Buildings/RallyPoint.php index 4f4733a2..4960ca56 100644 --- a/src/Data/Buildings/RallyPoint.php +++ b/src/Data/Buildings/RallyPoint.php @@ -15,6 +15,9 @@ use TravianZ\Enums\VillageEnums; use TravianZ\Factory\MovementsFactory; use TravianZ\Factory\UnitsFactory; use TravianZ\Utils\Generator; +use TravianZ\Data\Users\Nature; +use TravianZ\Factory\BuildingsFactory; +use TravianZ\Enums\BuildingEnums; final class RallyPoint extends Building { @@ -85,6 +88,30 @@ final class RallyPoint extends Building 'slot' => 'isRequired' ]; + /** + * @var array The set of rules to prepare a movement + */ + const PREPARE_MOVEMENT_RULES = [ + 'c' => 'isRequired|isInt|minValue=1|maxValue=4' + ]; + + /** + * @var array The set of rules to get a village by name + */ + const PREPARE_MOVEMENT_VILLAGE_NAME_RULES = [ + 'targetVillageName' => 'isRequired' + ]; + + /** + * @var array The set of rules for sending units + */ + const SEND_UNITS_RULES = [ + 'ckey' => 'isRequired', + 'ctar1' => 'isInt|minValue=0|maxValue=42', + 'ctar2' => 'isInt|minValue=-1|maxValue=42', + 'spy' => 'isInt|minValue=1|maxValue=2' + ]; + /** * @var Validator */ @@ -123,6 +150,26 @@ final class RallyPoint extends Building $this->validator = new Validator(); } + + /** + * {@inheritdoc} + * @see \TravianZ\Entity\Building::getBonus() + */ + public function getBonus(){ + // Initialize + $bonus = []; + + // Loop through the bonuses + for($i = $this->level; $i >= 1; $i--){ + if(!isset($this->bonus[$i])){ + continue; + } + + $bonus = array_replace_recursive($bonus, $this->bonus[$i]); + } + + return $bonus; + } /** * Update the user's evasion settings @@ -133,7 +180,7 @@ final class RallyPoint extends Building public function updateEvasionSettings(Village $village, array $parameters): array { // Check if the parameters are valid - if (!empty((new Validator())->validateInputs($parameters, self::UPDATE_EVASION_SETTINGS_RULES))) { + if (!empty($this->validator->validateInputs($parameters, self::UPDATE_EVASION_SETTINGS_RULES))) { return ['error' => INVALID_MAX_EVASIONS]; } @@ -283,7 +330,71 @@ final class RallyPoint extends Building } return $worldCellToCheck; + } + + /** + * Check the correctness of a sending units attemp + * + * @param Village $village + * @param array $parameters + * @return string|Village|Oases Returns an error or the target village/oases on success + */ + public function checkSendingUnits(Village $village, array $parameters) + { + // Check if the inserted units are valid + if (!empty($error = $this->checkUnits($village, $parameters))) { + return $error; + } + + // Check if the inserted units aren't enough + foreach ($parameters['units'] as $type => $unit) { + if ($unit > $village->getUnits()[$type]->amount) { + return CANNOT_SEND_MORE_UNITS_THAN_HAVE; + } + } + + // Check if the attack type is valid + if (!empty($this->validator->validateInputs($parameters, self::PREPARE_MOVEMENT_RULES))) { + return INVALID_ATTACK_TYPE; + } + + // Check if a village name was inserted + if (empty($this->validator->validateInputs($parameters, self::PREPARE_MOVEMENT_VILLAGE_NAME_RULES))) { + $worldCellToCheck = new Village( + $this->getDatabase(), + null, + 0, + $parameters['targetVillageName'] + ); + + // Check if the village/oases is null or doesn't exists + if ( + is_null($worldCellToCheck) || + $worldCellToCheck->getState() == VillageEnums::DOES_NOT_EXIST + ) { + return VILLAGE_DOES_NOT_EXIST; + } + } + + // Check parameters correctness + $worldCellToCheck = $this->checkRaid($village, $worldCellToCheck, $parameters); + + // If it's an oases, check if it can be normal attacked or enforced + if ( + $worldCellToCheck instanceof Oases && + $worldCellToCheck->owner instanceof Nature + ) { + if ($parameters['c'] == MovementEnums::NORMAL) { + return CANT_NORMAL_ATTACK_OASES; + } elseif ($parameters['c'] == MovementEnums::REINFORCEMENT) { + return CANT_ENFORCE_OASES; + } + } + + // Return the error/Village/Oases + return $worldCellToCheck; } + /** * Check the correctness of a farm list raid @@ -695,6 +806,311 @@ final class RallyPoint extends Building $this->addMovements($village, $movements); } + /** + * Prepare the units to send + * + * @param Village $village + * @param array $movements + */ + public function prepareUnitsToSend(Village $village, array $parameters): array + { + // Check if the attack type is not a spy attack + if ($parameters['c'] == MovementEnums::SPY) { + $toWorldCell = INVALID_ATTACK_TYPE; + } else { + // Check the parameters validity + $toWorldCell = $this->checkSendingUnits($village, $parameters); + } + + if (is_string($toWorldCell)) { + return [ + 'error' => $toWorldCell, + 'targetVillageName' => $parameters['targetVillageName'], + 'units' => $parameters['units'], + 'c' => $parameters['c'], + 'x' => $parameters['x'], + 'y' => $parameters['y'], + ]; + } + + // Initialize + $units = []; + $spy = $parameters['c'] != MovementEnums::REINFORCEMENT; + $catapultTargets = []; + $catapultTargetBuildings = []; + + // Check if it's a normal attack and there is atleast one catapult + if ($parameters['c'] == MovementEnums::NORMAL && $parameters['units'][8] > 0) { + $catapultTargets = $this->getBonus(); + } + + // Set the buildings + foreach ($catapultTargets as $type => $targets) { + foreach ($targets as $buildingID) { + $building = BuildingsFactory::newBuilding($buildingID, 0, 0); + $catapultTarget['id'] = $building->id; + $catapultTarget['name'] = $building->name; + $catapultTargetBuildings[$type][] = $catapultTarget; + } + } + + // Create the units and check if it's a spy attack + for ($i = 1; $i <= 10; $i++) { + // Set the units to 0, if empty + if ($parameters['units'][$i] == '') { + $parameters['units'][$i] = 0; + } + + $units[$i] = UnitsFactory::create($village->owner->tribe, $i, $parameters['units'][$i]); + + if ( + $spy && + $units[$i]->amount > 0 && + $units[$i]->classes[1] != UnitEnums::SCOUT + ) { + $spy = false; + } + } + + // Set the hero if present + if ($parameters['units'][11] > 0) { + $units[$i] = $village->getUnits()[11]; + } + + // If it's a spy attack, change the attack type + if ($spy) { + $parameters['c'] = MovementEnums::SPY; + } + + // Get the walking units time + $walkingUnitsTime = Generator::getWalkingUnitsTime($village, $toWorldCell, $units); + + // Add the prepared movement on the database and return the needed informations + return [ + 'ckey' => $this->addPreparedUnits($village, $toWorldCell, $parameters['units'], $parameters['c']), + 'units' => $parameters['units'], + 'prepareUnits' => true, + 'targetVillageVref' => $toWorldCell->vref, + 'targetVillageMapCheck' => Generator::getMapCheck($toWorldCell->vref), + 'targetVillageName' => $toWorldCell->name, + 'targetVillageCoordinates' => $toWorldCell->coordinates, + 'targetOwnerId' => $toWorldCell->owner->id, + 'targetOwnerUsername' => $toWorldCell->owner->username, + 'arrivalTime' => [ + Generator::getTimeFormat($walkingUnitsTime), + Generator::procMtime($walkingUnitsTime + time())[1] + ], + 'c' => $parameters['c'], + 'catapultTargetBuildings' => $catapultTargetBuildings, + 'x' => $parameters['x'], + 'y' => $parameters['y'], + ]; + } + + /** + * Add prepared units on the database + * + * @param Village $fromVillage The sender village + * @param WorldCell $toWorldCell The target village + * @param array $units The units [type => amount] + * @param int $type The movement type + * @return string Returns the generated prepared units key + */ + public function addPreparedUnits(Village $fromVillage, WorldCell $toWorldCell, array $units, int $type): string + { + // Generate the string identifier + $stringIdentifier = Generator::generateRandStr(10); + + // Delete any previously prepared units + $sql = 'DELETE FROM + ' . TB_PREFIX . 'a2b + WHERE + `from` = ?'; + + $this->getDatabase()->queryNew($sql, $fromVillage->vref); + + $sql = 'INSERT INTO + ' . TB_PREFIX . 'a2b + (ckey, `from`, `to`, u1, u2, u3, u4, u5, u6, u7, u8, u9, u10, u11, type) + VALUES + (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'; + + $this->getDatabase()->queryNew( + $sql, + $stringIdentifier, + $fromVillage->vref, + $toWorldCell->vref, + $units[1] ?? 0, + $units[2] ?? 0, + $units[3] ?? 0, + $units[4] ?? 0, + $units[5] ?? 0, + $units[6] ?? 0, + $units[7] ?? 0, + $units[8] ?? 0, + $units[9] ?? 0, + $units[10] ?? 0, + $units[11] ?? 0, + $type + ); + + return $stringIdentifier; + } + + /** + * Send previously prepared units + * + * @param Village $village + * @param array $movements + */ + public function sendUnits(Village $village, array $parameters): array + { + // Check the parameters validity + if (!empty($this->validator->validateInputs($parameters, self::SEND_UNITS_RULES))) { + return []; + } + + // Get the prepared units from the passed key + $preparedUnits = $this->getPreparedUnits($parameters['ckey']); + + // Check if there are no prepared units with that key + if (empty($preparedUnits)) { + return []; + } + + // Initialize + $validTargets = 0; + + // Check the catapult targets correctness + foreach ($this->getBonus() as $validCatapultTargets) { + foreach ($validCatapultTargets as $buildingID) { + // Check if the selected targets are on the list + if ( + ($parameters['ctar1'] == BuildingEnums::EMPTY || + $parameters['ctar1'] == $buildingID) || + ($parameters['ctar2'] == BuildingEnums::EMPTY || + $parameters['ctar2'] == -1 || + $parameters['ctar2'] == $buildingID) + ) { + $validTargets++; + } + + if ($validTargets == 2) { + break; + } + } + } + + // Check if the selected targets are valid + if ($validTargets < 2) { + return []; + } + + // Check the units correctness + $toWorldCell = $this->checkSendingUnits($village, $preparedUnits); + + // Check if the units aren't valid + if (is_string($toWorldCell)) { + return []; + } + + // Initialize + $units = []; + $time = time(); + + // Create the units + for ($i = 1; $i <= 10; $i++) { + $units[$i] = UnitsFactory::create($village->owner->tribe, $i, $preparedUnits['units'][$i]); + } + + // Set the hero if present + if ($parameters['units'][11] > 0) { + $units[$i] = $village->getUnits()[11]; + } + + // Create the movement + $movement = MovementsFactory::create( + $preparedUnits['c'], + $this->getDatabase(), + 0, + $village, + $toWorldCell, + $time, + $time + Generator::getWalkingUnitsTime($village, $toWorldCell, $units), + [], + $units, + 0, + 0, + 0, + [$parameters['ctar1'], $parameters['ctar2']] ?? [], + $parameters['spy'] ?? 0 + ); + + // Add the movement to the database + $movement->add(); + + // Remove the units from the village + $village->updateUnits($units, true); + + // Delete the prepared units + $this->deletePreparedUnits($parameters['ckey']); + + // Add the movement locally + $village->addMovement($movement); + + return []; + } + + /** + * Get previously prepared units + * + * @param string $key The prepared units key + * @return array Returns an array, containing all the prepared movement informations + */ + public function getPreparedUnits(string $key): array + { + $sql = 'SELECT * FROM + ' . TB_PREFIX . 'a2b + WHERE + ckey = ?'; + + $res = $this->getDatabase()->queryNew($sql, $key)[0]; + + // If the units don't exist, return + if (empty($res)) { + return []; + } + + // Initialize + $informations = [ + 'lastTarget' => $res['to'], + 'c' => $res['type'], + 'units' => [] + ]; + + // Create the units array + for($i = 1; $i <= 11; $i++) { + $informations['units'][$i] = $res['u'.$i]; + } + + return $informations; + } + + /** + * Delete prepared units from the database + * + * @param string $key The prepared units key + */ + public function deletePreparedUnits(string $key) + { + $sql = 'DELETE FROM + ' . TB_PREFIX . 'a2b + WHERE + ckey = ?'; + + $this->getDatabase()->queryNew($sql, $key); + } + /** * Add one ore more movements to the database, after checking their correctness * diff --git a/src/Data/GetInformations.php b/src/Data/GetInformations.php index 8d803e8e..2056dbf9 100644 --- a/src/Data/GetInformations.php +++ b/src/Data/GetInformations.php @@ -382,6 +382,7 @@ trait GetInformations 'gold' => $session->getUser()->gold, 'tribe' => $session->getUser()->tribe, 'alliance' => $session->getUser()->alliance, + 'underBeginnerProtection' => $session->getUser()->isUnderBeginnerProtection(), 'maxEvasion' => $session->getUser()->maxEvasion, 'questNumber' => $session->getUser()->questNumber, 'selectedVillage' => $session->getUser()->selectedVillage, diff --git a/src/Entity/Attack.php b/src/Entity/Attack.php index 91a8d55b..bc9c7143 100644 --- a/src/Entity/Attack.php +++ b/src/Entity/Attack.php @@ -89,20 +89,20 @@ abstract class Attack extends Movement $this->id = $this->ref = $this->db->queryNew( $sql, $this->from->vref, - $this->units[1]->amount, - $this->units[2]->amount, - $this->units[3]->amount, - $this->units[4]->amount, - $this->units[5]->amount, - $this->units[6]->amount, - $this->units[7]->amount, - $this->units[8]->amount, - $this->units[9]->amount, - $this->units[10]->amount, - $this->units[11]->amount, - $this->catapultTargets[0], - $this->catapultTargets[1], - $this->spy + $this->units[1]->amount ?? 0, + $this->units[2]->amount ?? 0, + $this->units[3]->amount ?? 0, + $this->units[4]->amount ?? 0, + $this->units[5]->amount ?? 0, + $this->units[6]->amount ?? 0, + $this->units[7]->amount ?? 0, + $this->units[8]->amount ?? 0, + $this->units[9]->amount ?? 0, + $this->units[10]->amount ?? 0, + $this->units[11]->amount ?? 0, + $this->catapultTargets[0] ?? 0, + $this->catapultTargets[1] ?? 0, + $this->spy ?? 0 ); return parent::addMovement(); diff --git a/src/Entity/Building.php b/src/Entity/Building.php index c119c385..9b04712f 100644 --- a/src/Entity/Building.php +++ b/src/Entity/Building.php @@ -86,7 +86,7 @@ abstract class Building /** * @var array The bonus provided by this building */ - private $bonus; + protected $bonus; /** * @var array The prerequisites needed to build this building diff --git a/src/Entity/Movement.php b/src/Entity/Movement.php index b8be361f..e1934145 100644 --- a/src/Entity/Movement.php +++ b/src/Entity/Movement.php @@ -64,7 +64,7 @@ abstract class Movement /** * @var IDbConnection */ - private $db; + protected $db; public function __construct( IDbConnection $db, diff --git a/src/Factory/BuildingsFactory.php b/src/Factory/BuildingsFactory.php index 04382e9d..8e7be41f 100644 --- a/src/Factory/BuildingsFactory.php +++ b/src/Factory/BuildingsFactory.php @@ -196,42 +196,58 @@ abstract class BuildingsFactory case BuildingEnums::RALLY_POINT: return [ 1 => [], - 3 => [BuildingEnums::WAREHOUSE, BuildingEnums::GRANARY], + 3 => [ + 2 => + [ + BuildingEnums::WAREHOUSE, + BuildingEnums::GRANARY + ] + ], 5 => [ - BuildingEnums::WOODCUTTER, - BuildingEnums::CLAY_PIT, - BuildingEnums::IRON_MINE, - BuildingEnums::CROPLAND, - BuildingEnums::SAWMILL, - BuildingEnums::BRICKYARD, - BuildingEnums::IRON_FOUNDRY, - BuildingEnums::GRAIN_MILL, - BuildingEnums::BAKERY + 0 => + [ + BuildingEnums::WOODCUTTER, + BuildingEnums::CLAY_PIT, + BuildingEnums::IRON_MINE, + BuildingEnums::CROPLAND, + BuildingEnums::SAWMILL, + BuildingEnums::BRICKYARD, + BuildingEnums::IRON_FOUNDRY, + BuildingEnums::GRAIN_MILL, + BuildingEnums::BAKERY + ] ], 10 => [ - BuildingEnums::ACADEMY, - BuildingEnums::ARMOURY, - BuildingEnums::BARRACKS, - BuildingEnums::BLACKSMITH, - BuildingEnums::BREWERY, - BuildingEnums::EMBASSY, - BuildingEnums::GREAT_BARRACKS, - BuildingEnums::GREAT_STABLE, - BuildingEnums::GREAT_WORKSHOP, - BuildingEnums::HERO_MANSION, - BuildingEnums::HORSE_DRINKING_TROUGH, - BuildingEnums::MAIN_BUILDING, - BuildingEnums::MARKETPLACE, - BuildingEnums::PALACE, - BuildingEnums::RALLY_POINT, - BuildingEnums::RESIDENCE, - BuildingEnums::STABLE, - BuildingEnums::TOURNAMENT_SQUARE, - BuildingEnums::TOWN_HALL, - BuildingEnums::TRADE_OFFICE, - BuildingEnums::TREASURY, - BuildingEnums::WONDER_OF_THE_WORLD, - BuildingEnums::WORKSHOP + 1 => + [ + BuildingEnums::ACADEMY, + BuildingEnums::BARRACKS, + BuildingEnums::STABLE, + BuildingEnums::WORKSHOP, + BuildingEnums::ARMOURY, + BuildingEnums::BLACKSMITH, + BuildingEnums::RALLY_POINT, + BuildingEnums::GREAT_BARRACKS, + BuildingEnums::GREAT_STABLE, + BuildingEnums::GREAT_WORKSHOP, + BuildingEnums::HERO_MANSION, + BuildingEnums::TOURNAMENT_SQUARE + ], + + 2 => + [ + 2 => BuildingEnums::BREWERY, + BuildingEnums::EMBASSY, + BuildingEnums::HORSE_DRINKING_TROUGH, + BuildingEnums::MAIN_BUILDING, + BuildingEnums::MARKETPLACE, + BuildingEnums::PALACE, + BuildingEnums::RESIDENCE, + BuildingEnums::TOWN_HALL, + BuildingEnums::TRADE_OFFICE, + BuildingEnums::TREASURY, + BuildingEnums::WONDER_OF_THE_WORLD + ] ] ]; case BuildingEnums::MARKETPLACE: diff --git a/src/Lang/en.php b/src/Lang/en.php index eaff168b..dba5e7f1 100755 --- a/src/Lang/en.php +++ b/src/Lang/en.php @@ -670,7 +670,7 @@ define("NW","North West"); define("NE","North East"); define("SW","South West"); define("SE","South East"); -define("RANDOM","random"); +define("RANDOM","Random"); define("ACCEPT_RULES"," I accept the game rules and general terms and conditions."); define("ONE_PER_SERVER","Each player may only own ONE account per server."); define("BEFORE_REGISTER","Before you register an account you should read the instructions of Travian ro1 to see the specific advantages and disadvantages of the three tribes."); @@ -746,6 +746,9 @@ define("OK","Ok"); define("SENDTROOP","Send troops"); define("TROOP","Troops"); define("NOTROOP","no troops"); +define("MILITARY","Military"); +define("INFRASTRUCTURE","Infastructure"); +define("RESOURCES","Resources"); //map define("X","X"); @@ -811,6 +814,20 @@ define("WE_LOOKED","We looked 404 times already but can't find anything"); define("CALCULATED","Calculated in"); define("SERVER_TIME","Server time:"); +//SEND UNITS +define("INVALID_ATTACK_TYPE","Invalid attack type"); +define("CANT_NORMAL_ATTACK_OASES","You can't normal attack this oases"); +define("CANT_ENFORCE_OASES","You can't enforce this oases"); +define("DESTINATION","Destination"); +define("IN","in"); +define("TO","to"); +define("ARRIVED","Arrived"); +define("OPTIONS","Options"); +define("WARNING_UNDER_PROTECTION","Caution: Attacking a player will make you lose the protection!"); +define("SCOUT_RES_AND_UNITS","Scout resources and troops"); +define("SCOUT_DEF_AND_UNITS","Scout defences and troops"); +define("CANNOT_SEND_MORE_UNITS_THAN_HAVE","You cannot send more units than you have"); + //FARM LIST define("EDIT","edit"); define("ADD_RAID","Add raid"); @@ -1364,7 +1381,7 @@ But to raise such a great Wonder would be no easy task, one would need construct Tens of thousands of scouts roamed across all existence searching in vain for these mystical plans, looking in all places but the dreaded Natarian Capital, yet could not find them. Today however, they return bearing good news, they return baring the locations of the plans, hidden by the armies of the Natars inside secret strongholds constructed to be hidden from the eyes of man. Now begins the final stretch, when the greatest armies of the Free people and the Natars will clash across the world for the fate of all that lies under heaven. This is the war that will echo across the eons, this is your war, and here you shall etch your name across history, here you shall become legend. -\"".WWVILLAGE."\" +\"".WW_VILLAGE."\" To conquer one, the following things must happen: diff --git a/src/Models/BuildingModel.php b/src/Models/BuildingModel.php index c3f3ef6d..f9d01c9f 100644 --- a/src/Models/BuildingModel.php +++ b/src/Models/BuildingModel.php @@ -19,29 +19,25 @@ use TravianZ\Account\Session; use TravianZ\Data\GetInformations; use TravianZ\Data\Validator; use TravianZ\Data\Buildings\Academy; +use TravianZ\Data\Buildings\MainBuilding; use TravianZ\Data\Buildings\Marketplace; use TravianZ\Data\Buildings\Palace; +use TravianZ\Data\Buildings\RallyPoint; +use TravianZ\Data\Movements\Raid; use TravianZ\Data\Movements\ReturningTrade; use TravianZ\Data\Movements\Trade; use TravianZ\Database\Database; use TravianZ\Entity\Building; -use TravianZ\Entity\Training; use TravianZ\Entity\TrainingField; use TravianZ\Entity\Village; +use TravianZ\Entity\Villages; use TravianZ\Enums\BuildingEnums; +use TravianZ\Enums\BuildingJobEnums; use TravianZ\Enums\ResearchEnums; use TravianZ\Exceptions\InvalidParametersException; use TravianZ\Factory\BuildingsFactory; -use TravianZ\Factory\UnitsFactory; use TravianZ\Mvc\Model; use TravianZ\Utils\Generator; -use TravianZ\Enums\BuildingJobEnums; -use TravianZ\Data\Buildings\MainBuilding; -use TravianZ\Data\Buildings\Residence; -use TravianZ\Enums\UnitEnums; -use TravianZ\Entity\Villages; -use TravianZ\Data\Buildings\RallyPoint; -use TravianZ\Data\Movements\Raid; /** * @author iopietro @@ -181,7 +177,7 @@ class BuildingModel extends Model $selectedBuilding = BuildingsFactory::newBuilding( $building->id, $building->position, - $building->level + $sameBuilding + 1 + $building->level ); // Set the building ID @@ -192,7 +188,7 @@ class BuildingModel extends Model } // If the building is more than level 0, check if an action can be executed - if ($selectedBuilding->level - $sameBuilding - 1 > 0) { + if ($selectedBuilding->level > 0) { // Get the class method name to call $methodToCall = 'manage'.str_replace(' ', '', $selectedBuilding); $results = []; @@ -204,6 +200,9 @@ class BuildingModel extends Model } } + // Increase building level + $selectedBuilding->level += $sameBuilding + 1; + // Get the village infomations $villageInformations = $this->getVillageInformations($selectedVillage); @@ -708,6 +707,15 @@ class BuildingModel extends Model return ['villageExpansions' => $villageExpansions]; } + /** + * Manage the rally point + * + * @param RallyPoint $building + * @param Village $village + * @param array $parameters + * @throws InvalidParametersException + * @return array + */ private function manageRallyPoint(RallyPoint $building, Village $village, array $parameters): array { // Check if the menu parameter is valid @@ -727,17 +735,55 @@ class BuildingModel extends Model $action = self::RALLY_POINT_ACTIONS[$parameters['GET']['t']]; $results = []; - // Execute the marketplace selected action + // Execute the rally point selected action if (method_exists($this, $action)) { $results = $this->$action($building, $village, $parameters); } - + return array_merge_recursive( $results, ['parameters' => ['t' => $parameters['GET']['t']]] ); } + /** + * View the rally point movements + * + * @param RallyPoint $building + * @param Village $village + * @param array $parameters + * @return array + */ + private function rallyPointViewMovements(RallyPoint $building, Village $village, array $parameters): array + { + // Check if there is a movement to send + $results = $this->rallyPointSendUnits($building, $village, $parameters); + + return $results ?? []; + } + + /** + * Send units to another village + * + * @param RallyPoint $building + * @param Village $village + * @param array $parameters + * @return array + */ + private function rallyPointSendUnits(RallyPoint $building, Village $village, array $parameters): array + { + // Check if there's an action to execute + // TODO: Don't repeat it every time + if (isset($parameters['POST']['action'])) { + $action = $parameters['POST']['action']; + if (method_exists($building, $action)) { + $results = $building->$action($village, $parameters['POST']); + } + } + + return $results ?? []; + } + /** * Manage the gold club functions (raid list, etc.) * diff --git a/src/Models/VillageModel.php b/src/Models/VillageModel.php index c89658d3..f4581da2 100644 --- a/src/Models/VillageModel.php +++ b/src/Models/VillageModel.php @@ -61,7 +61,7 @@ class VillageModel extends Model if (isset($parameters['GET']['newdid'])) { $this->session->getUser()->changeSelectedVillage($parameters['GET']['newdid']); } - + $selectedVillage = new Village( Database::getInstance(), $this->session->getUser(), diff --git a/templates/sendUnits/attack.tpl b/templates/sendUnits/attack.tpl index 0b2718e4..a6fbf7e7 100644 --- a/templates/sendUnits/attack.tpl +++ b/templates/sendUnits/attack.tpl @@ -1,330 +1,117 @@ -generateRandStr(6); +{$attackType = [1 => $smarty.const.U14, $smarty.const.REINFORCE, $smarty.const.NORMALATTACK, $smarty.const.RAID]} + - if (!isset($process['t1']) || $process['t1'] == ''){ $t1 = 0; }else{ $t1 = $process['t1']; } - if (!isset($process['t2']) || $process['t2'] == ''){ $t2 = 0; }else{ $t2 = $process['t2']; } - if (!isset($process['t3']) || $process['t3'] == ''){ $t3 = 0; }else{ $t3 = $process['t3']; if ($session->tribe == 3) $scout=1; } - if (!isset($process['t4']) || $process['t4'] == ''){ $t4 = 0; }else{ $t4 = $process['t4']; if ($session->tribe == 1 || $session->tribe == 2 || $session->tribe == 4 || $session->tribe == 5) $scout=1; } - if (!isset($process['t5']) || $process['t5'] == ''){ $t5 = 0; }else{ $t5 = $process['t5']; } - if (!isset($process['t6']) || $process['t6'] == ''){ $t6 = 0; }else{ $t6 = $process['t6']; } - if (!isset($process['t7']) || $process['t7'] == ''){ $t7 = 0; }else{ $t7 = $process['t7']; } - if (!isset($process['t8']) || $process['t8'] == ''){ $t8 = 0; }else{ $t8 = $process['t8']; } - if (!isset($process['t9']) || $process['t9'] == ''){ $t9 = 0; }else{ $t9 = $process['t9']; } - if (!isset($process['t10']) || $process['t10'] == ''){ $t10 = 0; }else{ $t10 = $process['t10']; } - if (!isset($process['t11']) || $process['t11'] == ''){ $t11 = 0; }else{ $t11 = $process['t11']; $showhero=1; } - +{$colspan = 10} +{if $units[11] > 0} + {$colspan = 11} +{/if} -for($i = 1; $i <= 11; $i++){ - $totalunits += (($i != 3 && $session->tribe == 3) || - ($i != 4 && $session->tribe != 3)) ? (!empty($process['t'.$i]) ? $process['t'.$i] : 0) : 0; -} - -if (isset($scout) && $scout == 1 && isset($totalunits) && $totalunits == 0 && $process['c'] != 2) { - $process['c'] = 1; -} -$id = $database->addA2b($ckey, time(), $process['0'], $t1, $t2, $t3, $t4, $t5, $t6, $t7, $t8, $t9, $t10, $t11, $process['c']); - -$actionType = (["Scout", "Reinforcement", "Normal attack", "Raid"])[$process['c'] - 1]; - -$uid = $session->uid; -$tribe = $session->tribe; -$start = ($tribe - 1) * 10 + 1; -$end = $tribe * 10; -?> - -

-
- - - - - - - - - - - - - - - - - - - - - - - -
Destination: (|)
Owner:getUserField($process['2'],'username',0); ?>
- - - - - - - - - - - - - - - - - - - - - - - getUnitName($i)."\" alt=\"".$technology->getUnitName($i)."\" />"; - } if (!empty($process['t11'])){ - echo ""; - - }?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - ".$process['t11']."";} ?> - - - - - - - - - - - - - - - - - - - - - - +
">
\"Hero\"
Troops0"; }else{ echo ">".$process['t1'];} ?>0"; }else{ echo ">".$process['t2'];} ?>0"; }else{ echo ">".$process['t3'];} ?>0"; }else{ echo ">".$process['t4'];} ?>0"; }else{ echo ">".$process['t5'];} ?>0"; }else{ echo ">".$process['t6'];} ?>0"; }else{ echo ">".$process['t7'];} ?>0"; }else{ $kata='1'; echo ">".$process['t8'];} ?>0"; }else{ echo ">".$process['t9'];} ?>0"; }else{ echo ">".$process['t10'];} ?>
Options">Scout resources and troops
- Scout defences and troops
Destination: - - - - getTypeLevel(16) == 20 && $process['t8'] >= 20) { ?> - - - - (will be attacked by catapult(s)) -
+ - - + + - - - - - - - - - - - - - - getWalkingTroopsTime($village->wid, $process[0], $session->uid, $session->tribe, $process, 1, 't'); - $time = $database->getArtifactsValueInfluence($session->uid, $village->wid, 2, $troopsTime); - ?> - - - + + + - -
Destination: - ONLY shoot with a normal attack (they dont shoot with raids!)"; - ?> - {$smarty.const.DESTINATION}: + {$targetVillageName} ({$targetVillageCoordinates['x']}|{$targetVillageCoordinates['y']}) +
Arrived: - -
in getTimeFormat($time); ?>
- -
at procMtime(date('U') + $time, 9)?> hours
- -
{$smarty.const.OWNER}: + {$targetOwnerUsername} +
- + + + + + + - + - + + + + {foreach $villagePresentUnits.unitsArray as $type => $unit} + + {/foreach} + + + - + {for $i = 1 to 11} + {if $i == 11 && $units[$i] == 0} + {continue} + {/if} + + {if $units[$i] == 0} + + {else} + + {/if} + {/for} - - + -hasBeginnerProtection($village->wid) == 1 && $database->hasBeginnerProtection($process['0']) == 0){ - echo"Caution: Attacking a player will lose the protection!"; - } - if($database->hasBeginnerProtection($process['0']) == 1) { - echo"User presently has beginners protection"; - } else { -?> -

-class="dynamic_img " src="img/x.gif" alt="OK" type="image" onclick="if (this.disabled==false) {document.getElementsByTagName('form')[0].submit();} this.disabled=true;" onLoad="this.disabled=false;">

+ {if !empty($catapultTargetBuildings)} + + + + + + + {/if} + + {if $c == 1} + + + + + + + {/if} + + + + + + + +
{$targetVillageName}{$attackType[$c]} {$smarty.const.TO} {$targetVillageName}
+ {if $type <= 10}{$unit.name}{else}{$smarty.const.HERO}{/if} +
{$smarty.const.TROOPS} + 0 + + {$units[$i]} +
{$smarty.const.DESTINATION}: + {$targetName = 'ctar1'} + {$randomTargetValue = 0} + {include file=$smarty.const.TEMPLATES_DIR|cat:'sendUnits/catapultTargets.tpl'} - - - + {if $units[8] >= 20} + {$targetName = 'ctar2'} + {$randomTargetValue = -1} + {include file=$smarty.const.TEMPLATES_DIR|cat:'sendUnits/catapultTargets.tpl'} + {/if} +
{$smarty.const.OPTIONS} + {$smarty.const.SCOUT_RES_AND_UNITS}
+ {$smarty.const.SCOUT_DEF_AND_UNITS}
{$smarty.const.ARRIVED} +
{$smarty.const.IN} {$arrivalTime[0]}
+
+ {$smarty.const.AT} {$arrivalTime[1]} + {$smarty.const.HOURS} +
+
+ +{if $underBeginnerProtection} + {$smarty.const.WARNING_UNDER_PROTECTION} +{/if} + +

+ +

diff --git a/templates/sendUnits/catapultTargets.tpl b/templates/sendUnits/catapultTargets.tpl new file mode 100644 index 00000000..d8113d85 --- /dev/null +++ b/templates/sendUnits/catapultTargets.tpl @@ -0,0 +1,17 @@ +{$groupNames = [$smarty.const.RESOURCES, $smarty.const.INFRASTRUCTURE, $smarty.const.MILITARY]} + + \ No newline at end of file diff --git a/templates/sendUnits/search.tpl b/templates/sendUnits/search.tpl index 851ca719..a5966b7e 100644 --- a/templates/sendUnits/search.tpl +++ b/templates/sendUnits/search.tpl @@ -3,7 +3,7 @@ @@ -14,7 +14,7 @@ {$smarty.const.OR} @@ -22,7 +22,7 @@ @@ -36,4 +36,4 @@
- + diff --git a/templates/sendUnits/units.tpl b/templates/sendUnits/units.tpl index b650a20d..f201078a 100644 --- a/templates/sendUnits/units.tpl +++ b/templates/sendUnits/units.tpl @@ -1,161 +1,39 @@ -

{$smarty.const.SEND_TROOPS}

+ + + {$quantity = [[1, 4, 7 ,9], [2, 5, 8 ,10], [3, 6, 11]]} + {$quantityCount = count($quantity) - 1} + {$class = [ + 1 => 'line-first column-first large', + 4 => 'line-first large', + 7 => 'line-first regular', + 9 => 'line-first column-last small', + 2 => 'column-first large', + 5 => 'large', + 8 => 'regular', + 10 => 'column-last small', + 3 => 'line-last column-first large', + 6 => 'line-last large', + 11 => 'line-last regular' + ]} - - - -
- - - "; -} else { - echo "(0)"; -} -?> - - - - "; -} else { - echo "(0)"; -} -?> - - - "; -} else { - echo "(0)"; -} -?> - - - - - "; -} else { - echo "(0)"; -} -?> - - - - - "; -} else { - echo "(0)"; -} -?> - - - - "; -} else { - echo "(0)"; -} -?> - - - "; -} else { - echo "(0)"; -} -?> - - - "; -} else { - echo "(0)"; -} -?> - - - - - "; -} else { - echo "(0)"; -} -?> - - - "; -} else { - echo "(0)"; -} -?> - - - "; - } - ?> - - - -
Legionnaire - unitarray['u1']<=0) {echo ' disabled="disabled"';}?> - name="t1" value="" maxlength="6" type="text"> - unitarray['u1'] > 0) { - echo "unitarray['u1'] . "; return false;\">(" . $village->unitarray['u1'] . ")Equites Legati unitarray['u4']<=0) {echo ' disabled="disabled"';}?> - name="t4" value="" maxlength="6" type="text"> - unitarray['u4'] > 0) { - echo "unitarray['u4'] . "; return false;\">(" . $village->unitarray['u4'] . ")Battering Ram unitarray['u7']<=0) {echo ' disabled="disabled"';}?> - name="t7" value="" maxlength="6" type="text"> - unitarray['u7'] > 0) { - echo "unitarray['u7'] . "; return false;\">(" . $village->unitarray['u7'] . ")Senator unitarray['u9']<=0) {echo ' disabled="disabled"';}?> - name="t9" value="" maxlength="6" type="text"> - unitarray['u9'] > 0) { - echo "unitarray['u9'] . "; return false;\">(" . $village->unitarray['u9'] . ")
Praetorian unitarray['u2']<=0) {echo ' disabled="disabled"';}?> - name="t2" value="" maxlength="6" type="text"> - unitarray['u2'] > 0) { - echo "unitarray['u2'] . "; return false;\">(" . $village->unitarray['u2'] . ")Equites Imperatoris unitarray['u5']<=0) {echo ' disabled="disabled"';}?> - name="t5" value="" maxlength="6" type="text"> - unitarray['u5'] > 0) { - echo "unitarray['u5'] . "; return false;\">(" . $village->unitarray['u5'] . ")Fire Catapult unitarray['u8']<=0) {echo ' disabled="disabled"';}?> - name="t8" value="" maxlength="6" type="text"> - unitarray['u8'] > 0) { - echo "unitarray['u8'] . "; return false;\">(" . $village->unitarray['u8'] . ")Settler unitarray['u10']<=0) {echo ' disabled="disabled"';}?> - name="t10" value="" maxlength="6" type="text"> - unitarray['u10'] > 0) { - echo "unitarray['u10'] . "; return false;\">(" . $village->unitarray['u10'] . ")
Imperian unitarray['u3']<=0) {echo ' disabled="disabled"';}?> - name="t3" value="" maxlength="6" type="text"> - unitarray['u3'] > 0) { - echo "unitarray['u3'] . "; return false;\">(" . $village->unitarray['u3'] . ")Equites Caesaris unitarray['u6']<=0) {echo ' disabled="disabled"';}?> - name="t6" value="" maxlength="6" type="text"> - unitarray['u6'] > 0) { - echo "unitarray['u6'] . "; return false;\">(" . $village->unitarray['u6'] . ")unitarray['hero'] > 0) { - echo "\"Hero\" "; - echo "unitarray['hero']."; return false;\">(".$village->unitarray['hero'].")
\ No newline at end of file + {for $i = 0 to $quantityCount} + + {for $j = 0 to count($quantity[$i]) - 1} + {$type = $quantity[$i][$j]} + {if $type == 11 && $villagePresentUnits.unitsArray[$type].amount == 0} + {continue} + {/if} + + {if $type <= 10}{$villagePresentUnits.unitsArray[$type].name}{else}{$smarty.const.U0}{/if} + 0}value="{$units[$type]}"{/if}> + {if $villagePresentUnits.unitsArray[$type].amount > 0} + ({$villagePresentUnits.unitsArray[$type].amount}) + {else} + (0) + {/if} + + {/for} + + {/for} + + diff --git a/templates/village/buildings/16.tpl b/templates/village/buildings/16.tpl index 2d122b60..a77f8a09 100644 --- a/templates/village/buildings/16.tpl +++ b/templates/village/buildings/16.tpl @@ -3,7 +3,7 @@ {if !isset($parameters['t'])} {include file=$smarty.const.TEMPLATES_DIR|cat:'village/buildings/rallyPoint/movements.tpl'} {elseif $parameters['t'] == 1} - {include file=$smarty.const.TEMPLATES_DIR|cat:'sendUnits/search.tpl'} + {include file=$smarty.const.TEMPLATES_DIR|cat:'village/buildings/rallyPoint/sendUnits.tpl'} {elseif $parameters['t'] == 2} {include file=$smarty.const.TEMPLATES_DIR|cat:'simulator/.tpl'} {elseif $parameters['t'] == 3} diff --git a/templates/village/buildings/rallyPoint/sendUnits.tpl b/templates/village/buildings/rallyPoint/sendUnits.tpl new file mode 100644 index 00000000..636adab5 --- /dev/null +++ b/templates/village/buildings/rallyPoint/sendUnits.tpl @@ -0,0 +1,11 @@ +{if !isset($prepareUnits)} +
+ {include file=$smarty.const.TEMPLATES_DIR|cat:'sendUnits/units.tpl'} + {include file=$smarty.const.TEMPLATES_DIR|cat:'sendUnits/search.tpl'} + {include file=$smarty.const.TEMPLATES_DIR|cat:'error.tpl'} +
+{else} +
+ {include file=$smarty.const.TEMPLATES_DIR|cat:'sendUnits/attack.tpl'} +
+{/if} \ No newline at end of file