mirror of
https://github.com/AverageConsumer/kanto-gear.git
synced 2026-08-28 18:24:42 +02:00
Add live-switchable modern gear themes
This commit is contained in:
@@ -208,6 +208,12 @@ testing the Retroid Pocket 5 dual-screen support, collecting detailed
|
||||
diagnostics, and working with us for more than 24 hours to identify and verify
|
||||
the Android display-routing fixes.
|
||||
|
||||
The optional Modern Light and Modern Dark themes adapt the angular panels,
|
||||
dark surfaces, and red-and-blue accents shared by
|
||||
[CustCast's Thor UI work](https://github.com/CustCast/PokeRogue-App-Android-Thor).
|
||||
Thanks to CustCast for making the original artwork available and inviting its
|
||||
use in Kanto Gear.
|
||||
|
||||
Kanto Gear's own code is available under the [MIT License](LICENSE). That
|
||||
license does not replace or extend the licenses, rights or ownership of
|
||||
Gen1Recomp, Dramatic Shape Voxel Mod, Pokemon or their respective assets.
|
||||
|
||||
+90
-35
@@ -2,17 +2,28 @@ local WIDTH, HEIGHT = 160, 144
|
||||
local HEADER = 20
|
||||
local G
|
||||
|
||||
local KANTO_PALETTE = {
|
||||
{ 155, 188, 15 }, { 139, 172, 15 }, { 48, 98, 48 }, { 15, 56, 15 },
|
||||
}
|
||||
local INK, DARK, MID, PAPER
|
||||
local THEME = {
|
||||
style = "classic",
|
||||
classic = {
|
||||
{ 155, 188, 15 }, { 139, 172, 15 }, { 48, 98, 48 }, { 15, 56, 15 },
|
||||
},
|
||||
light = {
|
||||
{ 248, 249, 252 }, { 222, 226, 235 }, { 39, 45, 58 }, { 12, 15, 22 },
|
||||
},
|
||||
dark = {
|
||||
{ 12, 15, 22 }, { 31, 37, 50 }, { 190, 198, 212 }, { 245, 247, 251 },
|
||||
},
|
||||
red = { 227 / 255, 27 / 255, 35 / 255, 1 },
|
||||
blue = { 52 / 255, 53 / 255, 143 / 255, 1 },
|
||||
white = { 248 / 255, 249 / 255, 252 / 255, 1 },
|
||||
}
|
||||
local RADAR_RED = { 220 / 255, 38 / 255, 28 / 255, 1 }
|
||||
local MAP_EXIT = { 0.20, 0.65, 1, 1 }
|
||||
local MAP_ITEM = { 1, 0.72, 0.10, 1 }
|
||||
local MAP_HIDDEN = { 0.90, 0.30, 0.85, 1 }
|
||||
local CHOICE_QUIET = 0.32
|
||||
local SECONDARY_BACKGROUND
|
||||
local RADAR_FRAMES = 16
|
||||
local PC_LIST_KINDS = {
|
||||
pc_box_withdraw = true, pc_box_deposit = true,
|
||||
pc_box_release = true, pc_box_change = true,
|
||||
@@ -57,15 +68,17 @@ local function fillerColor(palette)
|
||||
end
|
||||
|
||||
local function usePalette(palette)
|
||||
palette = validPalette(palette) and palette or KANTO_PALETTE
|
||||
palette = validPalette(palette) and palette or THEME.classic
|
||||
PAPER, MID, DARK, INK = rgba(palette[1]), rgba(palette[2]),
|
||||
rgba(palette[3]), rgba(palette[4])
|
||||
SECONDARY_BACKGROUND = rgb24(fillerColor(palette))
|
||||
end
|
||||
|
||||
usePalette(KANTO_PALETTE)
|
||||
assert(validPalette(KANTO_PALETTE)
|
||||
and inverted(KANTO_PALETTE)[1] == KANTO_PALETTE[4]
|
||||
usePalette(THEME.classic)
|
||||
assert(validPalette(THEME.classic)
|
||||
and validPalette(THEME.light)
|
||||
and validPalette(THEME.dark)
|
||||
and inverted(THEME.classic)[1] == THEME.classic[4]
|
||||
and fillerColor({ { 255, 255, 255 }, { 200, 100, 100 },
|
||||
{ 120, 20, 80 }, { 0, 0, 0 } })[1] == 120
|
||||
and SECONDARY_BACKGROUND == 0x0F380F, "theme palette helpers")
|
||||
@@ -596,7 +609,19 @@ local function centered(value, y, c, scale)
|
||||
end
|
||||
|
||||
local function outline(x, y, w, h, c)
|
||||
box("line", x + 0.5, y + 0.5, w - 1, h - 1, c or INK)
|
||||
c = c or INK
|
||||
if THEME.style == "classic" or w < 5 or h < 5 then
|
||||
box("line", x + 0.5, y + 0.5, w - 1, h - 1, c)
|
||||
return
|
||||
end
|
||||
box("fill", x + 2, y, w - 4, 1, c)
|
||||
box("fill", x + 2, y + h - 1, w - 4, 1, c)
|
||||
box("fill", x, y + 2, 1, h - 4, c)
|
||||
box("fill", x + w - 1, y + 2, 1, h - 4, c)
|
||||
box("fill", x + 1, y + 1, 1, 1, c)
|
||||
box("fill", x + w - 2, y + 1, 1, 1, c)
|
||||
box("fill", x + 1, y + h - 2, 1, 1, c)
|
||||
box("fill", x + w - 2, y + h - 2, 1, 1, c)
|
||||
end
|
||||
|
||||
local function hpBar(x, y, w, hp, maxHp)
|
||||
@@ -613,9 +638,15 @@ local function expBar(x, y, w, ratio, selected)
|
||||
end
|
||||
|
||||
local function button(x, y, w, h, label, selected)
|
||||
box("fill", x, y, w, h, selected and DARK or MID)
|
||||
outline(x, y, w, h, INK)
|
||||
local c = selected and PAPER or INK
|
||||
local modern = THEME.style ~= "classic"
|
||||
box("fill", x, y, w, h, modern and selected and THEME.red
|
||||
or selected and DARK or MID)
|
||||
outline(x, y, w, h, modern and THEME.blue or INK)
|
||||
if modern and selected then
|
||||
box("fill", x + 2, y + 2, 2, math.max(1, h - 4), THEME.white)
|
||||
end
|
||||
local c = modern and selected and THEME.white
|
||||
or selected and PAPER or INK
|
||||
text(fit(label, math.floor((w - 8) / 6)),
|
||||
x + math.max(4, math.floor((w - #fit(label, math.floor((w - 8) / 6)) * 6) / 2)),
|
||||
y + math.floor((h - 7) / 2), c)
|
||||
@@ -626,6 +657,7 @@ local function inside(x, y, left, top, width, height)
|
||||
end
|
||||
|
||||
return function(mod)
|
||||
local RADAR_FRAMES = 16
|
||||
local function isLowBattery(state, percent)
|
||||
percent = tonumber(percent)
|
||||
return percent ~= nil and percent <= 20
|
||||
@@ -657,6 +689,8 @@ return function(mod)
|
||||
{ key = "theme", label = "THEME", type = "choice",
|
||||
default = "kanto", choices = {
|
||||
{ "KANTO GREEN", "kanto" }, { "MATCH GAME", "match" },
|
||||
{ "MODERN LIGHT", "modern_light" },
|
||||
{ "MODERN DARK", "modern_dark" },
|
||||
{ "OG", "og" }, { "OG INVERTED", "og_inv" },
|
||||
{ "SGB", "sgb" }, { "ADVANCED", "advanced" },
|
||||
{ "VERSION COLOR", "version" },
|
||||
@@ -808,6 +842,8 @@ return function(mod)
|
||||
})[PaletteFX.mode] or "kanto"
|
||||
end
|
||||
if theme == "og" then return PaletteFX.GRAYS end
|
||||
if theme == "modern_light" then return THEME.light end
|
||||
if theme == "modern_dark" then return THEME.dark end
|
||||
if theme == "og_inv" then return inverted(PaletteFX.GRAYS) end
|
||||
if theme == "version" then return PaletteFX.ogBg() end
|
||||
if theme == "sgb" or theme == "sgb_inv" then
|
||||
@@ -821,13 +857,15 @@ return function(mod)
|
||||
local pack = PaletteFX.gbcPack()
|
||||
return yellow or (pack and pack.palettes and pack.palettes.MEWMON)
|
||||
end
|
||||
return KANTO_PALETTE
|
||||
return THEME.classic
|
||||
end
|
||||
|
||||
local function refreshTheme(force)
|
||||
local theme = mod.options:get("theme") or "kanto"
|
||||
local key = theme .. (theme == "match" and (":" .. PaletteFX.mode) or "")
|
||||
if not force and key == themeKey then return end
|
||||
THEME.style = theme == "modern_light" and "modern_light"
|
||||
or theme == "modern_dark" and "modern_dark" or "classic"
|
||||
usePalette(themePalette(theme))
|
||||
invalidateLocalMap()
|
||||
themeKey, dirty = key, true
|
||||
@@ -1093,37 +1131,46 @@ return function(mod)
|
||||
y + (maxH - ih * scale) / 2, 0, scale, scale)
|
||||
end
|
||||
|
||||
local function battery()
|
||||
local function battery(foreground)
|
||||
foreground = foreground or PAPER
|
||||
local state, percent = system.getPowerInfo()
|
||||
percent = tonumber(percent)
|
||||
local low = isLowBattery(state, percent)
|
||||
if low ~= batteryLow then nextClock = 0 end
|
||||
batteryLow = low
|
||||
box("line", 143.5, 6.5, 12, 7, PAPER)
|
||||
box("fill", 155, 9, 2, 3, PAPER)
|
||||
box("line", 143.5, 6.5, 12, 7, foreground)
|
||||
box("fill", 155, 9, 2, 3, foreground)
|
||||
if percent and (not low or math.floor(love.timer.getTime()) % 2 == 0) then
|
||||
box("fill", 145, 8, math.floor(9 * math.max(0, math.min(100, percent)) / 100),
|
||||
4, PAPER)
|
||||
4, foreground)
|
||||
end
|
||||
end
|
||||
|
||||
local function header(title, back, paged)
|
||||
box("fill", 0, 0, WIDTH, HEADER, DARK)
|
||||
local modern = THEME.style ~= "classic"
|
||||
local background = modern and (THEME.style == "modern_dark" and MID or DARK)
|
||||
or DARK
|
||||
local foreground = modern and THEME.white or PAPER
|
||||
box("fill", 0, 0, WIDTH, HEADER, background)
|
||||
if modern then
|
||||
box("fill", 0, HEADER - 2, WIDTH, 2, THEME.blue)
|
||||
box("fill", 0, HEADER - 2, 42, 2, THEME.red)
|
||||
end
|
||||
if back then
|
||||
text("<", 4, 6, PAPER)
|
||||
text(fit(title, 12), 16, 6, PAPER)
|
||||
text("<", 4, 6, foreground)
|
||||
text(fit(title, 12), 16, 6, foreground)
|
||||
elseif paged then
|
||||
local label = fit(title, 10)
|
||||
text("<", 4, 6, PAPER)
|
||||
text(label, 48 - math.floor(#label * 3), 6, PAPER)
|
||||
text(">", 88, 6, PAPER)
|
||||
text("<", 4, 6, foreground)
|
||||
text(label, 48 - math.floor(#label * 3), 6, foreground)
|
||||
text(">", 88, 6, foreground)
|
||||
else
|
||||
text(fit(title, 14), 5, 6, PAPER)
|
||||
text(fit(title, 14), 5, 6, foreground)
|
||||
end
|
||||
local clock = clockText(not system.is24HourClock
|
||||
or system.is24HourClock() ~= false)
|
||||
text(clock, 137 - #clock * 6, 6, PAPER)
|
||||
battery()
|
||||
text(clock, 137 - #clock * 6, 6, foreground)
|
||||
battery(foreground)
|
||||
end
|
||||
|
||||
local function stackHas(target)
|
||||
@@ -1217,20 +1264,22 @@ return function(mod)
|
||||
end
|
||||
|
||||
local function drawTitle()
|
||||
box("fill", 0, 0, WIDTH, HEIGHT, DARK)
|
||||
color(PAPER)
|
||||
local modern = THEME.style ~= "classic"
|
||||
local foreground = modern and INK or PAPER
|
||||
box("fill", 0, 0, WIDTH, HEIGHT, modern and PAPER or DARK)
|
||||
color(foreground)
|
||||
G.circle("line", 80, 29, 15)
|
||||
G.circle("line", 80, 29, 6)
|
||||
for i = 0, 7 do
|
||||
local a = i * math.pi / 4
|
||||
box("fill", math.floor(78 + math.cos(a) * 17),
|
||||
math.floor(27 + math.sin(a) * 17), 4, 4, PAPER)
|
||||
math.floor(27 + math.sin(a) * 17), 4, 4, foreground)
|
||||
end
|
||||
centered("KANTO GEAR", 56, PAPER, 2)
|
||||
box("fill", 28, 78, 104, 1, PAPER)
|
||||
centered("DUAL DISPLAY", 87, PAPER)
|
||||
centered("LINK READY", 104, MID)
|
||||
centered("START GAME ABOVE", 125, PAPER)
|
||||
centered("KANTO GEAR", 56, foreground, 2)
|
||||
box("fill", 28, 78, 104, 1, modern and THEME.red or PAPER)
|
||||
centered("DUAL DISPLAY", 87, foreground)
|
||||
centered("LINK READY", 104, modern and THEME.blue or MID)
|
||||
centered("START GAME ABOVE", 125, foreground)
|
||||
end
|
||||
|
||||
local function drawDim(alpha, prompt)
|
||||
@@ -2322,7 +2371,13 @@ return function(mod)
|
||||
if pendingFly then drawFlyPrompt()
|
||||
elseif pendingAction then drawActionPrompt() end
|
||||
end
|
||||
outline(1, 1, WIDTH - 2, HEIGHT - 2, INK)
|
||||
if THEME.style ~= "classic" then
|
||||
outline(1, 1, WIDTH - 2, HEIGHT - 2, THEME.blue)
|
||||
box("fill", 3, 1, 16, 1, THEME.red)
|
||||
box("fill", WIDTH - 19, HEIGHT - 2, 16, 1, THEME.red)
|
||||
else
|
||||
outline(1, 1, WIDTH - 2, HEIGHT - 2, INK)
|
||||
end
|
||||
G.setCanvas()
|
||||
G.pop()
|
||||
end
|
||||
|
||||
@@ -2,6 +2,9 @@ package.path = "./?.lua;./?/init.lua;" .. package.path
|
||||
|
||||
local T = require("tests.modkit")
|
||||
local path = os.getenv("KANTO_GEAR_MOD_PATH") or "mods/kanto_gear"
|
||||
local entry = assert(loadfile(path .. "/main.lua"))()
|
||||
T.check(debug.getinfo(entry, "u").nups <= 60,
|
||||
"Kanto Gear stays within LuaJIT's 60-upvalue function limit")
|
||||
local newCanvas = T.love.graphics.newCanvas
|
||||
T.love.graphics.newCanvas = function(...)
|
||||
local canvas = newCanvas(...)
|
||||
@@ -18,6 +21,9 @@ T.check(run.loader.exports.kanto_gear ~= nil, "Kanto Gear registers")
|
||||
local options = run.loader.optionSchemas.kanto_gear
|
||||
T.eq(#options, 6, "Kanto Gear keeps its settings compact")
|
||||
T.eq(options[1].label, "THEME", "theme setting is device-neutral")
|
||||
T.eq(#options[1].choices, 9, "classic and modern themes share one setting")
|
||||
T.eq(options[1].choices[3][2], "modern_light", "modern light theme is available")
|
||||
T.eq(options[1].choices[4][2], "modern_dark", "modern dark theme is available")
|
||||
T.eq(options[2].label, "INFO", "assist features use one preset")
|
||||
T.eq(options[4].label, "GEAR SCREEN", "display setting is device-neutral")
|
||||
T.eq(options[5].label, "BATTLE VIEW", "battle layout uses one setting")
|
||||
@@ -64,6 +70,12 @@ T.eq(run.loader.hooks:call("battle.caught_marker_visible",
|
||||
function() return false end, {}), false,
|
||||
"disabling Kanto's icon does not force the native marker")
|
||||
run.loader.modOptions.kanto_gear.caught_icon = true
|
||||
for _, theme in ipairs({ "modern_light", "modern_dark", "kanto" }) do
|
||||
run.loader.modOptions.kanto_gear.theme = theme
|
||||
run.loader.events:emit("mod.options_changed",
|
||||
{ mod = "kanto_gear", key = "theme" })
|
||||
end
|
||||
T.eq(#run.errors, 0, "theme changes apply live without mod errors")
|
||||
run.loader.hooks:call("input.step", function() end, game, 1 / 60)
|
||||
swapPressed = false
|
||||
T.eq(run.loader.hooks:call("render.output_enabled",
|
||||
|
||||
Reference in New Issue
Block a user