mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-28 09:54:43 +02:00
49a5408c2d
A Pokémon's level is printed on four Gen 1 surfaces -- both battle healthboxes, the party rows, and both status pages -- and every one of them prints it unconditionally. There is no seam, so a mode that wants the number gone has two options today and both are bad: paint over the engine's own pixels from render.hud (four rectangles, a background shade to match, and the palette flashes and healthbox slide to survive), or monkey-patch the render modules from inside the sandbox, which works and is exactly what CONTRIBUTING-mods.md tells mods not to do. The motivating case is a battle royale that scales every party to a shared rung rising with its fog: the number is the same for everyone, it changes on a clock, and it reads as a threat it is not -- a Lv37 opponent looks dangerous to a player who has not worked out that their own team is Lv37 too. A randomizer keeping an encounter unreadable, a challenge run that forbids level-checking and a blind Nuzlocke want the same switch. New hook `pokemon.level_visible`, taking the shape the presentation predicates on the battle screen already use -- battle.status_hud_visible, battle.bottom_ui_visible, battle.caught_marker_visible: consulted behind Runtime.wantsHook, default visible, only an explicit false suppresses. It is not named battle.* because a level is not a battle-only readout, and it carries the surface that asked (battle.enemy / battle.player / party / summary) so a mode can hide an opponent's level and keep its own. src/ui/LevelDisplay.lua holds the one definition of "visible", so the four call sites are a one-line guard each rather than four copies of the same five lines that can drift apart. No layout moves. Each site keeps its own hand-rolled PrintLevel rule (home/pokemon.asm:335-345), it just asks first. Two details are deliberate: a status condition still replaces the level on a healthbox exactly as in the cart, so hiding a level never hides PSN or BRN (the guard is an elseif on the existing status branch); and on status page 2 the <to> arrow is hidden with the level it points at, because an arrow with nothing after it is half a sentence. Gen 1 only. The Gen 2 screens and the Gen 1 PC box list -- where the level is part of a row label rather than a drawn field -- keep their own readouts and do not consult the hook. Both are stated as follow-ups in the RFC and beside the hook in docs/modding.md, so a mod author reads the limit before depending on it. Verification: tests/modkit/cases/pokemon_level_visible.lua covers the contract through the public mod API; gate_hooks picks the hook up on its own because it walks the live catalog; gate_meta_coverage is satisfied by the change that introduces the seam, so it never enters the DEBT ledger. tests/run_modkit.lua 33/33, tests/run_engine.lua 327/331 -- the same four audio/hostshell suites fail unchanged on dev without this branch. Co-Authored-By: Claude <noreply@anthropic.com>