Files
game-marathon/backend/app/schemas/event.py
2025-12-15 03:50:04 +07:00

175 lines
4.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from datetime import datetime
from pydantic import BaseModel, Field
from typing import Literal
from app.models.event import EventType
from app.schemas.user import UserPublic
# Event type literals for Pydantic
EventTypeLiteral = Literal[
"golden_hour",
"common_enemy",
"double_risk",
"jackpot",
"swap",
"rematch",
]
class EventCreate(BaseModel):
type: EventTypeLiteral
duration_minutes: int | None = Field(
None,
description="Duration in minutes. If not provided, uses default for event type."
)
challenge_id: int | None = Field(
None,
description="For common_enemy event - the challenge everyone will get"
)
class EventEffects(BaseModel):
points_multiplier: float = 1.0
drop_free: bool = False
special_action: str | None = None # "swap", "rematch"
description: str = ""
class EventResponse(BaseModel):
id: int
type: EventTypeLiteral
start_time: datetime
end_time: datetime | None
is_active: bool
created_by: UserPublic | None
data: dict | None
created_at: datetime
class Config:
from_attributes = True
class ActiveEventResponse(BaseModel):
event: EventResponse | None
effects: EventEffects
time_remaining_seconds: int | None = None
class SwapRequest(BaseModel):
target_participant_id: int
class CommonEnemyLeaderboard(BaseModel):
participant_id: int
user: UserPublic
completed_at: datetime | None
rank: int | None
bonus_points: int
# Event descriptions and default durations
EVENT_INFO = {
EventType.GOLDEN_HOUR: {
"name": "Золотой час",
"description": "Все очки x1.5!",
"default_duration": 45,
"points_multiplier": 1.5,
"drop_free": False,
},
EventType.COMMON_ENEMY: {
"name": "Общий враг",
"description": "Все получают одинаковый челлендж. Первые 3 получают бонус!",
"default_duration": None, # Until all complete
"points_multiplier": 1.0,
"drop_free": False,
},
EventType.DOUBLE_RISK: {
"name": "Двойной риск",
"description": "Дропы бесплатны, но очки x0.5",
"default_duration": 120,
"points_multiplier": 0.5,
"drop_free": True,
},
EventType.JACKPOT: {
"name": "Джекпот",
"description": "Следующий спин — сложный челлендж с x3 очками!",
"default_duration": None, # 1 spin
"points_multiplier": 3.0,
"drop_free": False,
},
EventType.SWAP: {
"name": "Обмен",
"description": "Можно поменяться заданием с другим участником",
"default_duration": 60,
"points_multiplier": 1.0,
"drop_free": False,
"special_action": "swap",
},
EventType.REMATCH: {
"name": "Реванш",
"description": "Можно переделать проваленный челлендж за 50% очков",
"default_duration": 240,
"points_multiplier": 0.5,
"drop_free": False,
"special_action": "rematch",
},
}
# Bonus points for Common Enemy top 3
COMMON_ENEMY_BONUSES = {
1: 50,
2: 30,
3: 15,
}
class SwapCandidate(BaseModel):
"""Participant available for assignment swap"""
participant_id: int
user: UserPublic
challenge_title: str
challenge_description: str
challenge_points: int
challenge_difficulty: str
game_title: str
# Two-sided swap confirmation schemas
SwapRequestStatusLiteral = Literal["pending", "accepted", "declined", "cancelled"]
class SwapRequestCreate(BaseModel):
"""Request to swap assignment with another participant"""
target_participant_id: int
class SwapRequestChallengeInfo(BaseModel):
"""Challenge info for swap request display"""
title: str
description: str
points: int
difficulty: str
game_title: str
class SwapRequestResponse(BaseModel):
"""Response for a swap request"""
id: int
status: SwapRequestStatusLiteral
from_user: UserPublic
to_user: UserPublic
from_challenge: SwapRequestChallengeInfo
to_challenge: SwapRequestChallengeInfo
created_at: datetime
responded_at: datetime | None
class Config:
from_attributes = True
class MySwapRequests(BaseModel):
"""User's incoming and outgoing swap requests"""
incoming: list[SwapRequestResponse]
outgoing: list[SwapRequestResponse]