- it was written as a string without "$output.=" in front, // so it was evaluated and thrown, with no effect. Replicated via the flag // 'skip_closing_tags' below. // 2) U13: the call $generator->getTimeFormat(...) for the training duration // was executed, but the result was never concatenated to $output - // the duration did not appear on that row at all. Replicated via the flag // 'skip_duration' below (the call is made identically, only the result // is no longer displayed). // If at some point you want to FIX these 2 bugs (not just keep them //), just delete the two entries in $bugOverrides below. // ============================================================================ //check if there is unit needed in the village $result = mysqli_query($database->dblink, "SELECT * FROM " . TB_PREFIX . "units WHERE `vref` = " . (int) $village->wid . ""); $units_array = mysqli_fetch_array($result); $count_hero = mysqli_fetch_array(mysqli_query($database->dblink, "SELECT Count(*) as Total FROM " . TB_PREFIX . "hero WHERE `uid` = " . $database->escape($session->uid) . ""), MYSQLI_ASSOC); $count_hero = $count_hero['Total']; // Explicit lookup instead of dynamic variables ${'u'.$unitID}. Variables // u1, u2, u3, u5, u6, u11... are defined elsewhere (just like in // the original that accessed them dynamically) - here we just put them in a single // array, without changing where the values ​​come from. The "?? []" fallback is just // defensive (avoid notices), the original didn't have one and assumed that // the variables always exist. $unitData = [ 1 => $u1 ?? [], 2 => $u2 ?? [], 3 => $u3 ?? [], 5 => $u5 ?? [], 6 => $u6 ?? [], 11 => $u11 ?? [], 12 => $u12 ?? [], 13 => $u13 ?? [], 15 => $u15 ?? [], 16 => $u16 ?? [], 21 => $u21 ?? [], 22 => $u22 ?? [], 24 => $u24 ?? [], 25 => $u25 ?? [], 26 => $u26 ?? [], ]; // The single source of truth for "which units belong to each tribe", used // both when displaying the rows and when validating ?train=ID below (in // the original it was duplicated: once implicitly through the 3 if(tribe==X) blocks, // once explicitly in the switch in the validationArray). // The first ID in each list (1, 11, 21) is the base unit of the tribe - // it is always displayed, without research check, exactly as in the original. $tribeUnits = [ 1 => [1, 2, 3, 5, 6], 2 => [11, 12, 13, 15, 16], 3 => [21, 22, 24, 25, 26], ]; // The 2 pre-existing bugs, explicitly identified on the unit (see note above). $bugOverrides = [ 3 => ['skip_closing_tags' => true], 13 => ['skip_duration' => true], ]; // Render a row from the hero training table for a unit. // Replace the 15 nearly identical blocks in the unfactored original. $renderTrainRow = function ($unitID, $unitData, $unitName, $units_array, $bugOptions = []) use ($database, $session, $village, $building, $generator, $id) { $skipDuration = $bugOptions['skip_duration'] ?? false; $skipClosingTags = $bugOptions['skip_closing_tags'] ?? false; $data = $unitData[$unitID]; $row = ""; $row .= ""; $row .= "
"; $row .= "\"""; $row .= $unitName; $row .= "
"; $row .= "
"; $row .= "\"Wood\"" . $data['wood'] . "|"; $row .= "\"Clay\"" . $data['clay'] . "|"; $row .= "\"Iron\"" . $data['iron'] . "|"; $row .= "\"Crop\"" . $data['crop'] . "|"; $row .= "\"Crop6|"; $row .= "\"Duration\""; // The call is always made (just like in the original, including for U13); // only the display of the result is omitted for the pre-existing bug of U13. $durationText = $generator->getTimeFormat($database->getArtifactsValueInfluence($session->uid, $village->wid, 5, $data['time'] / SPEED) * 3); if (!$skipDuration) { $row .= $durationText; } //-- If available resources combined are not enough, remove NPC button $total_required = (int) ($data['wood'] + $data['clay'] + $data['iron'] + $data['crop']); if ($session->userinfo['gold'] >= 3 && $building->getTypeLevel(17) >= 1 && $village->atotal >= $total_required) { $row .= "|\"NPC"; } $row .= "
"; $row .= ""; $row .= "
"; if ($village->awood < $data['wood'] || $village->aclay < $data['clay'] || $village->airon < $data['iron'] || $village->acrop < $data['crop']) { $row .= "" . NOT . "" . ENOUGH_RESOURCES . ""; } elseif ($units_array['u' . $unitID] == 0) { $row .= "" . NOT_UNITS . ""; } else { $row .= "" . TRAIN . ""; } // Pre-existing U3 bug: closing tags are no longer added. if (!$skipClosingTags) { $row .= "
"; } return $row; }; if ($count_hero < 3) { $output = ""; if (isset($tribeUnits[$session->tribe])) { foreach ($tribeUnits[$session->tribe] as $index => $unitID) { $isBaseUnit = ($index === 0); // u1 / u11 / u21: mereu afisat, fara research check $unitName = constant('U' . $unitID); $bugOptions = $bugOverrides[$unitID] ?? []; if ($isBaseUnit || $database->checkIfResearched($village->wid, 't' . $unitID) != 0) { $output .= $renderTrainRow($unitID, $unitData, $unitName, $units_array, $bugOptions); } } } //HERO TRAINING if (isset($_GET['train'])) { $validationArray = $tribeUnits[$session->tribe] ?? []; // check for a valid unit value if (in_array($_GET['train'], $validationArray)) { if ($count_hero < 3) { $unitID = $_GET['train']; mysqli_query($database->dblink, "INSERT INTO " . TB_PREFIX . "hero (`uid`, `wref`, `regeneration`, `unit`, `name`, `level`, `points`, `experience`, `dead`, `health`, `attack`, `defence`, `attackbonus`, `defencebonus`, `trainingtime`, `autoregen`, `intraining`) VALUES (" . $database->escape($session->uid) . ", " . (int) $village->wid . ", 0, " . $unitID . ", '" . $database->escape($session->username) . "', 0, 5, 0, 0, 100, 0, 0, 0, 0, " . round((time() + ($unitData[$unitID]['time'] / SPEED) * 3)) . ", 50, 1)"); mysqli_query($database->dblink, "UPDATE " . TB_PREFIX . "units SET `u$unitID` = `u$unitID` - 1 WHERE `vref` = " . (int) $village->wid); mysqli_query($database->dblink, " UPDATE " . TB_PREFIX . "vdata SET `wood` = `wood` - " . (int) $unitData[$unitID]['wood'] . ", `clay` = `clay` - " . (int) $unitData[$unitID]['clay'] . ", `iron` = `iron` - " . (int) $unitData[$unitID]['iron'] . ", `crop` = `crop` - " . (int) $unitData[$unitID]['crop'] . " WHERE `wref` = " . (int) $village->wid); } header("Location: build.php?id=" . $id . ""); exit; } } echo $output; } // NOTE (pre-existing behavior, kept unchanged): if $count_hero >= 3, // $output is no longer created and no longer echoed - but the
" . TRAIN_HERO . "
below // is outside this if and is displayed unconditionally. In that case the file // generates an "orphan" , without a corresponding . This was also the case in // the original file. ?>