-- The Cianwood photo studio's portrait card (engine/printer/print_party.asm -- PrintPartyMonPage1), reached through `special PhotoStudio` (src/script/ -- gen2/Specials.lua H.PhotoStudio) once the fishing guru's own yes/no gate -- (CianwoodPhotoStudioFishingGuruScript, maps/CianwoodPhotoStudio.asm) has -- been answered yes and a party mon picked. -- -- On the cart, farcall PrintPartymon draws PrintPartyMonPage1 to the -- background so SendScreenToPrinter has pixels to walk out the serial port, -- then a second card (PrintPartyMonPage2, the mon's other three moves and -- its non-HP stats) goes out behind it. There is no Game Boy Printer here -- -- same reason src/ui/gen2/UnownPrinter.lua takes its A press nowhere and -- PrintDiploma is stubbed in Specials.lua -- -- so only page 1 is worth transcribing: it is the portrait itself, the -- part a player actually watches happen, while page 2 only ever existed as -- ink on a strip of thermal paper nobody in this port owns. H.PhotoStudio -- pushes this screen for the "hold still" beat and then always lands on -- the cancel branch afterward, exactly as a cartridge with nothing plugged -- into its link port would. -- -- Coordinates below are the literal hlcoord operands -- PrintPartyMonPage1 writes at, not a layout guessed from a screenshot: -- -- hlcoord 0, 0 PrepMonFrontpic, a 7x7 block -- hlcoord 8, 0 "№." then the dex number, 3 digits, leading zeros -- hlcoord 8, 2 the level (PrintLevel_Force3Digits) -- hlcoord 12, 2 the HP icon then the max HP, 3 digits -- one field, no -- separate current-HP column -- hlcoord 8, 4 the nickname -- hlcoord 9, 6 a bare '/' then the species name at hlcoord 10, 6 -- hlcoord 0, 7 Textbox, 9 rows by 18 columns -- the border the fields -- below sit inside -- hlcoord 1, 9 "OT/" then the OT name at hlcoord 4, 9 -- hlcoord 1, 11 "№" then the id number at hlcoord 4, 11, 5 digits -- hlcoord 1, 14 "MOVE" then the first move's name at hlcoord 7, 14 -- PlaceGenderAndShininess: gender at hlcoord 17, 2, the shiny ⁂ at 18, 2 -- -- The pic-drawing and palette plumbing (picFor/drawPic, PIC_PAD) is the same -- shape src/ui/gen2/SummaryMenu.lua uses for its own PrepMonFrontpic block; -- kept as its own small copy here rather than reached through SummaryMenu so -- this screen has no dependency on the stats screen's paging state. local Assets = require("src.render.Assets") local Chrome = require("src.ui.gen2.Chrome") local Font = require("src.render.Font") local GbcPalette = require("src.render.GbcPalette") local Palettes = require("src.world.gen2.Palettes") local Strings = require("src.core.Strings") local PhotoStudio = {} PhotoStudio.__index = PhotoStudio PhotoStudio.isOpaque = true function PhotoStudio:wantsFillScale() return true end local PIC_PAD = { [7] = { 0, 0 }, [6] = { 1, 1 }, [5] = { 1, 2 } } local function num(value, width, leadingZeros) return Chrome.number(value, width, leadingZeros) end -- opts: mon, playerName, pokemon, moves, palettes, onClose() function PhotoStudio.new(game, opts) opts = opts or {} local self = setmetatable({}, PhotoStudio) self.game = game local data = (game and game.data) or {} local save = game and game.save self.mon = opts.mon self.playerName = opts.playerName or (save and save.player and save.player.name) or "?" self.pokemon = opts.pokemon or data.pokemon self.moves = opts.moves or data.moves self.palettes = opts.palettes or data.gen2Palettes self.onClose = opts.onClose self.done = false self.picCache = {} return self end function PhotoStudio:speciesDef() local mon = self.mon return mon and self.pokemon and self.pokemon[mon.species] end function PhotoStudio:finish() if self.done then return end self.done = true if self.onClose then self.onClose() end end function PhotoStudio:update(_dt) if self.done then return end local input = self.game and self.game.input if not input then return end if input:wasPressed("a") or input:wasPressed("b") then self:finish() end end function PhotoStudio:picFor(species) local def = species and self.pokemon and self.pokemon[species] local path = def and def.spriteFront if not path then return nil end local cached = self.picCache[path] if cached == nil then -- `and` truncates a multi-return, so the pcall has to stand alone. local ok, image = pcall(Assets.image, path) cached = (ok and image) or false self.picCache[path] = cached end return cached or nil end -- PrepMonFrontpic at hlcoord 0, 0: a 7x7 block with the pic centred in it. function PhotoStudio:drawPic() local mon = self.mon local image = mon and self:picFor(mon.species) if not image then return end local G = love.graphics local colors = self.palettes and mon.species and Palettes.monColors(self.palettes, mon.species, mon.shiny) or nil local blank = colors and GbcPalette.color(colors, 1) or { 255, 255, 255 } G.setColor(blank[1] / 255, blank[2] / 255, blank[3] / 255, 1) G.rectangle("fill", 0, 0, 7 * 8, 7 * 8) local wide = math.floor(image:getWidth() / 8) local pad = PIC_PAD[wide] or PIC_PAD[7] G.setColor(1, 1, 1, 1) local function body() G.draw(image, pad[1] * 8, pad[2] * 8) end if colors and GbcPalette.available() then GbcPalette.with(colors, body) else body() end G.setColor(1, 1, 1, 1) end function PhotoStudio:moveName() local mon = self.mon local entry = mon and mon.moves and mon.moves[1] if not entry then return "-" end local def = self.moves and self.moves[entry.id] return (def and def.name) or entry.id end function PhotoStudio:drawPanel() -- PrintPartyMonPage1 opens with LoadFontsBattleExtra, and the card is -- written in that sheet's glyphs: '№' ($74), '' ($73) and '' ($6e) -- are a middle dot, a closing quote and a kana on the normal extra sheet. local wasBattle = Font.useBattleExtra(true) Chrome.clear() local mon = self.mon or {} local def = self:speciesDef() self:drawPic() Chrome.print(Strings("№."), 8, 0) Chrome.print(num((def and def.dex) or 0, 3, true), 10, 0) Chrome.print(Strings("") .. num(mon.level or 1, 2), 8, 2) -- `ld de, wTempMonMaxHP / lb bc, 2, 3 / call PrintNum`: one field, the -- mon's max HP -- the card has no separate current-HP column, unlike the -- stats screen's pink page. Chrome.print(Strings("HP"), 12, 2) Chrome.print(num(mon.maxHp or mon.hp or 0, 3), 14, 2) -- PlaceGenderAndShininess: gender at hlcoord 17, 2, the shiny ⁂ at 18, 2. if mon.gender == "male" then Chrome.print(Strings("♂"), 17, 2) elseif mon.gender == "female" then Chrome.print(Strings("♀"), 17, 2) end if mon.shiny then Chrome.print(Strings("⁂"), 18, 2) end Chrome.print(mon.nickname or mon.name or mon.species or "?", 8, 4) Chrome.print(Strings("/"), 9, 6) Chrome.print((def and def.name) or mon.species or "?", 10, 6) Chrome.textbox(0, 7, 18, 9) Chrome.print(Strings("OT/"), 1, 9) Chrome.print(mon.ot or self.playerName, 4, 9) Chrome.print(Strings("№"), 1, 11) Chrome.print(num(mon.otId or 0, 5, true), 4, 11) Chrome.print(Strings("MOVE"), 1, 14) Chrome.print(self:moveName(), 7, 14) Font.useBattleExtra(wasBattle) end function PhotoStudio:draw() self:drawPanel() end -- PrintPartyMonPage1 opens on ClearBGPalettes / ClearTilemap -- (engine/printer/print_party.asm:134-135), so the card owns the screen -- outright. The panel itself starts from Chrome.clear(), so white IS the -- surround here and the fill just carries it to the window edge. function PhotoStudio:drawsWidescreen() return true end function PhotoStudio:drawWidescreen(winW, winH) local G = love.graphics G.setColor(1, 1, 1, 1) G.rectangle("fill", 0, 0, winW, winH) local scale = Chrome.fitScale(winW, winH) local ox, oy = Chrome.fitOrigin(winW, winH, scale) G.push() G.translate(ox, oy) G.scale(scale, scale) self:drawPanel() G.pop() end return PhotoStudio