forked from sass/tipibot
Change exp leveling system
This commit is contained in:
@@ -9,7 +9,7 @@ from discord import app_commands
|
||||
|
||||
from core import sheets
|
||||
import strings as S
|
||||
from core.member_sync import announce_birthday, sync_member
|
||||
from core.member_sync import announce_birthday, sync_member, today_local
|
||||
|
||||
|
||||
class BirthdayPages(discord.ui.View):
|
||||
@@ -44,7 +44,7 @@ def _build_birthday_pages(
|
||||
Returns (pages, start_index) where start_index is the current month.
|
||||
"""
|
||||
rows = sheets.get_cache()
|
||||
today = datetime.date.today()
|
||||
today = today_local()
|
||||
|
||||
by_month: dict[int, list[tuple[int, str, int | None]]] = {m: [] for m in range(1, 13)}
|
||||
|
||||
@@ -298,8 +298,8 @@ def register_dev_member_commands(
|
||||
for fmt in ["%d/%m/%Y", "%Y-%m-%d"]:
|
||||
try:
|
||||
bday = datetime.datetime.strptime(bday_str, fmt).date()
|
||||
if 1920 <= bday.year <= datetime.date.today().year:
|
||||
today = datetime.date.today()
|
||||
if 1920 <= bday.year <= today_local().year:
|
||||
today = today_local()
|
||||
age = today.year - bday.year - ((today.month, today.day) < (bday.month, bday.day))
|
||||
embed.add_field(name=S.MEMBER_UI["age_field"], value=S.MEMBER_UI["age_val"].format(age=age), inline=True)
|
||||
break
|
||||
|
||||
@@ -317,16 +317,18 @@ LEVEL_ROLES: list[tuple[int, str]] = [
|
||||
|
||||
|
||||
def get_level(exp: int) -> int:
|
||||
"""Level = max(1, floor(sqrt(exp/6))).
|
||||
Level 5 @ 150 EXP, 10 @ 600, 20 @ 2400, 30 @ 5400."""
|
||||
return max(1, int(math.sqrt(max(0, exp) / 6)))
|
||||
"""Level = max(1, floor(sqrt(exp/10))).
|
||||
Level 5 @ 250 EXP, 10 @ 1000, 20 @ 4000, 30 @ 9000."""
|
||||
return max(1, int(math.sqrt(max(0, exp) / 10)))
|
||||
|
||||
|
||||
def exp_for_level(level: int) -> int:
|
||||
"""Minimum cumulative EXP to reach this level. level^2 * 6."""
|
||||
"""Minimum cumulative EXP to reach this level.
|
||||
Recurrence: exp_for_level(L) = L*20 - 10 + exp_for_level(L-1), base 0.
|
||||
Closed form: 10*level^2."""
|
||||
if level <= 1:
|
||||
return 0
|
||||
return level * level * 6
|
||||
return 10 * level * level
|
||||
|
||||
|
||||
def level_role_name(level: int) -> str:
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import calendar
|
||||
import logging
|
||||
from datetime import datetime, date
|
||||
from dataclasses import dataclass, field
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import discord
|
||||
|
||||
@@ -13,6 +15,20 @@ from . import sheets
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
_PLACEHOLDER = {"-", "x", "n/a", "none", "ei"}
|
||||
_TZ = ZoneInfo("Europe/Tallinn")
|
||||
|
||||
|
||||
def today_local() -> date:
|
||||
"""Today's date in Europe/Tallinn — the bot's operational timezone, independent of host TZ."""
|
||||
return datetime.now(_TZ).date()
|
||||
|
||||
|
||||
def _shift_year_safe(d: date, year: int) -> date:
|
||||
"""Move `d` to `year`; Feb 29 falls back to Feb 28 when the target year is non-leap."""
|
||||
try:
|
||||
return d.replace(year=year)
|
||||
except ValueError:
|
||||
return d.replace(year=year, day=28)
|
||||
|
||||
|
||||
def _is_placeholder(val: str) -> bool:
|
||||
@@ -72,7 +88,7 @@ def _parse_birthday(raw: str) -> date | None:
|
||||
raw = str(raw).strip()
|
||||
if _is_placeholder(raw):
|
||||
return None
|
||||
today = date.today()
|
||||
today = today_local()
|
||||
for fmt, has_year in [("%d/%m/%Y", True), ("%Y-%m-%d", True), ("%m-%d", False)]:
|
||||
try:
|
||||
parsed = datetime.strptime(raw, fmt).date()
|
||||
@@ -90,21 +106,32 @@ def _is_birthday_soon(birthday_str: str, window_days: int | None = None) -> bool
|
||||
if bday is None:
|
||||
return False
|
||||
window = window_days or config.BIRTHDAY_WINDOW_DAYS
|
||||
today = date.today()
|
||||
this_year_bday = bday.replace(year=today.year)
|
||||
today = today_local()
|
||||
this_year_bday = _shift_year_safe(bday, today.year)
|
||||
if this_year_bday < today:
|
||||
this_year_bday = bday.replace(year=today.year + 1)
|
||||
this_year_bday = _shift_year_safe(bday, today.year + 1)
|
||||
delta = (this_year_bday - today).days
|
||||
return 0 <= delta <= window
|
||||
|
||||
|
||||
def is_birthday_today(birthday_str: str) -> bool:
|
||||
"""Return True if today is the member's birthday (any supported date format)."""
|
||||
"""Return True if today is the member's birthday (any supported date format).
|
||||
|
||||
Feb 29 babies are observed on Feb 28 in non-leap years.
|
||||
"""
|
||||
bday = _parse_birthday(birthday_str)
|
||||
if bday is None:
|
||||
return False
|
||||
today = date.today()
|
||||
return bday.month == today.month and bday.day == today.day
|
||||
today = today_local()
|
||||
if bday.month == today.month and bday.day == today.day:
|
||||
return True
|
||||
if (
|
||||
bday.month == 2 and bday.day == 29
|
||||
and today.month == 2 and today.day == 28
|
||||
and not calendar.isleap(today.year)
|
||||
):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
async def sync_member(
|
||||
|
||||
Reference in New Issue
Block a user