From 6b4dfe6b9bf257af8c53d2ac84036c9483509169 Mon Sep 17 00:00:00 2001 From: DramaticShape Date: Sat, 8 Aug 2026 12:37:57 -0400 Subject: [PATCH] shiny: tint from the body colour, and the fixes the screenshots found Four things, all found by shooting the feature rather than by reading it. The flat-pic tint was a no-op for the five colour-table species. tintFor ran synthetic reference colours through the lookup, none of them were IN it, so every ratio came back 1 and the tint was discarded -- a shiny Gyarados drew an ordinary blue pic. Those species now measure the tint from the table's own entries. It was also a no-op for most SLIDE species, for a better-hidden reason: a hue rotation moves red toward cyan and cyan toward red, so averaged over a balanced set of references the ratios cancel and every species reports no tint. Charizard and Ponyta both came back neutral. The tint is now measured against the colour each species is actually MADE of -- a modal body colour, generated into data/shiny_colors.lua as `dom`. 132 of 151 now carry a usable tint; the rest genuinely shift too little for one to mean anything. The sparkle drew sixty quads a frame that nobody could see. It was built to numbers a tenth of the scale of a mon card -- a ring seven units across, inside a Gyarados -- and additive drawing keeps the depth test, so all of it was rejected. Sized against the card now, and pulled toward the camera the way the move-animation card is. And the summary PIC cannot be recoloured by touching pixels: the art is four-shade DMG grey and the colour is applied afterwards by the palette pass. That attempt is reverted, with the reason left where the next person will look for it. The star is the designation that works there. Also: tools/shiny_colors.py now resolves its own paths instead of hardcoding a worktree, and the extract test gained a hard failure when NOTHING recolours -- which is what a missing colour table looks like from the outside, and it passed through it once already. Evidence in .claude/shiny_update, every case beside its own control. --- data/shiny_colors.lua | 906 ++++++++++++++++++++++++++++++++++++++++++ lib/ShinyFx.lua | 41 +- lib/ShinyPalette.lua | 59 ++- lib/ShinyUI.lua | 51 +++ tests/shiny_shots.lua | 242 +++++++++++ tools/shiny_colors.py | 47 ++- 6 files changed, 1329 insertions(+), 17 deletions(-) create mode 100644 tests/shiny_shots.lua diff --git a/data/shiny_colors.lua b/data/shiny_colors.lua index e6cbc54..3b348c4 100644 --- a/data/shiny_colors.lua +++ b/data/shiny_colors.lua @@ -25,176 +25,386 @@ return { [1] = { name = "bulbasaur", hueRange = { min = -45, max = 70 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x52BD9C, slide = { h = -30, l = 2, s = -1 }, }, [2] = { name = "ivysaur", hueRange = { min = -40, max = 45 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x6AC5C5, slide = { h = -50, l = 2, s = 1 }, }, [3] = { name = "venusaur", hueRange = { min = -30, max = 40 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x6ABDCD, slide = { h = -40, l = 2, s = 1 }, }, [4] = { name = "charmander", hueRange = { min = -25, max = 20 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xEE8B31, slide = { h = 28, l = 0, s = -1 }, }, [5] = { name = "charmeleon", hueRange = { min = -10, max = 55 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xD54A6A, slide = { h = -20, l = 1, s = -1 }, }, [6] = { name = "charizard", hueRange = { min = -20, max = 15 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xF68B29, slide = { h = -136, l = 0, s = -6 }, }, [7] = { name = "squirtle", hueRange = { min = -50, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xACFFFF, slide = { h = 30, l = -3, s = 2 }, }, [8] = { name = "wartortle", hueRange = { min = -50, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x8BA4E6, slide = { h = -50, l = -3, s = -2 }, }, [9] = { name = "blastoise", hueRange = { min = -30, max = 35 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x7B9CBD, slide = { h = -35, l = -1, s = -3 }, }, [10] = { name = "caterpie", hueRange = { min = -30, max = 80 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x629441, slide = { h = -45, l = 2, s = -1 }, }, [11] = { name = "metapod", hueRange = { min = -20, max = 60 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xACF662, slide = { h = -55, l = 0, s = 0 }, }, [12] = { name = "butterfree", hueRange = { min = -40, max = 50 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xD5F6F6, slide = { h = 140, l = 0, s = 0 }, }, [13] = { name = "weedle", hueRange = { min = 0, max = 50 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xE67331, slide = { h = 46, l = 0, s = 0 }, }, [14] = { name = "kakuna", hueRange = { min = -25, max = 40 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xDECD31, slide = { h = 30, l = 0, s = 0 }, }, [15] = { name = "beedrill", hueRange = { min = -20, max = 50 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFB44A, slide = { h = 145, l = 0, s = -3 }, }, [16] = { name = "pidgey", hueRange = { min = -30, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFE6A4, slide = { h = 40, l = 1, s = -2 }, }, [17] = { name = "pidgeotto", hueRange = { min = -30, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFE6A4, slide = { h = 40, l = 1, s = 0 }, }, [18] = { name = "pidgeot", hueRange = { min = -35, max = 20 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFE6A4, slide = { h = 40, l = 1, s = -3 }, }, [19] = { name = "rattata", hueRange = { min = -40, max = 60 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x9C6AC5, slide = { h = -105, l = 0, s = -5 }, }, [20] = { name = "raticate", hueRange = { min = -30, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xF6EEC5, slide = { h = -30, l = 1, s = -4 }, }, [21] = { name = "spearow", hueRange = { min = -30, max = 20 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFE6A4, slide = { h = -25, l = 1, s = -2 }, }, [22] = { name = "fearow", hueRange = { min = -25, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xDCD294, slide = { h = 140, l = 3, s = -5 }, }, [23] = { name = "ekans", hueRange = { min = -30, max = 40 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xAC7BBD, slide = { h = -155, l = -2, s = -5 }, }, [24] = { name = "arbok", hueRange = { min = -70, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xA48BBD, slide = { h = -80, l = 0, s = -4 }, }, [25] = { name = "pikachu", hueRange = { min = -15, max = 25 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFDE31, slide = { h = -25, l = 1, s = 0 }, }, [26] = { name = "raichu", hueRange = { min = -15, max = 25 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xF6A429, slide = { h = 25, l = 0, s = -2 }, }, [27] = { name = "sandshrew", hueRange = { min = -40, max = 40 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xA49C52, slide = { h = -159, l = -1, s = -4 }, }, [28] = { name = "sandslash", hueRange = { min = -20, max = 25 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xCDBD08, slide = { h = 25, l = 1, s = -6 }, }, [29] = { name = "nidoran_f", hueRange = { min = -60, max = 70 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xD5DEF6, slide = { h = 70, l = -2, s = 2 }, }, [30] = { name = "nidorina", hueRange = { min = -80, max = 80 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x9CD5DE, slide = { h = 100, l = 0, s = 0 }, }, [31] = { name = "nidoqueen", hueRange = { min = -60, max = 80 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x7B9CBD, slide = { h = 50, l = 0, s = -5 }, }, [32] = { name = "nidoran_m", hueRange = { min = -70, max = 20 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xF694D5, slide = { h = -96, l = 0, s = 0 }, }, [33] = { name = "nidorino", hueRange = { min = -70, max = 20 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xE68BCD, slide = { h = -99, l = 0, s = 0 }, }, [34] = { name = "nidoking", hueRange = { min = -50, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xBD83C5, slide = { h = -60, l = 0, s = 0 }, }, [35] = { name = "clefairy", hueRange = { min = -40, max = 50 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFC5C5, -- Stadium ships a real alternate texture for this one; 350 -- colours move, every other colour stays exactly as it was. lut = { @@ -291,6 +501,12 @@ return { [36] = { name = "clefable", hueRange = { min = -40, max = 50 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFD5CD, -- Stadium ships a real alternate texture for this one; 223 -- colours move, every other colour stays exactly as it was. lut = { @@ -355,16 +571,34 @@ return { [37] = { name = "vulpix", hueRange = { min = -30, max = 35 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xCD9C8B, slide = { h = 27, l = 0, s = 3 }, }, [38] = { name = "ninetales", hueRange = { min = -30, max = 50 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFEEB4, slide = { h = -130, l = 0, s = -2 }, }, [39] = { name = "jigglypuff", hueRange = { min = -40, max = 40 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFCDDE, -- Stadium ships a real alternate texture for this one; 394 -- colours move, every other colour stays exactly as it was. lut = { @@ -472,6 +706,12 @@ return { [40] = { name = "wigglytuff", hueRange = { min = -40, max = 40 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFCDDE, -- Stadium ships a real alternate texture for this one; 409 -- colours move, every other colour stays exactly as it was. lut = { @@ -583,451 +823,991 @@ return { [41] = { name = "zubat", hueRange = { min = -30, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x73DEF6, slide = { h = -110, l = -1, s = -2 }, }, [42] = { name = "golbat", hueRange = { min = -25, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x29ACE6, slide = { h = -63, l = -6, s = -4 }, }, [43] = { name = "oddish", hueRange = { min = -40, max = 70 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x626A83, slide = { h = -50, l = 2, s = 3 }, }, [44] = { name = "gloom", hueRange = { min = -40, max = 65 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x626A83, slide = { h = 30, l = 3, s = 1 }, }, [45] = { name = "vileplume", hueRange = { min = -25, max = 60 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x626A83, slide = { h = 50, l = 3, s = 1 }, }, [46] = { name = "paras", hueRange = { min = -20, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xC5E6FF, slide = { h = 25, l = -3, s = 3 }, }, [47] = { name = "parasect", hueRange = { min = -20, max = 35 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xEE5231, slide = { h = 40, l = -4, s = 6 }, }, [48] = { name = "venonat", hueRange = { min = -60, max = 60 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x4A3952, slide = { h = -90, l = 0, s = 0 }, }, [49] = { name = "venomoth", hueRange = { min = -60, max = 100 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xF6C5E6, slide = { h = -90, l = 0, s = 1 }, }, [50] = { name = "diglett", hueRange = { min = -20, max = 35 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xBD6239, slide = { h = -50, l = 1, s = -2 }, }, [51] = { name = "dugtrio", hueRange = { min = -20, max = 35 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xBD6239, slide = { h = -50, l = 1, s = -2 }, }, [52] = { name = "meowth", hueRange = { min = -40, max = 35 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xF6EEAC, slide = { h = -55, l = 2, s = 0 }, }, [53] = { name = "persian", hueRange = { min = -20, max = 50 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFE6BD, slide = { h = -30, l = 0, s = -2 }, }, [54] = { name = "psyduck", hueRange = { min = -20, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFDE29, slide = { h = -142, l = 2, s = -2 }, }, [55] = { name = "golduck", hueRange = { min = -60, max = 50 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x8B9CAC, slide = { h = 20, l = 0, s = 3 }, }, [56] = { name = "mankey", hueRange = { min = -35, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFEEAC, slide = { h = 105, l = -1, s = -3 }, }, [57] = { name = "primeape", hueRange = { min = -35, max = 40 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFD59C, slide = { h = -50, l = 1, s = -3 }, }, [58] = { name = "growlithe", hueRange = { min = -35, max = 10 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xEEB420, slide = { h = 20, l = 0, s = 2 }, }, [59] = { name = "arcanine", hueRange = { min = -30, max = 20 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xF69429, slide = { h = 25, l = 1, s = -3 }, }, [60] = { name = "poliwag", hueRange = { min = -50, max = 50 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x6A7BA4, slide = { h = -20, l = 0, s = 3 }, }, [61] = { name = "poliwhirl", hueRange = { min = -50, max = 50 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x6A7BA4, slide = { h = 20, l = -2, s = 2 }, }, [62] = { name = "poliwrath", hueRange = { min = -50, max = 50 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x6A7BA4, slide = { h = -58, l = -2, s = 3 }, }, [63] = { name = "abra", hueRange = { min = -20, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xD5A420, slide = { h = 20, l = 1, s = -1 }, }, [64] = { name = "kadabra", hueRange = { min = -30, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xEECD5A, slide = { h = 10, l = 1, s = 1 }, }, [65] = { name = "alakazam", hueRange = { min = -30, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xEECD5A, slide = { h = 20, l = -2, s = 1 }, }, [66] = { name = "machop", hueRange = { min = -40, max = 60 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xACD5BD, slide = { h = 100, l = 0, s = 0 }, }, [67] = { name = "machoke", hueRange = { min = -70, max = 60 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x949CBD, slide = { h = -120, l = 1, s = -2 }, }, [68] = { name = "machamp", hueRange = { min = -70, max = 80 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xACD5C5, slide = { h = 100, l = 0, s = -2 }, }, [69] = { name = "bellsprout", hueRange = { min = -15, max = 15 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFFF18, slide = { h = -25, l = 0, s = -3 }, }, [70] = { name = "weepinbell", hueRange = { min = -25, max = 40 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xF8F860, slide = { h = -75, l = -1, s = -3 }, }, [71] = { name = "victreebel", hueRange = { min = -30, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFFF62, slide = { h = 40, l = -2, s = -3 }, }, [72] = { name = "tentacool", hueRange = { min = -40, max = 40 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x4AC5C5, slide = { h = 50, l = 2, s = 2 }, }, [73] = { name = "tentacruel", hueRange = { min = -40, max = 40 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x4AC5C5, slide = { h = 50, l = 2, s = 2 }, }, [74] = { name = "geodude", hueRange = { min = -180, max = 180 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x73735A, slide = { h = -70, l = 0, s = 0 }, }, [75] = { name = "graveler", hueRange = { min = -180, max = 180 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x525239, slide = { h = -55, l = 0, s = 0 }, }, [76] = { name = "golem", hueRange = { min = -50, max = 20 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x836A52, slide = { h = -55, l = 0, s = -2 }, }, [77] = { name = "ponyta", hueRange = { min = -25, max = 20 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFFF83, slide = { h = 40, l = 2, s = -1 }, }, [78] = { name = "rapidash", hueRange = { min = -25, max = 20 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFFF83, slide = { h = 40, l = 2, s = -1 }, }, [79] = { name = "slowpoke", hueRange = { min = -40, max = 40 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFF8B94, slide = { h = -90, l = -6, s = -3 }, }, [80] = { name = "slowbro", hueRange = { min = -40, max = 40 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xA4ACA4, slide = { h = -75, l = -4, s = -2 }, }, [81] = { name = "magnemite", hueRange = { min = -180, max = 180 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x5A5A5A, slide = { h = -30, l = 2, s = -4 }, }, [82] = { name = "magneton", hueRange = { min = -180, max = 180 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x5A5A5A, slide = { h = -30, l = 2, s = -4 }, }, [83] = { name = "farfetchd", hueRange = { min = -30, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xB4946A, slide = { h = 15, l = 1, s = 2 }, }, [84] = { name = "doduo", hueRange = { min = -10, max = 40 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xBD6200, slide = { h = 31, l = 1, s = 2 }, }, [85] = { name = "dodrio", hueRange = { min = -10, max = 40 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xB45A00, slide = { h = 31, l = 1, s = 2 }, }, [86] = { name = "seel", hueRange = { min = -40, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xE67373, slide = { h = -180, l = 3, s = -4 }, }, [87] = { name = "dewgong", hueRange = { min = -10, max = 10 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xDEEEDE, slide = { h = -180, l = 3, s = -4 }, }, [88] = { name = "grimer", hueRange = { min = -180, max = 180 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x5A4A5A, slide = { h = 125, l = -1, s = 1 }, }, [89] = { name = "muk", hueRange = { min = -180, max = 180 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x5A4A5A, slide = { h = -115, l = 0, s = 1 }, }, [90] = { name = "shellder", hueRange = { min = -70, max = 40 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x8B73C5, slide = { h = 120, l = 0, s = 0 }, }, [91] = { name = "cloyster", hueRange = { min = -70, max = 60 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x29104A, slide = { h = 140, l = 0, s = 0 }, }, [92] = { name = "gastly", hueRange = { min = -80, max = 50 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x201029, slide = { h = -124, l = 0, s = 0 }, }, [93] = { name = "haunter", hueRange = { min = -70, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x6A418B, slide = { h = -50, l = -2, s = -2 }, }, [94] = { name = "gengar", hueRange = { min = -90, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x5A3962, slide = { h = -55, l = -2, s = -1 }, }, [95] = { name = "onix", hueRange = { min = -180, max = 180 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xA4A4BD, slide = { h = -171, l = -3, s = 0 }, }, [96] = { name = "drowzee", hueRange = { min = -10, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFBD00, slide = { h = -110, l = 4, s = -4 }, }, [97] = { name = "hypno", hueRange = { min = -15, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xE6BD18, slide = { h = -80, l = 1, s = -3 }, }, [98] = { name = "krabby", hueRange = { min = -20, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xF63100, slide = { h = 40, l = -1, s = 0 }, }, [99] = { name = "kingler", hueRange = { min = -20, max = 25 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xBD6A31, slide = { h = 35, l = -1, s = 2 }, }, [100] = { name = "voltorb", hueRange = { min = -70, max = 10 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x8B3939, slide = { h = -95, l = 0, s = 0 }, }, [101] = { name = "electrode", hueRange = { min = -70, max = 10 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xBD4A4A, slide = { h = -95, l = 0, s = 0 }, }, [102] = { name = "exeggcute", hueRange = { min = -50, max = 40 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xF6B4BD, slide = { h = 70, l = 0, s = 0 }, }, [103] = { name = "exeggutor", hueRange = { min = -30, max = 40 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFEE83, slide = { h = -60, l = 2, s = -3 }, }, [104] = { name = "cubone", hueRange = { min = -25, max = 5 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xDEAC39, slide = { h = 160, l = 2, s = -5 }, }, [105] = { name = "marowak", hueRange = { min = -25, max = 5 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xDED5C5, slide = { h = 160, l = 2, s = -5 }, }, [106] = { name = "hitmonlee", hueRange = { min = -20, max = 50 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x94524A, slide = { h = 70, l = 0, s = -2 }, }, [107] = { name = "hitmonchan", hueRange = { min = -20, max = 50 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xA4836A, slide = { h = -145, l = 1, s = -1 }, }, [108] = { name = "lickitung", hueRange = { min = -50, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xF6A4A4, slide = { h = 60, l = -1, s = 1 }, }, [109] = { name = "koffing", hueRange = { min = -60, max = 90 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x73418B, slide = { h = -80, l = -1, s = 3 }, }, [110] = { name = "weezing", hueRange = { min = -60, max = 90 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x836A83, slide = { h = -90, l = 0, s = 1 }, }, [111] = { name = "rhyhorn", hueRange = { min = -180, max = 180 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xA4ACBD, slide = { h = 150, l = -1, s = 1 }, }, [112] = { name = "rhydon", hueRange = { min = -180, max = 180 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xA4A4AC, slide = { h = 58, l = 1, s = 1 }, }, [113] = { name = "chansey", hueRange = { min = -50, max = 60 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFD5E6, slide = { h = 80, l = 0, s = 0 }, }, [114] = { name = "tangela", hueRange = { min = -40, max = 20 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xEE5A73, slide = { h = -120, l = 0, s = 0 }, }, [115] = { name = "kangaskhan", hueRange = { min = -30, max = 50 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x836A4A, slide = { h = -176, l = 0, s = -2 }, }, [116] = { name = "horsea", hueRange = { min = -40, max = 40 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x83B4DE, slide = { h = -70, l = 0, s = -1 }, }, [117] = { name = "seadra", hueRange = { min = -30, max = 35 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x5AB4DE, slide = { h = -65, l = 2, s = 1 }, }, [118] = { name = "goldeen", hueRange = { min = -60, max = 40 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xF6F6D5, slide = { h = 50, l = 0, s = 3 }, }, [119] = { name = "seaking", hueRange = { min = -50, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xB43918, slide = { h = 40, l = 1, s = 3 }, }, [120] = { name = "staryu", hueRange = { min = -10, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xE14254, slide = { h = -176, l = 0, s = 0 }, }, [121] = { name = "starmie", hueRange = { min = -40, max = 50 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFF3888, slide = { h = -110, l = 0, s = 0 }, }, [122] = { name = "mr_mime", hueRange = { min = -30, max = 50 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFC5C5, slide = { h = 30, l = -2, s = 2 }, }, [123] = { name = "scyther", hueRange = { min = -30, max = 50 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x83C56A, slide = { h = -110, l = 0, s = 0 }, }, [124] = { name = "jynx", hueRange = { min = -10, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x525A73, slide = { h = 30, l = 0, s = 3 }, }, [125] = { name = "electabuzz", hueRange = { min = -20, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFEE00, slide = { h = -40, l = 2, s = -2 }, }, [126] = { name = "magmar", hueRange = { min = -15, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xEE3918, slide = { h = -60, l = 1, s = -2 }, }, [127] = { name = "pinsir", hueRange = { min = -60, max = 130 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x836A62, slide = { h = -150, l = 0, s = 0 }, }, [128] = { name = "tauros", hueRange = { min = -10, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xC59429, slide = { h = -20, l = 4, s = -2 }, }, [129] = { name = "magikarp", hueRange = { min = -30, max = 25 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xE64A31, slide = { h = 50, l = -1, s = 2 }, }, [130] = { name = "gyarados", hueRange = { min = -20, max = 50 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x62BDEE, -- Stadium ships a real alternate texture for this one; 481 -- colours move, every other colour stays exactly as it was. lut = { @@ -1157,106 +1937,232 @@ return { [131] = { name = "lapras", hueRange = { min = -15, max = 5 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x398BCD, slide = { h = 56, l = 2, s = 0 }, }, [132] = { name = "ditto", hueRange = { min = -60, max = 20 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xAC6294, slide = { h = -80, l = -2, s = 1 }, }, [133] = { name = "eevee", hueRange = { min = -30, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xBD7B4A, slide = { h = -140, l = 1, s = -5 }, }, [134] = { name = "vaporeon", hueRange = { min = -20, max = 50 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x6ABDC5, slide = { h = 87, l = 0, s = 0 }, }, [135] = { name = "jolteon", hueRange = { min = -25, max = 20 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFFF00, slide = { h = -20, l = -1, s = -5 }, }, [136] = { name = "flareon", hueRange = { min = -20, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xCD624A, slide = { h = -60, l = 0, s = -2 }, }, [137] = { name = "porygon", hueRange = { min = -40, max = 40 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xEEC5C5, slide = { h = -90, l = -3, s = 2 }, }, [138] = { name = "omanyte", hueRange = { min = -15, max = 60 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xDEBD83, slide = { h = -30, l = 1, s = -1 }, }, [139] = { name = "omastar", hueRange = { min = -15, max = 60 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xD5C583, slide = { h = -30, l = 1, s = -1 }, }, [140] = { name = "kabuto", hueRange = { min = -20, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xA46220, slide = { h = 40, l = 2, s = -7 }, }, [141] = { name = "kabutops", hueRange = { min = -40, max = 50 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x94735A, slide = { h = 50, l = 0, s = -5 }, }, [142] = { name = "aerodactyl", hueRange = { min = -60, max = 60 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xA49CB4, slide = { h = 50, l = -2, s = 2 }, }, [143] = { name = "snorlax", hueRange = { min = -10, max = 60 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xF6E6B4, slide = { h = 30, l = 1, s = -3 }, }, [144] = { name = "articuno", hueRange = { min = -20, max = 30 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x31A4D5, slide = { h = -40, l = 0, s = 1 }, }, [145] = { name = "zapdos", hueRange = { min = -20, max = 25 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFF9C39, slide = { h = -40, l = 2, s = 0 }, }, [146] = { name = "moltres", hueRange = { min = -20, max = 20 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xFFD500, slide = { h = -80, l = 5, s = -3 }, }, [147] = { name = "dratini", hueRange = { min = -40, max = 20 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x94A4E6, slide = { h = 40, l = 0, s = 0 }, }, [148] = { name = "dragonair", hueRange = { min = -30, max = 10 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0x4183BD, slide = { h = 50, l = 2, s = -3 }, }, [149] = { name = "dragonite", hueRange = { min = -20, max = 25 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xE6AC5A, slide = { h = 130, l = 0, s = -4 }, }, [150] = { name = "mewtwo", hueRange = { min = -70, max = 90 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xBDBDDE, slide = { h = -40, l = -1, s = -2 }, }, [151] = { name = "mew", hueRange = { min = -40, max = 60 }, + -- the colour this species is mostly MADE of, and what its shiny + -- shift does to it. A flat sprite cannot be recoloured, only + -- multiplied, and the multiply has to be measured against the + -- body colour: averaged over a balanced set of references a + -- hue rotation cancels itself out to no tint at all. + dom = 0xEEDEEE, slide = { h = -80, l = 0, s = 0 }, }, } diff --git a/lib/ShinyFx.lua b/lib/ShinyFx.lua index b3b652d..71a7149 100644 --- a/lib/ShinyFx.lua +++ b/lib/ShinyFx.lua @@ -42,12 +42,24 @@ local ShinyFx = {} -- ------- shape and timing +-- Sized against the mon CARD, which is what a Pokemon occupies here: a card +-- is BattleBillboard.FULL_W / FULL_PIC * GB_W units across, i.e. about 46 +-- wide and 41 tall. The first version of this was built to numbers a tenth +-- of that and drew sixty quads a frame that nobody could see -- a ring seven +-- units across, inside a Gyarados. ShinyFx.LIFE = 0.75 -- seconds from spring to gone ShinyFx.STARS = 10 -- around the ring -ShinyFx.RISE = 10 -- world units the ring climbs over its life -ShinyFx.SPREAD = 7 -- how far out the ring opens -ShinyFx.CHEST = 9 -- height above the tile the burst starts at -ShinyFx.SIZE = 3.2 -- a star's world size at full brightness +ShinyFx.RISE = 14 -- world units the ring climbs over its life +ShinyFx.SPREAD = 24 -- how far out the ring opens -- wider than the + -- body, or the stars are inside the Pokemon +ShinyFx.CHEST = 20 -- height above the tile the burst starts at +ShinyFx.SIZE = 7 -- a star's world size at full brightness + +-- Additive drawing keeps the depth TEST (Voxel3D.blend sets lequal with +-- writes off), so a star level with the model is rejected by it however +-- bright it is. The extra pull puts the ring in front of the Pokemon it +-- belongs to, the same trick the move-animation card uses. +ShinyFx.PULL_BONUS = 6 -- one per side, nil when nothing is playing local live = { player = nil, enemy = nil } @@ -132,12 +144,24 @@ local function easeOut(u) return 1 - (1 - u) * (1 - u) end -- Draw whatever is playing. `arena` and `groundY` come from the scene, the -- same two the mon cards are placed from, so a sparkle lands where its -- Pokemon is standing rather than where the layout thinks it should be. +-- Why a burst did not draw, for a driver to read back. Rendering faults are +-- invisible to the test suite and this one has four separate ways to be a +-- no-op, all of them silent. +ShinyFx.debug = { calls = 0, noArena = 0, noImage = 0, noMesh = 0, + noLive = 0, quads = 0 } + function ShinyFx.draw(arena, groundY, pull) - if not arena then return end + local dbg = ShinyFx.debug + dbg.calls = dbg.calls + 1 + if not arena then dbg.noArena = dbg.noArena + 1 return end local img = starImage() - if not img then return end + if not img then dbg.noImage = dbg.noImage + 1 return end local mesh = BattleBillboard.mesh() - if not mesh then return end + if not mesh then dbg.noMesh = dbg.noMesh + 1 return end + if not (live.player or live.enemy) then + dbg.noLive = dbg.noLive + 1 + return + end local drew = false for _, side in ipairs({ "player", "enemy" }) do @@ -174,7 +198,8 @@ function ShinyFx.draw(arena, groundY, pull) Mat4.mul(Mat4.translate(x, baseY, z), Mat4.rotateY(yaw)), Mat4.mul(Mat4.translate(ox, oy, 0), Mat4.scale(k, k, 1))) love.graphics.setColor(1, 1, 1, alpha) - Voxel3D.draw(mesh, img, m, pull) + Voxel3D.draw(mesh, img, m, (pull or 0) + ShinyFx.PULL_BONUS) + dbg.quads = dbg.quads + 1 end end end diff --git a/lib/ShinyPalette.lua b/lib/ShinyPalette.lua index ba49c73..c493246 100644 --- a/lib/ShinyPalette.lua +++ b/lib/ShinyPalette.lua @@ -285,15 +285,60 @@ local REFS = { function ShinyPalette.tintFor(dex) local hit = tintCache[dex] if hit ~= nil then return hit or nil end - local fn = ShinyPalette.transform(ShinyPalette.forDex(dex)) + local spec = ShinyPalette.forDex(dex) + local fn = ShinyPalette.transform(spec) if not fn then tintCache[dex] = false; return nil end local sr, sg, sb, n = 0, 0, 0, 0 - for _, c in ipairs(REFS) do - local r, g, b = fn(c[1], c[2], c[3]) - sr = sr + r / c[1] - sg = sg + g / c[2] - sb = sb + b / c[3] - n = n + 1 + + if spec.lut then + -- A lookup table answers only the colours that are IN it, so running + -- synthetic references through one returns them untouched and reports a + -- tint of exactly 1 -- i.e. no tint, for the five species whose shiny is + -- the most dramatic in the game. (A shiny Gyarados came out with an + -- ordinary blue pic for precisely this reason.) The table's own entries + -- are the right sample: they are what this Pokemon is actually made of. + for from, to in pairs(spec.lut) do + local fr, fg, fb = floor(from / 65536) % 256, floor(from / 256) % 256, + from % 256 + local tr, tg, tb = floor(to / 65536) % 256, floor(to / 256) % 256, + to % 256 + -- guard the near-black entries: a ratio against 2 is noise, and a + -- handful of them would swamp the mean + if fr > 24 and fg > 24 and fb > 24 then + sr = sr + tr / fr + sg = sg + tg / fg + sb = sb + tb / fb + n = n + 1 + end + end + end + + -- A slide: measure it against the colour this Pokemon is mostly MADE of. + -- + -- Averaging over a balanced set of references does not work, and the + -- reason is worth keeping: a hue rotation moves red toward cyan and cyan + -- toward red, so over a symmetric wheel the ratios cancel and every + -- species reports a tint of 1. Charizard and Ponyta both came back with no + -- tint at all that way. One real body colour, rotated, is the whole + -- answer. + if n == 0 and spec.dom then + local dr = floor(spec.dom / 65536) % 256 + local dg = floor(spec.dom / 256) % 256 + local db = spec.dom % 256 + if dr > 12 and dg > 12 and db > 12 then + local r, g, b = fn(dr, dg, db) + sr, sg, sb, n = r / dr, g / dg, b / db, 1 + end + end + + if n == 0 then + for _, c in ipairs(REFS) do + local r, g, b = fn(c[1], c[2], c[3]) + sr = sr + r / c[1] + sg = sg + g / c[2] + sb = sb + b / c[3] + n = n + 1 + end end local t = { max(TINT_FLOOR, min(1, sr / n)), diff --git a/lib/ShinyUI.lua b/lib/ShinyUI.lua index ec0ec18..a4ca0f3 100644 --- a/lib/ShinyUI.lua +++ b/lib/ShinyUI.lua @@ -123,6 +123,57 @@ function ShinyUI.installSummary() return unpack(out) end + -- The summary PIC, through its PALETTE. + -- + -- Recolouring the sprite's pixels here does NOT work, and it is worth + -- writing down why rather than leaving it to be re-attempted: the summary + -- art is four-shade DMG grey, and the screen's colour is applied + -- afterwards by the palette pass over the finished frame. Whatever RGB is + -- put in the ImageData is remapped away by it. The colour of that pic + -- lives in the palette and nowhere else, so the palette is what has to + -- move. (Tried it, shot it, reverted it.) + -- + -- This is the ADVANCED-palette answer, and it is better than a multiply: + -- SetPal_StatusScreen hands the pic zone the species palette + -- (PaletteFX.monPal), and sgbPalettes is a method on the MENU, so unlike + -- the battle pic's image cache it knows which individual is on screen. + -- Running those four colours through the species' own shiny transform + -- gives the summary a genuinely recoloured Pokemon -- brightening + -- included, which a draw-colour multiply cannot do. + -- + -- Only ZONE entries are touched. The first palette the engine returns is + -- the whole-screen HP-bar one, and rotating that would recolour the text. + local innerPal = SummaryMenu.sgbPalettes + if type(innerPal) == "function" then + function SummaryMenu:sgbPalettes(game, ...) + local out = innerPal(self, game, ...) + if type(out) ~= "table" or not Shiny.isShiny(self.mon) then return out end + local def = game and game.data and game.data.pokemon + and game.data.pokemon[self.mon.species] + local fn = def and def.dex + and ShinyPalette.transform(ShinyPalette.forDex(def.dex)) + if not fn then return out end + for _, z in ipairs(out) do + if type(z) == "table" and z.w and z.h and type(z.colors) == "table" then + -- copied, never mutated in place: monPal hands back the dataset's + -- own palette table, and writing through it would recolour every + -- Pokemon of the species everywhere for the rest of the process + local cols = {} + for i, c in ipairs(z.colors) do + if type(c) == "table" and c[1] then + local r, g, b = fn(c[1], c[2], c[3]) + cols[i] = { r, g, b } + else + cols[i] = c + end + end + z.colors = cols + end + end + return out + end + end + SummaryMenu.dramaticShapeShiny = true end diff --git a/tests/shiny_shots.lua b/tests/shiny_shots.lua new file mode 100644 index 0000000..7839842 --- /dev/null +++ b/tests/shiny_shots.lua @@ -0,0 +1,242 @@ +-- Driver: photograph the shiny system, each case beside its own control. +-- +-- SHOT_DIR=mods/DramaticShapeVoxelMod/.claude/shiny_update \ +-- POKEPORT_DRIVER=mods/DramaticShapeVoxelMod/tests/shiny_shots.lua \ +-- "/c/Program Files/LOVE/lovec.exe" . +-- +-- SHOT_DIR must already exist -- the capture writes with io.open. +-- +-- EVERY CASE IS SHOT TWICE, the same species on the same tile, once +-- ordinary and once shiny. A single shiny screenshot proves nothing: these +-- are N64 models under a day/night tint on generated ground, and "that +-- looks a bit purple" is not evidence. The pair is. +-- +-- The four species are chosen to exercise the four things that can break: +-- +-- GYARADOS one of the five Stadium gives a REAL alternate texture, so +-- it runs the explicit colour table rather than the HSL slide. +-- Blue to red, the least deniable shiny in Gen 1. +-- CHARIZARD the biggest slide in the set (H -136, S -6). Also the one +-- whose canonical shiny is famously black, which the Stadium +-- values do NOT reproduce -- they give a dusky slate-violet. +-- Shot precisely so that difference is on the record. +-- GOLBAT L -6, the darkest lightness step there is. If the guard +-- rails are wrong this is where it goes to mud. +-- PONYTA made of fire. Its flames are GENERATED frames, excluded +-- from the recolour, so the correct result is a recoloured +-- body with an ordinary mane. That exclusion is invisible in +-- every other species. +return function(game) + local U = dofile("tests/drivers/util.lua") + local DIR = os.getenv("SHOT_DIR") + or "mods/DramaticShapeVoxelMod/.claude/shiny_update" + local BattleState = require("src.battle.BattleState") + local Pokemon = require("src.pokemon.Pokemon") + + local exports = game.mods and game.mods.exports + local lib = exports and exports.DRAMATIC_SHAPE and exports.DRAMATIC_SHAPE.lib + if not lib then + U.log("DRAMATIC_SHAPE is not loaded -- nothing to shoot") + return + end + local Shiny = lib.require("Shiny") + local ShinyFx = lib.require("ShinyFx") + local OverworldBattle = lib.require("OverworldBattle") + local StadiumInstall = lib.require("StadiumInstall") + local StadiumPack = lib.require("StadiumPack") + + -- ------- the models + -- + -- REV went to 3 with the shiny variants, so an existing cache is stale and + -- the game rebuilds all 151 on the loading screen. That is a minute or so + -- of frames, and it has to be waited out rather than assumed: shooting + -- before it lands gets flat 2D pics and a very confusing set of images. + -- Driven from HERE rather than waited on. The build is normally pumped by + -- the loading screen StadiumScreen.maybePush puts up on the first world + -- frame, but a driver owns the frame loop and that screen never came up -- + -- a first run sat at "idle 0/151" for twelve thousand frames and shot four + -- unrecoloured Pokemon. Calling begin/step directly is both faster and + -- honest about what is being tested, which is the extraction, not the + -- screen that usually triggers it. + if not StadiumInstall.ready() then + local ok, err = StadiumInstall.begin() + U.log(("stadium build: begin=%s %s"):format(tostring(ok), tostring(err or ""))) + local guard = 0 + while not StadiumInstall.ready() and guard < 2000 do + -- several species per frame: 151 of them at one a frame is a long + -- wait for no reason, and nothing here needs to be drawn + for _ = 1, 6 do StadiumInstall.step() end + U.wait(1) + guard = guard + 1 + local st = StadiumInstall.status + if st and st.state == "failed" then + U.log("stadium build FAILED: " .. tostring(st.error)) + break + end + if guard % 10 == 0 then + U.log((" building: %s %d/%d"):format(tostring(st and st.state), + (st and st.done) or 0, (st and st.total) or 0)) + end + end + end + U.log("stadium ready: " .. tostring(StadiumInstall.ready())) + + -- and prove the shiny packs are actually THERE before shooting anything + for _, dex in ipairs({ 130, 6, 42, 77 }) do + U.log((" pack %03d: normal=%s shiny=%s"):format( + dex, tostring(StadiumPack.available(dex, false)), + tostring(StadiumPack.available(dex, true)))) + end + + -- STADIUM A: models, staged on the map + OverworldBattle.setting:setValue("stadium", game) + U.log("3D-BTL = " .. tostring(OverworldBattle.setting:get())) + + game.save.player.name = "RED" + game.save.party = { Pokemon.new(game.data, "PIKACHU", 50) } + + local CASES = { + { "GYARADOS", 40, "ROUTE_1", 5, 8 }, + { "CHARIZARD", 50, "ROUTE_1", 5, 8 }, + { "GOLBAT", 40, "ROUTE_1", 5, 8 }, + { "PONYTA", 40, "ROUTE_1", 5, 8 }, + } + + -- Odds are the real lever, so the shiny half goes through the SAME path a + -- player's encounter does -- decided inside Pokemon.new by a roll -- rather + -- than being stamped on afterwards. 1 means every mon; a huge denominator + -- means none, which is what makes the control a control. + local function setOdds(shiny) + Shiny.setOdds(shiny and 1 or 100000000) + end + + local function toMenu() + for _ = 1, 16 do U.tap(game, "a") U.wait(8) end + end + + local function leave() + while game.stack:top() and game.stack:top() ~= game.overworld do + game.stack:pop() + end + U.wait(10) + end + + for i, c in ipairs(CASES) do + local species, level, map, cx, cy = c[1], c[2], c[3], c[4], c[5] + if not game.data.pokemon[species] then + U.log("no such species in this dataset: " .. species) + else + for _, variant in ipairs({ "normal", "shiny" }) do + local shiny = (variant == "shiny") + setOdds(shiny) + + U.teleport(game, map, cx, cy, "down") + U.wait(90) -- let the neighbourhood's meshes land + + local battle = BattleState.newWild(game, species, level) + battle.onFinish = function() end + game.overworld:pushBattle(battle) + + local mon = battle.enemy and battle.enemy.mon + U.log(("%s %s: isShiny=%s dvs=%s/%s/%s/%s flag=%s"):format( + species, variant, tostring(Shiny.isShiny(mon)), + tostring(mon and mon.dvs and mon.dvs.attack), + tostring(mon and mon.dvs and mon.dvs.defense), + tostring(mon and mon.dvs and mon.dvs.speed), + tostring(mon and mon.dvs and mon.dvs.special), + tostring(mon and mon.shiny))) + + -- THE ARRIVAL. Shot during the send-out rather than after it, + -- because the sparkle is three quarters of a second long and the + -- menu is well past it. Three frames close together, so one of them + -- lands mid-burst whatever the intro's pacing does on this map. + U.wait(70) + if shiny then + for k = 1, 3 do + U.shot(game, ("%s/%d_%s_arrival_%d.png") + :format(DIR, i, species:lower(), k)) + U.wait(10) + end + end + + toMenu() + U.shot(game, ("%s/%d_%s_%s.png") + :format(DIR, i, species:lower(), variant)) + + -- and the sparkle again, armed deliberately and shot on the next + -- frame. The arrival shots above catch it in its real moment but + -- depend on intro timing; this one is the effect itself, on the + -- record, at a known point in its life. + if shiny then + for k, v in pairs(ShinyFx.debug) do ShinyFx.debug[k] = 0 end + ShinyFx.arm("enemy") + U.wait(4) + U.shot(game, ("%s/%d_%s_sparkle.png"):format(DIR, i, species:lower())) + local d = ShinyFx.debug + U.log((" fx: calls=%d noArena=%d noImage=%d noMesh=%d noLive=%d quads=%d") + :format(d.calls, d.noArena, d.noImage, d.noMesh, d.noLive, + d.quads)) + end + + leave() + end + end + end + + -- ------- the FLAT art + -- + -- Everything above is the STADIUM rung, which draws recoloured 3D models + -- and never touches a pic. The tint is the other half of the feature and + -- needs its own rung to be visible at all: 2D-3D stands the game's own + -- battle pics up as cards, which is the path ShinyUI tints. + OverworldBattle.setting:setValue(true, game) + U.log("3D-BTL = " .. tostring(OverworldBattle.setting:get()) .. " (cards)") + for _, variant in ipairs({ "normal", "shiny" }) do + setOdds(variant == "shiny") + U.teleport(game, "ROUTE_1", 5, 8, "down") + U.wait(90) + local battle = BattleState.newWild(game, "GYARADOS", 40) + battle.onFinish = function() end + game.overworld:pushBattle(battle) + U.log(("cards %s: isShiny=%s"):format( + variant, tostring(Shiny.isShiny(battle.enemy and battle.enemy.mon)))) + U.wait(70) + toMenu() + U.shot(game, ("%s/6_cards_gyarados_%s.png"):format(DIR, variant)) + leave() + end + + -- ------- the status page + -- + -- A shiny and an ordinary mon of the SAME species, so the star is the only + -- difference between the two images. + local SummaryMenu = require("src.ui.SummaryMenu") + for _, variant in ipairs({ "normal", "shiny" }) do + setOdds(variant == "shiny") + local mon = Pokemon.new(game.data, "GYARADOS", 40) + U.log(("summary %s: isShiny=%s flag=%s"):format( + variant, tostring(Shiny.isShiny(mon)), tostring(mon.shiny))) + game.save.party = { mon } + game.stack:push(SummaryMenu.new(game, mon)) + U.wait(20) + U.shot(game, ("%s/5_status_%s.png"):format(DIR, variant)) + leave() + end + + -- ------- the odds actually being odds + -- + -- Not a screenshot, but it belongs in the same run: the rate is the thing + -- a player experiences, and it is the one claim a picture cannot make. + Shiny.setOdds(8192) + local n, hits = 4000, 0 + for _ = 1, n do + if Shiny.isShiny(Pokemon.new(game.data, "RATTATA", 5)) then + hits = hits + 1 + end + end + U.log(("odds check: %d shinies in %d at 1/8192 (expect ~0-2)") + :format(hits, n)) + + Shiny.setOdds(8192) + U.log("done -- " .. DIR) +end diff --git a/tools/shiny_colors.py b/tools/shiny_colors.py index 11cf6b9..07878c4 100644 --- a/tools/shiny_colors.py +++ b/tools/shiny_colors.py @@ -37,8 +37,11 @@ import json import os from PIL import Image -SS = r"C:\Users\blcha\Desktop\DRAMATIC_SHAPE\pokemon-gen1-recomp-project\mods\DramaticShapeVoxelMod\.claude\shiny_stadium" -OUT = r"C:\Users\blcha\Desktop\DRAMATIC_SHAPE\pokemon-gen1-recomp-project\mods\DramaticShapeVoxelMod\.claude\worktrees\shiny-system\data\shiny_colors.lua" +HERE = os.path.dirname(os.path.abspath(__file__)) +MOD = os.path.dirname(HERE) +# the research tree (gitignored -- see the provenance note above) +SS = os.path.join(MOD, ".claude", "shiny_stadium") +OUT = os.path.join(MOD, "data", "shiny_colors.lua") vals = json.load(open(os.path.join(SS, "stadium_shiny_values.json"), encoding="utf-8")) V = vals["species"] @@ -83,6 +86,37 @@ def lut_for(dex): return {k: v for k, v in pairs.items() if k != v} +def dominant(dex): + """The most-covering opaque colour across this species' BODY textures. + + Deliberately not the mean: a mean over a Pokemon with a light belly and a + dark back lands on a mid-grey that belongs to neither, and the tint drawn + from it would be no tint. The modal colour is a real colour off the model. + """ + d = slugs[dex] + counts = {} + for fn in sorted(os.listdir(os.path.join(TEX, "normal", d))): + idx = int(fn.replace("tex_", "").replace(".png", "")) + if kind.get((dex, idx), "body") != "body": + continue + im = Image.open(os.path.join(TEX, "normal", d, fn)).convert("RGBA") + px = im.load() + for y in range(im.size[1]): + for x in range(im.size[0]): + c = px[x, y] + if c[3] < 8: + continue + # skip the near-black and near-white structural colours: + # outlines and eye whites are on every model and say nothing + # about which Pokemon this is + if max(c[:3]) < 30 or min(c[:3]) > 225: + continue + counts[c[:3]] = counts.get(c[:3], 0) + 1 + if not counts: + return None + return max(counts.items(), key=lambda kv: kv[1])[0] + + lines = [] w = lines.append @@ -118,6 +152,15 @@ for dex in sorted(V): w(" [%d] = {" % int(dex)) w(' name = "%s",' % e["name"]) w(" hueRange = { min = %d, max = %d }," % (hr["min"], hr["max"])) + dom = dominant(dex) + if dom: + w(" -- the colour this species is mostly MADE of, and what its" + " shiny") + w(" -- shift does to it. A flat sprite cannot be recoloured, only") + w(" -- multiplied, and the multiply has to be measured against the") + w(" -- body colour: averaged over a balanced set of references a") + w(" -- hue rotation cancels itself out to no tint at all.") + w(" dom = 0x%02X%02X%02X," % dom) if e["special_texture"]: n_lut += 1 lut = lut_for(dex)