mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-25 15:01:11 +02:00
copy rintro
This commit is contained in:
@@ -98,6 +98,7 @@ CacheContract.VERSION_REQUIRED_FILES_OVERRIDE = {
|
|||||||
"assets/generated/title/crystal_logo.png",
|
"assets/generated/title/crystal_logo.png",
|
||||||
"assets/generated/title/crystal_wordmark.png",
|
"assets/generated/title/crystal_wordmark.png",
|
||||||
"assets/generated/title/crystal_suicune.png",
|
"assets/generated/title/crystal_suicune.png",
|
||||||
|
"assets/generated/title/copyright_splash.png",
|
||||||
"assets/generated/splash/ditto.png",
|
"assets/generated/splash/ditto.png",
|
||||||
"assets/generated/intro/chris.png",
|
"assets/generated/intro/chris.png",
|
||||||
"assets/generated/intro/kris.png",
|
"assets/generated/intro/kris.png",
|
||||||
|
|||||||
@@ -258,6 +258,44 @@ local function colorize(image, palFor)
|
|||||||
return out
|
return out
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- engine/movie/splash.asm:20-30 sets SCGB_GAMEFREAK_LOGO before Copyright, so
|
||||||
|
-- the card runs on gfx/sgb/predef.pal:79 PREDEFPAL_GAMEFREAK_LOGO_BG.
|
||||||
|
local COPYRIGHT_TILES = 29
|
||||||
|
local COPYRIGHT_BG = {
|
||||||
|
{ 0, 0, 0 }, { 66, 90, 90 }, { 173, 173, 173 }, { 255, 255, 255 },
|
||||||
|
}
|
||||||
|
|
||||||
|
-- data/copyright.asm at hlcoord 2, 7 (engine/menus/intro_menu.asm:1315-1326).
|
||||||
|
local COPYRIGHT_LINES = {
|
||||||
|
{ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
|
||||||
|
0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c },
|
||||||
|
{ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
|
||||||
|
0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x7a, 0x7b, 0x7c },
|
||||||
|
{ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
|
||||||
|
0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c },
|
||||||
|
}
|
||||||
|
|
||||||
|
local function extractCopyright(self)
|
||||||
|
local symbol = self:symbol("CopyrightGFX")
|
||||||
|
local raw = self.rom:bytes(symbol.bank, symbol.address,
|
||||||
|
COPYRIGHT_TILES * TILE_BYTES)
|
||||||
|
self:write2bpp(raw, COPYRIGHT_TILES * 8, 8, "title/copyright.png")
|
||||||
|
|
||||||
|
local painted = {}
|
||||||
|
for index, tile in ipairs(tilesFrom2bpp(raw)) do
|
||||||
|
painted[index] = colorize(tile, function() return COPYRIGHT_BG end)
|
||||||
|
end
|
||||||
|
local backdrop = COPYRIGHT_BG[1]
|
||||||
|
local splash = ImageWriter.blank(160, 144,
|
||||||
|
backdrop[1] / 255, backdrop[2] / 255, backdrop[3] / 255, 1)
|
||||||
|
for row, line in ipairs(COPYRIGHT_LINES) do
|
||||||
|
for column, id in ipairs(line) do
|
||||||
|
blitTile(splash, painted[id - 0x60 + 1], (1 + column) * 8, (6 + row) * 8)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self:save(splash, "title/copyright_splash.png")
|
||||||
|
end
|
||||||
|
|
||||||
function CrystalMovie.extractTitle(self)
|
function CrystalMovie.extractTitle(self)
|
||||||
self:beginStage("Title screen")
|
self:beginStage("Title screen")
|
||||||
|
|
||||||
@@ -348,6 +386,7 @@ function CrystalMovie.extractTitle(self)
|
|||||||
local gemTinted = colorize(gem, function() return pals.obj[1] end)
|
local gemTinted = colorize(gem, function() return pals.obj[1] end)
|
||||||
self:save(gemTinted, "title/crystal_gem.png")
|
self:save(gemTinted, "title/crystal_gem.png")
|
||||||
self:save(gem, "title/crystal_gem_gray.png")
|
self:save(gem, "title/crystal_gem_gray.png")
|
||||||
|
extractCopyright(self)
|
||||||
self:tick("Title screen", 4, 5)
|
self:tick("Title screen", 4, 5)
|
||||||
|
|
||||||
local function unit(color) return { color[1] / 255, color[2] / 255, color[3] / 255 } end
|
local function unit(color) return { color[1] / 255, color[2] / 255, color[3] / 255 } end
|
||||||
@@ -356,7 +395,7 @@ function CrystalMovie.extractTitle(self)
|
|||||||
generation = 2,
|
generation = 2,
|
||||||
layout = "crystal_title",
|
layout = "crystal_title",
|
||||||
source = "ROM:TitleSuicuneGFX + TitleLogoGFX + TitleCrystalGFX"
|
source = "ROM:TitleSuicuneGFX + TitleLogoGFX + TitleCrystalGFX"
|
||||||
.. " + TitleScreenPalettes",
|
.. " + TitleScreenPalettes + CopyrightGFX",
|
||||||
screen = "assets/generated/title/crystal_screen.png",
|
screen = "assets/generated/title/crystal_screen.png",
|
||||||
screenGray = "assets/generated/title/crystal_screen_gray.png",
|
screenGray = "assets/generated/title/crystal_screen_gray.png",
|
||||||
image = "assets/generated/title/crystal_logo.png",
|
image = "assets/generated/title/crystal_logo.png",
|
||||||
@@ -371,6 +410,10 @@ function CrystalMovie.extractTitle(self)
|
|||||||
suicuneEvery = 8,
|
suicuneEvery = 8,
|
||||||
gem = "assets/generated/title/crystal_gem.png",
|
gem = "assets/generated/title/crystal_gem.png",
|
||||||
gemGray = "assets/generated/title/crystal_gem_gray.png",
|
gemGray = "assets/generated/title/crystal_gem_gray.png",
|
||||||
|
copyright = "assets/generated/title/copyright.png",
|
||||||
|
copyrightSplash = "assets/generated/title/copyright_splash.png",
|
||||||
|
copyrightBackdrop = unit(COPYRIGHT_BG[1]),
|
||||||
|
copyrightInk = unit(COPYRIGHT_BG[4]),
|
||||||
-- Strip 0 starts at OAM (64, -$22) and stops at OAM y 22, i.e. screen
|
-- Strip 0 starts at OAM (64, -$22) and stops at OAM y 22, i.e. screen
|
||||||
-- (56, 6) (engine/movie/title.asm:306-311,340-362).
|
-- (56, 6) (engine/movie/title.asm:306-311,340-362).
|
||||||
gemX = 56,
|
gemX = 56,
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ local HOLD_FRAMES = 100
|
|||||||
-- Only used when the extracted splash image is missing.
|
-- Only used when the extracted splash image is missing.
|
||||||
local LINE_Y = { 48, 64, 80 }
|
local LINE_Y = { 48, 64, 80 }
|
||||||
|
|
||||||
|
-- Gold boots on the default BGP; Crystal inverts under SCGB_GAMEFREAK_LOGO
|
||||||
|
-- (../pokecrystal/engine/movie/splash.asm:20-30).
|
||||||
|
local DEFAULT_BACKDROP = { 1, 1, 1 }
|
||||||
|
local DEFAULT_INK = { 0, 0, 0 }
|
||||||
|
|
||||||
local function tryImage(path)
|
local function tryImage(path)
|
||||||
if not path then return nil end
|
if not path then return nil end
|
||||||
local ok, image = pcall(Assets.image, path)
|
local ok, image = pcall(Assets.image, path)
|
||||||
@@ -43,6 +48,8 @@ function CopyrightSplash.new(game, opts)
|
|||||||
self.image = tryImage(opts.image)
|
self.image = tryImage(opts.image)
|
||||||
or tryImage(title.copyrightSplash)
|
or tryImage(title.copyrightSplash)
|
||||||
or tryImage("assets/generated/title/copyright_splash.png")
|
or tryImage("assets/generated/title/copyright_splash.png")
|
||||||
|
self.backdrop = opts.backdrop or title.copyrightBackdrop or DEFAULT_BACKDROP
|
||||||
|
self.ink = opts.ink or title.copyrightInk or DEFAULT_INK
|
||||||
-- Text fallback only when the ROM extract is missing (tests / bare boots).
|
-- Text fallback only when the ROM extract is missing (tests / bare boots).
|
||||||
self.lines = opts.lines
|
self.lines = opts.lines
|
||||||
self.frames = 0
|
self.frames = 0
|
||||||
@@ -78,17 +85,24 @@ function CopyrightSplash:update(_dt)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function CopyrightSplash:fillBackdrop(width, height)
|
||||||
|
local G = love.graphics
|
||||||
|
local c = self.backdrop
|
||||||
|
G.setColor(c[1], c[2], c[3], 1)
|
||||||
|
G.rectangle("fill", 0, 0, width, height)
|
||||||
|
end
|
||||||
|
|
||||||
function CopyrightSplash:drawPanel()
|
function CopyrightSplash:drawPanel()
|
||||||
local G = love.graphics
|
local G = love.graphics
|
||||||
G.setColor(1, 1, 1, 1)
|
self:fillBackdrop(SCREEN_W, SCREEN_H)
|
||||||
G.rectangle("fill", 0, 0, SCREEN_W, SCREEN_H)
|
|
||||||
if self.image then
|
if self.image then
|
||||||
|
G.setColor(1, 1, 1, 1)
|
||||||
G.draw(self.image, 0, 0)
|
G.draw(self.image, 0, 0)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if not self.lines then return end
|
if not self.lines then return end
|
||||||
-- The Gen 2 font is a fixed 8px cell, so centring is a character count.
|
-- The Gen 2 font is a fixed 8px cell, so centring is a character count.
|
||||||
G.setColor(0, 0, 0, 1)
|
G.setColor(self.ink[1], self.ink[2], self.ink[3], 1)
|
||||||
for index, line in ipairs(self.lines) do
|
for index, line in ipairs(self.lines) do
|
||||||
local y = LINE_Y[index]
|
local y = LINE_Y[index]
|
||||||
if y then
|
if y then
|
||||||
@@ -104,8 +118,7 @@ end
|
|||||||
|
|
||||||
function CopyrightSplash:drawWidescreen(winW, winH)
|
function CopyrightSplash:drawWidescreen(winW, winH)
|
||||||
local G = love.graphics
|
local G = love.graphics
|
||||||
G.setColor(1, 1, 1, 1)
|
self:fillBackdrop(winW, winH)
|
||||||
G.rectangle("fill", 0, 0, winW, winH)
|
|
||||||
local scale = Chrome.fitScale(winW, winH)
|
local scale = Chrome.fitScale(winW, winH)
|
||||||
G.push()
|
G.push()
|
||||||
G.translate(Chrome.fitOrigin(winW, winH, scale))
|
G.translate(Chrome.fitOrigin(winW, winH, scale))
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
-- Crystal's boot copyright card is white text on black: SplashScreen sets
|
||||||
|
-- SCGB_GAMEFREAK_LOGO before calling Copyright, so the card runs on
|
||||||
|
-- PREDEFPAL_GAMEFREAK_LOGO_BG rather than the default BGP Gold's DMG boot
|
||||||
|
-- leaves up (../pokecrystal/engine/movie/splash.asm:21-30). The card used to
|
||||||
|
-- hardcode a white fill and Crystal shipped no extracted splash at all, so the
|
||||||
|
-- first screen of the game was blank white.
|
||||||
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
||||||
|
|
||||||
|
local T = require("tests.modkit")
|
||||||
|
local CopyrightSplash = require("src.ui.gen2.CopyrightSplash")
|
||||||
|
|
||||||
|
local function colorsEq(got, want, message)
|
||||||
|
T.eq(#got, 3, message .. " (three channels)")
|
||||||
|
for index = 1, 3 do
|
||||||
|
T.eq(got[index], want[index], message .. " channel " .. index)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local gold = CopyrightSplash.new({}, { title = {} })
|
||||||
|
colorsEq(gold.backdrop, { 1, 1, 1 }, "Gold keeps the white card")
|
||||||
|
colorsEq(gold.ink, { 0, 0, 0 }, "Gold keeps black text")
|
||||||
|
|
||||||
|
local crystal = CopyrightSplash.new({}, {
|
||||||
|
title = {
|
||||||
|
copyrightBackdrop = { 0, 0, 0 },
|
||||||
|
copyrightInk = { 1, 1, 1 },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
colorsEq(crystal.backdrop, { 0, 0, 0 }, "Crystal's card is black")
|
||||||
|
colorsEq(crystal.ink, { 1, 1, 1 }, "Crystal's text is white")
|
||||||
|
|
||||||
|
-- The extractor has to emit the image too, or the card is an empty backdrop.
|
||||||
|
local CrystalMovie = require("src.import.CrystalMovie")
|
||||||
|
T.eq(type(CrystalMovie.extractTitle), "function",
|
||||||
|
"CrystalMovie still owns the Crystal title stage")
|
||||||
|
|
||||||
|
local CacheContract = require("src.import.CacheContract")
|
||||||
|
local required = CacheContract.VERSION_REQUIRED_FILES_OVERRIDE.crystal
|
||||||
|
local found = false
|
||||||
|
for _, path in ipairs(required) do
|
||||||
|
if path == "assets/generated/title/copyright_splash.png" then found = true end
|
||||||
|
end
|
||||||
|
T.eq(found, true, "a Crystal cache without the splash is rebuilt")
|
||||||
|
|
||||||
|
T.finish("copyright splash backdrop")
|
||||||
Reference in New Issue
Block a user