release: prepare Kanto Gear 1.3.0

This commit is contained in:
AverageConsumer
2026-08-05 23:50:48 +02:00
parent 79df437935
commit 486f4f6976
4 changed files with 111 additions and 117 deletions
+43 -28
View File
@@ -7,8 +7,8 @@ battles, menus and contextual touch controls move to the second display.
> [!IMPORTANT]
> This is an **unofficial Android public test build**, not an official
> Gen1Recomp release. It is verified on an **AYN Thor running Android 13** and
> is intended to work on comparable Android dual-display devices. Other
> handhelds, docks and HDMI setups still need community testing.
> community-tested on a **Retroid Pocket 5 with the Retroid Dual Screen Add-on**.
> Other handhelds, docks and HDMI setups still need community testing.
![The Pokemon Lab rendered on the main display](kanto-gear-lab-2026.png)
@@ -25,31 +25,42 @@ battles, menus and contextual touch controls move to the second display.
second display when those screens are active.
- Can hide duplicated battle UI on the main display. On the tested Thor, the
main UI returns immediately when the second display is switched off.
- Offers `AUTO`, `HANDHELD` and `EXTRA SCREEN` display targeting for handheld,
- Offers `AUTO`, `HANDHELD` and `EXTERNAL` display targeting for handheld,
docked and TV-style layouts.
- Works without the Voxel Mod. The matching Voxel performance fork is an
optional visual upgrade.
## Which downloads do I need?
Use this matched release set:
| Download | Required? | What it provides |
| --- | --- | --- |
| [`gen1recomp-android-0.1.72-kanto.4.apk`](https://github.com/AverageConsumer/gen1recomp/releases/tag/v0.1.72-kanto.4) | **Required** | Android host with the dual-display bridge and device-routing fixes |
| [`Kanto-Gear-Mod-1.3.0.zip`](https://github.com/AverageConsumer/kanto-gear/releases/tag/v1.3.0) | **Required** | Kanto Gear itself |
| [`DRAMATIC_SHAPE-1.6.0-android.2.zip`](https://github.com/AverageConsumer/DramaticShapeVoxelMod/releases/tag/v1.6.0-android.2) | Optional | Tested Android 3D renderer and Stadium compatibility fix |
The official Gen1Recomp Android release does not yet contain the complete host
support used by Kanto Gear, so the APK fork is currently required. Kanto Gear
works without the Voxel fork; install it only if you want the 3D renderer.
## Install on Android
You need your own supported Pokemon Red, Blue or Yellow ROM. No ROM or
ROM-extracted game data is included here.
> [!IMPORTANT]
> For the complete tested Android experience, use the exact three-part release
> set linked below: the Gen1Recomp Android test APK, Kanto Gear, and the
> Dramatic Shape Android performance fork. The host and Kanto Gear are
> required; the Voxel fork is technically optional but is the recommended 3D
> renderer for this package. Do not substitute the official host or mix
> Use the matched versions above. The host APK and Kanto Gear are required;
> the Voxel fork is optional. Do not substitute the official host or mix
> versions from different release sets.
1. Download `gen1recomp-android-0.1.69-kanto.3.apk` from the latest
[Gen1Recomp Android test release](https://github.com/AverageConsumer/gen1recomp/releases/tag/v0.1.69-kanto.3)
1. Download `gen1recomp-android-0.1.72-kanto.4.apk` from the matching
[Gen1Recomp Android test release](https://github.com/AverageConsumer/gen1recomp/releases/tag/v0.1.72-kanto.4)
and install it.
2. Download `Kanto-Gear-Mod-1.2.0.zip` from the latest
[Kanto Gear release](https://github.com/AverageConsumer/kanto-gear/releases/tag/v1.2.0).
2. Download `Kanto-Gear-Mod-1.3.0.zip` from the matching
[Kanto Gear release](https://github.com/AverageConsumer/kanto-gear/releases/tag/v1.3.0).
3. Start **Gen1Recomp Android Test**, import your ROM, open the **MODS** tab,
tap **Import mod .zip**, and choose `Kanto-Gear-Mod-1.2.0.zip`.
tap **Import mod .zip**, and choose `Kanto-Gear-Mod-1.3.0.zip`.
4. Make sure **Kanto Gear** is enabled, then start the game. The companion
appears automatically when Android reports a suitable second display.
@@ -76,7 +87,7 @@ Gear package because handhelds need additional frame-pacing work. If you want
the tested Android 3D setup:
1. Download the latest `.zip` from the
[Kanto Gear Voxel performance fork](https://github.com/AverageConsumer/DramaticShapeVoxelMod/releases/tag/v1.6.0-android.1).
[Kanto Gear Voxel performance fork](https://github.com/AverageConsumer/DramaticShapeVoxelMod/releases/tag/v1.6.0-android.2).
2. If the original Dramatic Shape Voxel Mod is already installed, remove it
from the **MODS** tab first. Both versions intentionally use the same mod ID.
3. Import the performance-fork `.zip` through **MODS → Import mod .zip**.
@@ -96,7 +107,7 @@ handheld and the fork is not distributed as a PC replacement.
- **Tap the arrows in the header** for the same navigation without swiping.
Horizontal swipes and arrows also move through multi-page Guide and Area
views before continuing to the next section.
- **SPOILER LOCAL MAP** defaults to **OFF**. **MAP** adds a swipe page showing
- **AREA MAP** defaults to **OFF**. **MAP** adds a swipe page showing
the complete current map or floor and your live position; **ENHANCED** also
marks exits plus visible and hidden items that have not been collected. The
regular region map remains the Fly screen, so tapping its unlocked
@@ -112,23 +123,21 @@ handheld and the fork is not distributed as a PC replacement.
## Settings worth knowing
- **BOTTOM SCREEN → AUTO** is the recommended default.
- **GEAR SCREEN → AUTO** is the recommended default.
- **HANDHELD** prefers the other built-in display.
- **EXTRA SCREEN** prefers an external presentation display for TV-style use.
- **HIDE UPPER BATTLE UI** removes duplicated battle menus only while the
companion display is ready.
- **FULL BOTTOM BATTLE UI** additionally moves both HP/status panels to the
companion display. The current split layout remains the default.
- **PROFILE → PURIST** hides gameplay-assistance pages; **ENHANCED** enables
them; **CUSTOM** lets you choose each assist separately.
- **EXTERNAL** prefers an external presentation display for TV-style use.
- **BATTLE VIEW → STANDARD** keeps the normal game HUD. **GEAR** moves
duplicated battle controls to Kanto Gear, while **FULL GEAR** also moves the
HP/status panels. The standard split layout remains the default.
- **INFO → PURIST** hides gameplay-assistance pages; **ENHANCED** enables them.
## Tested release set
| Component | Version | Role |
| --- | --- | --- |
| [Kanto Gear](https://github.com/AverageConsumer/kanto-gear) | 1.2.0 public test | Required second-screen mod |
| [Gen1Recomp Android test fork](https://github.com/AverageConsumer/gen1recomp) | 0.1.69-kanto.3 | Required Android host APK |
| [Dramatic Shape performance fork](https://github.com/AverageConsumer/DramaticShapeVoxelMod) | 1.6.0-android.1 | Recommended for the complete tested 3D setup; technically optional |
| [Kanto Gear](https://github.com/AverageConsumer/kanto-gear) | 1.3.0 public test | Required second-screen mod |
| [Gen1Recomp Android test fork](https://github.com/AverageConsumer/gen1recomp) | 0.1.72-kanto.4 | Required Android host APK |
| [Dramatic Shape performance fork](https://github.com/AverageConsumer/DramaticShapeVoxelMod) | 1.6.0-android.2 | Optional Android 3D renderer |
Do not mix arbitrary releases from the three repositories. Each Kanto Gear
release links the exact set that was tested together.
@@ -139,8 +148,9 @@ Gear release sets manually as a matched group.
## Known limits
- The AYN Thor is the confirmed reference device. Comparable Android
dual-display hardware is intended to work but remains community-tested.
- The AYN Thor is the confirmed reference device. Retroid Pocket 5 support was
tested with Retroid's USB-C Dual Screen Add-on. Other Android dual-display
hardware, including GammaOS devices, still needs community testing.
- Desktop and ordinary single-screen builds have no companion display; the mod
stays inactive rather than opening another desktop window.
- External-monitor rotation, unusual three-display layouts and manufacturer
@@ -178,6 +188,11 @@ Their progress, code and project direction remain theirs. These forks exist to
test additional work without presenting it as official or asking upstream
users to debug our changes.
Special thanks to [@Rocky5150](https://github.com/Rocky5150) for patiently
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.
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.
+59 -87
View File
@@ -236,18 +236,13 @@ local function methodLines(methods)
return lines[1] or "", lines[2] or ""
end
local function profileFromAssists(get)
local hints, details = get("type_hints"), get("move_details")
local guide, area = get("guide"), get("area")
local radar, catchOdds = get("item_radar"), get("catch_odds")
if hints and details and guide and area and radar and catchOdds then
return "enhanced"
local function battleUIMode(value, legacyFull)
if value == "standard" or value == "gear" or value == "full" then
return value
end
if not hints and not details and not guide and not area and not radar
and not catchOdds then
return "purist"
end
return "custom"
if legacyFull == true then return "full" end
if value == true then return "gear" end
return "standard"
end
local function checklistPages(sections)
@@ -413,18 +408,11 @@ end
assert(not assistEnabled("purist", true)
and assistEnabled("enhanced", false)
and assistEnabled("custom", true), "assist profiles")
do
local values = { type_hints = true, move_details = true,
guide = true, area = true, item_radar = true,
catch_odds = true }
local function get(key) return values[key] end
assert(profileFromAssists(get) == "enhanced", "all assists enhanced")
values.guide = false
assert(profileFromAssists(get) == "custom", "mixed assists custom")
values.type_hints, values.move_details, values.area, values.item_radar,
values.catch_odds = false, false, false, false, false
assert(profileFromAssists(get) == "purist", "all assists purist")
end
assert(battleUIMode("standard", true) == "standard"
and battleUIMode("gear", false) == "gear"
and battleUIMode("full", false) == "full"
and battleUIMode(true, false) == "gear"
and battleUIMode(false, true) == "full", "battle UI settings")
do
local pages = checklistPages({
{ name = "TRAINERS", rows = { { done = true }, { done = false } } },
@@ -618,73 +606,65 @@ local function inside(x, y, left, top, width, height)
end
return function(mod)
local infoDefault = mod.options:get("info_level")
if infoDefault == nil then
local legacyProfile = mod.options:get("profile")
infoDefault = legacyProfile == "custom" and "legacy"
or legacyProfile == "purist" and "purist" or "enhanced"
end
local infoChoices = {
{ "PURIST", "purist" }, { "ENHANCED", "enhanced" },
}
if infoDefault == "legacy" then
infoChoices[#infoChoices + 1] = { "SAVED CUSTOM", "legacy" }
end
local battleDefault = mod.options:get("battle_view")
if battleDefault == nil then
battleDefault = battleUIMode(mod.options:get("hide_upper_battle_ui"),
mod.options:get("full_bottom_battle_ui"))
end
mod.options:define({
{ key = "theme", label = "BOTTOM THEME", type = "choice",
{ key = "theme", label = "THEME", type = "choice",
default = "kanto", choices = {
{ "KANTO GREEN", "kanto" }, { "MATCH GAME", "match" },
{ "OG", "og" }, { "OG INVERTED", "og_inv" },
{ "SGB", "sgb" }, { "ADVANCED", "advanced" },
{ "VERSION COLOR", "version" },
} },
{ key = "profile", label = "PROFILE", type = "choice",
default = "enhanced", choices = {
{ "PURIST", "purist" }, { "ENHANCED", "enhanced" },
{ "CUSTOM", "custom" },
}, sync = true, sets = {
purist = { type_hints = false, move_details = false,
guide = false, area = false, item_radar = false,
catch_odds = false },
enhanced = { type_hints = true, move_details = true,
guide = true, area = true, item_radar = true,
catch_odds = true },
custom = { profile = profileFromAssists },
} },
{ key = "type_hints", label = "ASSIST TYPE HINTS",
type = "toggle", default = true,
sets = { [false] = { profile = profileFromAssists },
[true] = { profile = profileFromAssists } } },
{ key = "move_details", label = "ASSIST MOVE INFO",
type = "toggle", default = true,
sets = { [false] = { profile = profileFromAssists },
[true] = { profile = profileFromAssists } } },
{ key = "guide", label = "ASSIST GUIDE PAGE",
type = "toggle", default = true,
sets = { [false] = { profile = profileFromAssists },
[true] = { profile = profileFromAssists } } },
{ key = "area", label = "ASSIST AREA PAGE",
type = "toggle", default = true,
sets = { [false] = { profile = profileFromAssists },
[true] = { profile = profileFromAssists } } },
{ key = "item_radar", label = "ASSIST ITEM RADAR",
type = "toggle", default = true,
sets = { [false] = { profile = profileFromAssists },
[true] = { profile = profileFromAssists } } },
{ key = "catch_odds", label = "ASSIST CATCH ODDS",
type = "toggle", default = true,
sets = { [false] = { profile = profileFromAssists },
[true] = { profile = profileFromAssists } } },
{ key = "local_map", label = "SPOILER LOCAL MAP",
{ key = "info_level", label = "INFO", type = "choice",
default = infoDefault, choices = infoChoices },
{ key = "local_map", label = "AREA MAP",
type = "choice", default = false, choices = {
{ "OFF", false }, { "MAP", true }, { "ENHANCED", "enhanced" },
} },
{ key = "display_target", label = "BOTTOM SCREEN", type = "choice",
{ key = "display_target", label = "GEAR SCREEN", type = "choice",
default = "auto", choices = {
{ "AUTO", "auto" }, { "HANDHELD", "handheld" },
{ "EXTRA SCREEN", "secondary" },
{ "EXTERNAL", "secondary" },
} },
{ key = "battle_view", label = "BATTLE VIEW",
type = "choice", default = battleDefault, choices = {
{ "STANDARD", "standard" }, { "GEAR", "gear" },
{ "FULL GEAR", "full" },
} },
{ key = "hide_upper_battle_ui", label = "HIDE UPPER BATTLE UI",
type = "toggle", default = false },
{ key = "full_bottom_battle_ui", label = "FULL BOTTOM BATTLE UI",
type = "toggle", default = false },
})
local function assist(key)
return assistEnabled(mod.options:get("profile"), mod.options:get(key))
local level = mod.options:get("info_level")
if level == "legacy" then
return assistEnabled("custom", mod.options:get(key))
end
return level ~= "purist"
end
local function currentBattleUIMode()
return mod.options:get("battle_view") or "standard"
end
local function fullBottomBattleUI()
return mod.options:get("full_bottom_battle_ui") == true
return currentBattleUIMode() == "full"
end
local function hideUpperBattleUI()
return fullBottomBattleUI() or mod.options:get("hide_upper_battle_ui")
return currentBattleUIMode() ~= "standard"
end
local runtime = rawget(_G, "love")
@@ -696,7 +676,7 @@ return function(mod)
end
local PaletteFX = require("src.render.PaletteFX")
local EngineFont = require("src.render.Font")
local EngineFont = mod.ui.Font
local canvas = G.newCanvas(WIDTH, HEIGHT, { dpiscale = 1 })
canvas:setFilter("nearest", "nearest")
@@ -723,7 +703,6 @@ return function(mod)
local mapAsset = nil
local localMap = nil
local spriteCache = {}
local caughtBall = nil
local touchDown = nil
local textSpeedToken
local textSpeedReleasePending = false
@@ -2061,20 +2040,13 @@ return function(mod)
end
local function drawCaughtBall(x, y)
if caughtBall == nil then
local ok, image = pcall(G.newImage,
"assets/generated/battle/balls.png")
if ok then
image:setFilter("nearest", "nearest")
caughtBall = { image = image,
quad = G.newQuad(0, 0, 8, 8, image:getDimensions()) }
else
caughtBall = false
end
end
if not caughtBall then return end
G.setColor(1, 1, 1, 1)
G.draw(caughtBall.image, caughtBall.quad, x, y)
box("fill", x + 2, y, 4, 1, INK)
box("fill", x + 1, y + 1, 6, 1, INK)
box("fill", x, y + 2, 8, 4, INK)
box("fill", x + 1, y + 6, 6, 1, INK)
box("fill", x + 2, y + 7, 4, 1, INK)
box("fill", x + 1, y + 3, 6, 2, PAPER)
box("fill", x + 3, y + 3, 2, 2, DARK)
end
local function drawFullBattleStatus(mon, y, player)
+2 -2
View File
@@ -1,7 +1,7 @@
{
"id": "kanto_gear",
"name": "Kanto Gear",
"version": "1.2.0",
"version": "1.3.0",
"api": 2,
"entry": "main.lua",
"category": "UI",
@@ -12,5 +12,5 @@
"optional_dependencies": [],
"conflicts": [],
"permissions": ["engine_internals"],
"description": "Dual-screen map, party, battle, PC and contextual touch controls for supported Gen1Recomp Android hosts. Public hardware test; currently verified on AYN Thor."
"description": "Dual-screen map, party, battle, PC and contextual touch controls for supported Gen1Recomp Android hosts. Tested on AYN Thor and Retroid Pocket 5."
}
+7
View File
@@ -15,6 +15,13 @@ T.love.graphics.newCanvas = newCanvas
T.eq(#run.errors, 0,
"Kanto Gear loads clean: " .. table.concat(run.errors, "; "))
T.check(run.loader.exports.kanto_gear ~= nil, "Kanto Gear registers")
local options = run.loader.optionSchemas.kanto_gear
T.eq(#options, 5, "Kanto Gear keeps its settings compact")
T.eq(options[1].label, "THEME", "theme setting is device-neutral")
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")
T.eq(#options[5].choices, 3, "battle view exposes three clear layouts")
local hooks = T.record.hooks(run.loader)
T.eq(hooks:depth("render.compose"), 1,
"Kanto Gear uses the upstream composition seam")