Download badge and boss sprite images locally during export

The seed export command now downloads badge images and boss sprites
from remote URLs and stores them in frontend/public/, rewriting the
JSON URLs to local paths. Sprites are namespaced by game version
(e.g. /boss-sprites/red/brock.png) so each generation can have
its own sprite style.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-08 22:13:30 +01:00
parent d2144e47bf
commit 8bd4ad1ecf
126 changed files with 3948 additions and 194 deletions

View File

@@ -4,13 +4,13 @@
"boss_type": "gym_leader",
"specialty_type": "flying",
"badge_name": "Zephyr Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/4/4a/Zephyr_Badge.png/35px-Zephyr_Badge.png",
"badge_image_url": "/badges/zephyr-badge.png",
"level_cap": 9,
"order": 1,
"after_route_name": "Violet City",
"location": "Violet Gym",
"section": "Main Story",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/4/4a/Zephyr_Badge.png/35px-Zephyr_Badge.png",
"sprite_url": "/boss-sprites/crystal/falkner.png",
"pokemon": []
},
{
@@ -18,13 +18,13 @@
"boss_type": "gym_leader",
"specialty_type": "bug",
"badge_name": "Hive Badge",
"badge_image_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/10.png?raw=true",
"badge_image_url": "/badges/hive-badge.png",
"level_cap": 16,
"order": 2,
"after_route_name": "Slowpoke Well",
"location": "Azalea Gym",
"section": "Main Story",
"sprite_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/10.png?raw=true",
"sprite_url": "/boss-sprites/crystal/bugsy.png",
"pokemon": []
},
{
@@ -32,13 +32,13 @@
"boss_type": "gym_leader",
"specialty_type": "normal",
"badge_name": "Plain Badge",
"badge_image_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/11.png?raw=true",
"badge_image_url": "/badges/plain-badge.png",
"level_cap": 20,
"order": 3,
"after_route_name": "Goldenrod City",
"location": "Goldenrod Gym",
"section": "Main Story",
"sprite_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/11.png?raw=true",
"sprite_url": "/boss-sprites/crystal/whitney.png",
"pokemon": []
},
{
@@ -46,13 +46,13 @@
"boss_type": "gym_leader",
"specialty_type": "ghost",
"badge_name": "Fog Badge",
"badge_image_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/12.png?raw=true",
"badge_image_url": "/badges/fog-badge.png",
"level_cap": 25,
"order": 4,
"after_route_name": null,
"location": "Ecruteak Gym",
"section": "Main Story",
"sprite_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/12.png?raw=true",
"sprite_url": "/boss-sprites/crystal/morty.png",
"pokemon": []
},
{
@@ -60,13 +60,13 @@
"boss_type": "gym_leader",
"specialty_type": "fighting",
"badge_name": "Storm Badge",
"badge_image_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/13.png?raw=true",
"badge_image_url": "/badges/storm-badge.png",
"level_cap": 30,
"order": 5,
"after_route_name": "Cianwood City",
"location": "Cianwood Gym",
"section": "Main Story",
"sprite_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/13.png?raw=true",
"sprite_url": "/boss-sprites/crystal/chuck.png",
"pokemon": []
},
{
@@ -74,13 +74,13 @@
"boss_type": "gym_leader",
"specialty_type": "steel",
"badge_name": "Mineral Badge",
"badge_image_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/14.png?raw=true",
"badge_image_url": "/badges/mineral-badge.png",
"level_cap": 35,
"order": 6,
"after_route_name": "Cianwood City",
"location": "Olivine Gym",
"section": "Main Story",
"sprite_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/14.png?raw=true",
"sprite_url": "/boss-sprites/crystal/jasmine.png",
"pokemon": []
},
{
@@ -88,13 +88,13 @@
"boss_type": "gym_leader",
"specialty_type": "ice",
"badge_name": "Glacier Badge",
"badge_image_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/15.png?raw=true",
"badge_image_url": "/badges/glacier-badge.png",
"level_cap": 31,
"order": 7,
"after_route_name": "Lake Of Rage",
"location": "Mahogany Gym",
"section": "Main Story",
"sprite_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/15.png?raw=true",
"sprite_url": "/boss-sprites/crystal/pryce.png",
"pokemon": []
},
{
@@ -102,13 +102,13 @@
"boss_type": "gym_leader",
"specialty_type": "dragon",
"badge_name": "Rising Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/5/58/Rising_Badge.png/35px-Rising_Badge.png",
"badge_image_url": "/badges/rising-badge.png",
"level_cap": 40,
"order": 8,
"after_route_name": "Blackthorn City",
"location": "Blackthorn Gym",
"section": "Main Story",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/5/58/Rising_Badge.png/35px-Rising_Badge.png",
"sprite_url": "/boss-sprites/crystal/clair.png",
"pokemon": []
},
{
@@ -186,13 +186,13 @@
"boss_type": "gym_leader",
"specialty_type": "electric",
"badge_name": "Thunder Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/a/a6/Thunder_Badge.png/35px-Thunder_Badge.png",
"badge_image_url": "/badges/thunder-badge.png",
"level_cap": 46,
"order": 14,
"after_route_name": "Vermilion City",
"location": "Vermilion Gym",
"section": "Endgame",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/a/a6/Thunder_Badge.png/35px-Thunder_Badge.png",
"sprite_url": "/boss-sprites/crystal/lt-surge.png",
"pokemon": []
},
{
@@ -200,13 +200,13 @@
"boss_type": "gym_leader",
"specialty_type": "psychic",
"badge_name": "Marsh Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/6/6b/Marsh_Badge.png/35px-Marsh_Badge.png",
"badge_image_url": "/badges/marsh-badge.png",
"level_cap": 48,
"order": 15,
"after_route_name": "Route 6",
"location": "Saffron Gym",
"section": "Endgame",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/6/6b/Marsh_Badge.png/35px-Marsh_Badge.png",
"sprite_url": "/boss-sprites/crystal/sabrina.png",
"pokemon": []
},
{
@@ -214,13 +214,13 @@
"boss_type": "gym_leader",
"specialty_type": "water",
"badge_name": "Cascade Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/9/9c/Cascade_Badge.png/35px-Cascade_Badge.png",
"badge_image_url": "/badges/cascade-badge.png",
"level_cap": 47,
"order": 16,
"after_route_name": "Cerulean City",
"location": "Cerulean Gym",
"section": "Endgame",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/9/9c/Cascade_Badge.png/35px-Cascade_Badge.png",
"sprite_url": "/boss-sprites/crystal/misty.png",
"pokemon": []
},
{
@@ -228,13 +228,13 @@
"boss_type": "gym_leader",
"specialty_type": "grass",
"badge_name": "Rainbow Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/b/b5/Rainbow_Badge.png/35px-Rainbow_Badge.png",
"badge_image_url": "/badges/rainbow-badge.png",
"level_cap": 46,
"order": 17,
"after_route_name": "Route 7",
"location": "Celadon Gym",
"section": "Endgame",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/b/b5/Rainbow_Badge.png/35px-Rainbow_Badge.png",
"sprite_url": "/boss-sprites/crystal/erika.png",
"pokemon": []
},
{
@@ -242,13 +242,13 @@
"boss_type": "gym_leader",
"specialty_type": "poison",
"badge_name": "Soul Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/7/7d/Soul_Badge.png/35px-Soul_Badge.png",
"badge_image_url": "/badges/soul-badge.png",
"level_cap": 39,
"order": 18,
"after_route_name": "Fuchsia City",
"location": "Fuchsia Gym",
"section": "Endgame",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/7/7d/Soul_Badge.png/35px-Soul_Badge.png",
"sprite_url": "/boss-sprites/crystal/janine.png",
"pokemon": []
},
{
@@ -256,13 +256,13 @@
"boss_type": "gym_leader",
"specialty_type": "rock",
"badge_name": "Boulder Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/d/dd/Boulder_Badge.png/35px-Boulder_Badge.png",
"badge_image_url": "/badges/boulder-badge.png",
"level_cap": 44,
"order": 19,
"after_route_name": "Pewter City",
"location": "Pewter Gym",
"section": "Endgame",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/d/dd/Boulder_Badge.png/35px-Boulder_Badge.png",
"sprite_url": "/boss-sprites/crystal/brock.png",
"pokemon": []
},
{
@@ -270,13 +270,13 @@
"boss_type": "gym_leader",
"specialty_type": "fire",
"badge_name": "Volcano Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/1/12/Volcano_Badge.png/35px-Volcano_Badge.png",
"badge_image_url": "/badges/volcano-badge.png",
"level_cap": 50,
"order": 20,
"after_route_name": "Cinnabar Island",
"location": "Cinnabar Gym",
"section": "Endgame",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/1/12/Volcano_Badge.png/35px-Volcano_Badge.png",
"sprite_url": "/boss-sprites/crystal/blaine.png",
"pokemon": []
},
{
@@ -284,13 +284,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Earth Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/7/78/Earth_Badge.png/35px-Earth_Badge.png",
"badge_image_url": "/badges/earth-badge.png",
"level_cap": 58,
"order": 21,
"after_route_name": null,
"location": "Viridian Gym",
"section": "Endgame",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/7/78/Earth_Badge.png/35px-Earth_Badge.png",
"sprite_url": "/boss-sprites/crystal/blue.png",
"pokemon": []
},
{

View File

@@ -4,13 +4,13 @@
"boss_type": "gym_leader",
"specialty_type": "rock",
"badge_name": "Coal Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/0/0b/Coal_Badge.png/35px-Coal_Badge.png",
"badge_image_url": "/badges/coal-badge.png",
"level_cap": 14,
"order": 1,
"after_route_name": "Oreburgh Mine",
"location": "Oreburgh Gym",
"section": "Main Story",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/0/0b/Coal_Badge.png/35px-Coal_Badge.png",
"sprite_url": "/boss-sprites/diamond/roark.png",
"pokemon": []
}
]

View File

@@ -4,13 +4,13 @@
"boss_type": "gym_leader",
"specialty_type": "rock",
"badge_name": "Stone Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/6/63/Stone_Badge.png/35px-Stone_Badge.png",
"badge_image_url": "/badges/stone-badge.png",
"level_cap": 15,
"order": 1,
"after_route_name": null,
"location": "Rustboro Gym",
"section": "Main Story",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/6/63/Stone_Badge.png/35px-Stone_Badge.png",
"sprite_url": "/boss-sprites/emerald/roxanne.png",
"pokemon": []
},
{
@@ -18,13 +18,13 @@
"boss_type": "gym_leader",
"specialty_type": "fighting",
"badge_name": "Knuckle Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/9/97/Knuckle_Badge.png/35px-Knuckle_Badge.png",
"badge_image_url": "/badges/knuckle-badge.png",
"level_cap": 19,
"order": 2,
"after_route_name": null,
"location": "Dewford Gym",
"section": "Main Story",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/9/97/Knuckle_Badge.png/35px-Knuckle_Badge.png",
"sprite_url": "/boss-sprites/emerald/brawly.png",
"pokemon": []
},
{
@@ -32,13 +32,13 @@
"boss_type": "gym_leader",
"specialty_type": "electric",
"badge_name": "Dynamo Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/3/34/Dynamo_Badge.png/35px-Dynamo_Badge.png",
"badge_image_url": "/badges/dynamo-badge.png",
"level_cap": 24,
"order": 3,
"after_route_name": null,
"location": "Mauville Gym",
"section": "Main Story",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/3/34/Dynamo_Badge.png/35px-Dynamo_Badge.png",
"sprite_url": "/boss-sprites/emerald/wattson.png",
"pokemon": []
},
{
@@ -46,13 +46,13 @@
"boss_type": "gym_leader",
"specialty_type": "fire",
"badge_name": "Heat Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/c/c4/Heat_Badge.png/35px-Heat_Badge.png",
"badge_image_url": "/badges/heat-badge.png",
"level_cap": 29,
"order": 4,
"after_route_name": null,
"location": "Lavaridge Gym",
"section": "Main Story",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/c/c4/Heat_Badge.png/35px-Heat_Badge.png",
"sprite_url": "/boss-sprites/emerald/flannery.png",
"pokemon": []
},
{
@@ -60,13 +60,13 @@
"boss_type": "gym_leader",
"specialty_type": "normal",
"badge_name": "Balance Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/6/63/Balance_Badge.png/35px-Balance_Badge.png",
"badge_image_url": "/badges/balance-badge.png",
"level_cap": 31,
"order": 5,
"after_route_name": null,
"location": "Petalburg Gym",
"section": "Main Story",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/6/63/Balance_Badge.png/35px-Balance_Badge.png",
"sprite_url": "/boss-sprites/emerald/norman.png",
"pokemon": []
},
{
@@ -74,13 +74,13 @@
"boss_type": "gym_leader",
"specialty_type": "flying",
"badge_name": "Feather Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/6/62/Feather_Badge.png/35px-Feather_Badge.png",
"badge_image_url": "/badges/feather-badge.png",
"level_cap": 33,
"order": 6,
"after_route_name": null,
"location": "Foretree Gym",
"section": "Main Story",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/6/62/Feather_Badge.png/35px-Feather_Badge.png",
"sprite_url": "/boss-sprites/emerald/winona.png",
"pokemon": []
},
{
@@ -88,13 +88,13 @@
"boss_type": "gym_leader",
"specialty_type": "psychic",
"badge_name": "Mind Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/c/cc/Mind_Badge.png/35px-Mind_Badge.png",
"badge_image_url": "/badges/mind-badge.png",
"level_cap": 42,
"order": 7,
"after_route_name": null,
"location": "Mossdeep Gym",
"section": "Main Story",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/c/cc/Mind_Badge.png/35px-Mind_Badge.png",
"sprite_url": "/boss-sprites/emerald/tate--lisa.png",
"pokemon": []
},
{
@@ -102,13 +102,13 @@
"boss_type": "gym_leader",
"specialty_type": "water",
"badge_name": "Rain Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/9/9b/Rain_Badge.png/35px-Rain_Badge.png",
"badge_image_url": "/badges/rain-badge.png",
"level_cap": 46,
"order": 8,
"after_route_name": null,
"location": "Sootopolis Gym",
"section": "Main Story",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/9/9b/Rain_Badge.png/35px-Rain_Badge.png",
"sprite_url": "/boss-sprites/emerald/wallace.png",
"pokemon": []
},
{

View File

@@ -4,13 +4,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Boulder Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/d/dd/Boulder_Badge.png/50px-Boulder_Badge.png",
"badge_image_url": "/badges/boulder-badge.png",
"level_cap": 14,
"order": 1,
"after_route_name": null,
"location": "Pewter City Gym",
"section": null,
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/d/dd/Boulder_Badge.png/50px-Boulder_Badge.png",
"sprite_url": "/boss-sprites/firered/brock.png",
"pokemon": [
{
"pokeapi_id": 74,
@@ -31,13 +31,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Cascade Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/9/9c/Cascade_Badge.png/50px-Cascade_Badge.png",
"badge_image_url": "/badges/cascade-badge.png",
"level_cap": 21,
"order": 2,
"after_route_name": null,
"location": "Cerulean City Gym",
"section": null,
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/9/9c/Cascade_Badge.png/50px-Cascade_Badge.png",
"sprite_url": "/boss-sprites/firered/misty.png",
"pokemon": [
{
"pokeapi_id": 120,
@@ -58,13 +58,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Thunder Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/a/a6/Thunder_Badge.png/50px-Thunder_Badge.png",
"badge_image_url": "/badges/thunder-badge.png",
"level_cap": 24,
"order": 3,
"after_route_name": null,
"location": "Vermillion City Gym",
"section": null,
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/a/a6/Thunder_Badge.png/50px-Thunder_Badge.png",
"sprite_url": "/boss-sprites/firered/lt-surge.png",
"pokemon": [
{
"pokeapi_id": 100,
@@ -91,13 +91,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Rainbow Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/b/b5/Rainbow_Badge.png/50px-Rainbow_Badge.png",
"badge_image_url": "/badges/rainbow-badge.png",
"level_cap": 29,
"order": 4,
"after_route_name": null,
"location": "Celadon City Gym",
"section": null,
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/b/b5/Rainbow_Badge.png/50px-Rainbow_Badge.png",
"sprite_url": "/boss-sprites/firered/erika.png",
"pokemon": []
},
{
@@ -105,13 +105,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Marsh Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/6/6b/Marsh_Badge.png/50px-Marsh_Badge.png",
"badge_image_url": "/badges/marsh-badge.png",
"level_cap": 43,
"order": 5,
"after_route_name": null,
"location": "Saffron City Gym",
"section": null,
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/6/6b/Marsh_Badge.png/50px-Marsh_Badge.png",
"sprite_url": "/boss-sprites/firered/sabrina.png",
"pokemon": []
},
{
@@ -119,13 +119,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Soul Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/7/7d/Soul_Badge.png/50px-Soul_Badge.png",
"badge_image_url": "/badges/soul-badge.png",
"level_cap": 43,
"order": 6,
"after_route_name": null,
"location": "Fuchsia City Gym",
"section": null,
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/7/7d/Soul_Badge.png/50px-Soul_Badge.png",
"sprite_url": "/boss-sprites/firered/koga.png",
"pokemon": []
},
{
@@ -133,13 +133,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Volcano Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/1/12/Volcano_Badge.png/50px-Volcano_Badge.png",
"badge_image_url": "/badges/volcano-badge.png",
"level_cap": 47,
"order": 7,
"after_route_name": null,
"location": "Cinnabar Island Gym",
"section": null,
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/1/12/Volcano_Badge.png/50px-Volcano_Badge.png",
"sprite_url": "/boss-sprites/firered/blaine.png",
"pokemon": []
},
{
@@ -147,13 +147,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "50",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/7/78/Earth_Badge.png/50px-Earth_Badge.png",
"badge_image_url": "/badges/50.png",
"level_cap": 50,
"order": 8,
"after_route_name": null,
"location": "Viridian City Gym",
"section": null,
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/7/78/Earth_Badge.png/50px-Earth_Badge.png",
"sprite_url": "/boss-sprites/firered/giovanni.png",
"pokemon": []
},
{
@@ -220,7 +220,7 @@
"badge_image_url": null,
"level_cap": 63,
"order": 13,
"after_route_name": null,
"after_route_name": "Victory Road",
"location": "Indigo Plateau",
"section": null,
"sprite_url": null,
@@ -231,6 +231,24 @@
"level": 59,
"order": 1
},
{
"pokeapi_id": 6,
"pokemon_name": "Charizard",
"level": 63,
"order": 1
},
{
"pokeapi_id": 3,
"pokemon_name": "Venusaur",
"level": 63,
"order": 1
},
{
"pokeapi_id": 9,
"pokemon_name": "Blastoise",
"level": 63,
"order": 1
},
{
"pokeapi_id": 65,
"pokemon_name": "Alakazam",
@@ -254,12 +272,6 @@
"pokemon_name": "Gyarados",
"level": 61,
"order": 5
},
{
"pokeapi_id": 6,
"pokemon_name": "Charizard",
"level": 63,
"order": 6
}
]
}

View File

@@ -4,13 +4,13 @@
"boss_type": "gym_leader",
"specialty_type": "flying",
"badge_name": "Zephyr Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/4/4a/Zephyr_Badge.png/35px-Zephyr_Badge.png",
"badge_image_url": "/badges/zephyr-badge.png",
"level_cap": 9,
"order": 1,
"after_route_name": "Violet City",
"location": "Violet Gym",
"section": "Main Story",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/4/4a/Zephyr_Badge.png/35px-Zephyr_Badge.png",
"sprite_url": "/boss-sprites/gold/falkner.png",
"pokemon": []
},
{
@@ -18,13 +18,13 @@
"boss_type": "gym_leader",
"specialty_type": "bug",
"badge_name": "Hive Badge",
"badge_image_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/10.png?raw=true",
"badge_image_url": "/badges/hive-badge.png",
"level_cap": 16,
"order": 2,
"after_route_name": "Slowpoke Well",
"location": "Azalea Gym",
"section": "Main Story",
"sprite_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/10.png?raw=true",
"sprite_url": "/boss-sprites/gold/bugsy.png",
"pokemon": []
},
{
@@ -32,13 +32,13 @@
"boss_type": "gym_leader",
"specialty_type": "normal",
"badge_name": "Plain Badge",
"badge_image_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/11.png?raw=true",
"badge_image_url": "/badges/plain-badge.png",
"level_cap": 20,
"order": 3,
"after_route_name": "Goldenrod City",
"location": "Goldenrod Gym",
"section": "Main Story",
"sprite_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/11.png?raw=true",
"sprite_url": "/boss-sprites/gold/whitney.png",
"pokemon": []
},
{
@@ -46,13 +46,13 @@
"boss_type": "gym_leader",
"specialty_type": "ghost",
"badge_name": "Fog Badge",
"badge_image_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/12.png?raw=true",
"badge_image_url": "/badges/fog-badge.png",
"level_cap": 25,
"order": 4,
"after_route_name": null,
"location": "Ecruteak Gym",
"section": "Main Story",
"sprite_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/12.png?raw=true",
"sprite_url": "/boss-sprites/gold/morty.png",
"pokemon": []
},
{
@@ -60,13 +60,13 @@
"boss_type": "gym_leader",
"specialty_type": "fighting",
"badge_name": "Storm Badge",
"badge_image_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/13.png?raw=true",
"badge_image_url": "/badges/storm-badge.png",
"level_cap": 30,
"order": 5,
"after_route_name": "Cianwood City",
"location": "Cianwood Gym",
"section": "Main Story",
"sprite_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/13.png?raw=true",
"sprite_url": "/boss-sprites/gold/chuck.png",
"pokemon": []
},
{
@@ -74,13 +74,13 @@
"boss_type": "gym_leader",
"specialty_type": "steel",
"badge_name": "Mineral Badge",
"badge_image_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/14.png?raw=true",
"badge_image_url": "/badges/mineral-badge.png",
"level_cap": 35,
"order": 6,
"after_route_name": "Cianwood City",
"location": "Olivine Gym",
"section": "Main Story",
"sprite_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/14.png?raw=true",
"sprite_url": "/boss-sprites/gold/jasmine.png",
"pokemon": []
},
{
@@ -88,13 +88,13 @@
"boss_type": "gym_leader",
"specialty_type": "ice",
"badge_name": "Glacier Badge",
"badge_image_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/15.png?raw=true",
"badge_image_url": "/badges/glacier-badge.png",
"level_cap": 31,
"order": 7,
"after_route_name": "Lake Of Rage",
"location": "Mahogany Gym",
"section": "Main Story",
"sprite_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/15.png?raw=true",
"sprite_url": "/boss-sprites/gold/pryce.png",
"pokemon": []
},
{
@@ -102,13 +102,13 @@
"boss_type": "gym_leader",
"specialty_type": "dragon",
"badge_name": "Rising Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/5/58/Rising_Badge.png/35px-Rising_Badge.png",
"badge_image_url": "/badges/rising-badge.png",
"level_cap": 40,
"order": 8,
"after_route_name": "Blackthorn City",
"location": "Blackthorn Gym",
"section": "Main Story",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/5/58/Rising_Badge.png/35px-Rising_Badge.png",
"sprite_url": "/boss-sprites/gold/clair.png",
"pokemon": []
},
{
@@ -186,13 +186,13 @@
"boss_type": "gym_leader",
"specialty_type": "electric",
"badge_name": "Thunder Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/a/a6/Thunder_Badge.png/35px-Thunder_Badge.png",
"badge_image_url": "/badges/thunder-badge.png",
"level_cap": 46,
"order": 14,
"after_route_name": "Vermilion City",
"location": "Vermilion Gym",
"section": "Endgame",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/a/a6/Thunder_Badge.png/35px-Thunder_Badge.png",
"sprite_url": "/boss-sprites/gold/lt-surge.png",
"pokemon": []
},
{
@@ -200,13 +200,13 @@
"boss_type": "gym_leader",
"specialty_type": "psychic",
"badge_name": "Marsh Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/6/6b/Marsh_Badge.png/35px-Marsh_Badge.png",
"badge_image_url": "/badges/marsh-badge.png",
"level_cap": 48,
"order": 15,
"after_route_name": "Route 6",
"location": "Saffron Gym",
"section": "Endgame",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/6/6b/Marsh_Badge.png/35px-Marsh_Badge.png",
"sprite_url": "/boss-sprites/gold/sabrina.png",
"pokemon": []
},
{
@@ -214,13 +214,13 @@
"boss_type": "gym_leader",
"specialty_type": "water",
"badge_name": "Cascade Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/9/9c/Cascade_Badge.png/35px-Cascade_Badge.png",
"badge_image_url": "/badges/cascade-badge.png",
"level_cap": 47,
"order": 16,
"after_route_name": "Cerulean City",
"location": "Cerulean Gym",
"section": "Endgame",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/9/9c/Cascade_Badge.png/35px-Cascade_Badge.png",
"sprite_url": "/boss-sprites/gold/misty.png",
"pokemon": []
},
{
@@ -228,13 +228,13 @@
"boss_type": "gym_leader",
"specialty_type": "grass",
"badge_name": "Rainbow Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/b/b5/Rainbow_Badge.png/35px-Rainbow_Badge.png",
"badge_image_url": "/badges/rainbow-badge.png",
"level_cap": 46,
"order": 17,
"after_route_name": "Route 7",
"location": "Celadon Gym",
"section": "Endgame",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/b/b5/Rainbow_Badge.png/35px-Rainbow_Badge.png",
"sprite_url": "/boss-sprites/gold/erika.png",
"pokemon": []
},
{
@@ -242,13 +242,13 @@
"boss_type": "gym_leader",
"specialty_type": "poison",
"badge_name": "Soul Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/7/7d/Soul_Badge.png/35px-Soul_Badge.png",
"badge_image_url": "/badges/soul-badge.png",
"level_cap": 39,
"order": 18,
"after_route_name": "Fuchsia City",
"location": "Fuchsia Gym",
"section": "Endgame",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/7/7d/Soul_Badge.png/35px-Soul_Badge.png",
"sprite_url": "/boss-sprites/gold/janine.png",
"pokemon": []
},
{
@@ -256,13 +256,13 @@
"boss_type": "gym_leader",
"specialty_type": "rock",
"badge_name": "Boulder Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/d/dd/Boulder_Badge.png/35px-Boulder_Badge.png",
"badge_image_url": "/badges/boulder-badge.png",
"level_cap": 44,
"order": 19,
"after_route_name": "Pewter City",
"location": "Pewter Gym",
"section": "Endgame",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/d/dd/Boulder_Badge.png/35px-Boulder_Badge.png",
"sprite_url": "/boss-sprites/gold/brock.png",
"pokemon": []
},
{
@@ -270,13 +270,13 @@
"boss_type": "gym_leader",
"specialty_type": "fire",
"badge_name": "Volcano Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/1/12/Volcano_Badge.png/35px-Volcano_Badge.png",
"badge_image_url": "/badges/volcano-badge.png",
"level_cap": 50,
"order": 20,
"after_route_name": "Cinnabar Island",
"location": "Cinnabar Gym",
"section": "Endgame",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/1/12/Volcano_Badge.png/35px-Volcano_Badge.png",
"sprite_url": "/boss-sprites/gold/blaine.png",
"pokemon": []
},
{
@@ -284,13 +284,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Earth Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/7/78/Earth_Badge.png/35px-Earth_Badge.png",
"badge_image_url": "/badges/earth-badge.png",
"level_cap": 58,
"order": 21,
"after_route_name": null,
"location": "Viridian Gym",
"section": "Endgame",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/7/78/Earth_Badge.png/35px-Earth_Badge.png",
"sprite_url": "/boss-sprites/gold/blue.png",
"pokemon": []
},
{

View File

@@ -4,13 +4,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Zephyr Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/4/4a/Zephyr_Badge.png/35px-Zephyr_Badge.png",
"badge_image_url": "/badges/zephyr-badge.png",
"level_cap": 13,
"order": 1,
"after_route_name": null,
"location": "Violet Gym",
"section": "Main Story",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/4/4a/Zephyr_Badge.png/35px-Zephyr_Badge.png",
"sprite_url": "/boss-sprites/heartgold/falkner.png",
"pokemon": []
},
{
@@ -18,13 +18,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Hive Badge",
"badge_image_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/10.png?raw=true",
"badge_image_url": "/badges/hive-badge.png",
"level_cap": 17,
"order": 2,
"after_route_name": null,
"location": "Azalea Gym",
"section": "Main Story",
"sprite_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/10.png?raw=true",
"sprite_url": "/boss-sprites/heartgold/bugsy.png",
"pokemon": []
},
{
@@ -32,13 +32,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Plain Badge",
"badge_image_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/11.png?raw=true",
"badge_image_url": "/badges/plain-badge.png",
"level_cap": 19,
"order": 3,
"after_route_name": null,
"location": "Goldenrod Gym",
"section": "Main Story",
"sprite_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/11.png?raw=true",
"sprite_url": "/boss-sprites/heartgold/whitney.png",
"pokemon": []
},
{
@@ -46,13 +46,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Fog Badge",
"badge_image_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/12.png?raw=true",
"badge_image_url": "/badges/fog-badge.png",
"level_cap": 25,
"order": 4,
"after_route_name": null,
"location": "Ecruteak Gym",
"section": "Main Story",
"sprite_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/12.png?raw=true",
"sprite_url": "/boss-sprites/heartgold/morty.png",
"pokemon": []
},
{
@@ -60,13 +60,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Storm Badge",
"badge_image_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/13.png?raw=true",
"badge_image_url": "/badges/storm-badge.png",
"level_cap": 31,
"order": 5,
"after_route_name": null,
"location": "Cianwood Gym",
"section": "Main Story",
"sprite_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/13.png?raw=true",
"sprite_url": "/boss-sprites/heartgold/chuck.png",
"pokemon": []
},
{
@@ -74,13 +74,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Mineral Badge",
"badge_image_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/14.png?raw=true",
"badge_image_url": "/badges/mineral-badge.png",
"level_cap": 35,
"order": 6,
"after_route_name": null,
"location": "Olivine Gym",
"section": "Main Story",
"sprite_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/14.png?raw=true",
"sprite_url": "/boss-sprites/heartgold/jasmine.png",
"pokemon": []
},
{
@@ -88,13 +88,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Glacier Badge",
"badge_image_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/15.png?raw=true",
"badge_image_url": "/badges/glacier-badge.png",
"level_cap": 34,
"order": 7,
"after_route_name": null,
"location": "Mahogany Gym",
"section": "Main Story",
"sprite_url": "https://github.com/PokeAPI/sprites/blob/master/sprites/badges/15.png?raw=true",
"sprite_url": "/boss-sprites/heartgold/pryce.png",
"pokemon": []
},
{
@@ -102,13 +102,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Rising Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/5/58/Rising_Badge.png/35px-Rising_Badge.png",
"badge_image_url": "/badges/rising-badge.png",
"level_cap": 41,
"order": 8,
"after_route_name": null,
"location": "Blackthorn Gym",
"section": "Main Story",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/5/58/Rising_Badge.png/35px-Rising_Badge.png",
"sprite_url": "/boss-sprites/heartgold/clair.png",
"pokemon": []
},
{
@@ -186,13 +186,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Boulder Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/d/dd/Boulder_Badge.png/35px-Boulder_Badge.png",
"badge_image_url": "/badges/boulder-badge.png",
"level_cap": 54,
"order": 14,
"after_route_name": null,
"location": "Pewter Gym",
"section": "Endgame",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/d/dd/Boulder_Badge.png/35px-Boulder_Badge.png",
"sprite_url": "/boss-sprites/heartgold/brock.png",
"pokemon": []
},
{
@@ -200,13 +200,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Cascade Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/9/9c/Cascade_Badge.png/35px-Cascade_Badge.png",
"badge_image_url": "/badges/cascade-badge.png",
"level_cap": 54,
"order": 15,
"after_route_name": null,
"location": "Cerulean Gym",
"section": "Endgame",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/9/9c/Cascade_Badge.png/35px-Cascade_Badge.png",
"sprite_url": "/boss-sprites/heartgold/misty.png",
"pokemon": []
},
{
@@ -214,13 +214,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Thunder Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/a/a6/Thunder_Badge.png/35px-Thunder_Badge.png",
"badge_image_url": "/badges/thunder-badge.png",
"level_cap": 53,
"order": 16,
"after_route_name": null,
"location": "Vermilion Gym",
"section": "Endgame",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/a/a6/Thunder_Badge.png/35px-Thunder_Badge.png",
"sprite_url": "/boss-sprites/heartgold/lt-surge.png",
"pokemon": []
},
{
@@ -228,13 +228,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Rainbow Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/b/b5/Rainbow_Badge.png/35px-Rainbow_Badge.png",
"badge_image_url": "/badges/rainbow-badge.png",
"level_cap": 56,
"order": 17,
"after_route_name": null,
"location": "Celadon Gym",
"section": "Endgame",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/b/b5/Rainbow_Badge.png/35px-Rainbow_Badge.png",
"sprite_url": "/boss-sprites/heartgold/erika.png",
"pokemon": []
},
{
@@ -242,13 +242,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Soul Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/7/7d/Soul_Badge.png/35px-Soul_Badge.png",
"badge_image_url": "/badges/soul-badge.png",
"level_cap": 50,
"order": 18,
"after_route_name": null,
"location": "Fuchsia Gym",
"section": "Endgame",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/7/7d/Soul_Badge.png/35px-Soul_Badge.png",
"sprite_url": "/boss-sprites/heartgold/janine.png",
"pokemon": []
},
{
@@ -256,13 +256,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Marsh Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/6/6b/Marsh_Badge.png/35px-Marsh_Badge.png",
"badge_image_url": "/badges/marsh-badge.png",
"level_cap": 55,
"order": 19,
"after_route_name": null,
"location": "Saffron Gym",
"section": "Endgame",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/6/6b/Marsh_Badge.png/35px-Marsh_Badge.png",
"sprite_url": "/boss-sprites/heartgold/sabrina.png",
"pokemon": []
},
{
@@ -270,13 +270,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Volcano Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/1/12/Volcano_Badge.png/35px-Volcano_Badge.png",
"badge_image_url": "/badges/volcano-badge.png",
"level_cap": 59,
"order": 20,
"after_route_name": null,
"location": "Cinnabar Gym",
"section": "Endgame",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/1/12/Volcano_Badge.png/35px-Volcano_Badge.png",
"sprite_url": "/boss-sprites/heartgold/blaine.png",
"pokemon": []
},
{
@@ -284,13 +284,13 @@
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Earth Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/7/78/Earth_Badge.png/35px-Earth_Badge.png",
"badge_image_url": "/badges/earth-badge.png",
"level_cap": 60,
"order": 21,
"after_route_name": null,
"location": "Viridian Gym",
"section": "Endgame",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/7/78/Earth_Badge.png/35px-Earth_Badge.png",
"sprite_url": "/boss-sprites/heartgold/blue.png",
"pokemon": []
},
{

View File

@@ -4,13 +4,13 @@
"boss_type": "gym_leader",
"specialty_type": "rock",
"badge_name": "Boulder Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/d/dd/Boulder_Badge.png/35px-Boulder_Badge.png",
"badge_image_url": "/badges/boulder-badge.png",
"level_cap": 14,
"order": 1,
"after_route_name": "Route 2 (South Towards Viridian City)",
"location": "Pewter Gym",
"section": null,
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/d/dd/Boulder_Badge.png/35px-Boulder_Badge.png",
"sprite_url": "/boss-sprites/red/brock.png",
"pokemon": []
},
{
@@ -18,13 +18,13 @@
"boss_type": "gym_leader",
"specialty_type": "water",
"badge_name": "Cascade Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/9/9c/Cascade_Badge.png/35px-Cascade_Badge.png",
"badge_image_url": "/badges/cascade-badge.png",
"level_cap": 21,
"order": 2,
"after_route_name": "Cerulean City",
"location": "Cerulean Gem",
"section": null,
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/9/9c/Cascade_Badge.png/35px-Cascade_Badge.png",
"sprite_url": "/boss-sprites/red/misty.png",
"pokemon": []
},
{
@@ -32,13 +32,13 @@
"boss_type": "gym_leader",
"specialty_type": "electric",
"badge_name": "Thunder Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/a/a6/Thunder_Badge.png/35px-Thunder_Badge.png",
"badge_image_url": "/badges/thunder-badge.png",
"level_cap": 24,
"order": 3,
"after_route_name": "Vermilion City",
"location": "Vermillion Gym",
"section": null,
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/a/a6/Thunder_Badge.png/35px-Thunder_Badge.png",
"sprite_url": "/boss-sprites/red/lt-surge.png",
"pokemon": []
},
{
@@ -46,13 +46,13 @@
"boss_type": "gym_leader",
"specialty_type": "grass",
"badge_name": "Rainbow Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/b/b5/Rainbow_Badge.png/35px-Rainbow_Badge.png",
"badge_image_url": "/badges/rainbow-badge.png",
"level_cap": 29,
"order": 4,
"after_route_name": "Celadon City",
"location": "Celadon Gym",
"section": null,
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/b/b5/Rainbow_Badge.png/35px-Rainbow_Badge.png",
"sprite_url": "/boss-sprites/red/erika.png",
"pokemon": []
},
{
@@ -60,13 +60,13 @@
"boss_type": "gym_leader",
"specialty_type": "psychic",
"badge_name": "Marsh Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/6/6b/Marsh_Badge.png/35px-Marsh_Badge.png",
"badge_image_url": "/badges/marsh-badge.png",
"level_cap": 43,
"order": 5,
"after_route_name": "Saffron City",
"location": "Saffron Gym",
"section": null,
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/6/6b/Marsh_Badge.png/35px-Marsh_Badge.png",
"sprite_url": "/boss-sprites/red/sabrina.png",
"pokemon": []
},
{
@@ -74,13 +74,13 @@
"boss_type": "gym_leader",
"specialty_type": "poison",
"badge_name": "Soul Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/7/7d/Soul_Badge.png/35px-Soul_Badge.png",
"badge_image_url": "/badges/soul-badge.png",
"level_cap": 43,
"order": 6,
"after_route_name": "Fuchsia City",
"location": "Fuchsia Gym",
"section": null,
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/7/7d/Soul_Badge.png/35px-Soul_Badge.png",
"sprite_url": "/boss-sprites/red/koga.png",
"pokemon": []
},
{
@@ -88,13 +88,13 @@
"boss_type": "gym_leader",
"specialty_type": "fire",
"badge_name": "Volcano Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/1/12/Volcano_Badge.png/35px-Volcano_Badge.png",
"badge_image_url": "/badges/volcano-badge.png",
"level_cap": 47,
"order": 7,
"after_route_name": "Cinnabar Island",
"location": "Cinnabar Gym",
"section": null,
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/1/12/Volcano_Badge.png/35px-Volcano_Badge.png",
"sprite_url": "/boss-sprites/red/blaine.png",
"pokemon": []
},
{
@@ -102,13 +102,13 @@
"boss_type": "gym_leader",
"specialty_type": "ground",
"badge_name": "Earth Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/7/78/Earth_Badge.png/35px-Earth_Badge.png",
"badge_image_url": "/badges/earth-badge.png",
"level_cap": 50,
"order": 8,
"after_route_name": null,
"location": "Viridian Gym",
"section": null,
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/7/78/Earth_Badge.png/35px-Earth_Badge.png",
"sprite_url": "/boss-sprites/red/giovanni.png",
"pokemon": []
},
{

View File

@@ -4,13 +4,13 @@
"boss_type": "gym_leader",
"specialty_type": "rock",
"badge_name": "Stone Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/6/63/Stone_Badge.png/35px-Stone_Badge.png",
"badge_image_url": "/badges/stone-badge.png",
"level_cap": 15,
"order": 1,
"after_route_name": "Rustboro City",
"location": "Rustboro Gym",
"section": "Main Story",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/6/63/Stone_Badge.png/35px-Stone_Badge.png",
"sprite_url": "/boss-sprites/ruby/roxanne.png",
"pokemon": []
},
{
@@ -18,13 +18,13 @@
"boss_type": "gym_leader",
"specialty_type": "fighting",
"badge_name": "Knuckle Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/9/97/Knuckle_Badge.png/35px-Knuckle_Badge.png",
"badge_image_url": "/badges/knuckle-badge.png",
"level_cap": 18,
"order": 2,
"after_route_name": "Dewford Town",
"location": "Dewford Gym",
"section": "Main Story",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/9/97/Knuckle_Badge.png/35px-Knuckle_Badge.png",
"sprite_url": "/boss-sprites/ruby/brawly.png",
"pokemon": []
},
{
@@ -32,13 +32,13 @@
"boss_type": "gym_leader",
"specialty_type": "electric",
"badge_name": "Dynamo Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/3/34/Dynamo_Badge.png/35px-Dynamo_Badge.png",
"badge_image_url": "/badges/dynamo-badge.png",
"level_cap": 23,
"order": 3,
"after_route_name": "Route 110",
"location": "Mauville Gym",
"section": "Main Story",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/3/34/Dynamo_Badge.png/35px-Dynamo_Badge.png",
"sprite_url": "/boss-sprites/ruby/wattson.png",
"pokemon": []
},
{
@@ -46,13 +46,13 @@
"boss_type": "gym_leader",
"specialty_type": "fire",
"badge_name": "Heat Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/c/c4/Heat_Badge.png/35px-Heat_Badge.png",
"badge_image_url": "/badges/heat-badge.png",
"level_cap": 28,
"order": 4,
"after_route_name": "Lavaridge Town",
"location": "Lavaridge Gym",
"section": "Main Story",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/c/c4/Heat_Badge.png/35px-Heat_Badge.png",
"sprite_url": "/boss-sprites/ruby/flannery.png",
"pokemon": []
},
{
@@ -60,13 +60,13 @@
"boss_type": "gym_leader",
"specialty_type": "normal",
"badge_name": "Balance Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/6/63/Balance_Badge.png/35px-Balance_Badge.png",
"badge_image_url": "/badges/balance-badge.png",
"level_cap": 31,
"order": 5,
"after_route_name": "Route 115",
"location": "Petalburg Gym",
"section": "Main Story",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/6/63/Balance_Badge.png/35px-Balance_Badge.png",
"sprite_url": "/boss-sprites/ruby/norman.png",
"pokemon": []
},
{
@@ -74,13 +74,13 @@
"boss_type": "gym_leader",
"specialty_type": "flying",
"badge_name": "Feather Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/6/62/Feather_Badge.png/35px-Feather_Badge.png",
"badge_image_url": "/badges/feather-badge.png",
"level_cap": 33,
"order": 6,
"after_route_name": "Route 119",
"location": "Foretree Gym",
"section": "Main Story",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/6/62/Feather_Badge.png/35px-Feather_Badge.png",
"sprite_url": "/boss-sprites/ruby/winona.png",
"pokemon": []
},
{
@@ -88,13 +88,13 @@
"boss_type": "gym_leader",
"specialty_type": "psychic",
"badge_name": "Mind Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/c/cc/Mind_Badge.png/35px-Mind_Badge.png",
"badge_image_url": "/badges/mind-badge.png",
"level_cap": 42,
"order": 7,
"after_route_name": "Mossdeep City",
"location": "Mossdeep Gym",
"section": "Main Story",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/c/cc/Mind_Badge.png/35px-Mind_Badge.png",
"sprite_url": "/boss-sprites/ruby/tate--lisa.png",
"pokemon": []
},
{
@@ -102,13 +102,13 @@
"boss_type": "gym_leader",
"specialty_type": "water",
"badge_name": "Rain Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/9/9b/Rain_Badge.png/35px-Rain_Badge.png",
"badge_image_url": "/badges/rain-badge.png",
"level_cap": 43,
"order": 8,
"after_route_name": "Sootopolis City",
"location": "Sootopolis Gym",
"section": "Main Story",
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/9/9b/Rain_Badge.png/35px-Rain_Badge.png",
"sprite_url": "/boss-sprites/ruby/wallace.png",
"pokemon": []
},
{

View File

@@ -4,13 +4,13 @@
"boss_type": "gym_leader",
"specialty_type": "rock",
"badge_name": "Boulder Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/d/dd/Boulder_Badge.png/35px-Boulder_Badge.png",
"badge_image_url": "/badges/boulder-badge.png",
"level_cap": 12,
"order": 1,
"after_route_name": null,
"location": "Pewter Gym",
"section": null,
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/d/dd/Boulder_Badge.png/35px-Boulder_Badge.png",
"sprite_url": "/boss-sprites/yellow/brock.png",
"pokemon": []
},
{
@@ -18,13 +18,13 @@
"boss_type": "gym_leader",
"specialty_type": "water",
"badge_name": "Cascade Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/9/9c/Cascade_Badge.png/35px-Cascade_Badge.png",
"badge_image_url": "/badges/cascade-badge.png",
"level_cap": 21,
"order": 2,
"after_route_name": null,
"location": "Cerulean Gem",
"section": null,
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/9/9c/Cascade_Badge.png/35px-Cascade_Badge.png",
"sprite_url": "/boss-sprites/yellow/misty.png",
"pokemon": []
},
{
@@ -32,13 +32,13 @@
"boss_type": "gym_leader",
"specialty_type": "electric",
"badge_name": "Thunder Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/a/a6/Thunder_Badge.png/35px-Thunder_Badge.png",
"badge_image_url": "/badges/thunder-badge.png",
"level_cap": 28,
"order": 3,
"after_route_name": null,
"location": "Vermillion Gym",
"section": null,
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/a/a6/Thunder_Badge.png/35px-Thunder_Badge.png",
"sprite_url": "/boss-sprites/yellow/lt-surge.png",
"pokemon": []
},
{
@@ -46,13 +46,13 @@
"boss_type": "gym_leader",
"specialty_type": "grass",
"badge_name": "Rainbow Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/b/b5/Rainbow_Badge.png/35px-Rainbow_Badge.png",
"badge_image_url": "/badges/rainbow-badge.png",
"level_cap": 32,
"order": 4,
"after_route_name": null,
"location": "Celadon Gym",
"section": null,
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/b/b5/Rainbow_Badge.png/35px-Rainbow_Badge.png",
"sprite_url": "/boss-sprites/yellow/erika.png",
"pokemon": []
},
{
@@ -60,13 +60,13 @@
"boss_type": "gym_leader",
"specialty_type": "psychic",
"badge_name": "Marsh Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/6/6b/Marsh_Badge.png/35px-Marsh_Badge.png",
"badge_image_url": "/badges/marsh-badge.png",
"level_cap": 50,
"order": 5,
"after_route_name": null,
"location": "Saffron Gym",
"section": null,
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/6/6b/Marsh_Badge.png/35px-Marsh_Badge.png",
"sprite_url": "/boss-sprites/yellow/sabrina.png",
"pokemon": []
},
{
@@ -74,13 +74,13 @@
"boss_type": "gym_leader",
"specialty_type": "poison",
"badge_name": "Soul Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/7/7d/Soul_Badge.png/35px-Soul_Badge.png",
"badge_image_url": "/badges/soul-badge.png",
"level_cap": 50,
"order": 6,
"after_route_name": null,
"location": "Fuchsia Gym",
"section": null,
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/7/7d/Soul_Badge.png/35px-Soul_Badge.png",
"sprite_url": "/boss-sprites/yellow/koga.png",
"pokemon": []
},
{
@@ -88,13 +88,13 @@
"boss_type": "gym_leader",
"specialty_type": "fire",
"badge_name": "Volcano Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/1/12/Volcano_Badge.png/35px-Volcano_Badge.png",
"badge_image_url": "/badges/volcano-badge.png",
"level_cap": 54,
"order": 7,
"after_route_name": null,
"location": "Cinnabar Gym",
"section": null,
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/1/12/Volcano_Badge.png/35px-Volcano_Badge.png",
"sprite_url": "/boss-sprites/yellow/blaine.png",
"pokemon": []
},
{
@@ -102,13 +102,13 @@
"boss_type": "gym_leader",
"specialty_type": "ground",
"badge_name": "Earth Badge",
"badge_image_url": "https://archives.bulbagarden.net/media/upload/thumb/7/78/Earth_Badge.png/35px-Earth_Badge.png",
"badge_image_url": "/badges/earth-badge.png",
"level_cap": 55,
"order": 8,
"after_route_name": null,
"location": "Viridian Gym",
"section": null,
"sprite_url": "https://archives.bulbagarden.net/media/upload/thumb/7/78/Earth_Badge.png/35px-Earth_Badge.png",
"sprite_url": "/boss-sprites/yellow/giovanni.png",
"pokemon": []
},
{

View File

@@ -1,6 +1,8 @@
"""Seed runner — reads JSON files and upserts into the database."""
import json
import re
import urllib.request
from pathlib import Path
from sqlalchemy import func, select
@@ -403,11 +405,58 @@ async def _export_routes(session: AsyncSession, vg_data: dict):
print(f"Routes: {exported} game files exported")
FRONTEND_PUBLIC = Path(__file__).resolve().parents[4] / "frontend" / "public"
def _slugify(name: str) -> str:
"""Convert a name to a filename-safe slug: lowercase, hyphens, no special chars."""
slug = name.lower().replace(" ", "-")
slug = re.sub(r"[^a-z0-9-]", "", slug)
return slug
def _download_image(
url: str,
output_dir: Path,
slug: str,
downloaded: set[str],
) -> str:
"""Download an image to output_dir/slug.ext if not already downloaded.
Returns the local path (relative to frontend/public).
"""
url_ext = url.rsplit(".", 1)[-1].split("?")[0].lower()
if url_ext in ("png", "jpg", "jpeg", "gif", "webp", "svg"):
ext = f".{url_ext}"
else:
ext = ".png"
filename = f"{slug}{ext}"
dest = output_dir / filename
if filename not in downloaded:
output_dir.mkdir(parents=True, exist_ok=True)
req = urllib.request.Request(url, headers={"User-Agent": "nuzlocke-tracker/1.0"})
try:
with urllib.request.urlopen(req, timeout=30) as resp:
dest.write_bytes(resp.read())
except (urllib.error.URLError, OSError) as exc:
print(f" Warning: failed to download {url}: {exc}")
return url
downloaded.add(filename)
print(f" Downloaded: {dest.relative_to(FRONTEND_PUBLIC)}")
return f"/{dest.relative_to(FRONTEND_PUBLIC)}"
async def _export_bosses(session: AsyncSession, vg_data: dict):
"""Export boss battles per version group."""
vg_result = await session.execute(select(VersionGroup))
slug_to_vg = {vg.slug: vg for vg in vg_result.scalars().all()}
badge_dir = FRONTEND_PUBLIC / "badges"
downloaded_badges: set[str] = set()
exported = 0
for vg_slug, vg_info in vg_data.items():
vg = slug_to_vg.get(vg_slug)
@@ -429,19 +478,37 @@ async def _export_bosses(session: AsyncSession, vg_data: dict):
continue
first_game_slug = list(vg_info["games"].keys())[0]
data = [
{
sprite_dir = FRONTEND_PUBLIC / "boss-sprites" / first_game_slug
downloaded_sprites: set[str] = set()
data = []
for b in bosses:
badge_image_url = b.badge_image_url
sprite_url = b.sprite_url
if badge_image_url and b.badge_name:
badge_slug = _slugify(b.badge_name)
badge_image_url = _download_image(
badge_image_url, badge_dir, badge_slug, downloaded_badges,
)
if sprite_url:
sprite_slug = _slugify(b.name)
sprite_url = _download_image(
sprite_url, sprite_dir, sprite_slug, downloaded_sprites,
)
data.append({
"name": b.name,
"boss_type": b.boss_type,
"specialty_type": b.specialty_type,
"badge_name": b.badge_name,
"badge_image_url": b.badge_image_url,
"badge_image_url": badge_image_url,
"level_cap": b.level_cap,
"order": b.order,
"after_route_name": b.after_route.name if b.after_route else None,
"location": b.location,
"section": b.section,
"sprite_url": b.sprite_url,
"sprite_url": sprite_url,
"pokemon": [
{
"pokeapi_id": bp.pokemon.pokeapi_id,
@@ -451,9 +518,7 @@ async def _export_bosses(session: AsyncSession, vg_data: dict):
}
for bp in sorted(b.pokemon, key=lambda p: p.order)
],
}
for b in bosses
]
})
_write_json(f"{first_game_slug}-bosses.json", data)
exported += 1