Several screens looked their cart strings up in the script cache on every draw, every frame or every read. Each now resolves them once:
- the Battle Arena's judgment titles, when the window opens;
- the Battle Dome's tourney title, when the tree opens, and a match card's win and match-number texts, when the card is built;
- the Frontier Pass map's landmark names and descriptions, when the map opens;
- the Pokédex search screen's option texts, when the cursor moves instead of on every frame of the option list;
- the party menu's action labels, once per action list;
- the Battle Pyramid bag's "Return to" place, when the bag opens;
- the expanded placeholders, when their table is built for the current script cache.
The runtime expanded {RIVAL} and {KUN} from text/placeholders.lua, the values the extractor reads from the US cart, so a translation never reached them: the rival stayed MAY or BRENDAN and the Japanese honorific stayed empty. Each value is a cart string the script cache also holds under its pret label (gText_ExpandedPlaceholder_May, _Brendan, _Kun, _Chan...); the placeholders now read it from there, with the extract's value as the fallback.
The rse/menus pack's cursor options are plain English strings. The Emerald profile lists sCursorOptions' strings, an action prints the cart's text for its option and a field move prints the move's name, as the cart does; the pack's labels still identify the actions.
The search screen's option titles and descriptions and its help lines come from the chrome pack's English copies. They are read by their pret labels instead (gText_DexSortNumericalTitle, gText_SearchForPkmnBasedOnParameters, gTypeNames[type]...), with the copies as the fallback.
The map name popup prints a Battle Pyramid floor's name through RomText.refIr(), and the region map reads Ever Grande City's two fly destinations by sEverGrandeCityNames' labels, so both follow a text override.
Several Battle Frontier screens print a cart string from the pack their extractor wrote, so a text override never reaches them although the script cache holds the same string. RomText.irOr() and RomText.refIr() read the cache's text by label, or by the symbol and address a pack reference keeps, and fall back on the pack's copy. The records window, the S.S. Tidal menu, the Battle Dome, the Battle Arena, the Apprentice, the Frontier Pass, the Trainer Hill records and the Pyramid bag's "Return to" line use them; the Dome's and the Arena's strings, kept without a symbol, are read by the label of their table.
Mapsec.name() returns Strings(name): every caller displays the name, so the region map, the PokéNav, the map name popup, Match Call, TV and the other screens that print it follow, and the RSE summary's met location is translated the same way.
The Pokédex entry passes its category and description through Strings() when drawn, and the starter selection and the Battle Factory build the same CopyMonCategoryText string the same way.
SummaryData.contestEffectDescription() and contestCategoryName() translate by the English text, like the move and ability descriptions, and the RSE summary, the move relearner and the contest move window print them.
Pokemon.abilityName() returns Strings(name), so the RSE summary and the battle ability placeholders show a translated name, as FireRed's summary already did. FireRed's summary no longer translates the getter's result a second time, and the battle adapter keys an ability outside its built-in table by Pokemon.romAbilityName(), so a translated name cannot become an unknown ability key.
Ruby and Sapphire 1.0/1.1/1.2 import, play, save, convert and link. Gen 3 shaders, braille, weather and reflection parity, link room players, RS custom carts and launcher support, Gen 3 link fixes for Emerald and FireRed/LeafGreen.
Since v0.3.29, Menu:draw sets the black text color only inside its title branch, where the title's white backing is drawn. A menu without a title, such as the Red/Blue/Yellow main menu (CONTINUE, NEW GAME, OPTION), printed its choices in whatever color was current: the white the box's fill and the previous frame leave behind. Tile glyphs are black on transparent and come out black whatever the color, so English never showed it, but a translation's TTF font draws in the current color and printed every choice white on white; only the tile cursor stayed visible.
The choices are now drawn after an unconditional black, as before v0.3.29, with or without a title.
Two screens print a name followed by a cart string, the way the US code builds them: the nickname screen's title (the species and gText_PkmnsNickname) and a secret base's name (the owner and gText_ApostropheSBase). The French, Italian and Spanish rows name it where their language puts it, through STR_VAR_1 ("Surnom de [STR_VAR_1]?", "BASE DE [STR_VAR_1]"), and their code fills the placeholder (pret pokeemerald multi-language, src/naming_screen.c:1746, src/secret_base.c:732); the German rows do the same ("Kosename f. [STR_VAR_1]"). A French nickname screen read "POUSSIFEUSurnom de ?".
Both now render the row with the name as STR_VAR_1 and use that text when the row prints it, a mod's catalog entry for the English source included; a row without the placeholder (FireRed's US and Japanese titles, the Japanese secret base row) keeps the name in front. English and Japanese text is unchanged.
A stat that rises or falls by two stages prints the cart's "sharply" or "harshly" row followed by its "rose!" or "fell!" row, as the US code buffers them. The French, Italian and Spanish rows for the two-stage change are the whole change ("monte beaucoup!", "sale di molto!", "subió mucho"), and their code skips the string that follows (pret pokeemerald multi-language, src/battle_message.c:4617); the German rows have the same shape ("steigt stark!"). A French battle printed "monte beaucoup!augmente!".
Secondary.sharpChange keeps the plain row only after a "sharply" or "harshly" row that ends with a space, as the US and Japanese ones do ("sharply ", "ぐーんと "). The move effects and the held items that raise a stat by two use it.
The battle text joins a foe's name to the cart's sText_WildPkmnPrefix or sText_FoePkmnPrefix the way the US code does, word first. The French, Italian and Spanish carts write those rows to follow the name (" sauvage", " salvaje", " selvatico") and append them (pret pokeemerald multi-language, src/battle_message.c:4042 and :4649), and the German row has the same shape (" (Wild)"), so a French battle read " sauvageZIGZATON utilise RUGISSEMENT!".
BattleText.withMonPrefix joins the two in the row's order: a row that starts with a space follows the name, and the US and Japanese rows ("Wild ", "やせいの ") still go first. Both the battle string placeholder (B_ATK_NAME_WITH_PREFIX and the other WITH_PREFIX codes) and the buffered name (State.prefixedName) use it, in FireRed/LeafGreen and Emerald alike.
- Fixes#2667: Align FireRed battle UI text and cursor positions with vanilla layout.
- Fixes#2663: Fix Battle Pyramid double trainer sight crash and party resolution.
- Fixes#2651: Fix crash when picking up Pokemon at the daycare (native step-counting and exp/level sync).
- Fixes#2668: Fix Faraway Island Mew encounter and grass rustle collision/despawn state.
- Fixes#2647: Fix status display and Leech Seed absorption/healing sequence timing.
- Fixes#2673: Set animTurn = 1 for instant Solar Beam execution in sunlight.
- Fix Cinnabar Island Seagallop boat cutscene off-map culling and sprite fallback.
FireRed's {KUN} placeholder always expanded to nothing: the frlg dialect has no placeholder source, so the text IR dropped it. On the cart it is gExpandedPlaceholder_Kun or _Chan by the player's gender (pokefirered/src/string_util.c:386), empty on the US cart and くん/ちゃん on the Japanese one.
The frlg dialect now names those two labels, and {KUN} prints the script cache's string for the player's gender, so a translation's text override for either label reaches every line that uses the placeholder. With the cache not loaded, or both strings empty as on the US cart, it still prints nothing and never asks for the gender. A label whose own text holds {KUN} expands it to nothing rather than recursing. Emerald keeps reading {KUN} from its placeholders.
_queueFindEnrichment allows two thumbnail starts per frame, but it counted a
row against that allowance even when _startFindThumb ignored it. A row already
resolved to "failed", or with no thumbnail at all, is ignored there, so two such
rows above a card spent the allowance every frame and the card never got a
download. It stayed on its MOD placeholder (no spinner) for the whole session.
Skip rows that have already resolved, so only a row that actually starts a
download is counted. Adds a regression test that fails without the change.