mirror of
https://github.com/DramaticShape/DramaticShapeVoxelMod.git
synced 2026-08-12 09:10:49 +02:00
shiny Pokemon, on by default
Gen 1 has no shininess of its own, but it has the four DVs Gen 2 reads to decide it -- and the engine already ships that reading (Stats.isShiny, its own comment calling it "the RBY virtual shiny", allowlisted for mods precisely so an indicator mod can call it). Nothing new is stored on a Pokemon and nothing migrates: every save already contains the answer, and this starts drawing it. Random DVs land on the pattern 1 in 8192, which is the classic rate and the default the odds dial ships at. Deriving rather than storing is what makes it survive a save, a box, a trade and an evolution with no second copy of the truth to drift. mon.shiny is a cache written from the DVs, never read as the source. The roll goes in Pokemon.new -- every wild, gift, starter and traded mon is built there, and it is before the battle bakes its sprite, which battle.started is already too late for. It draws from the mod's own random stream so installing this does not shift the sequence damage rolls and encounter slots come out of. Trainers stay ordinary by themselves: the engine pins their DVs, as the real games do. The models are genuinely recoloured, as part of the extraction. Each species is decoded once, packed as usual, then recoloured and packed again as NNNs.dsm. The colours are Stadium's own HSL slide (hue in degrees, saturation and lightness on a -8..+8 scale at 12.5% a step); five species carry an explicit colour table instead, because Stadium gives them a real alternate texture that no single slide reproduces -- Jigglypuff's body must stay pink while its irises rotate to green. Extraction is the right moment because StadiumFx's generated frames are still marked there and the packer drops the marker: it is the last point a flame is distinguishable from a hide. A shiny Charizard has a shiny hide and an ordinary fire. The normal packs are written BEFORE the recolour, so they come out byte-identical and stadium_extract_test still diffs all 151 against the Python oracle unchanged -- no format change, no DSM4, no second implementation to keep in step. REV goes to 3 so an existing cache rebuilds. Flat art is tinted instead, because the engine bakes a species palette into a cache with no notion of which individual is drawn. The tint comes from that species' own slide rather than a generic gold. A multiply can only darken, so species whose shiny is lighter read quieter there than on the model; the status page's star is the mode-proof mark. Tests: 58 assertions in tests/shiny_test.lua, including the colour transform against 640 real colour pairs lifted from the verified texture set, the DV model, the read side, and the end-to-end through the engine's own constructor. stadium_extract_test gains --mod (worktrees have neither the ROM nor the packs, both gitignored) and now also checks that every shiny pack is the same length as its twin and actually differs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+31
-2
@@ -61,7 +61,14 @@ StadiumInstall.FORMAT = "DSM3"
|
||||
-- is the hermite-animation decode fix: the five keyframe species (Pidgeot,
|
||||
-- Dodrio, Exeggutor, Tangela, Magmar) come out garbled or bind-posed from
|
||||
-- any rev-1 build.
|
||||
StadiumInstall.REV = 2
|
||||
--
|
||||
-- Rev 3 adds the shiny variants (NNNs.dsm). The normal packs are unchanged
|
||||
-- byte for byte, so this is exactly the case REV exists for and not a FORMAT
|
||||
-- bump: nothing about DSM3 moved, there is simply a second file per species
|
||||
-- that a rev-2 cache does not have. Without the bump a player who already
|
||||
-- installed would keep a complete-looking cache with no shiny models in it,
|
||||
-- and every shiny they met would silently show its normal colours.
|
||||
StadiumInstall.REV = 3
|
||||
|
||||
StadiumInstall.COUNT = 151
|
||||
|
||||
@@ -211,12 +218,34 @@ local status = { state = "idle", done = 0, total = StadiumInstall.COUNT }
|
||||
|
||||
StadiumInstall.status = status
|
||||
|
||||
local function writePack(species, bytes)
|
||||
-- The shiny variant rides beside its species as NNNs.dsm.
|
||||
--
|
||||
-- A separate FILE rather than a second block inside NNN.dsm, and that is a
|
||||
-- deliberate trade. A second block would mean a new magic (DSM4), the same
|
||||
-- change mirrored into tools/stadium_pack.py, a regenerated oracle and a
|
||||
-- re-run of the 34MB byte diff -- the project's central safety net disturbed
|
||||
-- for a feature that does not need the format to move at all. As its own
|
||||
-- file it is the SAME DSM3 a normal pack is, written by the same writer and
|
||||
-- read by the same reader, and the 151 normal packs stay byte-identical.
|
||||
--
|
||||
-- A species with no shiny variant simply has no NNNs.dsm, and StadiumPack
|
||||
-- falls back to the normal model. That is also what a half-finished install
|
||||
-- looks like, which is the behaviour we want from one.
|
||||
local function writePack(species, bytes, shinyBytes)
|
||||
local f = fs()
|
||||
if not f then return false, "no filesystem" end
|
||||
local ok, err = f.write(("%s/%03d.dsm"):format(StadiumInstall.DIR, species),
|
||||
bytes)
|
||||
if not ok then return false, tostring(err) end
|
||||
if shinyBytes then
|
||||
-- A failed shiny write is not a failed install: the species still has
|
||||
-- its model. Left unwritten, the runtime shows the normal one.
|
||||
local sok, serr = f.write(
|
||||
("%s/%03ds.dsm"):format(StadiumInstall.DIR, species), shinyBytes)
|
||||
if not sok and V.mod and V.mod.log then
|
||||
V.mod.log.warn("shiny pack %03d not written: %s", species, tostring(serr))
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user