Crystal boots from a user-supplied ROM, imports a full cache and is playable:
copyright, the Crystal intro movie, the animated title, gender select, Oak,
and out into Johto. 122 of the cart's 169 script specials are implemented.
Import and data
- tools/make_crystal_manifest.py derives the manifest by importing
make_gold_manifest as a library, with three additive keyword seams. Gold and
Silver still regenerate byte-identical, which is the standing requirement for
touching that generator.
- crystal_symbol_deltas.py and crystal_movie_symbols.py carry the symbol delta:
Crystal renames the credits mons, splits the trainer card, Pokegear and
pack-pal blocks by gender, and replaces the intro and title outright.
- Crystal-only manifest keys: engineFlagOrder (162 flags to Gold's 93, so the
badge block sits one higher) and unownCharmap (the main charmap parser stops
at the first newcharmap so the two cannot contaminate each other).
Extractor
- RomExtractorGen2 becomes three-edition. Crystal corrections: PAL_MAP_BANK
0x13, a flat PICS_FIX pic bank, audio bank 0x5e, the mapSongs id-100 hole,
seven NPC trades, a TradeTexts stride of 8, the five Crystal tileset anim
steps with per-row degrade, and the column-major trainer card portraits.
- New: animated front sprites (frames, bitmasks, play and idle scripts), the
Battle Tower roster, Kris assets, Mobile System GB art, and the Crystal
intro and title via src/import/CrystalMovie.lua.
Engine
- GameVersion gains engine(id) and fixes(id). Gold and Silver keep their
original bugs where the bug is not hardware dependent; Crystal gets the fixes
Crystal shipped: Lucky Number boxes 10-14, surfing onto an NPC, and the
Reflect and Light Screen defence overflow.
- Crystal story: Suicune and Eusine, Celebi behind the GS Ball flag, the Ruins
of Alph chambers, Buena, the Move Tutor, the Poke Seer, and the Battle Tower
including the wInBattleTowerBattle badge-boost guard.
- Kris and the gender flag, animated fronts in battle and the summary screen,
and mon caught data.
Verification
- Every extracted asset is pixel-compared against pret's own source PNGs.
- Gold caches are byte-identical before and after, file for file.
- New Crystal suites plus a T2 Gen 2 tier; the full suite passes.
- Replaced `teardownMountedSession` and `flushEditorPackageLoaded` with a unified `SessionLifecycle` approach for managing session transitions and resource cleanup.
- Implemented `SessionLifecycle.endEditorSession` and `SessionLifecycle.endGameSession` to streamline the teardown process for editor and game sessions.
- Introduced `Assets.releaseSession` to handle GPU resource release at session end, ensuring efficient memory management.
- Updated `Game` and `Game2` reset methods to include world and canvas resource releases.
- Enhanced `MapLoader` with a new `releaseAll` method for eager GPU cache cleanup.
- Added tests to verify the new session lifecycle functionality and resource management.
This commit improves the stability and performance of in-process transitions, particularly during editor and game session changes.
further improves and addresses #1662 specifically around android gc pressure.
- Introduced `teardownMountedSession` to handle cleanup of mounted versions, generated data, and mod states during transitions between the editor and launcher.
- Added `flushEditorPackageLoaded` to evict save-editor modules from `package.loaded` dynamically, ensuring a clean state for subsequent sessions.
- Implemented `Game:reset` and `Game2:reset` methods to clear session-specific fields, allowing for a fresh start when returning to the launcher.
- Enhanced `Renderer` and `TileRenderer` to release GPU resources immediately, preventing memory leaks during rapid transitions.
- Updated `MagnetTrainRide` to support OAM priority overlays and manage background rendering with new shader functionality.
This commit improves the stability and performance of the application during in-process transitions, particularly on Android.
fixes Yellow color palette for title screen
fixes#1662#1643#1536 and finishes fixing #1597
Drives NamingScreen:drawPanel() with a mod-loaded Strings catalog and
checks the translated text reaches Font.draw for the prompt, a
keyboard cell, the lower/END bottom-row labels, and both lines of the
nickname header (checking the mod's word order actually took, not just
the mon name splicing in), plus a vanilla no-mod case proving the
fallback is unchanged. Reverting src/ui/gen2/NamingScreen.lua to its
pre-fix content fails 6 of the 9 checks, reproducing the reported gap
exactly.
No real shader runs headless (love_stub does not stub newShader), so
this cannot check a rendered pixel. Font.encode/drawCode/advanceOf/
width are replaced with fakes that hand printThrough a fixed list of
glyph codes, so what is checked is the two things that decide the
outcome: which glyphs skip the shade-remap shader, and what colour is
active when each one draws -- for an all-tile string, an all-TTF one,
a string that mixes both (proving the switch is per glyph, not per
call), an inverted call, and DMG mode's own resolved palette.
Reverting src/ui/gen2/Chrome.lua to its pre-fix content fails every
TTF-mode check. A per-string version of the fix (Font.ttfActive()
checked once for the whole call instead of per glyph) also fails the
mixed-string case here, since it would flatten the naming screen's
tile-based <PK>/<MN> cells to a plain ink tint whenever a TTF is
loaded at all, losing their shader-remapped colour even though they
never draw from the TTF.
Drives OptionsMenu:drawPanel() with a mod-loaded Strings catalog and
checks the translated text reaches Font.draw for a cart-original row
(label and its display value), a port-added row's label, and CANCEL,
plus a vanilla no-mod case proving the fallback is unchanged. Reverting
src/ui/gen2/OptionsMenu.lua to its pre-fix content fails 4 of the 9
checks, reproducing the reported bug exactly.
Drives a real turn per case and compares the emitted line to the label in
data/text/battle.asm. Six of the eleven checks fail against the text as it
stood.
The tail case wraps each changed line through Chrome.wrap at the box's own
width and holds it to the two rows printMessage draws. That is the check
that caught SpikesText needing a third row, which is why Spikes is not in
this change.
Silver: derived import manifest (tools/make_silver_manifest.py re-resolves
the Gold manifest's symbols from pokesilver.sym), silver GameVersion row,
generation-keyed extractor routing, required-files override, edition save
stamping (a Silver playthrough no longer writes into the Gold save),
checkver-driven edition data, SILVER/KAMON/OSCAR/MAX presets, GOLD rival
default, edition credits banner, Lugia title screen (OAM layouts, bob,
trail, palettes as title.lua data keys with Gold defaults so old caches
need no re-import), packaging for every build target, docs, and tests.
Launcher: the installed-mods list is one continuous scroll (rows culled to
the viewport) instead of a pager with an inner scroll viewport; the pad
cursor's edge-scroll no longer runs it to the bottom. The game dropdown
shows just the initial and caret. Find-tab behavior unchanged.
Title tempo: a sprite-anim frame shows duration+1 ticks
(engine/sprite_anims/core.asm GetSpriteAnimFrame), which locks both
editions' 64-tick wing beat to the 64-tick sine bob; the title screens no
longer run fast and out of phase.
Every existing test around these callsites only ever runs with an
empty/fixture Data.text, so none of them could tell a properly-wired
romText/t._X call apart from a literal that never looked at the
catalog at all -- every assertion passed either way, the same coverage
gap the museum ticket clerk and status abbreviation fixes hit earlier.
Seven new tests fake the real label for each fix and assert the pushed
or queued message uses the translated value, plus a vanilla case per
fix confirming the no-catalog fallback still matches the original
English literal exactly:
- box_release_confirmation_romtext.lua (BoxMenu _OnceReleasedText, via
a TextBox.new spy so real pagination/choice behavior stays intact)
- slot_machine_lined_up_romtext.lua (SlotMachine _LinedUpText, symbol
concatenated in front of the translated suffix)
- battle_fainted_message_romtext.lua (BattleState onFaint, both
_PlayerMonFaintedText and _EnemyMonFaintedText, confirming the raw
name reaches each without a duplicated "Enemy")
- battle_catch_messages_romtext.lua (BattleState storeCaughtMon,
_ItemUseBallText06 plus both _ItemUseBallText07/08 branches on
EVENT_MET_BILL)
- battle_ball_dodge_romtext.lua (BattleState throwBall,
_ItemUseBallText00's \f-merge collapsing to exactly one queued
message)
- overworld_field_faint_heal_romtext.lua (OverworldController
applyFieldPoison's _PokemonFaintedText, and
useSoftboiledFieldMove's _ItemUseNoEffectText/_PotionText including
the recovered-amount slot the old literal never showed)
- overworld_hidden_item_romtext.lua (OverworldController
tryHiddenObject's _FoundHiddenItemText, both the {PLAYER} token and
the item name landing in the right slots)
Confirmed several of these fail against the pre-fix code and pass
against the current code, not just reasoned about it. Not every one of
the 15 fixed callsites has its own dedicated test -- the ShopMenu,
LinkBattle, trainer-withdraw/sent-out and the normal (non-hidden)
found-item sites share the same romText mechanism already proven
correct by the seven tests above, and building the heavier fixtures
each would need (a full mart flow, a link session, a trainer AI
switch, an object_event NPC) wasn't judged worth it for what would be
the same assertion shape again.