import datetime from peewee import * import resources.Environment as Env from src.model.BaseModel import BaseModel from src.model.Crew import Crew from src.model.User import User from src.model.enums.GameStatus import GameStatus from src.model.enums.income_tax.IncomeTaxEventType import IncomeTaxEventType from src.model.game.GameOutcome import GameOutcome from src.service.date_service import datetime_is_after, get_remaining_duration from src.utils.string_utils import get_belly_formatted class DavyBackFight(BaseModel): """ DavyBackFight class """ challenger_crew: Crew | ForeignKeyField = ForeignKeyField( Crew, backref="davy_back_fights_challengers" ) opponent_crew: Crew | ForeignKeyField = ForeignKeyField( Crew, backref="davy_back_fights_opponents" ) challenger_chest: int | BigIntegerField = BigIntegerField(default=0) opponent_chest: int | BigIntegerField = BigIntegerField(default=0) participants_count: int | IntegerField = IntegerField() duration_hours: int | IntegerField = IntegerField() penalty_days = IntegerField() status: int | SmallIntegerField = SmallIntegerField( default=GameStatus.AWAITING_OPPONENT_CONFIRMATION ) start_date: datetime.datetime | DateTimeField = DateTimeField(null=True) end_date: datetime.datetime | DateTimeField = DateTimeField(null=True) conscript: User | ForeignKeyField = ForeignKeyField( User, backref="davy_back_fights_conscripts", null=True ) conscript_date: datetime.datetime | DateTimeField = DateTimeField(null=True) penalty_end_date: datetime.datetime | DateTimeField = DateTimeField(null=True) penalty_payout: int | BigIntegerField = BigIntegerField(default=0) is_auto_accepted: bool | BooleanField = BooleanField(default=False) # Backlinks davy_back_fight_participants = None class Meta: db_table = "davy_back_fight" @staticmethod async def delete_expired_requests(): """ Delete expire requests, so requests that are in AWAITING_OPPONENT_CONFIRMATION status and were created more than x minutes ago """ DavyBackFight.delete().where( DavyBackFight.status == GameStatus.AWAITING_OPPONENT_CONFIRMATION, DavyBackFight.date < ( datetime.datetime.now() - datetime.timedelta(minutes=Env.DAVY_BACK_FIGHT_REQUEST_EXPIRATION_TIME.get_int()) ), ).execute() def get_participants(self, crew: Crew = None) -> list[any]: """ Get all the participants of a Davy Back Fight :param crew: The crew object :return: The list of participants """ if crew is None: return self.davy_back_fight_participants return [p for p in self.davy_back_fight_participants if p.crew == crew] def get_participants_users(self, crew: Crew = None) -> list[User]: """ Get all the participants of a Davy Back Fight :param crew: The crew object :return: The list of participants """ if crew is None: return [p.user for p in self.davy_back_fight_participants] return [p.user for p in self.davy_back_fight_participants if p.crew == crew] def get_non_participants_users(self, crew: Crew) -> list[any]: """ Get all the non-participants of a Davy Back Fight :param crew: The crew object :return: The list of non-participants """ return [m for m in crew.get_members() if m not in self.get_participants_users(crew=crew)] def get_status(self) -> GameStatus: """ Get the status of the Davy Back Fight :return: The status """ return GameStatus(self.status) def in_progress(self) -> bool: """ Check if the game is in progress :return: True if the game is in progress, False otherwise """ return self.get_status() is GameStatus.IN_PROGRESS def has_ended(self) -> bool: """ Check if the game has ended :return: True if the game has ended, False otherwise """ return self.get_status().is_finished() def get_crew_gain(self, crew: Crew) -> int: """ Get the crew gain :param crew: The crew object :return: The crew gain """ return sum([p.contribution for p in self.davy_back_fight_participants if p.crew == crew]) def get_opponent_crew(self, crew: Crew): """ Get the opponent crew :param crew: The crew object :return: The opponent crew """ if crew == self.challenger_crew: return self.opponent_crew return self.challenger_crew def get_in_progress_display_status(self, crew: Crew) -> GameStatus: """ Get the in progress display status [WINNING, LOSING, DRAW] :param crew: The crew object :return: The in progress display status """ crew_total = self.get_crew_gain(crew) opponent_total = self.get_crew_gain(self.get_opponent_crew(crew)) if crew_total > opponent_total: return GameStatus.WINNING if crew_total < opponent_total: return GameStatus.LOSING return GameStatus.DRAW def get_participant(self, user: User) -> any: """ Get the participant :param user: The user object :return: The participant """ from src.model.DavyBackFightParticipant import DavyBackFightParticipant return self.davy_back_fight_participants.where( DavyBackFightParticipant.user == user ).get_or_none() def is_participant(self, user: User) -> bool: """ Check if the user is a participant :param user: The user object :return: True if the user is a participant, False otherwise """ return self.get_participant(user) is not None @staticmethod def get_contribution_events() -> list[IncomeTaxEventType]: """ Get the tax events that generate a DBF contribution :return: The contribution events """ return [IncomeTaxEventType.GAME, IncomeTaxEventType.FIGHT, IncomeTaxEventType.PLUNDER] def get_chest_amount(self, crew: Crew) -> int: """ Get the chest amount :param crew: The crew object :return: The chest amount """ if crew == self.challenger_crew: return self.challenger_chest return self.opponent_chest def get_opponent_chest_amount(self, crew: Crew) -> int: """ Get the chest amount :param crew: The crew object :return: The chest amount """ return self.get_chest_amount(self.get_opponent_crew(crew)) def get_winner_crew(self) -> Crew | None: """ Get the winner :return: The winner """ if self.get_status() not in [GameStatus.WON, GameStatus.LOST]: return None if self.get_status() is GameStatus.WON: return self.challenger_crew return self.opponent_crew def is_winner_crew(self, crew: Crew) -> bool: """ Check if the crew is the winner :param crew: The crew object :return: True if the crew is the winner, False otherwise """ return self.get_winner_crew() == crew def get_remaining_time(self) -> str: from src.service.date_service import get_remaining_duration return get_remaining_duration(self.end_date) def get_outcome(self) -> GameOutcome: """ Get the outcome of the game :return: The outcome """ from src.model.DavyBackFightParticipant import DavyBackFightParticipant if DavyBackFightParticipant.get_total_contributions( self, self.challenger_crew ) >= DavyBackFightParticipant.get_total_contributions(self, self.opponent_crew): return GameOutcome.CHALLENGER_WON return GameOutcome.OPPONENT_WON def get_penalty_payout(self): """ Get the penalty payout :return: The penalty payout """ if self.get_status() is GameStatus.WON: return self.challenger_chest + self.penalty_payout return self.opponent_chest + self.penalty_payout def get_penalty_payout_formatted(self): """ Get the penalty payout formatted :return: The penalty payout formatted """ return get_belly_formatted(self.get_penalty_payout()) def in_penalty_period(self) -> bool: """ Check if the game is in penalty period :return: True if the game is in penalty period, False otherwise """ return datetime_is_after(self.penalty_end_date) def get_penalty_remaining_time(self) -> str: """ Get the penalty remaining time :return: The penalty remaining time """ return get_remaining_duration(self.penalty_end_date) @staticmethod def get_max_participants(challenger_crew: Crew, opponent_crew: Crew) -> int: """ Get the max participants :param challenger_crew: The challenger crew :param opponent_crew: The opponent crew :return: The max participants """ return min(challenger_crew.get_member_count(), opponent_crew.get_member_count()) @staticmethod def get_active_status() -> list[GameStatus]: """ Get the active status :return: The active status """ return [GameStatus.COUNTDOWN_TO_START, GameStatus.IN_PROGRESS] @staticmethod def get_ended_status() -> list[GameStatus]: """ Get the ended status :return: The ended status """ return [GameStatus.WON, GameStatus.LOST] @staticmethod def get_active() -> list["DavyBackFight"]: """ Get the active Davy Back Fights :return: The active Davy Back Fights """ return DavyBackFight.select().where( DavyBackFight.status << DavyBackFight.get_active_status() ) @staticmethod def get_crew_with_enough_members() -> list[Crew]: """ Get the crews with enough members for Davy Back Fight :return: The crews with enough members for Davy Back Fight """ return [ c for c in Crew.select() if c.get_member_count() >= Env.DAVY_BACK_FIGHT_MIN_PARTICIPANTS.get_int() ] @staticmethod def get_crews_in_active() -> list[Crew]: """ Returns the crew in active Davy Back Fight :return: The crew in active Davy Back Fight """ active = DavyBackFight.get_active() return [d.challenger_crew for d in active] + [d.opponent_crew for d in active] @staticmethod def get_ended_with_penalty() -> list["DavyBackFight"]: """ Get the ended Davy Back Fights with penalty still active :return: The ended Davy Back Fights with penalty """ return DavyBackFight.select().where( DavyBackFight.status.in_(DavyBackFight.get_ended_status()), DavyBackFight.penalty_end_date > datetime.datetime.now(), ) @staticmethod def get_crews_in_penalty() -> list[Crew]: """ Returns the crew in Davy Back Fight penalty :return: The crew in Davy Back Fight penalty """ ended_with_penalty = DavyBackFight.get_ended_with_penalty() return [d.challenger_crew for d in ended_with_penalty] + [ d.opponent_crew for d in ended_with_penalty ] DavyBackFight.create_table()