One_Piece_Bounty_Bot / src /model /DailyReward.py
github-actions[bot]
Automated sync from GitHub
71e71e8
Raw
History Blame Contribute Delete
7.94 kB
import datetime
from peewee import *
import resources.Environment as Env
from src.model.BaseModel import BaseModel
from src.model.GroupChat import GroupChat
from src.model.User import User
from src.model.enums.daily_reward.DailyRewardBonus import DailyRewardBonus, DailyRewardBonusType
from src.model.enums.daily_reward.DailyRewardLimitation import DailyRewardLimitation
from src.model.enums.daily_reward.DailyRewardPrizeSource import DailyRewardPrizeSource
from src.model.enums.daily_reward.DailyRewardPrizeType import DailyRewardPrizeType
from src.service.date_service import get_day_in_past, is_same_day
from src.utils.math_utils import get_value_from_percentage
class DailyReward(BaseModel):
"""
DailyReward class
"""
user: User | ForeignKeyField = ForeignKeyField(User, backref="daily_bonuses")
base_amount: int | BigIntegerField = BigIntegerField()
bonus_list: str | TextField = TextField()
total_amount: int | BigIntegerField = BigIntegerField()
streak_count: int | IntegerField = IntegerField()
limitation: str | DailyRewardLimitation = CharField(max_length=20)
prize_type: DailyRewardPrizeType | CharField = CharField(max_length=20, null=True)
prize_value: str | CharField = CharField(max_length=50, null=True)
prize_source: DailyRewardPrizeSource | CharField = CharField(max_length=20, null=True)
group_chat: GroupChat | ForeignKeyField = ForeignKeyField(
GroupChat, backref="daily_rewards", null=True
)
message_id: int | IntegerField = IntegerField(null=True)
message_id_prize: int | IntegerField = IntegerField(null=True)
class Meta:
db_table = "daily_reward"
@staticmethod
def reset():
"""
Reset the daily rewards
"""
User.reset_daily_reward()
@staticmethod
def get_daily_reward_reset_times():
"""
Get how many times daily reward is reset during the day
"""
cron_expression = Env.CRON_DAILY_REWARD.get()
cron_parts = cron_expression.split()
# Every hour, so 24 times
if cron_parts[1] == "*":
return 24
# Every x hours
if "*/" in cron_parts[1]:
return 24 // int(cron_parts[1].split("/")[1])
# Once
return 1
@staticmethod
def get_next_reward_time() -> datetime.datetime:
from src.service.date_service import get_next_run
return get_next_run(Env.CRON_DAILY_REWARD.get())
@staticmethod
def get_remaining_time_to_next_reward() -> str:
from src.service.date_service import get_remaining_duration
return get_remaining_duration(DailyReward.get_next_reward_time())
@staticmethod
def get_last_streak_reward(user: User) -> "DailyReward":
"""
Get the last streak reward for the user
:param user: The user
:return: The last streak reward
"""
return (
DailyReward.select()
.where((DailyReward.user == user) & (DailyReward.date >= get_day_in_past(1)))
.order_by(DailyReward.date.desc())
.first()
)
@staticmethod
def get_user_streak_count(user: User) -> int:
"""
Get the user's streak count
:param user: The user
:return: The streak count
"""
# Get the last reward that is from yesterday or later
last_streak_reward = DailyReward.get_last_streak_reward(user)
if last_streak_reward is None:
return 1
streak_count = last_streak_reward.streak_count
# Is from yesterday, add one
if is_same_day(last_streak_reward.date, get_day_in_past(1)):
return streak_count + 1
return last_streak_reward.streak_count
@staticmethod
def get_bonuses_for_user(user: User, base_amount: int) -> list[DailyRewardBonus]:
"""
Get the bonus_list for the user
:param user: The user
:param base_amount: The base amount
:return: The bonus_list
"""
bonus_list: list[DailyRewardBonus] = []
total_amount = base_amount
for bonus_type in list(DailyRewardBonusType):
multiplier = None
match bonus_type:
# Streak
case DailyRewardBonusType.STREAK:
value = Env.DAILY_REWARD_BONUS_BASE_STREAK.get_int()
streak_count = min(
DailyReward.get_user_streak_count(user),
Env.DAILY_REWARD_BONUS_MAX_STREAK.get_int(),
)
multiplier = streak_count
value *= multiplier
# Location
case DailyRewardBonusType.LOCATION:
multiplier = user.location_level
value = Env.DAILY_REWARD_BONUS_BASE_LOCATION.get_int() * multiplier
# Crew level
case DailyRewardBonusType.CREW_LEVEL:
if not user.is_crew_member():
continue
multiplier = user.crew.level
value = Env.DAILY_REWARD_BONUS_BASE_CREW_LEVEL.get_int() * multiplier
# Crew MVP
case DailyRewardBonusType.CREW_MVP:
if not user.has_crew_mvp_bonus():
continue
value = Env.DAILY_REWARD_BONUS_CREW_MVP.get_int()
case _:
raise ValueError(f"Invalid bonus type: {bonus_type}")
amount = int(get_value_from_percentage(total_amount, value))
total_amount += amount
bonus_list.append(DailyRewardBonus(bonus_type, value, amount, multiplier))
return bonus_list
def get_days_to_next_prize(self) -> int:
"""
Get the days to next prize
:return: The days to next prize
"""
prize_days = Env.DAILY_REWARD_STREAK_DAYS.get_int()
last_streak_reward = self.get_last_streak_reward(self.user)
# Not yet up to minimum streak days.
# Ex. Day 3 with prize days 7, so 4 days remaining
if last_streak_reward.streak_count < prize_days:
return prize_days - last_streak_reward.streak_count
# Ex. Day 9 with prize days 7, so 5 days remaining
return prize_days - (last_streak_reward.streak_count % prize_days)
def get_base_belly_prize_offer(self) -> int:
"""
Get the base belly prize
:return: The base belly prize offer
"""
return self.total_amount
@staticmethod
def get_minimum_belly_prize() -> int:
"""
Get the minimum belly prize
:return: The minimum belly prize
"""
return 1
def get_maximum_belly_prize(self) -> int:
"""
Get the maximum belly prize
:return: The maximum belly prize
"""
return self.total_amount * 2
@staticmethod
def get_reward_count_for_user(user: User) -> int:
"""
Get the reward count for the user
:param user: The user
:return: The reward count for the user
"""
return DailyReward.select().where(DailyReward.user == user).count()
def should_award_prize(self) -> bool:
"""
Should award prize
:return: Should award prize
"""
# First time ever claiming reward, award prize
if DailyReward.get_reward_count_for_user(self.user) == 1:
return True
# User has reached streak
if self.get_days_to_next_prize() != Env.DAILY_REWARD_STREAK_DAYS.get_int():
return False
# Award if it's the first claim of the day
rewards_today = (
DailyReward.select()
.where((DailyReward.user == self.user) & (DailyReward.date >= get_day_in_past()))
.count()
)
return rewards_today == 1
DailyReward.create_table()