Implement Retire HoF (Gauntlet) rule enforcement for genlockes
When retireHoF is enabled, surviving HoF Pokemon and their evolutionary families are retired at leg advancement and treated as duplicates in all subsequent legs — both in the encounter modal and bulk randomize. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,17 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import selectinload
|
||||
|
||||
from app.core.database import get_session
|
||||
from app.models.encounter import Encounter
|
||||
from app.models.evolution import Evolution
|
||||
from app.models.game import Game
|
||||
from app.models.genlocke import Genlocke, GenlockeLeg
|
||||
from app.models.nuzlocke_run import NuzlockeRun
|
||||
from app.schemas.genlocke import GenlockeCreate, GenlockeResponse
|
||||
from app.services.families import build_families
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@@ -140,6 +144,37 @@ async def advance_leg(
|
||||
status_code=400, detail="Next leg already has a run"
|
||||
)
|
||||
|
||||
# Compute retired Pokemon families if retireHoF is enabled
|
||||
if genlocke.genlocke_rules.get("retireHoF", False):
|
||||
# Query surviving caught Pokemon from the completed run
|
||||
# "Surviving HoF" = caught, not fainted, not shiny
|
||||
survivors_result = await session.execute(
|
||||
select(Encounter.pokemon_id).where(
|
||||
Encounter.run_id == current_leg.run_id,
|
||||
Encounter.status == "caught",
|
||||
Encounter.faint_level.is_(None),
|
||||
Encounter.is_shiny.is_(False),
|
||||
)
|
||||
)
|
||||
survivor_ids = [row[0] for row in survivors_result]
|
||||
|
||||
if survivor_ids:
|
||||
# Build family map from evolution data
|
||||
evo_result = await session.execute(select(Evolution))
|
||||
evolutions = evo_result.scalars().all()
|
||||
pokemon_to_family = build_families(evolutions)
|
||||
|
||||
# Collect all family members of surviving Pokemon
|
||||
retired: set[int] = set()
|
||||
for pid in survivor_ids:
|
||||
retired.add(pid)
|
||||
for member in pokemon_to_family.get(pid, []):
|
||||
retired.add(member)
|
||||
|
||||
current_leg.retired_pokemon_ids = sorted(retired)
|
||||
else:
|
||||
current_leg.retired_pokemon_ids = []
|
||||
|
||||
# Create a new run for the next leg
|
||||
new_run = NuzlockeRun(
|
||||
game_id=next_leg.game_id,
|
||||
@@ -162,3 +197,56 @@ async def advance_leg(
|
||||
)
|
||||
)
|
||||
return result.scalar_one()
|
||||
|
||||
|
||||
class RetiredLegResponse(BaseModel):
|
||||
leg_order: int
|
||||
retired_pokemon_ids: list[int]
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class RetiredFamiliesResponse(BaseModel):
|
||||
retired_pokemon_ids: list[int]
|
||||
by_leg: list[RetiredLegResponse]
|
||||
|
||||
|
||||
@router.get(
|
||||
"/{genlocke_id}/retired-families",
|
||||
response_model=RetiredFamiliesResponse,
|
||||
)
|
||||
async def get_retired_families(
|
||||
genlocke_id: int,
|
||||
session: AsyncSession = Depends(get_session),
|
||||
):
|
||||
# Verify genlocke exists
|
||||
genlocke = await session.get(Genlocke, genlocke_id)
|
||||
if genlocke is None:
|
||||
raise HTTPException(status_code=404, detail="Genlocke not found")
|
||||
|
||||
# Query all legs with retired_pokemon_ids
|
||||
result = await session.execute(
|
||||
select(GenlockeLeg)
|
||||
.where(
|
||||
GenlockeLeg.genlocke_id == genlocke_id,
|
||||
GenlockeLeg.retired_pokemon_ids.isnot(None),
|
||||
)
|
||||
.order_by(GenlockeLeg.leg_order)
|
||||
)
|
||||
legs = result.scalars().all()
|
||||
|
||||
cumulative: set[int] = set()
|
||||
by_leg: list[RetiredLegResponse] = []
|
||||
for leg in legs:
|
||||
ids = leg.retired_pokemon_ids or []
|
||||
cumulative.update(ids)
|
||||
by_leg.append(RetiredLegResponse(
|
||||
leg_order=leg.leg_order,
|
||||
retired_pokemon_ids=ids,
|
||||
))
|
||||
|
||||
return RetiredFamiliesResponse(
|
||||
retired_pokemon_ids=sorted(cumulative),
|
||||
by_leg=by_leg,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user