diff --git a/src/battle/gen2/Mon.lua b/src/battle/gen2/Mon.lua index 3caa03f5..4b79c460 100644 --- a/src/battle/gen2/Mon.lua +++ b/src/battle/gen2/Mon.lua @@ -112,7 +112,13 @@ function Mon.syncIdentity(mon, data) if mon.dvs then mon.gender = Mon.gender(def, mon.dvs, { species = mon.species, level = mon.level }) - mon.shiny = Mon.isShiny(mon.dvs, + -- shiny is monotonic once true, the same as opts.shiny winning over + -- shiny.roll at Mon.new: a forced shiny (the scripted-shiny path, DVs + -- that do not themselves read as shiny) must not un-shiny the moment + -- this runs again, and it runs on every SummaryMenu open via + -- refreshStats. A mon not already shiny still promotes normally if + -- its DVs justify it, e.g. after an edit. + mon.shiny = mon.shiny or Mon.isShiny(mon.dvs, { species = mon.species, def = def, level = mon.level }) if mon.species == Unown.SPECIES then mon.unownLetter = Unown.letterFromDVs(mon.dvs) diff --git a/tests/engine/gen2_new_seams.lua b/tests/engine/gen2_new_seams.lua index f4a54a75..39a3ed56 100644 --- a/tests/engine/gen2_new_seams.lua +++ b/tests/engine/gen2_new_seams.lua @@ -468,6 +468,32 @@ do T.eq(forced.shiny, true, "opts.shiny still wins over shiny.roll") end) + -- Mon.syncIdentity (wired into refreshStats, which SummaryMenu.new calls + -- on every menu open) used to recompute mon.shiny from DVs unconditionally, + -- so opening the summary screen on a forced shiny -- one whose DVs do not + -- happen to match the natural pattern -- un-shinied it the moment the menu + -- opened. shiny is monotonic once true: a natural roll or a forced one + -- both stay shiny through any later refresh, the way opts.shiny already + -- wins at construction. + do + local forced = Mon.new(DATA, "SEEDMON", 5, { dvs = plainDvs, shiny = true }) + T.eq(forced.shiny, true, "still shiny straight out of Mon.new") + Mon.syncIdentity(forced, DATA) + T.eq(forced.shiny, true, "syncIdentity does not clobber a forced shiny") + Mon.refreshStats(forced, DATA) + T.eq(forced.shiny, true, + "refreshStats (SummaryMenu.new's call) does not either") + + -- the natural cases are unaffected: DVs that read shiny stay shiny, + -- DVs that do not stay plain + local natural = Mon.new(DATA, "SEEDMON", 5, { dvs = shinyDvs }) + Mon.syncIdentity(natural, DATA) + T.eq(natural.shiny, true, "a naturally shiny mon still reads shiny") + local plain = Mon.new(DATA, "SEEDMON", 5, { dvs = plainDvs }) + Mon.syncIdentity(plain, DATA) + T.eq(plain.shiny, false, "a plain mon is not promoted to shiny") + end + local genderCtx withHook("gender.roll", function(nextFn, ctx) genderCtx = ctx