Add Pinwheel Clause support for zone-based encounters in route groups
Allows each sub-zone within a route group to have its own independent encounter when the Pinwheel Clause rule is enabled (default on), instead of the entire group sharing a single encounter. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
"""add pinwheel clause support
|
||||
|
||||
Revision ID: a1b2c3d4e5f7
|
||||
Revises: f6a7b8c9d0e1
|
||||
Create Date: 2026-02-07 12:00:00.000000
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = 'a1b2c3d4e5f7'
|
||||
down_revision: Union[str, Sequence[str], None] = 'f6a7b8c9d0e1'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.add_column(
|
||||
'routes',
|
||||
sa.Column('pinwheel_zone', sa.SmallInteger(), nullable=True),
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_column('routes', 'pinwheel_zone')
|
||||
@@ -50,15 +50,30 @@ async def create_encounter(
|
||||
detail="Cannot create encounter on a parent route. Use a child route instead.",
|
||||
)
|
||||
|
||||
# If this route has a parent, check if any sibling already has an encounter
|
||||
# If this route has a parent, check if sibling already has an encounter
|
||||
if route.parent_route_id is not None:
|
||||
# Get all sibling route IDs (routes with same parent, including this one)
|
||||
# Get all sibling routes (routes with same parent, including this one)
|
||||
siblings_result = await session.execute(
|
||||
select(Route.id).where(Route.parent_route_id == route.parent_route_id)
|
||||
select(Route).where(Route.parent_route_id == route.parent_route_id)
|
||||
)
|
||||
sibling_ids = [r for r in siblings_result.scalars().all()]
|
||||
siblings = siblings_result.scalars().all()
|
||||
|
||||
# Check if any sibling already has an encounter in this run
|
||||
# Determine which siblings to check based on pinwheel clause
|
||||
pinwheel_on = run.rules.get("pinwheelClause", True) if run.rules else True
|
||||
any_has_zone = any(s.pinwheel_zone is not None for s in siblings)
|
||||
|
||||
if pinwheel_on and any_has_zone:
|
||||
# Zone-aware: only check siblings in the same zone (null treated as 0)
|
||||
my_zone = route.pinwheel_zone if route.pinwheel_zone is not None else 0
|
||||
sibling_ids = [
|
||||
s.id for s in siblings
|
||||
if (s.pinwheel_zone if s.pinwheel_zone is not None else 0) == my_zone
|
||||
]
|
||||
else:
|
||||
# No pinwheel clause or no zones defined: all siblings share
|
||||
sibling_ids = [s.id for s in siblings]
|
||||
|
||||
# Check if any relevant sibling already has an encounter in this run
|
||||
existing_encounter = await session.execute(
|
||||
select(Encounter)
|
||||
.where(
|
||||
|
||||
@@ -80,6 +80,7 @@ async def list_game_routes(
|
||||
"game_id": route.game_id,
|
||||
"order": route.order,
|
||||
"parent_route_id": route.parent_route_id,
|
||||
"pinwheel_zone": route.pinwheel_zone,
|
||||
"encounter_methods": methods,
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ class Route(Base):
|
||||
parent_route_id: Mapped[int | None] = mapped_column(
|
||||
ForeignKey("routes.id", ondelete="CASCADE"), index=True, default=None
|
||||
)
|
||||
pinwheel_zone: Mapped[int | None] = mapped_column(SmallInteger, default=None)
|
||||
|
||||
game: Mapped["Game"] = relationship(back_populates="routes")
|
||||
route_encounters: Mapped[list["RouteEncounter"]] = relationship(
|
||||
|
||||
@@ -7,6 +7,7 @@ class RouteResponse(CamelModel):
|
||||
game_id: int
|
||||
order: int
|
||||
parent_route_id: int | None = None
|
||||
pinwheel_zone: int | None = None
|
||||
encounter_methods: list[str] = []
|
||||
|
||||
|
||||
@@ -56,12 +57,14 @@ class RouteCreate(CamelModel):
|
||||
name: str
|
||||
order: int
|
||||
parent_route_id: int | None = None
|
||||
pinwheel_zone: int | None = None
|
||||
|
||||
|
||||
class RouteUpdate(CamelModel):
|
||||
name: str | None = None
|
||||
order: int | None = None
|
||||
parent_route_id: int | None = None
|
||||
pinwheel_zone: int | None = None
|
||||
|
||||
|
||||
class RouteReorderItem(CamelModel):
|
||||
|
||||
@@ -1333,6 +1333,7 @@
|
||||
{
|
||||
"name": "Pinwheel Forest (Outside)",
|
||||
"order": 23,
|
||||
"pinwheel_zone": 1,
|
||||
"encounters": [
|
||||
{
|
||||
"pokeapi_id": 533,
|
||||
@@ -1379,6 +1380,7 @@
|
||||
{
|
||||
"name": "Pinwheel Forest (Inside)",
|
||||
"order": 24,
|
||||
"pinwheel_zone": 2,
|
||||
"encounters": [
|
||||
{
|
||||
"pokeapi_id": 550,
|
||||
|
||||
@@ -1321,6 +1321,7 @@
|
||||
{
|
||||
"name": "Pinwheel Forest (Outside)",
|
||||
"order": 25,
|
||||
"pinwheel_zone": 1,
|
||||
"encounters": [
|
||||
{
|
||||
"pokeapi_id": 535,
|
||||
@@ -1359,6 +1360,7 @@
|
||||
{
|
||||
"name": "Pinwheel Forest (Inside)",
|
||||
"order": 26,
|
||||
"pinwheel_zone": 2,
|
||||
"encounters": [
|
||||
{
|
||||
"pokeapi_id": 550,
|
||||
|
||||
@@ -1333,6 +1333,7 @@
|
||||
{
|
||||
"name": "Pinwheel Forest (Outside)",
|
||||
"order": 23,
|
||||
"pinwheel_zone": 1,
|
||||
"encounters": [
|
||||
{
|
||||
"pokeapi_id": 533,
|
||||
@@ -1379,6 +1380,7 @@
|
||||
{
|
||||
"name": "Pinwheel Forest (Inside)",
|
||||
"order": 24,
|
||||
"pinwheel_zone": 2,
|
||||
"encounters": [
|
||||
{
|
||||
"pokeapi_id": 10016,
|
||||
|
||||
@@ -1321,6 +1321,7 @@
|
||||
{
|
||||
"name": "Pinwheel Forest (Outside)",
|
||||
"order": 25,
|
||||
"pinwheel_zone": 1,
|
||||
"encounters": [
|
||||
{
|
||||
"pokeapi_id": 535,
|
||||
@@ -1359,6 +1360,7 @@
|
||||
{
|
||||
"name": "Pinwheel Forest (Inside)",
|
||||
"order": 26,
|
||||
"pinwheel_zone": 2,
|
||||
"encounters": [
|
||||
{
|
||||
"pokeapi_id": 10016,
|
||||
|
||||
@@ -109,9 +109,14 @@ async def upsert_routes(
|
||||
game_id=game_id,
|
||||
order=child["order"],
|
||||
parent_route_id=parent_id,
|
||||
pinwheel_zone=child.get("pinwheel_zone"),
|
||||
).on_conflict_do_update(
|
||||
constraint="uq_routes_game_name",
|
||||
set_={"order": child["order"], "parent_route_id": parent_id},
|
||||
set_={
|
||||
"order": child["order"],
|
||||
"parent_route_id": parent_id,
|
||||
"pinwheel_zone": child.get("pinwheel_zone"),
|
||||
},
|
||||
)
|
||||
await session.execute(stmt)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user