Add genlocke leg progression with advance endpoint and run context
When a run belonging to a genlocke is completed or failed, the genlocke status updates accordingly. The run detail API now includes genlocke context (leg order, total legs, genlocke name). A new advance endpoint creates the next leg's run, and the frontend shows genlocke-aware UI including a "Leg X of Y" banner, advance button, and contextual messaging in the end-run modal. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -79,3 +79,86 @@ async def create_genlocke(
|
||||
)
|
||||
)
|
||||
return result.scalar_one()
|
||||
|
||||
|
||||
@router.post(
|
||||
"/{genlocke_id}/legs/{leg_order}/advance",
|
||||
response_model=GenlockeResponse,
|
||||
)
|
||||
async def advance_leg(
|
||||
genlocke_id: int,
|
||||
leg_order: int,
|
||||
session: AsyncSession = Depends(get_session),
|
||||
):
|
||||
# Load genlocke with legs
|
||||
result = await session.execute(
|
||||
select(Genlocke)
|
||||
.where(Genlocke.id == genlocke_id)
|
||||
.options(
|
||||
selectinload(Genlocke.legs).selectinload(GenlockeLeg.game),
|
||||
)
|
||||
)
|
||||
genlocke = result.scalar_one_or_none()
|
||||
if genlocke is None:
|
||||
raise HTTPException(status_code=404, detail="Genlocke not found")
|
||||
|
||||
if genlocke.status != "active":
|
||||
raise HTTPException(
|
||||
status_code=400, detail="Genlocke is not active"
|
||||
)
|
||||
|
||||
# Find the current leg
|
||||
current_leg = None
|
||||
next_leg = None
|
||||
for leg in genlocke.legs:
|
||||
if leg.leg_order == leg_order:
|
||||
current_leg = leg
|
||||
elif leg.leg_order == leg_order + 1:
|
||||
next_leg = leg
|
||||
|
||||
if current_leg is None:
|
||||
raise HTTPException(status_code=404, detail="Leg not found")
|
||||
|
||||
# Verify current leg's run is completed
|
||||
if current_leg.run_id is None:
|
||||
raise HTTPException(
|
||||
status_code=400, detail="Current leg has no run"
|
||||
)
|
||||
current_run = await session.get(NuzlockeRun, current_leg.run_id)
|
||||
if current_run is None or current_run.status != "completed":
|
||||
raise HTTPException(
|
||||
status_code=400, detail="Current leg's run is not completed"
|
||||
)
|
||||
|
||||
if next_leg is None:
|
||||
raise HTTPException(
|
||||
status_code=400, detail="No next leg to advance to"
|
||||
)
|
||||
|
||||
if next_leg.run_id is not None:
|
||||
raise HTTPException(
|
||||
status_code=400, detail="Next leg already has a run"
|
||||
)
|
||||
|
||||
# Create a new run for the next leg
|
||||
new_run = NuzlockeRun(
|
||||
game_id=next_leg.game_id,
|
||||
name=f"{genlocke.name} \u2014 Leg {next_leg.leg_order}",
|
||||
status="active",
|
||||
rules=genlocke.nuzlocke_rules,
|
||||
)
|
||||
session.add(new_run)
|
||||
await session.flush()
|
||||
|
||||
next_leg.run_id = new_run.id
|
||||
await session.commit()
|
||||
|
||||
# Reload with relationships
|
||||
result = await session.execute(
|
||||
select(Genlocke)
|
||||
.where(Genlocke.id == genlocke_id)
|
||||
.options(
|
||||
selectinload(Genlocke.legs).selectinload(GenlockeLeg.game),
|
||||
)
|
||||
)
|
||||
return result.scalar_one()
|
||||
|
||||
Reference in New Issue
Block a user