sendTroops() inlined ~65 lines deciding the catapult targets ctar1/ctar2: the
"Rivals great confusion" artefact lookup, the rally-point-level-driven list of
invalid target buildings, the troop/level eligibility rules and the Teuton
Brewery / artefact adjustments. Move that whole block into
resolveCatapultTargets(&$post, $data), which mutates $post['ctar1']/['ctar2'] by
reference exactly as before; sendTroops() now calls it before building the
attack. None of the block's locals were used afterwards. Behaviour-preserving.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Both branches of Hero() (single hero when !$all, full list when $all) computed
the same five derived stats (atk/di/dc/ob/db) and assembled a byte-identical
hero stat array from a getHero() entry plus its unit base data. Extract that
into buildHeroStats($hero, $herodata) and call it from both branches.
Behaviour-preserving.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Cases 1 to 4 of the procUnits() switch had a byte-identical body (send troops
when the rally-point form is submitted, otherwise load the unit form). Stack the
four case labels and keep a single shared body via switch fall-through.
Behaviour-preserving.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
upgradeSword() and upgradeArmour() were near-identical: the only differences
were the AB-tech key prefix ('b' vs 'a'), the building type whose level gates
the research (Smithy 12 vs Armoury 13) and the matching bid building data
($bid12 vs $bid13). Merge them into a single upgradeWeaponOrArmour($get, $type)
parameterised by the prefix, deriving the building type from it, and route both
procTechno() cases through it. Resolves the pre-existing //TODO. Behaviour-
preserving.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
sendMessage, massmessage and sysmessage are POSTed to directly, bypassing
admin.php's central csrf_verify(). Add csrf_verify() (after the admin access
check, via the shared GameEngine/Admin/csrf.php) and csrf_field() in their
forms (Newmessage.tpl, massmessage.tpl, sysmessage.tpl; the mass/sys templates
have both a prepare and an execute form).
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
The post-delete admin-log block referenced variables that were never defined
($admid/$adminID/$medalid/$uid), so on PHP 8.1+ (mysqli throws on error) the
malformed INSERT raised an uncaught mysqli_sql_exception → HTTP 500 after the
medal was already deleted. Use the correct ids ($admid from session, $uid from
POST), look up the target player's username (escaped), and redirect to the
sanitized $uid.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
editAli, delAli, medals, delallymedal, delallymedalbyaid, delallymedalbyweek
and deletemedalbyweek are POSTed to directly, bypassing admin.php's central
csrf_verify(). Add csrf_verify() (after the admin access check, via the shared
GameEngine/Admin/csrf.php) and csrf_field() in their forms (playermedals.tpl,
editAli.tpl, delAli.tpl, delmedal.tpl, allymedals.tpl, delallymedal.tpl).
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
editVillageOwner, renameVillage, editBuildings and editResources are POSTed
to directly, bypassing admin.php's central csrf_verify(). Add csrf_verify()
(after the admin access check, via the shared GameEngine/Admin/csrf.php) and
csrf_field() in their forms (editVillage.tpl, village.tpl, editResources.tpl).
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
addTroops and addABTroops are POSTed to directly, bypassing admin.php's
central csrf_verify(). Add csrf_verify() (after the admin access check, via
the shared GameEngine/Admin/csrf.php) and csrf_field() in their forms.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>