develop #19

Merged
TheFurya merged 17 commits from develop into main 2026-02-13 09:32:50 +01:00
82 changed files with 246752 additions and 340964 deletions
@@ -0,0 +1,10 @@
---
# nuzlocke-tracker-36wg
title: Make footer stick to bottom of viewport
status: todo
type: bug
created_at: 2026-02-13T07:47:48Z
updated_at: 2026-02-13T07:47:48Z
---
On pages with little content, the footer appears right after the content instead of staying at the bottom of the viewport. The footer should always be at the bottom of the browser window, pushing down when there's enough content but not floating in the middle of the page when content is short (sticky footer pattern).
@@ -0,0 +1,35 @@
---
# nuzlocke-tracker-bi4e
title: Integrate name suggestions into encounter registration UI
status: completed
type: task
priority: normal
created_at: 2026-02-11T15:56:44Z
updated_at: 2026-02-11T20:48:02Z
parent: nuzlocke-tracker-igl3
---
Show name suggestions in the encounter registration flow so users can pick a nickname with a single click.
## Requirements
- When a user registers a new Pokemon encounter, display 5-10 name suggestions below/near the nickname input
- Each suggestion is a clickable chip/button that fills in the nickname field
- Include a "regenerate" button to get a fresh batch of suggestions
- Only show suggestions if the run has a naming scheme selected
- The nickname input should still be editable for manual entry
## Implementation Notes
- **Data fetching**: Call `GET /api/v1/runs/{run_id}/name-suggestions?count=10` to get suggestions from the backend.
- **Regeneration**: Each call to the endpoint returns a fresh random batch (backend handles exclusion of used names).
- **No dictionary data in frontend**: All suggestion logic lives in the backend.
## Checklist
- [x] Add a name suggestions component (chips/buttons with regenerate)
- [x] Integrate the component into the encounter registration modal/form
- [x] Wire up the backend API endpoint to the component via React Query
- [x] Ensure clicking a suggestion populates the nickname field
- [x] Ensure regenerate fetches a new batch from the API
- [x] Hide suggestions gracefully if no naming scheme is set on the run
@@ -0,0 +1,36 @@
---
# nuzlocke-tracker-c6ly
title: Build name suggestion engine
status: completed
type: task
priority: normal
created_at: 2026-02-11T15:56:44Z
updated_at: 2026-02-11T20:44:27Z
parent: nuzlocke-tracker-igl3
blocking:
- nuzlocke-tracker-bi4e
---
Build the backend service and API endpoint that picks random name suggestions from the dictionary based on a selected naming scheme.
## Requirements
- Given a category and a run ID, return 5-10 unique suggestions
- The engine queries the run's existing encounter nicknames and excludes them from suggestions
- Support regeneration (return a fresh batch, avoiding previously shown suggestions where possible)
- Handle edge case where category is nearly exhausted gracefully (return fewer suggestions)
## Implementation Notes
- **Backend service**: A Python module that loads the dictionary JSON, filters by category, excludes used names, and picks random suggestions.
- **API endpoint**: `GET /api/v1/runs/{run_id}/name-suggestions?count=10` — reads the run's `naming_scheme`, fetches encounter nicknames, returns suggestions.
- **No new DB tables needed**: Used names come from `Encounter.nickname` on the run's encounters.
- **Caching**: Load the dictionary once and cache in memory (it's static data).
## Checklist
- [x] Create a service module for name suggestion logic (e.g. `services/name_suggestions.py`)
- [x] Implement dictionary loading with in-memory caching
- [x] Implement random selection from a category with exclusion of used names
- [x] Add API endpoint for fetching suggestions
- [x] Add unit tests for the suggestion logic
@@ -1,11 +1,34 @@
--- ---
# nuzlocke-tracker-igl3 # nuzlocke-tracker-igl3
title: Name Generation title: Name Generation
status: draft status: completed
type: epic type: epic
priority: deferred priority: normal
created_at: 2026-02-05T13:45:15Z created_at: 2026-02-05T13:45:15Z
updated_at: 2026-02-10T12:05:44Z updated_at: 2026-02-11T20:48:02Z
--- ---
For nuzlockes I want to implement name generation. The user should be able to provide a naming scheme or a list of nick names that can then be selected when a new encounter is registered. Implement a dictionary-based nickname generation system for Nuzlocke runs. Instead of using an LLM API to generate names on the fly, provide a static dictionary of words categorised by theme. A word can belong to multiple categories, making it usable across different naming schemes.
## Architecture Decisions
- **Dictionary storage**: Static JSON file in `backend/src/app/seeds/data/`, alongside other seed data. Not exposed to frontend directly.
- **Dictionary format**: Category-keyed structure (`{ "mythology": ["Apollo", ...], "space": ["Nova", ...] }`) for fast lookup by naming scheme. Words may appear in multiple categories.
- **Suggestion logic**: Backend service with API endpoint. Frontend calls the backend to get suggestions.
- **Used-name tracking**: No new storage needed. The existing `Encounter.nickname` field already tracks assigned names. The suggestion engine queries encounter nicknames for the current run and excludes them.
- **Naming scheme per run**: Dedicated nullable `naming_scheme` column on `NuzlockeRun` (not in the `rules` JSONB).
## Approach
- **Static dictionary**: A local data file (JSON) containing words organised by category (e.g. mythology, food, space, nature, warriors, music, etc.)
- **~150-200 words per category**: A typical Nuzlocke has ~100 encounters, so this provides ample variety without repetition.
- **Name suggestion UX**: When registering a new encounter, the user is shown 5-10 suggested names from their chosen naming scheme. They can click one to select it, or regenerate for a fresh batch.
- **Naming scheme selection**: Users pick a naming scheme (category) per run, either at run creation or in run settings.
## Success Criteria
- [x] Word dictionary data file exists with multiple categories, each containing 150-200 words
- [x] Name suggestion engine picks random names from the selected category, avoiding duplicates already used in the run
- [x] Encounter registration UI shows 5-10 clickable name suggestions
- [x] User can regenerate suggestions if none fit
- [x] User can select a naming scheme per run
@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-l272
title: Add boss data to seed files for all games
status: completed
type: feature
priority: normal
created_at: 2026-02-11T20:23:20Z
updated_at: 2026-02-11T20:31:27Z
---
Add gym leaders, Elite Four, champions and equivalents for all remaining games. Add kahuna and totem boss types for Alola games. Create 11 new seed files, complete 2 existing ones, and update frontend types/UI for new boss types.
@@ -0,0 +1,38 @@
---
# nuzlocke-tracker-m86o
title: Add naming scheme selection to run configuration
status: completed
type: task
priority: normal
created_at: 2026-02-11T15:56:44Z
updated_at: 2026-02-11T20:37:00Z
parent: nuzlocke-tracker-igl3
blocking:
- nuzlocke-tracker-bi4e
---
Allow users to select a naming scheme (category) for their Nuzlocke run.
## Requirements
- Add a `naming_scheme` column to the NuzlockeRun model (nullable string — user may not want auto-naming)
- Provide a dropdown/selector in run creation and run settings where the user can pick a category
- List available categories dynamically by querying a backend endpoint that reads the dictionary file
- Allow changing the naming scheme mid-run
## Implementation Notes
- **Storage**: Dedicated nullable `naming_scheme` column on `NuzlockeRun` (not in the `rules` JSONB). This is a first-class run setting.
- **Migration**: Add an Alembic migration for the new column.
- **API**: Add/update the run creation and update endpoints to accept `namingScheme`.
- **Categories endpoint**: Add a GET endpoint that returns the list of available category names from the dictionary file, so the frontend can populate the dropdown.
## Checklist
- [x] Add `naming_scheme` nullable column to NuzlockeRun model
- [x] Create Alembic migration for the new column
- [x] Update run Pydantic schemas to include `namingScheme`
- [x] Update run creation and update endpoints to persist the naming scheme
- [x] Add GET endpoint to list available naming categories from the dictionary
- [x] Add naming scheme selector to run creation UI
- [x] Add naming scheme selector to run settings UI
@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-opg6
title: Exclude Max Raid den routes from Sword/Shield game data
status: completed
type: task
priority: normal
created_at: 2026-02-13T08:17:07Z
updated_at: 2026-02-13T08:17:53Z
---
Sword/Shield game JSONs contain ~561 den child routes out of ~1,007 total entries (~56%). These are Max Raid Battle dens named like '(Den I - ...)'. Add a filter_den_routes() function in processing.py and call it in __main__.py for sword-shield only, then re-run the import.
@@ -0,0 +1,17 @@
---
# nuzlocke-tracker-qgfv
title: Clean up stale duplicate routes in game JSON files
status: completed
type: task
priority: normal
created_at: 2026-02-13T07:24:40Z
updated_at: 2026-02-13T07:25:56Z
---
Game JSON files (especially Gen 7) have stale route entries from a previous import that used different naming. The seeder upserted without cleaning up, so the DB accumulated both old (e.g. 'Route 1') and new (e.g. 'Alola Route 1') entries. Then --export dumped both to JSON, creating duplicates with conflicting order values.
## Checklist
- [ ] Identify all affected game JSON files
- [ ] Remove stale/duplicate route entries (the ones not in route_order.json)
- [ ] Reassign sequential order values to fix the gaps
- [ ] Verify no data loss (the kept routes should have all the encounter data)
@@ -1,11 +1,11 @@
--- ---
# nuzlocke-tracker-spx3 # nuzlocke-tracker-spx3
title: Evaluate separate seed/init container after PokeDB import title: Evaluate separate seed/init container after PokeDB import
status: draft status: scrapped
type: task type: task
priority: low priority: low
created_at: 2026-02-10T14:30:57Z created_at: 2026-02-10T14:30:57Z
updated_at: 2026-02-10T14:30:57Z updated_at: 2026-02-11T20:15:43Z
--- ---
After the PokeDB.org data import (beans-bs05) is complete, evaluate whether the seed data has grown enough to justify splitting seeding into a separate init container. After the PokeDB.org data import (beans-bs05) is complete, evaluate whether the seed data has grown enough to justify splitting seeding into a separate init container.
@@ -0,0 +1,11 @@
---
# nuzlocke-tracker-u4gc
title: Remove artificial Starter route, use PokeDB starter locations
status: completed
type: task
priority: normal
created_at: 2026-02-13T08:02:43Z
updated_at: 2026-02-13T08:06:47Z
---
Remove the artificial 'Starter' route from route_order.json, update special_encounters.json to use real location names, and handle gift→starter remapping in the import tool.
@@ -0,0 +1,38 @@
---
# nuzlocke-tracker-ueyy
title: Create name dictionary data file
status: completed
type: task
priority: normal
created_at: 2026-02-11T15:56:26Z
updated_at: 2026-02-11T20:42:16Z
parent: nuzlocke-tracker-igl3
blocking:
- nuzlocke-tracker-c6ly
---
Create a JSON data file containing themed words for nickname generation, stored in the backend alongside other seed data.
## Requirements
- Store at `backend/src/app/seeds/data/name_dictionary.json`
- Category-keyed structure for fast lookup:
```json
{
"mythology": ["Apollo", "Athena", "Loki", ...],
"space": ["Apollo", "Nova", "Nebula", ...],
"food": ["Basil", "Sage", "Pepper", ...]
}
```
- Words may appear in multiple categories
- Categories should include themes like: mythology, food, space, nature, warriors, music, literature, gems, ocean, weather, etc.
- Target 150-200 words per category
- Words should be short, punchy, and suitable as Pokemon nicknames (ideally 1-2 words, max ~12 characters)
- This file is NOT seeded into the database — it is read directly by the backend service at runtime
## Checklist
- [x] Create `backend/src/app/seeds/data/name_dictionary.json` with the category-keyed structure
- [x] Populate each category with 150-200 words
- [x] Validate no duplicates exist within a single category
- [x] Add a utility function to load the dictionary from disk (with caching)
@@ -0,0 +1,29 @@
"""add naming_scheme to nuzlocke_runs
Revision ID: e5f6a7b8c9d1
Revises: d4e5f6a7b9c0
Create Date: 2026-02-11 12:00:00.000000
"""
from collections.abc import Sequence
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision: str = "e5f6a7b8c9d1"
down_revision: str | Sequence[str] | None = "d4e5f6a7b9c0"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
op.add_column(
"nuzlocke_runs",
sa.Column("naming_scheme", sa.String(50), nullable=True),
)
def downgrade() -> None:
op.drop_column("nuzlocke_runs", "naming_scheme")
@@ -0,0 +1,25 @@
"""merge naming_scheme and genlocke_transfers
Revision ID: e5f70a1ca323
Revises: e5f6a7b8c9d1, e5f6a7b9c0d1
Create Date: 2026-02-11 21:49:29.942841
"""
from collections.abc import Sequence
# revision identifiers, used by Alembic.
revision: str = "e5f70a1ca323"
down_revision: str | Sequence[str] | None = ("e5f6a7b8c9d1", "e5f6a7b9c0d1")
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
"""Upgrade schema."""
pass
def downgrade() -> None:
"""Downgrade schema."""
pass
+32
View File
@@ -19,10 +19,41 @@ from app.schemas.run import (
RunResponse, RunResponse,
RunUpdate, RunUpdate,
) )
from app.services.naming import get_naming_categories, suggest_names
router = APIRouter() router = APIRouter()
@router.get("/naming-categories", response_model=list[str])
async def list_naming_categories():
return get_naming_categories()
@router.get("/{run_id}/name-suggestions", response_model=list[str])
async def get_name_suggestions(
run_id: int,
count: int = 10,
session: AsyncSession = Depends(get_session),
):
run = await session.get(NuzlockeRun, run_id)
if run is None:
raise HTTPException(status_code=404, detail="Run not found")
if not run.naming_scheme:
return []
# Collect nicknames already used in this run
result = await session.execute(
select(Encounter.nickname).where(
Encounter.run_id == run_id,
Encounter.nickname.isnot(None),
)
)
used_names = {row[0] for row in result}
return suggest_names(run.naming_scheme, used_names, count)
@router.post("", response_model=RunResponse, status_code=201) @router.post("", response_model=RunResponse, status_code=201)
async def create_run(data: RunCreate, session: AsyncSession = Depends(get_session)): async def create_run(data: RunCreate, session: AsyncSession = Depends(get_session)):
# Validate game exists # Validate game exists
@@ -35,6 +66,7 @@ async def create_run(data: RunCreate, session: AsyncSession = Depends(get_sessio
name=data.name, name=data.name,
status="active", status="active",
rules=data.rules, rules=data.rules,
naming_scheme=data.naming_scheme,
) )
session.add(run) session.add(run)
await session.commit() await session.commit()
+1
View File
@@ -22,6 +22,7 @@ class NuzlockeRun(Base):
) )
completed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) completed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
hof_encounter_ids: Mapped[list[int] | None] = mapped_column(JSONB, default=None) hof_encounter_ids: Mapped[list[int] | None] = mapped_column(JSONB, default=None)
naming_scheme: Mapped[str | None] = mapped_column(String(50), nullable=True)
game: Mapped["Game"] = relationship(back_populates="runs") game: Mapped["Game"] = relationship(back_populates="runs")
encounters: Mapped[list["Encounter"]] = relationship(back_populates="run") encounters: Mapped[list["Encounter"]] = relationship(back_populates="run")
+3
View File
@@ -9,6 +9,7 @@ class RunCreate(CamelModel):
game_id: int game_id: int
name: str name: str
rules: dict = {} rules: dict = {}
naming_scheme: str | None = None
class RunUpdate(CamelModel): class RunUpdate(CamelModel):
@@ -16,6 +17,7 @@ class RunUpdate(CamelModel):
status: str | None = None status: str | None = None
rules: dict | None = None rules: dict | None = None
hof_encounter_ids: list[int] | None = None hof_encounter_ids: list[int] | None = None
naming_scheme: str | None = None
class RunResponse(CamelModel): class RunResponse(CamelModel):
@@ -25,6 +27,7 @@ class RunResponse(CamelModel):
status: str status: str
rules: dict rules: dict
hof_encounter_ids: list[int] | None = None hof_encounter_ids: list[int] | None = None
naming_scheme: str | None = None
started_at: datetime started_at: datetime
completed_at: datetime | None completed_at: datetime | None
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,184 @@
[
{
"name": "Cheren",
"boss_type": "gym_leader",
"specialty_type": "normal",
"badge_name": "Basic Badge",
"badge_image_url": "/badges/basic-badge.png",
"level_cap": 13,
"order": 1,
"after_route_name": "Aspertia City",
"location": "Aspertia Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/black-2/cheren.png",
"pokemon": []
},
{
"name": "Roxie",
"boss_type": "gym_leader",
"specialty_type": "poison",
"badge_name": "Toxic Badge",
"badge_image_url": "/badges/toxic-badge.png",
"level_cap": 18,
"order": 2,
"after_route_name": "Virbank City",
"location": "Virbank Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/black-2/roxie.png",
"pokemon": []
},
{
"name": "Burgh",
"boss_type": "gym_leader",
"specialty_type": "bug",
"badge_name": "Insect Badge",
"badge_image_url": "/badges/insect-badge.png",
"level_cap": 24,
"order": 3,
"after_route_name": "Castelia City",
"location": "Castelia Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/black-2/burgh.png",
"pokemon": []
},
{
"name": "Elesa",
"boss_type": "gym_leader",
"specialty_type": "electric",
"badge_name": "Bolt Badge",
"badge_image_url": "/badges/bolt-badge.png",
"level_cap": 29,
"order": 4,
"after_route_name": "Nimbasa City",
"location": "Nimbasa Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/black-2/elesa.png",
"pokemon": []
},
{
"name": "Clay",
"boss_type": "gym_leader",
"specialty_type": "ground",
"badge_name": "Quake Badge",
"badge_image_url": "/badges/quake-badge.png",
"level_cap": 33,
"order": 5,
"after_route_name": "Driftveil City",
"location": "Driftveil Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/black-2/clay.png",
"pokemon": []
},
{
"name": "Skyla",
"boss_type": "gym_leader",
"specialty_type": "flying",
"badge_name": "Jet Badge",
"badge_image_url": "/badges/jet-badge.png",
"level_cap": 37,
"order": 6,
"after_route_name": "Mistralton City",
"location": "Mistralton Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/black-2/skyla.png",
"pokemon": []
},
{
"name": "Drayden",
"boss_type": "gym_leader",
"specialty_type": "dragon",
"badge_name": "Legend Badge",
"badge_image_url": "/badges/legend-badge.png",
"level_cap": 46,
"order": 7,
"after_route_name": "Opelucid City",
"location": "Opelucid Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/black-2/drayden.png",
"pokemon": []
},
{
"name": "Marlon",
"boss_type": "gym_leader",
"specialty_type": "water",
"badge_name": "Wave Badge",
"badge_image_url": "/badges/wave-badge.png",
"level_cap": 49,
"order": 8,
"after_route_name": "Humilau City",
"location": "Humilau Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/black-2/marlon.png",
"pokemon": []
},
{
"name": "Shauntal",
"boss_type": "elite_four",
"specialty_type": "ghost",
"badge_name": null,
"badge_image_url": null,
"level_cap": 57,
"order": 9,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/black-2/shauntal.png",
"pokemon": []
},
{
"name": "Grimsley",
"boss_type": "elite_four",
"specialty_type": "dark",
"badge_name": null,
"badge_image_url": null,
"level_cap": 57,
"order": 10,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/black-2/grimsley.png",
"pokemon": []
},
{
"name": "Caitlin",
"boss_type": "elite_four",
"specialty_type": "psychic",
"badge_name": null,
"badge_image_url": null,
"level_cap": 57,
"order": 11,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/black-2/caitlin.png",
"pokemon": []
},
{
"name": "Marshal",
"boss_type": "elite_four",
"specialty_type": "fighting",
"badge_name": null,
"badge_image_url": null,
"level_cap": 57,
"order": 12,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/black-2/marshal.png",
"pokemon": []
},
{
"name": "Iris",
"boss_type": "champion",
"specialty_type": "dragon",
"badge_name": null,
"badge_image_url": null,
"level_cap": 59,
"order": 13,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/black-2/iris.png",
"pokemon": []
}
]
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,212 @@
[
{
"name": "Cilan / Chili / Cress",
"boss_type": "gym_leader",
"specialty_type": null,
"badge_name": "Trio Badge",
"badge_image_url": "/badges/trio-badge.png",
"level_cap": 14,
"order": 1,
"after_route_name": "Striaton City",
"location": "Striaton Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/black/cilan--chili--cress.png",
"pokemon": []
},
{
"name": "Lenora",
"boss_type": "gym_leader",
"specialty_type": "normal",
"badge_name": "Basic Badge",
"badge_image_url": "/badges/basic-badge.png",
"level_cap": 20,
"order": 2,
"after_route_name": "Nacrene City",
"location": "Nacrene Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/black/lenora.png",
"pokemon": []
},
{
"name": "Burgh",
"boss_type": "gym_leader",
"specialty_type": "bug",
"badge_name": "Insect Badge",
"badge_image_url": "/badges/insect-badge.png",
"level_cap": 24,
"order": 3,
"after_route_name": "Castelia City",
"location": "Castelia Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/black/burgh.png",
"pokemon": []
},
{
"name": "Elesa",
"boss_type": "gym_leader",
"specialty_type": "electric",
"badge_name": "Bolt Badge",
"badge_image_url": "/badges/bolt-badge.png",
"level_cap": 27,
"order": 4,
"after_route_name": "Nimbasa City",
"location": "Nimbasa Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/black/elesa.png",
"pokemon": []
},
{
"name": "Clay",
"boss_type": "gym_leader",
"specialty_type": "ground",
"badge_name": "Quake Badge",
"badge_image_url": "/badges/quake-badge.png",
"level_cap": 31,
"order": 5,
"after_route_name": "Driftveil City",
"location": "Driftveil Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/black/clay.png",
"pokemon": []
},
{
"name": "Skyla",
"boss_type": "gym_leader",
"specialty_type": "flying",
"badge_name": "Jet Badge",
"badge_image_url": "/badges/jet-badge.png",
"level_cap": 35,
"order": 6,
"after_route_name": "Mistralton City",
"location": "Mistralton Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/black/skyla.png",
"pokemon": []
},
{
"name": "Brycen",
"boss_type": "gym_leader",
"specialty_type": "ice",
"badge_name": "Freeze Badge",
"badge_image_url": "/badges/freeze-badge.png",
"level_cap": 39,
"order": 7,
"after_route_name": "Icirrus City",
"location": "Icirrus Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/black/brycen.png",
"pokemon": []
},
{
"name": "Drayden",
"boss_type": "gym_leader",
"specialty_type": "dragon",
"badge_name": "Legend Badge",
"badge_image_url": "/badges/legend-badge.png",
"level_cap": 43,
"order": 8,
"after_route_name": "Opelucid City",
"location": "Opelucid Gym",
"section": "Black",
"sprite_url": "/boss-sprites/black/drayden.png",
"pokemon": []
},
{
"name": "Iris",
"boss_type": "gym_leader",
"specialty_type": "dragon",
"badge_name": "Legend Badge",
"badge_image_url": "/badges/legend-badge.png",
"level_cap": 43,
"order": 9,
"after_route_name": "Opelucid City",
"location": "Opelucid Gym",
"section": "White",
"sprite_url": "/boss-sprites/black/iris.png",
"pokemon": []
},
{
"name": "Shauntal",
"boss_type": "elite_four",
"specialty_type": "ghost",
"badge_name": null,
"badge_image_url": null,
"level_cap": 50,
"order": 10,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/black/shauntal.png",
"pokemon": []
},
{
"name": "Grimsley",
"boss_type": "elite_four",
"specialty_type": "dark",
"badge_name": null,
"badge_image_url": null,
"level_cap": 50,
"order": 11,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/black/grimsley.png",
"pokemon": []
},
{
"name": "Caitlin",
"boss_type": "elite_four",
"specialty_type": "psychic",
"badge_name": null,
"badge_image_url": null,
"level_cap": 50,
"order": 12,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/black/caitlin.png",
"pokemon": []
},
{
"name": "Marshal",
"boss_type": "elite_four",
"specialty_type": "fighting",
"badge_name": null,
"badge_image_url": null,
"level_cap": 52,
"order": 13,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/black/marshal.png",
"pokemon": []
},
{
"name": "N",
"boss_type": "other",
"specialty_type": "dragon",
"badge_name": null,
"badge_image_url": null,
"level_cap": 52,
"order": 14,
"after_route_name": null,
"location": "N's Castle",
"section": "Main Story",
"sprite_url": "/boss-sprites/black/n.png",
"pokemon": []
},
{
"name": "Ghetsis",
"boss_type": "other",
"specialty_type": null,
"badge_name": null,
"badge_image_url": null,
"level_cap": 54,
"order": 15,
"after_route_name": null,
"location": "N's Castle",
"section": "Main Story",
"sprite_url": "/boss-sprites/black/ghetsis.png",
"pokemon": []
}
]
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,184 @@
[
{
"name": "Roark",
"boss_type": "gym_leader",
"specialty_type": "rock",
"badge_name": "Coal Badge",
"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": "/boss-sprites/brilliant-diamond/roark.png",
"pokemon": []
},
{
"name": "Gardenia",
"boss_type": "gym_leader",
"specialty_type": "grass",
"badge_name": "Forest Badge",
"badge_image_url": "/badges/forest-badge.png",
"level_cap": 22,
"order": 2,
"after_route_name": "Eterna City",
"location": "Eterna Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/brilliant-diamond/gardenia.png",
"pokemon": []
},
{
"name": "Maylene",
"boss_type": "gym_leader",
"specialty_type": "fighting",
"badge_name": "Cobble Badge",
"badge_image_url": "/badges/cobble-badge.png",
"level_cap": 30,
"order": 3,
"after_route_name": "Veilstone City",
"location": "Veilstone Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/brilliant-diamond/maylene.png",
"pokemon": []
},
{
"name": "Crasher Wake",
"boss_type": "gym_leader",
"specialty_type": "water",
"badge_name": "Fen Badge",
"badge_image_url": "/badges/fen-badge.png",
"level_cap": 30,
"order": 4,
"after_route_name": "Pastoria City",
"location": "Pastoria Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/brilliant-diamond/crasher-wake.png",
"pokemon": []
},
{
"name": "Fantina",
"boss_type": "gym_leader",
"specialty_type": "ghost",
"badge_name": "Relic Badge",
"badge_image_url": "/badges/relic-badge.png",
"level_cap": 36,
"order": 5,
"after_route_name": "Hearthome City",
"location": "Hearthome Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/brilliant-diamond/fantina.png",
"pokemon": []
},
{
"name": "Byron",
"boss_type": "gym_leader",
"specialty_type": "steel",
"badge_name": "Mine Badge",
"badge_image_url": "/badges/mine-badge.png",
"level_cap": 39,
"order": 6,
"after_route_name": "Canalave City",
"location": "Canalave Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/brilliant-diamond/byron.png",
"pokemon": []
},
{
"name": "Candice",
"boss_type": "gym_leader",
"specialty_type": "ice",
"badge_name": "Icicle Badge",
"badge_image_url": "/badges/icicle-badge.png",
"level_cap": 42,
"order": 7,
"after_route_name": "Snowpoint City",
"location": "Snowpoint Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/brilliant-diamond/candice.png",
"pokemon": []
},
{
"name": "Volkner",
"boss_type": "gym_leader",
"specialty_type": "electric",
"badge_name": "Beacon Badge",
"badge_image_url": "/badges/beacon-badge.png",
"level_cap": 49,
"order": 8,
"after_route_name": "Sunyshore City",
"location": "Sunyshore Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/brilliant-diamond/volkner.png",
"pokemon": []
},
{
"name": "Aaron",
"boss_type": "elite_four",
"specialty_type": "bug",
"badge_name": null,
"badge_image_url": null,
"level_cap": 53,
"order": 9,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/brilliant-diamond/aaron.png",
"pokemon": []
},
{
"name": "Bertha",
"boss_type": "elite_four",
"specialty_type": "ground",
"badge_name": null,
"badge_image_url": null,
"level_cap": 55,
"order": 10,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/brilliant-diamond/bertha.png",
"pokemon": []
},
{
"name": "Flint",
"boss_type": "elite_four",
"specialty_type": "fire",
"badge_name": null,
"badge_image_url": null,
"level_cap": 55,
"order": 11,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/brilliant-diamond/flint.png",
"pokemon": []
},
{
"name": "Lucian",
"boss_type": "elite_four",
"specialty_type": "psychic",
"badge_name": null,
"badge_image_url": null,
"level_cap": 59,
"order": 12,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/brilliant-diamond/lucian.png",
"pokemon": []
},
{
"name": "Cynthia",
"boss_type": "champion",
"specialty_type": null,
"badge_name": null,
"badge_image_url": null,
"level_cap": 66,
"order": 13,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/brilliant-diamond/cynthia.png",
"pokemon": []
}
]
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -12,5 +12,173 @@
"section": "Main Story", "section": "Main Story",
"sprite_url": "/boss-sprites/diamond/roark.png", "sprite_url": "/boss-sprites/diamond/roark.png",
"pokemon": [] "pokemon": []
},
{
"name": "Gardenia",
"boss_type": "gym_leader",
"specialty_type": "grass",
"badge_name": "Forest Badge",
"badge_image_url": "/badges/forest-badge.png",
"level_cap": 22,
"order": 2,
"after_route_name": "Eterna City",
"location": "Eterna Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/diamond/gardenia.png",
"pokemon": []
},
{
"name": "Maylene",
"boss_type": "gym_leader",
"specialty_type": "fighting",
"badge_name": "Cobble Badge",
"badge_image_url": "/badges/cobble-badge.png",
"level_cap": 30,
"order": 3,
"after_route_name": "Veilstone City",
"location": "Veilstone Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/diamond/maylene.png",
"pokemon": []
},
{
"name": "Crasher Wake",
"boss_type": "gym_leader",
"specialty_type": "water",
"badge_name": "Fen Badge",
"badge_image_url": "/badges/fen-badge.png",
"level_cap": 30,
"order": 4,
"after_route_name": "Pastoria City",
"location": "Pastoria Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/diamond/crasher-wake.png",
"pokemon": []
},
{
"name": "Fantina",
"boss_type": "gym_leader",
"specialty_type": "ghost",
"badge_name": "Relic Badge",
"badge_image_url": "/badges/relic-badge.png",
"level_cap": 36,
"order": 5,
"after_route_name": "Hearthome City",
"location": "Hearthome Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/diamond/fantina.png",
"pokemon": []
},
{
"name": "Byron",
"boss_type": "gym_leader",
"specialty_type": "steel",
"badge_name": "Mine Badge",
"badge_image_url": "/badges/mine-badge.png",
"level_cap": 39,
"order": 6,
"after_route_name": "Canalave City",
"location": "Canalave Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/diamond/byron.png",
"pokemon": []
},
{
"name": "Candice",
"boss_type": "gym_leader",
"specialty_type": "ice",
"badge_name": "Icicle Badge",
"badge_image_url": "/badges/icicle-badge.png",
"level_cap": 42,
"order": 7,
"after_route_name": "Snowpoint City",
"location": "Snowpoint Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/diamond/candice.png",
"pokemon": []
},
{
"name": "Volkner",
"boss_type": "gym_leader",
"specialty_type": "electric",
"badge_name": "Beacon Badge",
"badge_image_url": "/badges/beacon-badge.png",
"level_cap": 49,
"order": 8,
"after_route_name": "Sunyshore City",
"location": "Sunyshore Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/diamond/volkner.png",
"pokemon": []
},
{
"name": "Aaron",
"boss_type": "elite_four",
"specialty_type": "bug",
"badge_name": null,
"badge_image_url": null,
"level_cap": 53,
"order": 9,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/diamond/aaron.png",
"pokemon": []
},
{
"name": "Bertha",
"boss_type": "elite_four",
"specialty_type": "ground",
"badge_name": null,
"badge_image_url": null,
"level_cap": 55,
"order": 10,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/diamond/bertha.png",
"pokemon": []
},
{
"name": "Flint",
"boss_type": "elite_four",
"specialty_type": "fire",
"badge_name": null,
"badge_image_url": null,
"level_cap": 55,
"order": 11,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/diamond/flint.png",
"pokemon": []
},
{
"name": "Lucian",
"boss_type": "elite_four",
"specialty_type": "psychic",
"badge_name": null,
"badge_image_url": null,
"level_cap": 59,
"order": 12,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/diamond/lucian.png",
"pokemon": []
},
{
"name": "Cynthia",
"boss_type": "champion",
"specialty_type": null,
"badge_name": null,
"badge_image_url": null,
"level_cap": 66,
"order": 13,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/diamond/cynthia.png",
"pokemon": []
} }
] ]
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,100 @@
[
{
"name": "Lord Kleavor",
"boss_type": "other",
"specialty_type": "bug",
"badge_name": null,
"badge_image_url": null,
"level_cap": 18,
"order": 1,
"after_route_name": null,
"location": "Grandtree Arena",
"section": "Main Story",
"sprite_url": "/boss-sprites/legends-arceus/lord-kleavor.png",
"pokemon": []
},
{
"name": "Lady Lilligant",
"boss_type": "other",
"specialty_type": "grass",
"badge_name": null,
"badge_image_url": null,
"level_cap": 30,
"order": 2,
"after_route_name": null,
"location": "Brava Arena",
"section": "Main Story",
"sprite_url": "/boss-sprites/legends-arceus/lady-lilligant.png",
"pokemon": []
},
{
"name": "Lord Arcanine",
"boss_type": "other",
"specialty_type": "fire",
"badge_name": null,
"badge_image_url": null,
"level_cap": 36,
"order": 3,
"after_route_name": null,
"location": "Molten Arena",
"section": "Main Story",
"sprite_url": "/boss-sprites/legends-arceus/lord-arcanine.png",
"pokemon": []
},
{
"name": "Lord Electrode",
"boss_type": "other",
"specialty_type": "electric",
"badge_name": null,
"badge_image_url": null,
"level_cap": 46,
"order": 4,
"after_route_name": null,
"location": "Moonview Arena",
"section": "Main Story",
"sprite_url": "/boss-sprites/legends-arceus/lord-electrode.png",
"pokemon": []
},
{
"name": "Lord Avalugg",
"boss_type": "other",
"specialty_type": "ice",
"badge_name": null,
"badge_image_url": null,
"level_cap": 56,
"order": 5,
"after_route_name": null,
"location": "Icepeak Arena",
"section": "Main Story",
"sprite_url": "/boss-sprites/legends-arceus/lord-avalugg.png",
"pokemon": []
},
{
"name": "Origin Dialga / Palkia",
"boss_type": "other",
"specialty_type": null,
"badge_name": null,
"badge_image_url": null,
"level_cap": 65,
"order": 6,
"after_route_name": null,
"location": "Temple of Sinnoh",
"section": "Main Story",
"sprite_url": "/boss-sprites/legends-arceus/origin-dialga--palkia.png",
"pokemon": []
},
{
"name": "Arceus",
"boss_type": "other",
"specialty_type": null,
"badge_name": null,
"badge_image_url": null,
"level_cap": 75,
"order": 7,
"after_route_name": null,
"location": "Temple of Sinnoh",
"section": "Main Story",
"sprite_url": "/boss-sprites/legends-arceus/arceus.png",
"pokemon": []
}
]
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,184 @@
[
{
"name": "Brock",
"boss_type": "gym_leader",
"specialty_type": "rock",
"badge_name": "Boulder Badge",
"badge_image_url": "/badges/boulder-badge.png",
"level_cap": 12,
"order": 1,
"after_route_name": null,
"location": "Pewter Gym",
"section": null,
"sprite_url": "/boss-sprites/lets-go-pikachu/brock.png",
"pokemon": []
},
{
"name": "Misty",
"boss_type": "gym_leader",
"specialty_type": "water",
"badge_name": "Cascade Badge",
"badge_image_url": "/badges/cascade-badge.png",
"level_cap": 21,
"order": 2,
"after_route_name": null,
"location": "Cerulean Gym",
"section": null,
"sprite_url": "/boss-sprites/lets-go-pikachu/misty.png",
"pokemon": []
},
{
"name": "Lt. Surge",
"boss_type": "gym_leader",
"specialty_type": "electric",
"badge_name": "Thunder Badge",
"badge_image_url": "/badges/thunder-badge.png",
"level_cap": 28,
"order": 3,
"after_route_name": null,
"location": "Vermilion Gym",
"section": null,
"sprite_url": "/boss-sprites/lets-go-pikachu/lt-surge.png",
"pokemon": []
},
{
"name": "Erika",
"boss_type": "gym_leader",
"specialty_type": "grass",
"badge_name": "Rainbow Badge",
"badge_image_url": "/badges/rainbow-badge.png",
"level_cap": 33,
"order": 4,
"after_route_name": null,
"location": "Celadon Gym",
"section": null,
"sprite_url": "/boss-sprites/lets-go-pikachu/erika.png",
"pokemon": []
},
{
"name": "Koga",
"boss_type": "gym_leader",
"specialty_type": "poison",
"badge_name": "Soul Badge",
"badge_image_url": "/badges/soul-badge.png",
"level_cap": 43,
"order": 5,
"after_route_name": null,
"location": "Fuchsia Gym",
"section": null,
"sprite_url": "/boss-sprites/lets-go-pikachu/koga.png",
"pokemon": []
},
{
"name": "Sabrina",
"boss_type": "gym_leader",
"specialty_type": "psychic",
"badge_name": "Marsh Badge",
"badge_image_url": "/badges/marsh-badge.png",
"level_cap": 43,
"order": 6,
"after_route_name": null,
"location": "Saffron Gym",
"section": null,
"sprite_url": "/boss-sprites/lets-go-pikachu/sabrina.png",
"pokemon": []
},
{
"name": "Blaine",
"boss_type": "gym_leader",
"specialty_type": "fire",
"badge_name": "Volcano Badge",
"badge_image_url": "/badges/volcano-badge.png",
"level_cap": 47,
"order": 7,
"after_route_name": null,
"location": "Cinnabar Gym",
"section": null,
"sprite_url": "/boss-sprites/lets-go-pikachu/blaine.png",
"pokemon": []
},
{
"name": "Giovanni",
"boss_type": "gym_leader",
"specialty_type": "ground",
"badge_name": "Earth Badge",
"badge_image_url": "/badges/earth-badge.png",
"level_cap": 49,
"order": 8,
"after_route_name": null,
"location": "Viridian Gym",
"section": null,
"sprite_url": "/boss-sprites/lets-go-pikachu/giovanni.png",
"pokemon": []
},
{
"name": "Lorelei",
"boss_type": "elite_four",
"specialty_type": "ice",
"badge_name": null,
"badge_image_url": null,
"level_cap": 54,
"order": 9,
"after_route_name": "Victory Road",
"location": "Indigo Plateau",
"section": null,
"sprite_url": "/boss-sprites/lets-go-pikachu/lorelei.png",
"pokemon": []
},
{
"name": "Bruno",
"boss_type": "elite_four",
"specialty_type": "fighting",
"badge_name": null,
"badge_image_url": null,
"level_cap": 56,
"order": 10,
"after_route_name": "Victory Road",
"location": "Indigo Plateau",
"section": null,
"sprite_url": "/boss-sprites/lets-go-pikachu/bruno.png",
"pokemon": []
},
{
"name": "Agatha",
"boss_type": "elite_four",
"specialty_type": "ghost",
"badge_name": null,
"badge_image_url": null,
"level_cap": 56,
"order": 11,
"after_route_name": "Victory Road",
"location": "Indigo Plateau",
"section": null,
"sprite_url": "/boss-sprites/lets-go-pikachu/agatha.png",
"pokemon": []
},
{
"name": "Lance",
"boss_type": "elite_four",
"specialty_type": "dragon",
"badge_name": null,
"badge_image_url": null,
"level_cap": 56,
"order": 12,
"after_route_name": "Victory Road",
"location": "Indigo Plateau",
"section": null,
"sprite_url": "/boss-sprites/lets-go-pikachu/lance.png",
"pokemon": []
},
{
"name": "Blue",
"boss_type": "champion",
"specialty_type": null,
"badge_name": null,
"badge_image_url": null,
"level_cap": 58,
"order": 13,
"after_route_name": "Victory Road",
"location": "Indigo Plateau",
"section": null,
"sprite_url": "/boss-sprites/lets-go-pikachu/blue.png",
"pokemon": []
}
]
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,372 @@
{
"mythology": [
"Zeus", "Hera", "Apollo", "Athena", "Ares",
"Hermes", "Artemis", "Hades", "Poseidon", "Demeter",
"Hephaestus", "Aphrodite", "Dionysus", "Persephone", "Eros",
"Nike", "Helios", "Selene", "Nyx", "Chronos",
"Atlas", "Titan", "Hydra", "Cerberus", "Minotaur",
"Medusa", "Pegasus", "Phoenix", "Chimera", "Cyclops",
"Icarus", "Orpheus", "Perseus", "Achilles", "Odysseus",
"Ajax", "Hector", "Paris", "Helen", "Circe",
"Calypso", "Siren", "Muse", "Oracle", "Sphinx",
"Styx", "Elysium", "Olympus", "Tartarus", "Nemesis",
"Odin", "Thor", "Loki", "Freya", "Tyr",
"Baldur", "Fenrir", "Jormungandr", "Ragnarok", "Valkyrie",
"Mjolnir", "Yggdrasil", "Bifrost", "Valhalla", "Asgard",
"Midgard", "Norns", "Huginn", "Muninn", "Sleipnir",
"Ra", "Osiris", "Isis", "Anubis", "Thoth",
"Bastet", "Sekhmet", "Sobek", "Horus", "Seth",
"Nephthys", "Ammit", "Scarab", "Apophis", "Khepri",
"Amaterasu", "Susanoo", "Tsukuyomi", "Izanagi", "Izanami",
"Raijin", "Fujin", "Inari", "Kitsune", "Tengu",
"Oni", "Tanuki", "Yokai", "Kami", "Byakko",
"Vishnu", "Shiva", "Brahma", "Kali", "Ganesh",
"Lakshmi", "Hanuman", "Indra", "Agni", "Surya",
"Garuda", "Naga", "Deva", "Asura", "Dharma",
"Karma", "Mantra", "Lotus", "Chakra", "Maya",
"Brigid", "Morrigan", "Dagda", "Lugh", "Danu",
"Cernunnos", "Oberon", "Titania", "Merlin", "Avalon",
"Excalibur", "Druid", "Banshee", "Sidhe", "Fomorian",
"Leviathan", "Golem", "Djinn", "Ifrit", "Typhon",
"Griffin", "Kraken", "Wyrm", "Drake", "Wyvern",
"Basilisk", "Manticore", "Harpy", "Gorgon", "Triton",
"Prometheus", "Pandora", "Daphne", "Echo", "Narcissus",
"Midas", "Theseus", "Orion", "Castor", "Pollux",
"Zephyr", "Boreas", "Aether", "Chaos", "Gaia",
"Uranus", "Rhea", "Hyperion", "Themis", "Mnemosyne",
"Clio", "Fury", "Fate", "Moira", "Clotho"
],
"food": [
"Basil", "Sage", "Thyme", "Rosemary", "Saffron",
"Ginger", "Pepper", "Cinnamon", "Nutmeg", "Clove",
"Paprika", "Wasabi", "Cumin", "Fennel", "Dill",
"Anise", "Cardamom", "Turmeric", "Coriander", "Oregano",
"Tarragon", "Chive", "Parsley", "Mint", "Vanilla",
"Mango", "Kiwi", "Peach", "Cherry", "Plum",
"Fig", "Lemon", "Lime", "Melon", "Berry",
"Olive", "Cocoa", "Mocha", "Latte", "Chai",
"Matcha", "Espresso", "Cider", "Mead", "Porter",
"Stout", "Sake", "Roux", "Bisque", "Broth",
"Frappe", "Sorbet", "Gelato", "Truffle", "Praline",
"Nougat", "Toffee", "Caramel", "Fudge", "Brioche",
"Croissant", "Baguette", "Pretzel", "Dumpling", "Gyoza",
"Mochi", "Tempura", "Ramen", "Udon", "Soba",
"Pesto", "Salsa", "Kimchi", "Naan", "Tofu",
"Panko", "Miso", "Tahini", "Hummus", "Falafel",
"Burrito", "Taco", "Nacho", "Churro", "Crepe",
"Waffle", "Scone", "Crumpet", "Biscuit", "Cobbler",
"Crisp", "Tart", "Torte", "Mousse", "Souffle",
"Quiche", "Gratin", "Fondue", "Risotto", "Gnocchi",
"Ravioli", "Penne", "Orzo", "Pilaf", "Paella",
"Tagine", "Curry", "Satay", "Bulgogi", "Teriyaki",
"Ponzu", "Sriracha", "Harissa", "Chutney", "Relish",
"Pickle", "Caper", "Anchovy", "Prawn", "Scallop",
"Brisket", "Bison", "Quinoa", "Barley", "Millet",
"Almond", "Pecan", "Walnut", "Cashew", "Pistachio",
"Hazel", "Acai", "Guava", "Lychee", "Papaya",
"Tamarind", "Kumquat", "Clementine", "Nectar", "Honey",
"Maple", "Agave", "Molasses", "Butter", "Cream",
"Brie", "Gouda", "Cheddar", "Ricotta", "Paneer",
"Toasted", "Smoked", "Braised", "Seared", "Glazed",
"Roasted", "Grilled", "Poached", "Zest", "Tang",
"Crunch", "Morsel", "Nibble", "Drizzle", "Dash",
"Pinch", "Sprig", "Garnish", "Feast", "Brunch",
"Savory", "Umami", "Tangy", "Citrus", "Jambon"
],
"space": [
"Nova", "Nebula", "Quasar", "Pulsar", "Cosmos",
"Comet", "Meteor", "Astral", "Stellar", "Solar",
"Lunar", "Orbit", "Eclipse", "Galaxy", "Vortex",
"Zenith", "Nadir", "Apogee", "Perigee", "Epoch",
"Apollo", "Gemini", "Mercury", "Venus", "Mars",
"Jupiter", "Saturn", "Neptune", "Uranus", "Pluto",
"Titan", "Europa", "Io", "Callisto", "Ganymede",
"Triton", "Charon", "Phobos", "Deimos", "Ceres",
"Juno", "Vesta", "Pallas", "Eris", "Sedna",
"Sirius", "Rigel", "Vega", "Altair", "Deneb",
"Polaris", "Canopus", "Betelgeuse", "Antares", "Aldebaran",
"Spica", "Arcturus", "Capella", "Procyon", "Achernar",
"Castor", "Pollux", "Regulus", "Fomalhaut", "Mira",
"Bellatrix", "Mintaka", "Alnilam", "Alnitak", "Saiph",
"Orion", "Lyra", "Draco", "Hydra", "Corvus",
"Aquila", "Cygnus", "Phoenix", "Andromeda", "Cassiopeia",
"Perseus", "Centauri", "Pegasus", "Scorpius", "Leo",
"Aries", "Virgo", "Libra", "Pisces", "Taurus",
"Photon", "Neutron", "Proton", "Plasma", "Flux",
"Prism", "Spectrum", "Horizon", "Corona", "Halo",
"Aurora", "Solstice", "Equinox", "Parallax", "Parsec",
"Lightyear", "Warp", "Void", "Rift", "Abyss",
"Singularity", "Binary", "Cluster", "Remnant", "Dwarf",
"Giant", "Supernova", "Stardust", "Starfall", "Skyfire",
"Sunspot", "Flare", "Radiance", "Luminous", "Beacon",
"Voyager", "Pioneer", "Sputnik", "Hubble", "Kepler",
"Galileo", "Cassini", "Rosetta", "Artemis", "Chandra",
"Solaris", "Nebular", "Asteria", "Celestia", "Astra",
"Solis", "Lumen", "Ignis", "Ember", "Blaze",
"Spark", "Glimmer", "Shimmer", "Twilight", "Dusk",
"Dawn", "Crescent", "Waning", "Waxing", "Umbra",
"Penumbra", "Perihelion", "Aphelion", "Azimuth", "Meridian",
"Helix", "Spiral", "Ring", "Arc", "Bolt",
"Surge", "Pulse", "Wave", "Drift", "Phase",
"Xenon", "Neon", "Argon", "Helium", "Lithium"
],
"nature": [
"Willow", "Cedar", "Birch", "Aspen", "Maple",
"Rowan", "Alder", "Elm", "Oak", "Pine",
"Spruce", "Juniper", "Laurel", "Ivy", "Fern",
"Moss", "Lichen", "Thistle", "Clover", "Briar",
"Thorn", "Reed", "Sage", "Basil", "Lotus",
"Orchid", "Dahlia", "Iris", "Lily", "Violet",
"Jasmine", "Heather", "Daisy", "Poppy", "Aster",
"Azalea", "Magnolia", "Wisteria", "Camellia", "Marigold",
"Hawk", "Falcon", "Eagle", "Osprey", "Heron",
"Crane", "Wren", "Finch", "Lark", "Robin",
"Sparrow", "Raven", "Crow", "Jay", "Dove",
"Swift", "Owl", "Kestrel", "Harrier", "Condor",
"Wolf", "Fox", "Bear", "Lynx", "Puma",
"Jaguar", "Panther", "Stag", "Elk", "Moose",
"Bison", "Badger", "Otter", "Mink", "Ermine",
"Viper", "Cobra", "Adder", "Gecko", "Newt",
"Coral", "Pearl", "Amber", "Flint", "Slate",
"Granite", "Basalt", "Quartz", "Mica", "Clay",
"Dune", "Mesa", "Butte", "Gorge", "Canyon",
"Ridge", "Summit", "Crest", "Peak", "Cliff",
"Bluff", "Dale", "Glen", "Vale", "Hollow",
"Meadow", "Prairie", "Tundra", "Taiga", "Savanna",
"Grove", "Copse", "Thicket", "Canopy", "Glade",
"Brook", "Creek", "Rivulet", "Spring", "Rapids",
"Cascade", "Torrent", "Eddy", "Delta", "Marsh",
"Bog", "Fen", "Mire", "Lagoon", "Oasis",
"Frost", "Dew", "Mist", "Haze", "Fog",
"Breeze", "Gust", "Gale", "Squall", "Tempest",
"Aurora", "Solstice", "Equinox", "Eclipse", "Dawn",
"Dusk", "Twilight", "Ember", "Spark", "Flame",
"Petal", "Bloom", "Blossom", "Sprout", "Seedling",
"Sapling", "Root", "Bark", "Sap", "Nectar",
"Pollen", "Spore", "Frond", "Tendril", "Vine",
"Bramble", "Nettle", "Sorrel", "Yarrow", "Tansy",
"Mushroom", "Fungi", "Truffle", "Morel", "Chanterelle"
],
"warriors": [
"Spartan", "Samurai", "Viking", "Shogun", "Ronin",
"Gladiator", "Centurion", "Legionary", "Tribune", "Praetor",
"Knight", "Paladin", "Templar", "Crusader", "Sentinel",
"Warden", "Marshal", "Captain", "General", "Admiral",
"Vanguard", "Raider", "Berserker", "Valkyrie", "Einherjar",
"Ninja", "Shinobi", "Kenshi", "Bushido", "Daimyo",
"Mongol", "Khan", "Sultan", "Shah", "Pharaoh",
"Legatus", "Consul", "Imperator", "Caesar", "Augustus",
"Hussar", "Cossack", "Janissary", "Mamluk", "Saracen",
"Apache", "Comanche", "Mohawk", "Zulu", "Aztec",
"Mayan", "Incan", "Sparrow", "Hawk", "Falcon",
"Talon", "Fang", "Claw", "Tusk", "Horn",
"Blade", "Saber", "Rapier", "Cutlass", "Katana",
"Claymore", "Scimitar", "Halberd", "Glaive", "Pike",
"Lance", "Javelin", "Spear", "Trident", "Mace",
"Flail", "Hammer", "Maul", "Axe", "Tomahawk",
"Dagger", "Stiletto", "Dirk", "Kunai", "Shuriken",
"Bow", "Longbow", "Crossbow", "Bolt", "Arrow",
"Quiver", "Shield", "Buckler", "Aegis", "Bulwark",
"Rampart", "Bastion", "Citadel", "Fortress", "Garrison",
"Helm", "Visor", "Gauntlet", "Bracer", "Greave",
"Cuirass", "Brigand", "Chainmail", "Plate", "Scale",
"Banner", "Standard", "Crest", "Sigil", "Herald",
"Siege", "Assault", "Charge", "Rally", "Flanker",
"Scout", "Ranger", "Sniper", "Archer", "Lancer",
"Dragoon", "Cavalry", "Infantry", "Legion", "Phalanx",
"Cohort", "Regiment", "Battalion", "Brigade", "Platoon",
"Striker", "Brawler", "Duelist", "Champion", "Conqueror",
"Warlord", "Overlord", "Chieftain", "Thane", "Jarl",
"Reaver", "Marauder", "Pillager", "Ravager", "Slayer",
"Titan", "Colossus", "Juggernaut", "Goliath", "Ajax",
"Hector", "Achilles", "Leonidas", "Hannibal", "Attila",
"Genghis", "Alexander", "Boudicca", "Shaka", "Saladin",
"Agincourt", "Thermopylae", "Troy", "Carthage", "Masada",
"Valor", "Honor", "Glory", "Fury", "Wrath"
],
"music": [
"Tempo", "Rhythm", "Melody", "Harmony", "Chord",
"Riff", "Solo", "Verse", "Chorus", "Bridge",
"Cadence", "Crescendo", "Forte", "Piano", "Allegro",
"Adagio", "Vivace", "Presto", "Staccato", "Legato",
"Vibrato", "Tremolo", "Glissando", "Arpeggio", "Pizzicato",
"Fermata", "Sforzando", "Rubato", "Ostinato", "Coda",
"Treble", "Bass", "Alto", "Tenor", "Soprano",
"Baritone", "Falsetto", "Contralto", "Aria", "Duet",
"Sonata", "Fugue", "Prelude", "Nocturne", "Etude",
"Opus", "Requiem", "Ballad", "Anthem", "Hymn",
"Lyric", "Serenade", "Caprice", "Fantasia", "Overture",
"Minuet", "Waltz", "Bolero", "Tango", "Mambo",
"Samba", "Rumba", "Salsa", "Swing", "Bebop",
"Funk", "Soul", "Blues", "Jazz", "Gospel",
"Grunge", "Punk", "Metal", "Rock", "Indie",
"Techno", "Trance", "House", "Dubstep", "Ambient",
"Synth", "Drone", "Fuzz", "Wah", "Reverb",
"Echo", "Loop", "Beat", "Drop", "Groove",
"Fiddle", "Banjo", "Lute", "Harp", "Lyre",
"Viola", "Cello", "Oboe", "Flute", "Fife",
"Bugle", "Cornet", "Trumpet", "Trombone", "Tuba",
"Sax", "Clarinet", "Bassoon", "Piccolo", "Organ",
"Cymbal", "Gong", "Chime", "Bell", "Snare",
"Tambourine", "Bongo", "Conga", "Djembe", "Tabla",
"Sitar", "Shamisen", "Koto", "Guzheng", "Erhu",
"Raga", "Mantra", "Chant", "Dirge", "Elegy",
"Refrain", "Motif", "Theme", "Encore", "Finale",
"Pitch", "Tone", "Note", "Scale", "Octave",
"Sharp", "Flat", "Major", "Minor", "Modal",
"Acoustic", "Electric", "Muted", "Resonant", "Harmonic",
"Sonic", "Stereo", "Mono", "Vinyl", "Track",
"Album", "Mixtape", "Jam", "Gig", "Venue",
"Stage", "Amp", "Speaker", "Mic", "Reed",
"Bow", "Pick", "Slide", "Hammer", "Mallet",
"Timpani", "Marimba", "Celesta", "Dulcimer", "Zither"
],
"literature": [
"Prose", "Verse", "Stanza", "Sonnet", "Haiku",
"Limerick", "Ballad", "Ode", "Epic", "Saga",
"Fable", "Myth", "Legend", "Tale", "Lore",
"Tome", "Codex", "Scroll", "Grimoire", "Almanac",
"Quill", "Ink", "Vellum", "Parchment", "Folio",
"Preface", "Prologue", "Epilogue", "Chapter", "Canto",
"Epitaph", "Elegy", "Dirge", "Psalm", "Hymn",
"Allegory", "Parable", "Satire", "Parody", "Irony",
"Motif", "Theme", "Trope", "Genre", "Canon",
"Muse", "Oracle", "Bard", "Scribe", "Sage",
"Hamlet", "Othello", "Prospero", "Oberon", "Titania",
"Puck", "Ariel", "Caliban", "Portia", "Cordelia",
"Macbeth", "Banquo", "Lear", "Juliet", "Romeo",
"Brutus", "Cassius", "Shylock", "Mercutio", "Falstaff",
"Gatsby", "Atticus", "Scout", "Holden", "Pip",
"Huck", "Ishmael", "Ahab", "Queequeg", "Dorian",
"Darcy", "Heathcliff", "Rochester", "Eyre", "Estella",
"Cosette", "Valjean", "Quixote", "Sancho", "Dulcinea",
"Odysseus", "Aeneas", "Beowulf", "Gilgamesh", "Roland",
"Percival", "Galahad", "Lancelot", "Gawain", "Merlin",
"Scheherazade", "Sinbad", "Aladdin", "Mowgli", "Baloo",
"Nemo", "Moreau", "Jekyll", "Hyde", "Dracula",
"Renfield", "Harker", "Shelley", "Bronte", "Austen",
"Poe", "Frost", "Wilde", "Twain", "Dickens",
"Tolstoy", "Kafka", "Orwell", "Hemingway", "Faulkner",
"Woolf", "Plath", "Dumas", "Hugo", "Verne",
"Cipher", "Riddle", "Enigma", "Rune", "Glyph",
"Sigil", "Symbol", "Token", "Emblem", "Crest",
"Aria", "Lyric", "Rhyme", "Meter", "Cadence",
"Pathos", "Ethos", "Logos", "Hubris", "Nemesis",
"Catharsis", "Climax", "Zenith", "Nadir", "Pivot",
"Twist", "Reverie", "Whimsy", "Satyr", "Nymph",
"Sprite", "Wraith", "Phantom", "Specter", "Shade",
"Vestige", "Relic", "Echo", "Mirage", "Revenant",
"Requiem", "Opus", "Magnum", "Novella", "Lexicon"
],
"gems": [
"Ruby", "Sapphire", "Emerald", "Diamond", "Topaz",
"Amethyst", "Opal", "Pearl", "Garnet", "Peridot",
"Onyx", "Jade", "Agate", "Jasper", "Quartz",
"Citrine", "Zircon", "Beryl", "Spinel", "Tanzanite",
"Tourmaline", "Morganite", "Kunzite", "Iolite", "Larimar",
"Sunstone", "Moonstone", "Bloodstone", "Lodestone", "Heliodor",
"Chrysolite", "Alexandrite", "Andalusite", "Labradorite", "Amazonite",
"Rhodonite", "Sodalite", "Fluorite", "Calcite", "Pyrite",
"Galena", "Bauxite", "Magnetite", "Hematite", "Malachite",
"Azurite", "Turquoise", "Lapis", "Lazuli", "Carnelian",
"Sardonyx", "Chalcedony", "Aventurine", "Obsidian", "Granite",
"Marble", "Basalt", "Pumice", "Slate", "Flint",
"Amber", "Coral", "Ivory", "Jet", "Nacre",
"Gold", "Silver", "Platinum", "Copper", "Bronze",
"Iron", "Steel", "Titanium", "Cobalt", "Nickel",
"Chrome", "Zinc", "Tin", "Lead", "Brass",
"Pewter", "Electrum", "Palladium", "Rhodium", "Iridium",
"Osmium", "Ruthenium", "Tungsten", "Bismuth", "Lithium",
"Cesium", "Radium", "Gallium", "Indium", "Thallium",
"Strontium", "Barium", "Cadmium", "Antimony", "Tellurium",
"Selenite", "Celestite", "Sphalerite", "Kyanite", "Prehnite",
"Apatite", "Danburite", "Howlite", "Lepidolite", "Sugilite",
"Charoite", "Seraphinite", "Moldavite", "Tektite", "Shungite",
"Crystal", "Prism", "Facet", "Carat", "Luster",
"Brilliance", "Clarity", "Sparkle", "Shimmer", "Glimmer",
"Gleam", "Sheen", "Polish", "Ore", "Vein",
"Nugget", "Ingot", "Alloy", "Forge", "Smelt",
"Temper", "Anneal", "Refine", "Crucible", "Slag",
"Geode", "Druzy", "Cabochon", "Cameo", "Inlay",
"Filigree", "Gilt", "Patina", "Verdigris", "Tarnish",
"Shard", "Sliver", "Splinter", "Fragment", "Chip",
"Matrix", "Stratum", "Seam", "Deposit", "Quarry",
"Cavern", "Grotto", "Trove", "Cache", "Vault",
"Crown", "Diadem", "Tiara", "Circlet", "Coronet",
"Amulet", "Talisman", "Pendant", "Brooch", "Signet"
],
"ocean": [
"Tide", "Wave", "Surf", "Swell", "Crest",
"Trough", "Breaker", "Ripple", "Current", "Drift",
"Riptide", "Undertow", "Maelstrom", "Whirlpool", "Eddy",
"Tsunami", "Surge", "Deluge", "Torrent", "Cascade",
"Coral", "Reef", "Atoll", "Lagoon", "Shoal",
"Sandbar", "Islet", "Archipelago", "Fjord", "Inlet",
"Cove", "Bay", "Gulf", "Sound", "Strait",
"Channel", "Harbor", "Marina", "Pier", "Wharf",
"Dock", "Jetty", "Quay", "Beacon", "Lighthouse",
"Anchor", "Helm", "Rudder", "Keel", "Hull",
"Bow", "Stern", "Port", "Mast", "Sail",
"Rigging", "Galley", "Frigate", "Sloop", "Schooner",
"Clipper", "Brigantine", "Corsair", "Buccaneer", "Mariner",
"Skipper", "Bosun", "Navigator", "Helmsman", "Admiral",
"Commodore", "Captain", "Privateer", "Seafarer", "Voyager",
"Kraken", "Leviathan", "Siren", "Selkie", "Nereid",
"Triton", "Poseidon", "Neptune", "Calypso", "Charybdis",
"Scylla", "Davy", "Locker", "Nautilus", "Nemo",
"Whale", "Orca", "Dolphin", "Narwhal", "Porpoise",
"Shark", "Barracuda", "Marlin", "Sailfish", "Swordfish",
"Manta", "Stingray", "Moray", "Grouper", "Snapper",
"Tuna", "Mackerel", "Herring", "Sardine", "Anchovy",
"Squid", "Octopus", "Ammonite", "Cuttlefish", "Jellyfish",
"Anemone", "Urchin", "Starfish", "Seahorse", "Conch",
"Abalone", "Clam", "Oyster", "Mussel", "Scallop",
"Lobster", "Crab", "Shrimp", "Barnacle", "Kelp",
"Seaweed", "Plankton", "Algae", "Brine", "Foam",
"Spray", "Spume", "Mist", "Salt", "Pearl",
"Trench", "Abyss", "Fathom", "Depth", "Benthic",
"Pelagic", "Abyssal", "Hadal", "Tidal", "Littoral",
"Estuary", "Delta", "Mangrove", "Marsh", "Wetland",
"Driftwood", "Flotsam", "Jetsam", "Wreck", "Salvage",
"Bounty", "Plunder", "Treasure", "Doubloon", "Cutlass",
"Cannon", "Broadside", "Mainsail", "Spinnaker", "Jib",
"Bowsprit", "Gangway", "Porthole", "Bulkhead", "Bilge"
],
"weather": [
"Storm", "Tempest", "Squall", "Gale", "Gust",
"Breeze", "Zephyr", "Draft", "Whirlwind", "Tornado",
"Cyclone", "Typhoon", "Hurricane", "Monsoon", "Sirocco",
"Mistral", "Chinook", "Foehn", "Harmattan", "Tramontane",
"Thunder", "Lightning", "Bolt", "Flash", "Strike",
"Rumble", "Crack", "Boom", "Clap", "Roar",
"Rain", "Drizzle", "Shower", "Downpour", "Deluge",
"Torrent", "Cloudburst", "Sprinkle", "Mizzle", "Sleet",
"Snow", "Blizzard", "Flurry", "Frost", "Ice",
"Hail", "Rime", "Hoarfrost", "Glaze", "Verglas",
"Fog", "Mist", "Haze", "Smog", "Murk",
"Overcast", "Gloom", "Shadow", "Shade", "Dusk",
"Cloud", "Cumulus", "Stratus", "Cirrus", "Nimbus",
"Cumulonimbus", "Alto", "Wisp", "Veil", "Canopy",
"Anvil", "Billow", "Plume", "Column", "Front",
"Ridge", "Trough", "Vortex", "Eye", "Funnel",
"Twister", "Spout", "Surge", "Flood", "Flicker",
"Cascade", "Gush", "Swell", "Crest", "Tide",
"Drought", "Arid", "Parch", "Scorch", "Blaze",
"Ember", "Kindle", "Sear", "Wither", "Dustbowl",
"Heat", "Warmth", "Balmy", "Swelter", "Muggy",
"Humid", "Sultry", "Tropic", "Equator", "Solstice",
"Equinox", "Aurora", "Borealis", "Mirage", "Shimmer",
"Glint", "Gleam", "Radiance", "Glow", "Halo",
"Rainbow", "Prism", "Spectrum", "Arc", "Bow",
"Dew", "Droplet", "Puddle", "Rivulet", "Stream",
"Thaw", "Melt", "Freeze", "Chill", "Nip",
"Bite", "Brisk", "Crisp", "Cool", "Cold",
"Frigid", "Glacial", "Polar", "Arctic", "Tundra",
"Permafrost", "Icecap", "Avalanche", "Snowdrift", "Whiteout",
"Barometer", "Pressure", "Isobar", "Celsius", "Kelvin",
"Climate", "Season", "Forecast", "Outlook", "Pattern",
"Windchill", "Dewpoint", "Updraft", "Downdraft", "Jetstream",
"Tradewind", "Doldrums", "Lull", "Calm", "Serene",
"Clear", "Sunny", "Bright", "Radiant", "Blazing"
]
}
@@ -1,16 +1,184 @@
[ [
{
"name": "Roxanne",
"boss_type": "gym_leader",
"specialty_type": "rock",
"badge_name": "Stone Badge",
"badge_image_url": "/badges/stone-badge.png",
"level_cap": 14,
"order": 1,
"after_route_name": "Rustboro City",
"location": "Rustboro Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/omega-ruby/roxanne.png",
"pokemon": []
},
{
"name": "Brawly",
"boss_type": "gym_leader",
"specialty_type": "fighting",
"badge_name": "Knuckle Badge",
"badge_image_url": "/badges/knuckle-badge.png",
"level_cap": 16,
"order": 2,
"after_route_name": "Dewford Town",
"location": "Dewford Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/omega-ruby/brawly.png",
"pokemon": []
},
{ {
"name": "Wattson", "name": "Wattson",
"boss_type": "gym_leader", "boss_type": "gym_leader",
"specialty_type": "electric", "specialty_type": "electric",
"badge_name": "Dynamo Badge", "badge_name": "Dynamo Badge",
"badge_image_url": "/badges/dynamo-badge.png", "badge_image_url": "/badges/dynamo-badge.png",
"level_cap": 15, "level_cap": 24,
"order": 1, "order": 3,
"after_route_name": "Rustboro City", "after_route_name": "Mauville City",
"location": "Mauville Gym", "location": "Mauville Gym",
"section": "Main Story", "section": "Main Story",
"sprite_url": "/boss-sprites/omega-ruby/wattson.png", "sprite_url": "/boss-sprites/omega-ruby/wattson.png",
"pokemon": [] "pokemon": []
},
{
"name": "Flannery",
"boss_type": "gym_leader",
"specialty_type": "fire",
"badge_name": "Heat Badge",
"badge_image_url": "/badges/heat-badge.png",
"level_cap": 29,
"order": 4,
"after_route_name": "Lavaridge Town",
"location": "Lavaridge Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/omega-ruby/flannery.png",
"pokemon": []
},
{
"name": "Norman",
"boss_type": "gym_leader",
"specialty_type": "normal",
"badge_name": "Balance Badge",
"badge_image_url": "/badges/balance-badge.png",
"level_cap": 31,
"order": 5,
"after_route_name": "Petalburg City",
"location": "Petalburg Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/omega-ruby/norman.png",
"pokemon": []
},
{
"name": "Winona",
"boss_type": "gym_leader",
"specialty_type": "flying",
"badge_name": "Feather Badge",
"badge_image_url": "/badges/feather-badge.png",
"level_cap": 33,
"order": 6,
"after_route_name": "Fortree City",
"location": "Fortree Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/omega-ruby/winona.png",
"pokemon": []
},
{
"name": "Tate & Liza",
"boss_type": "gym_leader",
"specialty_type": "psychic",
"badge_name": "Mind Badge",
"badge_image_url": "/badges/mind-badge.png",
"level_cap": 45,
"order": 7,
"after_route_name": "Mossdeep City",
"location": "Mossdeep Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/omega-ruby/tate--liza.png",
"pokemon": []
},
{
"name": "Wallace",
"boss_type": "gym_leader",
"specialty_type": "water",
"badge_name": "Rain Badge",
"badge_image_url": "/badges/rain-badge.png",
"level_cap": 46,
"order": 8,
"after_route_name": "Sootopolis City",
"location": "Sootopolis Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/omega-ruby/wallace.png",
"pokemon": []
},
{
"name": "Sidney",
"boss_type": "elite_four",
"specialty_type": "dark",
"badge_name": null,
"badge_image_url": null,
"level_cap": 50,
"order": 9,
"after_route_name": "Victory Road",
"location": "Ever Grande City",
"section": "Main Story",
"sprite_url": "/boss-sprites/omega-ruby/sidney.png",
"pokemon": []
},
{
"name": "Phoebe",
"boss_type": "elite_four",
"specialty_type": "ghost",
"badge_name": null,
"badge_image_url": null,
"level_cap": 52,
"order": 10,
"after_route_name": "Victory Road",
"location": "Ever Grande City",
"section": "Main Story",
"sprite_url": "/boss-sprites/omega-ruby/phoebe.png",
"pokemon": []
},
{
"name": "Glacia",
"boss_type": "elite_four",
"specialty_type": "ice",
"badge_name": null,
"badge_image_url": null,
"level_cap": 54,
"order": 11,
"after_route_name": "Victory Road",
"location": "Ever Grande City",
"section": "Main Story",
"sprite_url": "/boss-sprites/omega-ruby/glacia.png",
"pokemon": []
},
{
"name": "Drake",
"boss_type": "elite_four",
"specialty_type": "dragon",
"badge_name": null,
"badge_image_url": null,
"level_cap": 55,
"order": 12,
"after_route_name": "Victory Road",
"location": "Ever Grande City",
"section": "Main Story",
"sprite_url": "/boss-sprites/omega-ruby/drake.png",
"pokemon": []
},
{
"name": "Steven",
"boss_type": "champion",
"specialty_type": "steel",
"badge_name": null,
"badge_image_url": null,
"level_cap": 57,
"order": 13,
"after_route_name": "Victory Road",
"location": "Ever Grande City",
"section": "Main Story",
"sprite_url": "/boss-sprites/omega-ruby/steven.png",
"pokemon": []
} }
] ]
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,184 @@
[
{
"name": "Roark",
"boss_type": "gym_leader",
"specialty_type": "rock",
"badge_name": "Coal Badge",
"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": "/boss-sprites/platinum/roark.png",
"pokemon": []
},
{
"name": "Gardenia",
"boss_type": "gym_leader",
"specialty_type": "grass",
"badge_name": "Forest Badge",
"badge_image_url": "/badges/forest-badge.png",
"level_cap": 22,
"order": 2,
"after_route_name": "Eterna City",
"location": "Eterna Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/platinum/gardenia.png",
"pokemon": []
},
{
"name": "Fantina",
"boss_type": "gym_leader",
"specialty_type": "ghost",
"badge_name": "Relic Badge",
"badge_image_url": "/badges/relic-badge.png",
"level_cap": 26,
"order": 3,
"after_route_name": "Hearthome City",
"location": "Hearthome Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/platinum/fantina.png",
"pokemon": []
},
{
"name": "Maylene",
"boss_type": "gym_leader",
"specialty_type": "fighting",
"badge_name": "Cobble Badge",
"badge_image_url": "/badges/cobble-badge.png",
"level_cap": 30,
"order": 4,
"after_route_name": "Veilstone City",
"location": "Veilstone Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/platinum/maylene.png",
"pokemon": []
},
{
"name": "Crasher Wake",
"boss_type": "gym_leader",
"specialty_type": "water",
"badge_name": "Fen Badge",
"badge_image_url": "/badges/fen-badge.png",
"level_cap": 33,
"order": 5,
"after_route_name": "Pastoria City",
"location": "Pastoria Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/platinum/crasher-wake.png",
"pokemon": []
},
{
"name": "Byron",
"boss_type": "gym_leader",
"specialty_type": "steel",
"badge_name": "Mine Badge",
"badge_image_url": "/badges/mine-badge.png",
"level_cap": 37,
"order": 6,
"after_route_name": "Canalave City",
"location": "Canalave Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/platinum/byron.png",
"pokemon": []
},
{
"name": "Candice",
"boss_type": "gym_leader",
"specialty_type": "ice",
"badge_name": "Icicle Badge",
"badge_image_url": "/badges/icicle-badge.png",
"level_cap": 40,
"order": 7,
"after_route_name": "Snowpoint City",
"location": "Snowpoint Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/platinum/candice.png",
"pokemon": []
},
{
"name": "Volkner",
"boss_type": "gym_leader",
"specialty_type": "electric",
"badge_name": "Beacon Badge",
"badge_image_url": "/badges/beacon-badge.png",
"level_cap": 46,
"order": 8,
"after_route_name": "Sunyshore City",
"location": "Sunyshore Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/platinum/volkner.png",
"pokemon": []
},
{
"name": "Aaron",
"boss_type": "elite_four",
"specialty_type": "bug",
"badge_name": null,
"badge_image_url": null,
"level_cap": 53,
"order": 9,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/platinum/aaron.png",
"pokemon": []
},
{
"name": "Bertha",
"boss_type": "elite_four",
"specialty_type": "ground",
"badge_name": null,
"badge_image_url": null,
"level_cap": 55,
"order": 10,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/platinum/bertha.png",
"pokemon": []
},
{
"name": "Flint",
"boss_type": "elite_four",
"specialty_type": "fire",
"badge_name": null,
"badge_image_url": null,
"level_cap": 57,
"order": 11,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/platinum/flint.png",
"pokemon": []
},
{
"name": "Lucian",
"boss_type": "elite_four",
"specialty_type": "psychic",
"badge_name": null,
"badge_image_url": null,
"level_cap": 59,
"order": 12,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/platinum/lucian.png",
"pokemon": []
},
{
"name": "Cynthia",
"boss_type": "champion",
"specialty_type": null,
"badge_name": null,
"badge_image_url": null,
"level_cap": 62,
"order": 13,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/platinum/cynthia.png",
"pokemon": []
}
]
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,338 @@
[
{
"name": "Katy",
"boss_type": "gym_leader",
"specialty_type": "bug",
"badge_name": "Bug Badge",
"badge_image_url": "/badges/bug-badge.png",
"level_cap": 15,
"order": 1,
"after_route_name": null,
"location": "Cortondo Gym",
"section": "Victory Road",
"sprite_url": "/boss-sprites/scarlet/katy.png",
"pokemon": []
},
{
"name": "Brassius",
"boss_type": "gym_leader",
"specialty_type": "grass",
"badge_name": "Grass Badge",
"badge_image_url": "/badges/grass-badge.png",
"level_cap": 17,
"order": 2,
"after_route_name": null,
"location": "Artazon Gym",
"section": "Victory Road",
"sprite_url": "/boss-sprites/scarlet/brassius.png",
"pokemon": []
},
{
"name": "Iono",
"boss_type": "gym_leader",
"specialty_type": "electric",
"badge_name": "Electric Badge",
"badge_image_url": "/badges/electric-badge.png",
"level_cap": 24,
"order": 3,
"after_route_name": null,
"location": "Levincia Gym",
"section": "Victory Road",
"sprite_url": "/boss-sprites/scarlet/iono.png",
"pokemon": []
},
{
"name": "Kofu",
"boss_type": "gym_leader",
"specialty_type": "water",
"badge_name": "Water Badge",
"badge_image_url": "/badges/water-badge.png",
"level_cap": 30,
"order": 4,
"after_route_name": null,
"location": "Cascarrafa Gym",
"section": "Victory Road",
"sprite_url": "/boss-sprites/scarlet/kofu.png",
"pokemon": []
},
{
"name": "Larry",
"boss_type": "gym_leader",
"specialty_type": "normal",
"badge_name": "Normal Badge",
"badge_image_url": "/badges/normal-badge.png",
"level_cap": 36,
"order": 5,
"after_route_name": null,
"location": "Medali Gym",
"section": "Victory Road",
"sprite_url": "/boss-sprites/scarlet/larry.png",
"pokemon": []
},
{
"name": "Ryme",
"boss_type": "gym_leader",
"specialty_type": "ghost",
"badge_name": "Ghost Badge",
"badge_image_url": "/badges/ghost-badge.png",
"level_cap": 42,
"order": 6,
"after_route_name": null,
"location": "Montenevera Gym",
"section": "Victory Road",
"sprite_url": "/boss-sprites/scarlet/ryme.png",
"pokemon": []
},
{
"name": "Tulip",
"boss_type": "gym_leader",
"specialty_type": "psychic",
"badge_name": "Psychic Badge",
"badge_image_url": "/badges/psychic-badge.png",
"level_cap": 45,
"order": 7,
"after_route_name": null,
"location": "Alfornada Gym",
"section": "Victory Road",
"sprite_url": "/boss-sprites/scarlet/tulip.png",
"pokemon": []
},
{
"name": "Grusha",
"boss_type": "gym_leader",
"specialty_type": "ice",
"badge_name": "Ice Badge",
"badge_image_url": "/badges/ice-badge.png",
"level_cap": 48,
"order": 8,
"after_route_name": null,
"location": "Glaseado Gym",
"section": "Victory Road",
"sprite_url": "/boss-sprites/scarlet/grusha.png",
"pokemon": []
},
{
"name": "Rika",
"boss_type": "elite_four",
"specialty_type": "ground",
"badge_name": null,
"badge_image_url": null,
"level_cap": 58,
"order": 9,
"after_route_name": null,
"location": "Pokemon League",
"section": "Victory Road",
"sprite_url": "/boss-sprites/scarlet/rika.png",
"pokemon": []
},
{
"name": "Poppy",
"boss_type": "elite_four",
"specialty_type": "steel",
"badge_name": null,
"badge_image_url": null,
"level_cap": 59,
"order": 10,
"after_route_name": null,
"location": "Pokemon League",
"section": "Victory Road",
"sprite_url": "/boss-sprites/scarlet/poppy.png",
"pokemon": []
},
{
"name": "Larry",
"boss_type": "elite_four",
"specialty_type": "flying",
"badge_name": null,
"badge_image_url": null,
"level_cap": 60,
"order": 11,
"after_route_name": null,
"location": "Pokemon League",
"section": "Victory Road",
"sprite_url": "/boss-sprites/scarlet/larry.png",
"pokemon": []
},
{
"name": "Hassel",
"boss_type": "elite_four",
"specialty_type": "dragon",
"badge_name": null,
"badge_image_url": null,
"level_cap": 61,
"order": 12,
"after_route_name": null,
"location": "Pokemon League",
"section": "Victory Road",
"sprite_url": "/boss-sprites/scarlet/hassel.png",
"pokemon": []
},
{
"name": "Top Champion Geeta",
"boss_type": "champion",
"specialty_type": null,
"badge_name": null,
"badge_image_url": null,
"level_cap": 62,
"order": 13,
"after_route_name": null,
"location": "Pokemon League",
"section": "Victory Road",
"sprite_url": "/boss-sprites/scarlet/top-champion-geeta.png",
"pokemon": []
},
{
"name": "Champion Nemona",
"boss_type": "champion",
"specialty_type": null,
"badge_name": null,
"badge_image_url": null,
"level_cap": 66,
"order": 14,
"after_route_name": null,
"location": "Pokemon League",
"section": "Victory Road",
"sprite_url": "/boss-sprites/scarlet/champion-nemona.png",
"pokemon": []
},
{
"name": "Giacomo",
"boss_type": "other",
"specialty_type": "dark",
"badge_name": null,
"badge_image_url": null,
"level_cap": 21,
"order": 15,
"after_route_name": null,
"location": "Team Star Dark Crew Base",
"section": "Starfall Street",
"sprite_url": "/boss-sprites/scarlet/giacomo.png",
"pokemon": []
},
{
"name": "Mela",
"boss_type": "other",
"specialty_type": "fire",
"badge_name": null,
"badge_image_url": null,
"level_cap": 27,
"order": 16,
"after_route_name": null,
"location": "Team Star Fire Crew Base",
"section": "Starfall Street",
"sprite_url": "/boss-sprites/scarlet/mela.png",
"pokemon": []
},
{
"name": "Atticus",
"boss_type": "other",
"specialty_type": "poison",
"badge_name": null,
"badge_image_url": null,
"level_cap": 33,
"order": 17,
"after_route_name": null,
"location": "Team Star Poison Crew Base",
"section": "Starfall Street",
"sprite_url": "/boss-sprites/scarlet/atticus.png",
"pokemon": []
},
{
"name": "Ortega",
"boss_type": "other",
"specialty_type": "fairy",
"badge_name": null,
"badge_image_url": null,
"level_cap": 50,
"order": 18,
"after_route_name": null,
"location": "Team Star Fairy Crew Base",
"section": "Starfall Street",
"sprite_url": "/boss-sprites/scarlet/ortega.png",
"pokemon": []
},
{
"name": "Eri",
"boss_type": "other",
"specialty_type": "fighting",
"badge_name": null,
"badge_image_url": null,
"level_cap": 56,
"order": 19,
"after_route_name": null,
"location": "Team Star Fighting Crew Base",
"section": "Starfall Street",
"sprite_url": "/boss-sprites/scarlet/eri.png",
"pokemon": []
},
{
"name": "Stony Cliff Titan",
"boss_type": "other",
"specialty_type": "rock",
"badge_name": null,
"badge_image_url": null,
"level_cap": 16,
"order": 20,
"after_route_name": null,
"location": "South Province (Area Three)",
"section": "Path of Legends",
"sprite_url": "/boss-sprites/scarlet/stony-cliff-titan.png",
"pokemon": []
},
{
"name": "Open Sky Titan",
"boss_type": "other",
"specialty_type": "flying",
"badge_name": null,
"badge_image_url": null,
"level_cap": 20,
"order": 21,
"after_route_name": null,
"location": "West Province (Area One)",
"section": "Path of Legends",
"sprite_url": "/boss-sprites/scarlet/open-sky-titan.png",
"pokemon": []
},
{
"name": "Lurking Steel Titan",
"boss_type": "other",
"specialty_type": "steel",
"badge_name": null,
"badge_image_url": null,
"level_cap": 29,
"order": 22,
"after_route_name": null,
"location": "East Province (Area Three)",
"section": "Path of Legends",
"sprite_url": "/boss-sprites/scarlet/lurking-steel-titan.png",
"pokemon": []
},
{
"name": "Quaking Earth Titan",
"boss_type": "other",
"specialty_type": "ground",
"badge_name": null,
"badge_image_url": null,
"level_cap": 45,
"order": 23,
"after_route_name": null,
"location": "Asado Desert",
"section": "Path of Legends",
"sprite_url": "/boss-sprites/scarlet/quaking-earth-titan.png",
"pokemon": []
},
{
"name": "False Dragon Titan",
"boss_type": "other",
"specialty_type": "water",
"badge_name": null,
"badge_image_url": null,
"level_cap": 56,
"order": 24,
"after_route_name": null,
"location": "Casseroya Lake",
"section": "Path of Legends",
"sprite_url": "/boss-sprites/scarlet/false-dragon-titan.png",
"pokemon": []
}
]
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+226
View File
@@ -0,0 +1,226 @@
[
{
"name": "Totem Gumshoos",
"boss_type": "totem",
"specialty_type": "normal",
"badge_name": null,
"badge_image_url": null,
"level_cap": 12,
"order": 1,
"after_route_name": null,
"location": "Verdant Cavern",
"section": "Melemele Island",
"sprite_url": "/boss-sprites/sun/totem-gumshoos.png",
"pokemon": []
},
{
"name": "Hala",
"boss_type": "kahuna",
"specialty_type": "fighting",
"badge_name": null,
"badge_image_url": null,
"level_cap": 15,
"order": 2,
"after_route_name": null,
"location": "Iki Town",
"section": "Melemele Island",
"sprite_url": "/boss-sprites/sun/hala.png",
"pokemon": []
},
{
"name": "Totem Wishiwashi",
"boss_type": "totem",
"specialty_type": "water",
"badge_name": null,
"badge_image_url": null,
"level_cap": 24,
"order": 3,
"after_route_name": null,
"location": "Brooklet Hill",
"section": "Akala Island",
"sprite_url": "/boss-sprites/sun/totem-wishiwashi.png",
"pokemon": []
},
{
"name": "Totem Salazzle",
"boss_type": "totem",
"specialty_type": "fire",
"badge_name": null,
"badge_image_url": null,
"level_cap": 24,
"order": 4,
"after_route_name": null,
"location": "Wela Volcano Park",
"section": "Akala Island",
"sprite_url": "/boss-sprites/sun/totem-salazzle.png",
"pokemon": []
},
{
"name": "Totem Lurantis",
"boss_type": "totem",
"specialty_type": "grass",
"badge_name": null,
"badge_image_url": null,
"level_cap": 24,
"order": 5,
"after_route_name": null,
"location": "Lush Jungle",
"section": "Akala Island",
"sprite_url": "/boss-sprites/sun/totem-lurantis.png",
"pokemon": []
},
{
"name": "Olivia",
"boss_type": "kahuna",
"specialty_type": "rock",
"badge_name": null,
"badge_image_url": null,
"level_cap": 27,
"order": 6,
"after_route_name": null,
"location": "Ruins of Life",
"section": "Akala Island",
"sprite_url": "/boss-sprites/sun/olivia.png",
"pokemon": []
},
{
"name": "Totem Vikavolt",
"boss_type": "totem",
"specialty_type": "bug",
"badge_name": null,
"badge_image_url": null,
"level_cap": 29,
"order": 7,
"after_route_name": null,
"location": "Hokulani Observatory",
"section": "Ula'ula Island",
"sprite_url": "/boss-sprites/sun/totem-vikavolt.png",
"pokemon": []
},
{
"name": "Totem Mimikyu",
"boss_type": "totem",
"specialty_type": "ghost",
"badge_name": null,
"badge_image_url": null,
"level_cap": 33,
"order": 8,
"after_route_name": null,
"location": "Thrifty Megamart",
"section": "Ula'ula Island",
"sprite_url": "/boss-sprites/sun/totem-mimikyu.png",
"pokemon": []
},
{
"name": "Nanu",
"boss_type": "kahuna",
"specialty_type": "dark",
"badge_name": null,
"badge_image_url": null,
"level_cap": 34,
"order": 9,
"after_route_name": null,
"location": "Malie City",
"section": "Ula'ula Island",
"sprite_url": "/boss-sprites/sun/nanu.png",
"pokemon": []
},
{
"name": "Totem Kommo-o",
"boss_type": "totem",
"specialty_type": "dragon",
"badge_name": null,
"badge_image_url": null,
"level_cap": 45,
"order": 10,
"after_route_name": null,
"location": "Vast Poni Canyon",
"section": "Poni Island",
"sprite_url": "/boss-sprites/sun/totem-kommo-o.png",
"pokemon": []
},
{
"name": "Hapu",
"boss_type": "kahuna",
"specialty_type": "ground",
"badge_name": null,
"badge_image_url": null,
"level_cap": 48,
"order": 11,
"after_route_name": null,
"location": "Exeggutor Island",
"section": "Poni Island",
"sprite_url": "/boss-sprites/sun/hapu.png",
"pokemon": []
},
{
"name": "Hala",
"boss_type": "elite_four",
"specialty_type": "fighting",
"badge_name": null,
"badge_image_url": null,
"level_cap": 56,
"order": 12,
"after_route_name": null,
"location": "Pokemon League",
"section": "Pokemon League",
"sprite_url": "/boss-sprites/sun/hala.png",
"pokemon": []
},
{
"name": "Olivia",
"boss_type": "elite_four",
"specialty_type": "rock",
"badge_name": null,
"badge_image_url": null,
"level_cap": 56,
"order": 13,
"after_route_name": null,
"location": "Pokemon League",
"section": "Pokemon League",
"sprite_url": "/boss-sprites/sun/olivia.png",
"pokemon": []
},
{
"name": "Acerola",
"boss_type": "elite_four",
"specialty_type": "ghost",
"badge_name": null,
"badge_image_url": null,
"level_cap": 56,
"order": 14,
"after_route_name": null,
"location": "Pokemon League",
"section": "Pokemon League",
"sprite_url": "/boss-sprites/sun/acerola.png",
"pokemon": []
},
{
"name": "Kahili",
"boss_type": "elite_four",
"specialty_type": "flying",
"badge_name": null,
"badge_image_url": null,
"level_cap": 56,
"order": 15,
"after_route_name": null,
"location": "Pokemon League",
"section": "Pokemon League",
"sprite_url": "/boss-sprites/sun/kahili.png",
"pokemon": []
},
{
"name": "Professor Kukui",
"boss_type": "champion",
"specialty_type": null,
"badge_name": null,
"badge_image_url": null,
"level_cap": 58,
"order": 16,
"after_route_name": null,
"location": "Pokemon League",
"section": "Pokemon League",
"sprite_url": "/boss-sprites/sun/professor-kukui.png",
"pokemon": []
}
]
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,156 @@
[
{
"name": "Milo",
"boss_type": "gym_leader",
"specialty_type": "grass",
"badge_name": "Grass Badge",
"badge_image_url": "/badges/grass-badge.png",
"level_cap": 20,
"order": 1,
"after_route_name": null,
"location": "Turffield Stadium",
"section": "Main Story",
"sprite_url": "/boss-sprites/sword/milo.png",
"pokemon": []
},
{
"name": "Nessa",
"boss_type": "gym_leader",
"specialty_type": "water",
"badge_name": "Water Badge",
"badge_image_url": "/badges/water-badge.png",
"level_cap": 24,
"order": 2,
"after_route_name": null,
"location": "Hulbury Stadium",
"section": "Main Story",
"sprite_url": "/boss-sprites/sword/nessa.png",
"pokemon": []
},
{
"name": "Kabu",
"boss_type": "gym_leader",
"specialty_type": "fire",
"badge_name": "Fire Badge",
"badge_image_url": "/badges/fire-badge.png",
"level_cap": 27,
"order": 3,
"after_route_name": null,
"location": "Motostoke Stadium",
"section": "Main Story",
"sprite_url": "/boss-sprites/sword/kabu.png",
"pokemon": []
},
{
"name": "Bea",
"boss_type": "gym_leader",
"specialty_type": "fighting",
"badge_name": "Fighting Badge",
"badge_image_url": "/badges/fighting-badge.png",
"level_cap": 36,
"order": 4,
"after_route_name": null,
"location": "Stow-on-Side Stadium",
"section": "Sword",
"sprite_url": "/boss-sprites/sword/bea.png",
"pokemon": []
},
{
"name": "Allister",
"boss_type": "gym_leader",
"specialty_type": "ghost",
"badge_name": "Ghost Badge",
"badge_image_url": "/badges/ghost-badge.png",
"level_cap": 36,
"order": 5,
"after_route_name": null,
"location": "Stow-on-Side Stadium",
"section": "Shield",
"sprite_url": "/boss-sprites/sword/allister.png",
"pokemon": []
},
{
"name": "Opal",
"boss_type": "gym_leader",
"specialty_type": "fairy",
"badge_name": "Fairy Badge",
"badge_image_url": "/badges/fairy-badge.png",
"level_cap": 38,
"order": 6,
"after_route_name": null,
"location": "Ballonlea Stadium",
"section": "Main Story",
"sprite_url": "/boss-sprites/sword/opal.png",
"pokemon": []
},
{
"name": "Gordie",
"boss_type": "gym_leader",
"specialty_type": "rock",
"badge_name": "Rock Badge",
"badge_image_url": "/badges/rock-badge.png",
"level_cap": 42,
"order": 7,
"after_route_name": null,
"location": "Circhester Stadium",
"section": "Sword",
"sprite_url": "/boss-sprites/sword/gordie.png",
"pokemon": []
},
{
"name": "Melony",
"boss_type": "gym_leader",
"specialty_type": "ice",
"badge_name": "Ice Badge",
"badge_image_url": "/badges/ice-badge.png",
"level_cap": 42,
"order": 8,
"after_route_name": null,
"location": "Circhester Stadium",
"section": "Shield",
"sprite_url": "/boss-sprites/sword/melony.png",
"pokemon": []
},
{
"name": "Piers",
"boss_type": "gym_leader",
"specialty_type": "dark",
"badge_name": "Dark Badge",
"badge_image_url": "/badges/dark-badge.png",
"level_cap": 46,
"order": 9,
"after_route_name": null,
"location": "Spikemuth",
"section": "Main Story",
"sprite_url": "/boss-sprites/sword/piers.png",
"pokemon": []
},
{
"name": "Raihan",
"boss_type": "gym_leader",
"specialty_type": "dragon",
"badge_name": "Dragon Badge",
"badge_image_url": "/badges/dragon-badge.png",
"level_cap": 48,
"order": 10,
"after_route_name": null,
"location": "Hammerlocke Stadium",
"section": "Main Story",
"sprite_url": "/boss-sprites/sword/raihan.png",
"pokemon": []
},
{
"name": "Leon",
"boss_type": "champion",
"specialty_type": null,
"badge_name": null,
"badge_image_url": null,
"level_cap": 65,
"order": 11,
"after_route_name": null,
"location": "Wyndon Stadium",
"section": "Main Story",
"sprite_url": "/boss-sprites/sword/leon.png",
"pokemon": []
}
]
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,254 @@
[
{
"name": "Totem Gumshoos",
"boss_type": "totem",
"specialty_type": "normal",
"badge_name": null,
"badge_image_url": null,
"level_cap": 12,
"order": 1,
"after_route_name": null,
"location": "Verdant Cavern",
"section": "Melemele Island",
"sprite_url": "/boss-sprites/ultra-sun/totem-gumshoos.png",
"pokemon": []
},
{
"name": "Hala",
"boss_type": "kahuna",
"specialty_type": "fighting",
"badge_name": null,
"badge_image_url": null,
"level_cap": 15,
"order": 2,
"after_route_name": null,
"location": "Iki Town",
"section": "Melemele Island",
"sprite_url": "/boss-sprites/ultra-sun/hala.png",
"pokemon": []
},
{
"name": "Totem Araquanid",
"boss_type": "totem",
"specialty_type": "water",
"badge_name": null,
"badge_image_url": null,
"level_cap": 24,
"order": 3,
"after_route_name": null,
"location": "Brooklet Hill",
"section": "Akala Island",
"sprite_url": "/boss-sprites/ultra-sun/totem-araquanid.png",
"pokemon": []
},
{
"name": "Totem Salazzle",
"boss_type": "totem",
"specialty_type": "fire",
"badge_name": null,
"badge_image_url": null,
"level_cap": 24,
"order": 4,
"after_route_name": null,
"location": "Wela Volcano Park",
"section": "Akala Island",
"sprite_url": "/boss-sprites/ultra-sun/totem-salazzle.png",
"pokemon": []
},
{
"name": "Totem Lurantis",
"boss_type": "totem",
"specialty_type": "grass",
"badge_name": null,
"badge_image_url": null,
"level_cap": 24,
"order": 5,
"after_route_name": null,
"location": "Lush Jungle",
"section": "Akala Island",
"sprite_url": "/boss-sprites/ultra-sun/totem-lurantis.png",
"pokemon": []
},
{
"name": "Olivia",
"boss_type": "kahuna",
"specialty_type": "rock",
"badge_name": null,
"badge_image_url": null,
"level_cap": 27,
"order": 6,
"after_route_name": null,
"location": "Ruins of Life",
"section": "Akala Island",
"sprite_url": "/boss-sprites/ultra-sun/olivia.png",
"pokemon": []
},
{
"name": "Totem Vikavolt",
"boss_type": "totem",
"specialty_type": "bug",
"badge_name": null,
"badge_image_url": null,
"level_cap": 29,
"order": 7,
"after_route_name": null,
"location": "Hokulani Observatory",
"section": "Ula'ula Island",
"sprite_url": "/boss-sprites/ultra-sun/totem-vikavolt.png",
"pokemon": []
},
{
"name": "Totem Mimikyu",
"boss_type": "totem",
"specialty_type": "ghost",
"badge_name": null,
"badge_image_url": null,
"level_cap": 33,
"order": 8,
"after_route_name": null,
"location": "Thrifty Megamart",
"section": "Ula'ula Island",
"sprite_url": "/boss-sprites/ultra-sun/totem-mimikyu.png",
"pokemon": []
},
{
"name": "Totem Togedemaru",
"boss_type": "totem",
"specialty_type": "electric",
"badge_name": null,
"badge_image_url": null,
"level_cap": 33,
"order": 9,
"after_route_name": null,
"location": "Hokulani Observatory",
"section": "Ula'ula Island",
"sprite_url": "/boss-sprites/ultra-sun/totem-togedemaru.png",
"pokemon": []
},
{
"name": "Nanu",
"boss_type": "kahuna",
"specialty_type": "dark",
"badge_name": null,
"badge_image_url": null,
"level_cap": 34,
"order": 10,
"after_route_name": null,
"location": "Malie City",
"section": "Ula'ula Island",
"sprite_url": "/boss-sprites/ultra-sun/nanu.png",
"pokemon": []
},
{
"name": "Totem Kommo-o",
"boss_type": "totem",
"specialty_type": "dragon",
"badge_name": null,
"badge_image_url": null,
"level_cap": 45,
"order": 11,
"after_route_name": null,
"location": "Vast Poni Canyon",
"section": "Poni Island",
"sprite_url": "/boss-sprites/ultra-sun/totem-kommo-o.png",
"pokemon": []
},
{
"name": "Totem Ribombee",
"boss_type": "totem",
"specialty_type": "fairy",
"badge_name": null,
"badge_image_url": null,
"level_cap": 50,
"order": 12,
"after_route_name": null,
"location": "Seafolk Village",
"section": "Poni Island",
"sprite_url": "/boss-sprites/ultra-sun/totem-ribombee.png",
"pokemon": []
},
{
"name": "Hapu",
"boss_type": "kahuna",
"specialty_type": "ground",
"badge_name": null,
"badge_image_url": null,
"level_cap": 48,
"order": 13,
"after_route_name": null,
"location": "Exeggutor Island",
"section": "Poni Island",
"sprite_url": "/boss-sprites/ultra-sun/hapu.png",
"pokemon": []
},
{
"name": "Molayne",
"boss_type": "elite_four",
"specialty_type": "steel",
"badge_name": null,
"badge_image_url": null,
"level_cap": 56,
"order": 14,
"after_route_name": null,
"location": "Pokemon League",
"section": "Pokemon League",
"sprite_url": "/boss-sprites/ultra-sun/molayne.png",
"pokemon": []
},
{
"name": "Olivia",
"boss_type": "elite_four",
"specialty_type": "rock",
"badge_name": null,
"badge_image_url": null,
"level_cap": 56,
"order": 15,
"after_route_name": null,
"location": "Pokemon League",
"section": "Pokemon League",
"sprite_url": "/boss-sprites/ultra-sun/olivia.png",
"pokemon": []
},
{
"name": "Acerola",
"boss_type": "elite_four",
"specialty_type": "ghost",
"badge_name": null,
"badge_image_url": null,
"level_cap": 56,
"order": 16,
"after_route_name": null,
"location": "Pokemon League",
"section": "Pokemon League",
"sprite_url": "/boss-sprites/ultra-sun/acerola.png",
"pokemon": []
},
{
"name": "Kahili",
"boss_type": "elite_four",
"specialty_type": "flying",
"badge_name": null,
"badge_image_url": null,
"level_cap": 56,
"order": 17,
"after_route_name": null,
"location": "Pokemon League",
"section": "Pokemon League",
"sprite_url": "/boss-sprites/ultra-sun/kahili.png",
"pokemon": []
},
{
"name": "Hau",
"boss_type": "champion",
"specialty_type": null,
"badge_name": null,
"badge_image_url": null,
"level_cap": 58,
"order": 18,
"after_route_name": null,
"location": "Pokemon League",
"section": "Pokemon League",
"sprite_url": "/boss-sprites/ultra-sun/hau.png",
"pokemon": []
}
]
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+184
View File
@@ -0,0 +1,184 @@
[
{
"name": "Viola",
"boss_type": "gym_leader",
"specialty_type": "bug",
"badge_name": "Bug Badge",
"badge_image_url": "/badges/bug-badge.png",
"level_cap": 12,
"order": 1,
"after_route_name": "Santalune City",
"location": "Santalune Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/x/viola.png",
"pokemon": []
},
{
"name": "Grant",
"boss_type": "gym_leader",
"specialty_type": "rock",
"badge_name": "Cliff Badge",
"badge_image_url": "/badges/cliff-badge.png",
"level_cap": 25,
"order": 2,
"after_route_name": "Cyllage City",
"location": "Cyllage Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/x/grant.png",
"pokemon": []
},
{
"name": "Korrina",
"boss_type": "gym_leader",
"specialty_type": "fighting",
"badge_name": "Rumble Badge",
"badge_image_url": "/badges/rumble-badge.png",
"level_cap": 32,
"order": 3,
"after_route_name": "Shalour City",
"location": "Shalour Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/x/korrina.png",
"pokemon": []
},
{
"name": "Ramos",
"boss_type": "gym_leader",
"specialty_type": "grass",
"badge_name": "Plant Badge",
"badge_image_url": "/badges/plant-badge.png",
"level_cap": 34,
"order": 4,
"after_route_name": "Coumarine City",
"location": "Coumarine Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/x/ramos.png",
"pokemon": []
},
{
"name": "Clemont",
"boss_type": "gym_leader",
"specialty_type": "electric",
"badge_name": "Voltage Badge",
"badge_image_url": "/badges/voltage-badge.png",
"level_cap": 37,
"order": 5,
"after_route_name": "Lumiose City",
"location": "Lumiose Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/x/clemont.png",
"pokemon": []
},
{
"name": "Valerie",
"boss_type": "gym_leader",
"specialty_type": "fairy",
"badge_name": "Fairy Badge",
"badge_image_url": "/badges/fairy-badge.png",
"level_cap": 38,
"order": 6,
"after_route_name": "Laverre City",
"location": "Laverre Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/x/valerie.png",
"pokemon": []
},
{
"name": "Olympia",
"boss_type": "gym_leader",
"specialty_type": "psychic",
"badge_name": "Psychic Badge",
"badge_image_url": "/badges/psychic-badge.png",
"level_cap": 44,
"order": 7,
"after_route_name": "Anistar City",
"location": "Anistar Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/x/olympia.png",
"pokemon": []
},
{
"name": "Wulfric",
"boss_type": "gym_leader",
"specialty_type": "ice",
"badge_name": "Iceberg Badge",
"badge_image_url": "/badges/iceberg-badge.png",
"level_cap": 48,
"order": 8,
"after_route_name": "Snowbelle City",
"location": "Snowbelle Gym",
"section": "Main Story",
"sprite_url": "/boss-sprites/x/wulfric.png",
"pokemon": []
},
{
"name": "Malva",
"boss_type": "elite_four",
"specialty_type": "fire",
"badge_name": null,
"badge_image_url": null,
"level_cap": 63,
"order": 9,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/x/malva.png",
"pokemon": []
},
{
"name": "Siebold",
"boss_type": "elite_four",
"specialty_type": "water",
"badge_name": null,
"badge_image_url": null,
"level_cap": 63,
"order": 10,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/x/siebold.png",
"pokemon": []
},
{
"name": "Wikstrom",
"boss_type": "elite_four",
"specialty_type": "steel",
"badge_name": null,
"badge_image_url": null,
"level_cap": 63,
"order": 11,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/x/wikstrom.png",
"pokemon": []
},
{
"name": "Drasna",
"boss_type": "elite_four",
"specialty_type": "dragon",
"badge_name": null,
"badge_image_url": null,
"level_cap": 63,
"order": 12,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/x/drasna.png",
"pokemon": []
},
{
"name": "Diantha",
"boss_type": "champion",
"specialty_type": null,
"badge_name": null,
"badge_image_url": null,
"level_cap": 68,
"order": 13,
"after_route_name": "Victory Road",
"location": "Pokemon League",
"section": "Main Story",
"sprite_url": "/boss-sprites/x/diantha.png",
"pokemon": []
}
]
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1 -15
View File
@@ -2,7 +2,6 @@
"_comment": "Route progression order by version group. Aliases at the bottom map version groups that share the same ordering.", "_comment": "Route progression order by version group. Aliases at the bottom map version groups that share the same ordering.",
"routes": { "routes": {
"firered-leafgreen": [ "firered-leafgreen": [
"Starter",
"Pallet Town", "Pallet Town",
"Professor Oak's Laboratory", "Professor Oak's Laboratory",
"Route 01 (Kanto)", "Route 01 (Kanto)",
@@ -85,7 +84,6 @@
"Navel Rock" "Navel Rock"
], ],
"heartgold-soulsilver": [ "heartgold-soulsilver": [
"Starter",
"New Bark Town", "New Bark Town",
"Route 29 (Johto)", "Route 29 (Johto)",
"Cherrygrove City", "Cherrygrove City",
@@ -191,7 +189,6 @@
"Sinjoh Ruins" "Sinjoh Ruins"
], ],
"emerald": [ "emerald": [
"Starter",
"Littleroot Town", "Littleroot Town",
"Hoenn Route 101", "Hoenn Route 101",
"Hoenn Route 103", "Hoenn Route 103",
@@ -276,7 +273,6 @@
"Navel Rock" "Navel Rock"
], ],
"platinum": [ "platinum": [
"Starter",
"Twinleaf Town", "Twinleaf Town",
"Lake Verity", "Lake Verity",
"Route 201 (Sinnoh)", "Route 201 (Sinnoh)",
@@ -356,7 +352,6 @@
"Iron Ruins (Sinnoh)" "Iron Ruins (Sinnoh)"
], ],
"diamond-pearl": [ "diamond-pearl": [
"Starter",
"Twinleaf Town", "Twinleaf Town",
"Lake Verity", "Lake Verity",
"Route 201 (Sinnoh)", "Route 201 (Sinnoh)",
@@ -430,7 +425,6 @@
"Rock Peak Ruins (Sinnoh)" "Rock Peak Ruins (Sinnoh)"
], ],
"black-white": [ "black-white": [
"Starter",
"Nuvema Town", "Nuvema Town",
"Unova Route 1", "Unova Route 1",
"Unova Route 2", "Unova Route 2",
@@ -483,7 +477,6 @@
"Liberty Garden" "Liberty Garden"
], ],
"black-2-white-2": [ "black-2-white-2": [
"Starter",
"Aspertia City", "Aspertia City",
"Unova Route 19", "Unova Route 19",
"Floccesy Town", "Floccesy Town",
@@ -550,7 +543,6 @@
"Nature Preserve" "Nature Preserve"
], ],
"x-y": [ "x-y": [
"Starter",
"Vaniville Town", "Vaniville Town",
"Aquacorde Town", "Aquacorde Town",
"Kalos Route 02", "Kalos Route 02",
@@ -605,7 +597,6 @@
"Friend Safari" "Friend Safari"
], ],
"sun-moon": [ "sun-moon": [
"Starter",
"Iki Town", "Iki Town",
"Alola Route 1", "Alola Route 1",
"Trainers School (Alola)", "Trainers School (Alola)",
@@ -677,7 +668,7 @@
"Ruins of Conflict" "Ruins of Conflict"
], ],
"ultra-sun-ultra-moon": [ "ultra-sun-ultra-moon": [
"Starter", "Iki Town",
"Alola Route 1", "Alola Route 1",
"Trainers School (Alola)", "Trainers School (Alola)",
"Hau'oli City", "Hau'oli City",
@@ -762,7 +753,6 @@
"Ruins of Abundance" "Ruins of Abundance"
], ],
"sword-shield": [ "sword-shield": [
"Starter",
"Postwick", "Postwick",
"Slumbering Weald", "Slumbering Weald",
"Wedgehurst", "Wedgehurst",
@@ -848,7 +838,6 @@
"Meetup Spot" "Meetup Spot"
], ],
"brilliant-diamond-shining-pearl": [ "brilliant-diamond-shining-pearl": [
"Starter",
"Twinleaf Town", "Twinleaf Town",
"Lake Verity", "Lake Verity",
"Route 201 (Sinnoh)", "Route 201 (Sinnoh)",
@@ -943,7 +932,6 @@
"Hall of Origin" "Hall of Origin"
], ],
"legends-arceus": [ "legends-arceus": [
"Starter",
"Jubilife Village", "Jubilife Village",
"Aspiration Hill", "Aspiration Hill",
"Floaro Gardens", "Floaro Gardens",
@@ -1034,7 +1022,6 @@
"Lake Verity #2" "Lake Verity #2"
], ],
"scarlet-violet": [ "scarlet-violet": [
"Starter",
"Cabo Poco", "Cabo Poco",
"Poco Path", "Poco Path",
"Area One (South Province)", "Area One (South Province)",
@@ -1107,7 +1094,6 @@
"Random (Around Terrarium)" "Random (Around Terrarium)"
], ],
"legends-z-a": [ "legends-z-a": [
"Starter",
"Wild Zone 1", "Wild Zone 1",
"Wild Zone 2", "Wild Zone 2",
"Wild Zone 3", "Wild Zone 3",
+27 -15
View File
@@ -1,88 +1,102 @@
{ {
"encounters": { "encounters": {
"firered-leafgreen": { "firered-leafgreen": {
"Starter": [ "Professor Oak's Laboratory": [
{"pokeapi_id": 1, "pokemon_name": "bulbasaur", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}, {"pokeapi_id": 1, "pokemon_name": "bulbasaur", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 4, "pokemon_name": "charmander", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}, {"pokeapi_id": 4, "pokemon_name": "charmander", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 7, "pokemon_name": "squirtle", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5} {"pokeapi_id": 7, "pokemon_name": "squirtle", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}
] ]
}, },
"yellow": { "yellow": {
"Starter": [ "Pallet Town": [
{"pokeapi_id": 25, "pokemon_name": "pikachu", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5} {"pokeapi_id": 25, "pokemon_name": "pikachu", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}
] ]
}, },
"heartgold-soulsilver": { "heartgold-soulsilver": {
"Starter": [ "New Bark Town": [
{"pokeapi_id": 152, "pokemon_name": "chikorita", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}, {"pokeapi_id": 152, "pokemon_name": "chikorita", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 155, "pokemon_name": "cyndaquil", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}, {"pokeapi_id": 155, "pokemon_name": "cyndaquil", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 158, "pokemon_name": "totodile", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5} {"pokeapi_id": 158, "pokemon_name": "totodile", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}
] ]
}, },
"ruby-sapphire": {
"Hoenn Route 101": [
{"pokeapi_id": 252, "pokemon_name": "treecko", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 255, "pokemon_name": "torchic", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 258, "pokemon_name": "mudkip", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}
]
},
"emerald": { "emerald": {
"Starter": [ "Littleroot Town": [
{"pokeapi_id": 252, "pokemon_name": "treecko", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}, {"pokeapi_id": 252, "pokemon_name": "treecko", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 255, "pokemon_name": "torchic", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}, {"pokeapi_id": 255, "pokemon_name": "torchic", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 258, "pokemon_name": "mudkip", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5} {"pokeapi_id": 258, "pokemon_name": "mudkip", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}
] ]
}, },
"diamond-pearl": { "diamond-pearl": {
"Starter": [ "Twinleaf Town": [
{"pokeapi_id": 387, "pokemon_name": "turtwig", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}, {"pokeapi_id": 387, "pokemon_name": "turtwig", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 390, "pokemon_name": "chimchar", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}, {"pokeapi_id": 390, "pokemon_name": "chimchar", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 393, "pokemon_name": "piplup", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5} {"pokeapi_id": 393, "pokemon_name": "piplup", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}
] ]
}, },
"black-white": { "black-white": {
"Starter": [ "Nuvema Town": [
{"pokeapi_id": 495, "pokemon_name": "snivy", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 498, "pokemon_name": "tepig", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 501, "pokemon_name": "oshawott", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}
]
},
"black-2-white-2": {
"Aspertia City": [
{"pokeapi_id": 495, "pokemon_name": "snivy", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}, {"pokeapi_id": 495, "pokemon_name": "snivy", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 498, "pokemon_name": "tepig", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}, {"pokeapi_id": 498, "pokemon_name": "tepig", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 501, "pokemon_name": "oshawott", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5} {"pokeapi_id": 501, "pokemon_name": "oshawott", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}
] ]
}, },
"x-y": { "x-y": {
"Starter": [ "Vaniville Town": [
{"pokeapi_id": 650, "pokemon_name": "chespin", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}, {"pokeapi_id": 650, "pokemon_name": "chespin", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 653, "pokemon_name": "fennekin", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}, {"pokeapi_id": 653, "pokemon_name": "fennekin", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 656, "pokemon_name": "froakie", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5} {"pokeapi_id": 656, "pokemon_name": "froakie", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}
] ]
}, },
"sun-moon": { "sun-moon": {
"Starter": [ "Iki Town": [
{"pokeapi_id": 722, "pokemon_name": "rowlet", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}, {"pokeapi_id": 722, "pokemon_name": "rowlet", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 725, "pokemon_name": "litten", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}, {"pokeapi_id": 725, "pokemon_name": "litten", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 728, "pokemon_name": "popplio", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5} {"pokeapi_id": 728, "pokemon_name": "popplio", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}
] ]
}, },
"lets-go": { "lets-go": {
"Starter": [ "Professor Oak's Laboratory": [
{"pokeapi_id": 25, "pokemon_name": "pikachu", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}, {"pokeapi_id": 25, "pokemon_name": "pikachu", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 133, "pokemon_name": "eevee", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5} {"pokeapi_id": 133, "pokemon_name": "eevee", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}
] ]
}, },
"sword-shield": { "sword-shield": {
"Starter": [ "Postwick": [
{"pokeapi_id": 810, "pokemon_name": "grookey", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}, {"pokeapi_id": 810, "pokemon_name": "grookey", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 813, "pokemon_name": "scorbunny", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}, {"pokeapi_id": 813, "pokemon_name": "scorbunny", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 816, "pokemon_name": "sobble", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5} {"pokeapi_id": 816, "pokemon_name": "sobble", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}
] ]
}, },
"legends-arceus": { "legends-arceus": {
"Starter": [ "Jubilife Village": [
{"pokeapi_id": 722, "pokemon_name": "rowlet", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}, {"pokeapi_id": 722, "pokemon_name": "rowlet", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 155, "pokemon_name": "cyndaquil", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}, {"pokeapi_id": 155, "pokemon_name": "cyndaquil", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 501, "pokemon_name": "oshawott", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5} {"pokeapi_id": 501, "pokemon_name": "oshawott", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}
] ]
}, },
"scarlet-violet": { "scarlet-violet": {
"Starter": [ "Cabo Poco": [
{"pokeapi_id": 906, "pokemon_name": "sprigatito", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}, {"pokeapi_id": 906, "pokemon_name": "sprigatito", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 909, "pokemon_name": "fuecoco", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}, {"pokeapi_id": 909, "pokemon_name": "fuecoco", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 912, "pokemon_name": "quaxly", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5} {"pokeapi_id": 912, "pokemon_name": "quaxly", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}
] ]
}, },
"legends-z-a": { "legends-z-a": {
"Starter": [ "Wild Zone 1": [
{"pokeapi_id": 152, "pokemon_name": "chikorita", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}, {"pokeapi_id": 152, "pokemon_name": "chikorita", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 158, "pokemon_name": "totodile", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}, {"pokeapi_id": 158, "pokemon_name": "totodile", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5},
{"pokeapi_id": 498, "pokemon_name": "tepig", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5} {"pokeapi_id": 498, "pokemon_name": "tepig", "method": "starter", "encounter_rate": 100, "min_level": 5, "max_level": 5}
@@ -93,11 +107,9 @@
"red-blue": "firered-leafgreen", "red-blue": "firered-leafgreen",
"gold-silver": "heartgold-soulsilver", "gold-silver": "heartgold-soulsilver",
"crystal": "heartgold-soulsilver", "crystal": "heartgold-soulsilver",
"ruby-sapphire": "emerald",
"omega-ruby-alpha-sapphire": "emerald", "omega-ruby-alpha-sapphire": "emerald",
"platinum": "diamond-pearl", "platinum": "diamond-pearl",
"brilliant-diamond-shining-pearl": "diamond-pearl", "brilliant-diamond-shining-pearl": "diamond-pearl",
"black-2-white-2": "black-white",
"ultra-sun-ultra-moon": "sun-moon" "ultra-sun-ultra-moon": "sun-moon"
} }
} }
+47
View File
@@ -0,0 +1,47 @@
import json
import random
from functools import lru_cache
from pathlib import Path
DICTIONARY_PATH = (
Path(__file__).resolve().parents[1] / "seeds" / "data" / "name_dictionary.json"
)
@lru_cache(maxsize=1)
def _load_dictionary() -> dict[str, list[str]]:
if not DICTIONARY_PATH.exists():
return {}
with open(DICTIONARY_PATH) as f:
return json.load(f)
def get_naming_categories() -> list[str]:
"""Return sorted list of available naming category names."""
return sorted(_load_dictionary().keys())
def get_words_for_category(category: str) -> list[str]:
"""Return the word list for a category, or empty list if not found."""
return _load_dictionary().get(category, [])
def suggest_names(
category: str,
used_names: set[str],
count: int = 10,
) -> list[str]:
"""Pick random name suggestions from a category, excluding used names.
Returns up to `count` names. If the category is nearly exhausted,
returns fewer.
"""
words = get_words_for_category(category)
if not words:
return []
available = [w for w in words if w not in used_names]
if not available:
return []
return random.sample(available, min(count, len(available)))
+84
View File
@@ -0,0 +1,84 @@
from unittest.mock import patch
import pytest
from app.services.naming import (
get_naming_categories,
get_words_for_category,
suggest_names,
)
MOCK_DICTIONARY = {
"mythology": ["Apollo", "Athena", "Loki", "Thor", "Zeus"],
"food": ["Basil", "Sage", "Pepper", "Saffron", "Mango"],
"space": ["Apollo", "Nova", "Nebula", "Comet", "Vega"],
}
@pytest.fixture(autouse=True)
def _mock_dictionary():
with patch("app.services.naming._load_dictionary", return_value=MOCK_DICTIONARY):
yield
class TestGetNamingCategories:
def test_returns_sorted_categories(self):
result = get_naming_categories()
assert result == ["food", "mythology", "space"]
def test_returns_empty_for_empty_dictionary(self):
with patch("app.services.naming._load_dictionary", return_value={}):
assert get_naming_categories() == []
class TestGetWordsForCategory:
def test_returns_words_for_valid_category(self):
result = get_words_for_category("mythology")
assert result == ["Apollo", "Athena", "Loki", "Thor", "Zeus"]
def test_returns_empty_for_unknown_category(self):
assert get_words_for_category("nonexistent") == []
class TestSuggestNames:
def test_returns_requested_count(self):
result = suggest_names("mythology", set(), count=3)
assert len(result) == 3
assert all(name in MOCK_DICTIONARY["mythology"] for name in result)
def test_excludes_used_names(self):
used = {"Apollo", "Athena", "Loki"}
result = suggest_names("mythology", used, count=10)
assert set(result) <= {"Thor", "Zeus"}
assert not set(result) & used
def test_returns_fewer_when_category_nearly_exhausted(self):
used = {"Apollo", "Athena", "Loki", "Thor"}
result = suggest_names("mythology", used, count=10)
assert result == ["Zeus"]
def test_returns_empty_when_category_fully_exhausted(self):
used = {"Apollo", "Athena", "Loki", "Thor", "Zeus"}
result = suggest_names("mythology", used, count=10)
assert result == []
def test_returns_empty_for_unknown_category(self):
result = suggest_names("nonexistent", set(), count=10)
assert result == []
def test_no_duplicates_in_suggestions(self):
result = suggest_names("mythology", set(), count=5)
assert len(result) == len(set(result))
def test_default_count_is_ten(self):
# food has 5 words, so we should get all 5
result = suggest_names("food", set())
assert len(result) == 5
def test_cross_category_names_handled_independently(self):
# "Apollo" used in mythology shouldn't affect space
used = {"Apollo"}
mythology_result = suggest_names("mythology", used, count=10)
space_result = suggest_names("space", used, count=10)
assert "Apollo" not in mythology_result
assert "Apollo" not in space_result
+8
View File
@@ -28,3 +28,11 @@ export function updateRun(
export function deleteRun(id: number): Promise<void> { export function deleteRun(id: number): Promise<void> {
return api.del(`/runs/${id}`) return api.del(`/runs/${id}`)
} }
export function getNamingCategories(): Promise<string[]> {
return api.get('/runs/naming-categories')
}
export function getNameSuggestions(runId: number, count = 10): Promise<string[]> {
return api.get(`/runs/${runId}/name-suggestions?count=${count}`)
}
@@ -1,5 +1,6 @@
import { useState, useEffect, useMemo } from 'react' import { useState, useEffect, useMemo } from 'react'
import { useRoutePokemon } from '../hooks/useGames' import { useRoutePokemon } from '../hooks/useGames'
import { useNameSuggestions } from '../hooks/useRuns'
import { import {
EncounterMethodBadge, EncounterMethodBadge,
getMethodLabel, getMethodLabel,
@@ -15,6 +16,8 @@ import type {
interface EncounterModalProps { interface EncounterModalProps {
route: Route route: Route
gameId: number gameId: number
runId: number
namingScheme?: string | null
existing?: EncounterDetail existing?: EncounterDetail
dupedPokemonIds?: Set<number> dupedPokemonIds?: Set<number>
retiredPokemonIds?: Set<number> retiredPokemonIds?: Set<number>
@@ -92,6 +95,8 @@ function pickRandomPokemon(
export function EncounterModal({ export function EncounterModal({
route, route,
gameId, gameId,
runId,
namingScheme,
existing, existing,
dupedPokemonIds, dupedPokemonIds,
retiredPokemonIds, retiredPokemonIds,
@@ -120,6 +125,10 @@ export function EncounterModal({
const isEditing = !!existing const isEditing = !!existing
const showSuggestions = !!namingScheme && status === 'caught' && !isEditing
const { data: suggestions, refetch: regenerate, isFetching: loadingSuggestions } =
useNameSuggestions(showSuggestions ? runId : null)
// Pre-select pokemon when editing // Pre-select pokemon when editing
useEffect(() => { useEffect(() => {
if (existing && routePokemon) { if (existing && routePokemon) {
@@ -380,6 +389,39 @@ export function EncounterModal({
placeholder="Give it a name..." placeholder="Give it a name..."
className="w-full px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500" className="w-full px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
/> />
{showSuggestions && suggestions && suggestions.length > 0 && (
<div className="mt-2">
<div className="flex items-center justify-between mb-1.5">
<span className="text-xs text-gray-500 dark:text-gray-400">
Suggestions ({namingScheme})
</span>
<button
type="button"
onClick={() => regenerate()}
disabled={loadingSuggestions}
className="text-xs text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300 disabled:opacity-50 transition-colors"
>
{loadingSuggestions ? 'Loading...' : 'Regenerate'}
</button>
</div>
<div className="flex flex-wrap gap-1.5">
{suggestions.map((name) => (
<button
key={name}
type="button"
onClick={() => setNickname(name)}
className={`px-2.5 py-1 text-xs rounded-full border transition-colors ${
nickname === name
? 'bg-blue-100 border-blue-300 text-blue-800 dark:bg-blue-900/40 dark:border-blue-600 dark:text-blue-300'
: 'border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:border-blue-300 dark:hover:border-blue-600 hover:bg-blue-50 dark:hover:bg-blue-900/20'
}`}
>
{name}
</button>
))}
</div>
</div>
)}
</div> </div>
)} )}
@@ -27,6 +27,8 @@ const BOSS_TYPES = [
{ value: 'champion', label: 'Champion' }, { value: 'champion', label: 'Champion' },
{ value: 'rival', label: 'Rival' }, { value: 'rival', label: 'Rival' },
{ value: 'evil_team', label: 'Evil Team' }, { value: 'evil_team', label: 'Evil Team' },
{ value: 'kahuna', label: 'Kahuna' },
{ value: 'totem', label: 'Totem' },
{ value: 'other', label: 'Other' }, { value: 'other', label: 'Other' },
] ]
+17 -1
View File
@@ -1,6 +1,6 @@
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { toast } from 'sonner' import { toast } from 'sonner'
import { getRuns, getRun, createRun, updateRun, deleteRun } from '../api/runs' import { getRuns, getRun, createRun, updateRun, deleteRun, getNamingCategories, getNameSuggestions } from '../api/runs'
import type { CreateRunInput, UpdateRunInput } from '../types/game' import type { CreateRunInput, UpdateRunInput } from '../types/game'
export function useRuns() { export function useRuns() {
@@ -51,3 +51,19 @@ export function useDeleteRun() {
}, },
}) })
} }
export function useNamingCategories() {
return useQuery({
queryKey: ['naming-categories'],
queryFn: getNamingCategories,
staleTime: Infinity,
})
}
export function useNameSuggestions(runId: number | null) {
return useQuery({
queryKey: ['name-suggestions', runId],
queryFn: () => getNameSuggestions(runId!),
enabled: runId !== null,
})
}
+39 -2
View File
@@ -2,7 +2,7 @@ import { useMemo, useState } from 'react'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { GameGrid, RulesConfiguration, StepIndicator } from '../components' import { GameGrid, RulesConfiguration, StepIndicator } from '../components'
import { useGames, useGameRoutes } from '../hooks/useGames' import { useGames, useGameRoutes } from '../hooks/useGames'
import { useCreateRun, useRuns } from '../hooks/useRuns' import { useCreateRun, useRuns, useNamingCategories } from '../hooks/useRuns'
import type { Game, NuzlockeRules } from '../types' import type { Game, NuzlockeRules } from '../types'
import { DEFAULT_RULES } from '../types' import { DEFAULT_RULES } from '../types'
import { RULE_DEFINITIONS } from '../types/rules' import { RULE_DEFINITIONS } from '../types/rules'
@@ -14,11 +14,13 @@ export function NewRun() {
const { data: games, isLoading, error } = useGames() const { data: games, isLoading, error } = useGames()
const { data: runs } = useRuns() const { data: runs } = useRuns()
const createRun = useCreateRun() const createRun = useCreateRun()
const { data: namingCategories } = useNamingCategories()
const [step, setStep] = useState(1) const [step, setStep] = useState(1)
const [selectedGame, setSelectedGame] = useState<Game | null>(null) const [selectedGame, setSelectedGame] = useState<Game | null>(null)
const [rules, setRules] = useState<NuzlockeRules>(DEFAULT_RULES) const [rules, setRules] = useState<NuzlockeRules>(DEFAULT_RULES)
const [runName, setRunName] = useState('') const [runName, setRunName] = useState('')
const [namingScheme, setNamingScheme] = useState<string | null>(null)
const { data: routes } = useGameRoutes(selectedGame?.id ?? null) const { data: routes } = useGameRoutes(selectedGame?.id ?? null)
const hiddenRules = useMemo(() => { const hiddenRules = useMemo(() => {
@@ -44,7 +46,7 @@ export function NewRun() {
const handleCreate = () => { const handleCreate = () => {
if (!selectedGame) return if (!selectedGame) return
createRun.mutate( createRun.mutate(
{ gameId: selectedGame.id, name: runName, rules }, { gameId: selectedGame.id, name: runName, rules, namingScheme },
{ onSuccess: (data) => navigate(`/runs/${data.id}`) }, { onSuccess: (data) => navigate(`/runs/${data.id}`) },
) )
} }
@@ -180,6 +182,33 @@ export function NewRun() {
/> />
</div> </div>
{namingCategories && namingCategories.length > 0 && (
<div>
<label
htmlFor="naming-scheme"
className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
>
Naming Scheme
</label>
<select
id="naming-scheme"
value={namingScheme ?? ''}
onChange={(e) => setNamingScheme(e.target.value || null)}
className="w-full px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
>
<option value="">None (manual nicknames)</option>
{namingCategories.map((cat) => (
<option key={cat} value={cat}>
{cat.charAt(0).toUpperCase() + cat.slice(1)}
</option>
))}
</select>
<p className="mt-1 text-xs text-gray-500 dark:text-gray-400">
Get nickname suggestions from a themed word list when catching Pokemon.
</p>
</div>
)}
<div className="border-t border-gray-200 dark:border-gray-700 pt-4"> <div className="border-t border-gray-200 dark:border-gray-700 pt-4">
<h3 className="text-sm font-medium text-gray-500 dark:text-gray-400 mb-2"> <h3 className="text-sm font-medium text-gray-500 dark:text-gray-400 mb-2">
Summary Summary
@@ -203,6 +232,14 @@ export function NewRun() {
{enabledRuleCount} of {totalRuleCount} enabled {enabledRuleCount} of {totalRuleCount} enabled
</dd> </dd>
</div> </div>
<div className="flex justify-between">
<dt className="text-gray-600 dark:text-gray-400">Naming Scheme</dt>
<dd className="text-gray-900 dark:text-gray-100 font-medium">
{namingScheme
? namingScheme.charAt(0).toUpperCase() + namingScheme.slice(1)
: 'None'}
</dd>
</div>
</dl> </dl>
</div> </div>
</div> </div>
+33 -1
View File
@@ -1,6 +1,6 @@
import { useMemo, useState } from 'react' import { useMemo, useState } from 'react'
import { useParams, Link } from 'react-router-dom' import { useParams, Link } from 'react-router-dom'
import { useRun, useUpdateRun } from '../hooks/useRuns' import { useRun, useUpdateRun, useNamingCategories } from '../hooks/useRuns'
import { useGameRoutes } from '../hooks/useGames' import { useGameRoutes } from '../hooks/useGames'
import { useCreateEncounter, useUpdateEncounter } from '../hooks/useEncounters' import { useCreateEncounter, useUpdateEncounter } from '../hooks/useEncounters'
import { StatCard, PokemonCard, RuleBadges, StatusChangeModal, EndRunModal } from '../components' import { StatCard, PokemonCard, RuleBadges, StatusChangeModal, EndRunModal } from '../components'
@@ -51,6 +51,7 @@ export function RunDashboard() {
const createEncounter = useCreateEncounter(runIdNum) const createEncounter = useCreateEncounter(runIdNum)
const updateEncounter = useUpdateEncounter(runIdNum) const updateEncounter = useUpdateEncounter(runIdNum)
const updateRun = useUpdateRun(runIdNum) const updateRun = useUpdateRun(runIdNum)
const { data: namingCategories } = useNamingCategories()
const [selectedEncounter, setSelectedEncounter] = const [selectedEncounter, setSelectedEncounter] =
useState<EncounterDetail | null>(null) useState<EncounterDetail | null>(null)
const [showEndRun, setShowEndRun] = useState(false) const [showEndRun, setShowEndRun] = useState(false)
@@ -197,6 +198,37 @@ export function RunDashboard() {
<RuleBadges rules={run.rules} /> <RuleBadges rules={run.rules} />
</div> </div>
{/* Naming Scheme */}
{namingCategories && namingCategories.length > 0 && (
<div className="mb-6">
<h2 className="text-sm font-medium text-gray-500 dark:text-gray-400 mb-2">
Naming Scheme
</h2>
{isActive ? (
<select
value={run.namingScheme ?? ''}
onChange={(e) =>
updateRun.mutate({ namingScheme: e.target.value || null })
}
className="text-sm border border-gray-300 dark:border-gray-600 rounded-lg px-3 py-1.5 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100"
>
<option value="">None</option>
{namingCategories.map((cat) => (
<option key={cat} value={cat}>
{cat.charAt(0).toUpperCase() + cat.slice(1)}
</option>
))}
</select>
) : (
<span className="text-sm text-gray-900 dark:text-gray-100">
{run.namingScheme
? run.namingScheme.charAt(0).toUpperCase() + run.namingScheme.slice(1)
: 'None'}
</span>
)}
</div>
)}
{/* Active Team */} {/* Active Team */}
<div className="mb-6"> <div className="mb-6">
<div className="flex items-center justify-between mb-3"> <div className="flex items-center justify-between mb-3">
+6
View File
@@ -1329,6 +1329,8 @@ export function RunEncounters() {
champion: 'Champion', champion: 'Champion',
rival: 'Rival', rival: 'Rival',
evil_team: 'Evil Team', evil_team: 'Evil Team',
kahuna: 'Kahuna',
totem: 'Totem',
other: 'Boss', other: 'Boss',
} }
const bossTypeColors: Record<string, string> = { const bossTypeColors: Record<string, string> = {
@@ -1337,6 +1339,8 @@ export function RunEncounters() {
champion: 'border-red-400 dark:border-red-600', champion: 'border-red-400 dark:border-red-600',
rival: 'border-blue-400 dark:border-blue-600', rival: 'border-blue-400 dark:border-blue-600',
evil_team: 'border-gray-500 dark:border-gray-400', evil_team: 'border-gray-500 dark:border-gray-400',
kahuna: 'border-orange-400 dark:border-orange-600',
totem: 'border-teal-400 dark:border-teal-600',
other: 'border-gray-400 dark:border-gray-500', other: 'border-gray-400 dark:border-gray-500',
} }
@@ -1431,6 +1435,8 @@ export function RunEncounters() {
<EncounterModal <EncounterModal
route={selectedRoute} route={selectedRoute}
gameId={run!.gameId} gameId={run!.gameId}
runId={runIdNum}
namingScheme={run!.namingScheme}
existing={editingEncounter ?? undefined} existing={editingEncounter ?? undefined}
dupedPokemonIds={dupedPokemonIds} dupedPokemonIds={dupedPokemonIds}
retiredPokemonIds={retiredPokemonIds} retiredPokemonIds={retiredPokemonIds}
+4 -1
View File
@@ -90,6 +90,7 @@ export interface NuzlockeRun {
status: RunStatus status: RunStatus
rules: NuzlockeRules rules: NuzlockeRules
hofEncounterIds: number[] | null hofEncounterIds: number[] | null
namingScheme: string | null
startedAt: string startedAt: string
completedAt: string | null completedAt: string | null
} }
@@ -132,6 +133,7 @@ export interface CreateRunInput {
gameId: number gameId: number
name: string name: string
rules?: NuzlockeRules rules?: NuzlockeRules
namingScheme?: string | null
} }
export interface UpdateRunInput { export interface UpdateRunInput {
@@ -139,6 +141,7 @@ export interface UpdateRunInput {
status?: RunStatus status?: RunStatus
rules?: NuzlockeRules rules?: NuzlockeRules
hofEncounterIds?: number[] hofEncounterIds?: number[]
namingScheme?: string | null
} }
export interface CreateEncounterInput { export interface CreateEncounterInput {
@@ -160,7 +163,7 @@ export interface UpdateEncounterInput {
} }
// Boss battles // Boss battles
export type BossType = 'gym_leader' | 'elite_four' | 'champion' | 'rival' | 'evil_team' | 'other' export type BossType = 'gym_leader' | 'elite_four' | 'champion' | 'rival' | 'evil_team' | 'kahuna' | 'totem' | 'other'
export interface BossPokemon { export interface BossPokemon {
id: number id: number
@@ -19,7 +19,7 @@ from pathlib import Path
from .loader import load_pokedb_data, load_seed_config from .loader import load_pokedb_data, load_seed_config
from .mappings import PokemonMapper, LocationMapper, build_version_map, map_encounter_method from .mappings import PokemonMapper, LocationMapper, build_version_map, map_encounter_method
from .output import sort_routes, merge_special_encounters, write_game_json, write_games_json, write_pokemon_json from .output import sort_routes, merge_special_encounters, write_game_json, write_games_json, write_pokemon_json
from .processing import filter_encounters_for_game, process_encounters, build_routes from .processing import filter_encounters_for_game, process_encounters, build_routes, filter_den_routes
from .sprites import download_all_sprites, download_sprites from .sprites import download_all_sprites, download_sprites
SEEDS_DIR_CANDIDATES = [ SEEDS_DIR_CANDIDATES = [
@@ -200,6 +200,10 @@ def main(argv: list[str] | None = None) -> None:
# Build route hierarchy # Build route hierarchy
routes = build_routes(encounters_by_area, location_mapper) routes = build_routes(encounters_by_area, location_mapper)
# Filter out Max Raid den child routes (Sword/Shield only)
if vg_key == "sword-shield":
routes = filter_den_routes(routes)
# Merge special encounters (starters, gifts, fossils) # Merge special encounters (starters, gifts, fossils)
routes = merge_special_encounters(routes, config, vg_key, pokemon_mapper) routes = merge_special_encounters(routes, config, vg_key, pokemon_mapper)
+14 -1
View File
@@ -140,7 +140,20 @@ def merge_special_encounters(
)) ))
if location_name in route_map: if location_name in route_map:
route_map[location_name].encounters.extend(encounters) existing = route_map[location_name].encounters
for enc in encounters:
# If a starter encounter matches an existing gift encounter,
# update the method to "starter" instead of adding a duplicate.
if enc.method == "starter":
match = next(
(e for e in existing
if e.pokeapi_id == enc.pokeapi_id and e.method == "gift"),
None,
)
if match:
match.method = "starter"
continue
existing.append(enc)
else: else:
new_route = Route(name=location_name, order=0, encounters=encounters) new_route = Route(name=location_name, order=0, encounters=encounters)
routes.append(new_route) routes.append(new_route)
@@ -341,3 +341,15 @@ def build_routes(
)) ))
return routes return routes
def filter_den_routes(routes: list[Route]) -> list[Route]:
"""Remove Max Raid den child routes from the route list.
Dens are identified by "(Den " in the child route name.
Only children are filtered parent routes are kept.
"""
for route in routes:
if route.children:
route.children = [c for c in route.children if "(Den " not in c.name]
return routes