mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 16:31:05 +02:00
181 lines
6.5 KiB
Lua
181 lines
6.5 KiB
Lua
-- Gallery #7 (Total-conversion team): the smallest thing that is
|
|
-- recognizably a different game. Its own boot config, its own title
|
|
-- screen, its own three-species dex, its own single badge, and one map.
|
|
--
|
|
-- LEGAL POSTURE (constraint 1): the Red import still runs and supplies the
|
|
-- fallback infrastructure this conversion sits on -- the OVERWORLD tileset,
|
|
-- the font, the move table. The conversion overrides on top. Every pixel
|
|
-- under assets/ is original work generated by tools/make_assets.py; nothing
|
|
-- here transforms extracted Red art into "new" content.
|
|
local MAP = "SABLE_COVE"
|
|
local BADGE = "SABLE_TIDE_BADGE"
|
|
|
|
-- three original species; ids are namespaced so a mixed load cannot
|
|
-- collide with Red's
|
|
local DEX = {
|
|
{ id = "SABLE_EMBERKIT", name = "EMBERKIT", dex = 1, art = "emberkit",
|
|
types = { "FIRE" }, stats = { hp = 45, attack = 60, defense = 40,
|
|
speed = 65, special = 50 } },
|
|
{ id = "SABLE_TIDEPUP", name = "TIDEPUP", dex = 2, art = "tidepup",
|
|
types = { "WATER" }, stats = { hp = 50, attack = 48, defense = 60,
|
|
speed = 45, special = 55 } },
|
|
{ id = "SABLE_MOSSLING", name = "MOSSLING", dex = 3, art = "mossling",
|
|
types = { "GRASS", "POISON" }, stats = { hp = 55, attack = 50,
|
|
defense = 55, speed = 40,
|
|
special = 60 } },
|
|
}
|
|
|
|
return function(mod)
|
|
local ChipAsm = require("src.audio.ChipAsm")
|
|
|
|
-- ------- species, cries and icons
|
|
|
|
for _, entry in ipairs(DEX) do
|
|
mod.content.pokemon:register(entry.id, {
|
|
id = entry.id,
|
|
name = entry.name,
|
|
dex = entry.dex,
|
|
types = entry.types,
|
|
baseStats = entry.stats,
|
|
catchRate = 190,
|
|
baseExp = 64,
|
|
growthRate = "MEDIUM_FAST",
|
|
level1Moves = { "TACKLE" },
|
|
learnset = {
|
|
{ level = 7, move = "GROWL" },
|
|
{ level = 13, move = "QUICK_ATTACK" },
|
|
},
|
|
evolutions = {},
|
|
spriteFront = mod.path .. "/assets/" .. entry.art .. "_front.png",
|
|
spriteBack = mod.path .. "/assets/" .. entry.art .. "_back.png",
|
|
frontSize = 5,
|
|
cry = entry.id,
|
|
icon = { image = mod.path .. "/assets/" .. entry.art .. "_icon.png",
|
|
frames = 2 },
|
|
})
|
|
|
|
-- one authored chip effect per species, keyed by species id exactly
|
|
-- like the vanilla cry table
|
|
mod.content.cries:register(entry.id, {
|
|
chip = ChipAsm.sfx{
|
|
channels = { { hw = 1, program = {
|
|
{ pitchSweep = { pace = 2 + entry.dex, subtract = entry.dex == 2,
|
|
shift = 3 } },
|
|
{ squareNote = { len = 5, volume = 13, fade = 2,
|
|
frequency = 0x480 + entry.dex * 0x60 } },
|
|
} } },
|
|
}.chip,
|
|
pitch = 128, length = 128,
|
|
})
|
|
|
|
mod.content.icons:register(entry.id, {
|
|
image = mod.path .. "/assets/" .. entry.art .. "_icon.png",
|
|
frames = 2,
|
|
})
|
|
end
|
|
|
|
-- ------- the badge, which is an item like every vanilla badge
|
|
|
|
mod.content.items:register(BADGE, {
|
|
id = BADGE, name = "TIDEBADGE", price = 0, keyItem = true, tossable = false,
|
|
})
|
|
|
|
-- ------- the rules the engine used to hard-code
|
|
-- deep registry: register and patch are the same verb, and only the keys
|
|
-- named here move. Everything else keeps its imported value.
|
|
|
|
mod.content.constants:patch("dexSize", #DEX)
|
|
mod.content.constants:patch("dexDigits", 1)
|
|
mod.content.constants:patch("levelCap", 50)
|
|
-- override, not patch: under deep semantics a list APPENDS, so patching
|
|
-- here would leave Kanto's eight badges in front of this one. override
|
|
-- is the verb that drops a list, which is exactly what a conversion wants
|
|
mod.content.constants:override("badges", { { id = BADGE, name = "TIDE" } })
|
|
mod.content.constants:override("hmMoves", { "CUT", "SURF" })
|
|
|
|
-- ------- the one map
|
|
|
|
local blocks = {}
|
|
for i = 1, 10 * 9 do blocks[i] = 1 end
|
|
mod.content.maps:register(MAP, {
|
|
id = MAP,
|
|
label = "SableCove",
|
|
index = 1000,
|
|
tileset = "OVERWORLD",
|
|
width = 10, height = 9,
|
|
blocks = blocks,
|
|
borderBlock = 11,
|
|
warps = {}, objects = {}, signs = {},
|
|
})
|
|
|
|
mod.content.encounters:register(MAP, {
|
|
grass = { rate = 25, slots = {
|
|
{ level = 3, species = "SABLE_EMBERKIT" },
|
|
{ level = 3, species = "SABLE_TIDEPUP" },
|
|
{ level = 3, species = "SABLE_MOSSLING" },
|
|
{ level = 4, species = "SABLE_TIDEPUP" },
|
|
{ level = 4, species = "SABLE_MOSSLING" },
|
|
{ level = 5, species = "SABLE_EMBERKIT" },
|
|
{ level = 5, species = "SABLE_TIDEPUP" },
|
|
{ level = 5, species = "SABLE_MOSSLING" },
|
|
{ level = 6, species = "SABLE_EMBERKIT" },
|
|
{ level = 6, species = "SABLE_MOSSLING" },
|
|
} },
|
|
})
|
|
|
|
-- ------- the new game itself
|
|
|
|
mod.content.field:patch("boot", {
|
|
startMap = MAP, startX = 5, startY = 4, startFacing = "down",
|
|
playerName = "SABLE", rivalName = "CORAL",
|
|
startMoney = 1500,
|
|
lastHeal = { map = MAP, x = 5, y = 4 },
|
|
namePresets = { player = { "SABLE", "WREN", "PIKE" },
|
|
rival = { "CORAL", "REEF", "SHOAL" } },
|
|
-- the conversion owns the boot flow; splash and newGame keep the
|
|
-- engine screens, which is the point of naming them individually
|
|
screens = { title = "SableTitle" },
|
|
})
|
|
|
|
-- ------- the title screen
|
|
|
|
mod.content.screens:register("SableTitle", {
|
|
new = function(game, opts)
|
|
opts = opts or {}
|
|
local Font = mod.ui.Font
|
|
local state = { game = game, isOpaque = true, blink = 0 }
|
|
|
|
function state:update()
|
|
self.blink = (self.blink + 1) % 60
|
|
local input = game.input
|
|
if not input then return end
|
|
if input:wasPressed("a") or input:wasPressed("start") then
|
|
if opts.onNewGame then opts.onNewGame() end
|
|
end
|
|
end
|
|
|
|
function state:draw()
|
|
love.graphics.setColor(1, 1, 1, 1)
|
|
love.graphics.rectangle("fill", 0, 0, 160, 144)
|
|
love.graphics.setColor(0, 0, 0, 1)
|
|
Font.draw("SABLE COVE", 40, 40)
|
|
Font.draw("A MINI CONVERSION", 12, 56)
|
|
if self.blink < 40 then Font.draw("PRESS A", 52, 104) end
|
|
end
|
|
|
|
return state
|
|
end,
|
|
})
|
|
|
|
mod.events:on("game.ready", function(ev)
|
|
-- the payload carries the live Game; a conversion uses it to check
|
|
-- that its own boot config actually took
|
|
local boot = ev.game and ev.game.data and ev.game.data.field
|
|
and ev.game.data.field.boot
|
|
if not (boot and boot.startMap == MAP) then
|
|
mod.log:warn("another mod owns field.boot; raise this mod's priority "
|
|
.. "above %s to win the merge", tostring(boot and boot.startMap))
|
|
end
|
|
end)
|
|
end
|