Strings(stat:upper()) is a dynamic argument -- tools/modkit.py's
STRINGS_CALL harvester only matches a literal string right after
Strings(/Strings.source(, so it can't discover "ATTACK"/"DEFENSE"/etc.
from these call sites. Translation coverage happened to still work
only because the same literals are independently harvested from
unrelated call sites (MoveEffects.lua's STAT_LABEL, BattleState.lua's
literal Strings("ATTACK") calls) -- real but fragile, found in review.
Reuse the codebase's existing pattern for exactly this situation
(MoveEffects.lua's STAT_LABEL): a local table built at require time
with Strings.source(...), which the harvester can see, resolved to a
translated label at use time with Strings(TABLE[key]). Adds one such
table to ItemEffects.lua (covering its X-item and vitamin call sites,
including "hp") and one to TrainerAI.lua.
Both the player-side and AI-trainer stat-rise messages (X ATTACK/
DEFENSE/etc. and the vitamins) passed the raised stat's name as a raw
uppercase Lua string (stat:upper()), bypassing Strings() entirely, so
it always rendered in English regardless of the active language even
though the surrounding sentence template was already translated.
Wrap the substituted stat name in Strings() at every call site
(src/inventory/ItemEffects.lua's two player-side messages and
src/battle/TrainerAI.lua's AI-trainer X-item message, found in
review), reusing the same "ATTACK"/"DEFENSE"/"SPEED"/"SPECIAL"/"HP"
keys SummaryMenu.lua's stat labels already look up the same way.
ItemEffects.use walked speciesDef.tmhm with a bare ipairs() to check
whether the species could learn the machine's move. A record with no
tmhm field at all -- a mod species that never set one, or any record
missing it for whatever reason -- hit ipairs(nil) and took the whole
game down on the first TM/HM use, rather than reaching the ordinary
"can't learn that move" refusal a species whose list simply omits the
move already gets.
An absent list now reads the same as an empty one: nothing to learn,
same refusal, same sound, same text.
When a Pokemon faints in battle, onFaint() clears it from the battle
participant set. The revive item restored HP but never re-added the
mon to self.participants, so at awardExp() time the revived mon passed
the HP check but failed the participant gate -- getting no exp.
Fix: re-add the revived mon to battle.participants in the revive item
effect, so it's counted as a participant and receives its share of
experience at battle end.
Fixes#648
Introduce a tuned .luacheckrc and scripts/lint.sh so the engine has a
standing static-analysis baseline -- the tool that would have caught both
bugs in the previous commit before they shipped.
The config is high-signal by design: it keeps the categories that catch
real defects (undefined globals/locals, unused values, unreachable code)
and mutes the cosmetic ones the codebase deliberately lives with (a self/dt
an interface requires but a method ignores, documented empty fall-through
branches, long lines). It marks `love` mutable (games assign callbacks onto
it) and teaches it LuaJIT's table.unpack.
.luacheckrc is tracked via a .gitignore exception, matching how .github and
.gitignore opt out of the blanket dotfile ignore.
`luacheck src` now reports 7 benign warnings and 0 errors, down from 185.
Also drop one dead `require` (ItemEffects loaded src.pokemon.Pokemon and
never used it).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q6bFAiQyZ5jDmewsbB4LG9
# Closed issues
CLOSES#17: Incorrect Character Visuals (Only with GBC filter)
CLOSES#23: Could you allow the player to change the order of the moves
CLOSES#24: Evolution music not playing during evolution
CLOSES#26: Standing on door glitch
CLOSES#27: Battle Intro text automatically continues
CLOSES#29: Visual bug when zoomed out
CLOSES#32: Team Rocket recruiter doesn't battle with you unless you speak with him first
CLOSES#33: Developer/Debug Console
CLOSES#35: Professor Oak's introduction Inaccuracies
CLOSES#36: Missing Pokemon Dex entries when picking starter + Rival Pathing issues
CLOSES#39: Guy who stops player from skipping brock doesn't bring you to brock's gym + doesn't leave once you've beaten brock
CLOSES#40: Bill cutscene is broken
CLOSES#41: Ticket guy failing to be a Ticket guy
CLOSES#42: S.S. anne odd behavior + Missing sailing away animation
CLOSES#43: Dig Attack animation appears to be glitched
CLOSES#44: Pokeball flashing doesn't appear to be accurate
CLOSES#45: Inaccurate Cut Animation
CLOSES#46: Dugtrio i caught in diglett cave has two of the same move
CLOSES#47: Rival ignores player in Lavender Tower
CLOSES#48: Healing pad in lavender tower does not function
CLOSES#49: Incorrect dialogue with parched security guard
CLOSES#50: (Game Breaking!) Rocket grunt guarding poster refuses to move
CLOSES#51: Badges showing up as items I can deposit in PC
CLOSES#52: Visual bug on Celadon Department Store roof (Red Filter)
CLOSES#54: Visual issue on route 15 + Fuchsia City
CLOSES#56: Running animation missing
CLOSES#57: Safari Zone does not display steps while you are inside of it
CLOSES#58: (Game Breaking!) Softlock at cycling road gate
CLOSES#59: Bike visual issues
CLOSES#60: Cycling road not forcing you to get on your bike
CLOSES#61: No keycard doors in Silph Co.
CLOSES#63: Missing teleporter animation
CLOSES#64: Inaccurate spinning
CLOSES#65: Reimplement unused Silph Co. Chief and Professor Oak trainer battles