forked from retoor/devplacepy
159 lines
4.8 KiB
Python
159 lines
4.8 KiB
Python
# retoor <retoor@molodetz.nl>
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
|
|
from devplacepy.database import get_table
|
|
|
|
from .. import economy
|
|
from .common import GameError, _iso, _iso_week, _lvl, _now, conditional_update_farm
|
|
from .farm import ensure_farm, get_farm
|
|
|
|
TREASURY_UID = "treasury-main"
|
|
|
|
|
|
def _treasury():
|
|
return get_table("game_treasury")
|
|
|
|
|
|
def ensure_treasury() -> dict:
|
|
row = _treasury().find_one(uid=TREASURY_UID)
|
|
if row:
|
|
return row
|
|
_treasury().insert(
|
|
{
|
|
"uid": TREASURY_UID,
|
|
"balance": 0,
|
|
"collected_total": 0,
|
|
"granted_total": 0,
|
|
"updated_at": _iso(_now()),
|
|
}
|
|
)
|
|
return _treasury().find_one(uid=TREASURY_UID)
|
|
|
|
|
|
def treasury_balance() -> int:
|
|
row = _treasury().find_one(uid=TREASURY_UID)
|
|
return int(row.get("balance") or 0) if row else 0
|
|
|
|
|
|
def _treasury_update(set_clause: str, where_clause: str, params: dict) -> int:
|
|
from sqlalchemy import text
|
|
|
|
from devplacepy.database import db
|
|
|
|
sql = (
|
|
f"UPDATE game_treasury SET {set_clause}, updated_at = :updated_at "
|
|
f"WHERE uid = :treasury_uid AND ({where_clause})"
|
|
)
|
|
bind = {**params, "updated_at": _iso(_now()), "treasury_uid": TREASURY_UID}
|
|
with db:
|
|
result = db.executable.execute(text(sql), bind)
|
|
return result.rowcount
|
|
|
|
|
|
def credit_treasury(amount: int) -> None:
|
|
if amount <= 0:
|
|
return
|
|
ensure_treasury()
|
|
_treasury_update(
|
|
set_clause=(
|
|
"balance = COALESCE(balance, 0) + :amount, "
|
|
"collected_total = COALESCE(collected_total, 0) + :amount"
|
|
),
|
|
where_clause="1 = 1",
|
|
params={"amount": amount},
|
|
)
|
|
|
|
|
|
def _debit_treasury(amount: int) -> bool:
|
|
ensure_treasury()
|
|
rows = _treasury_update(
|
|
set_clause=(
|
|
"balance = COALESCE(balance, 0) - :amount, "
|
|
"granted_total = COALESCE(granted_total, 0) + :amount"
|
|
),
|
|
where_clause="COALESCE(balance, 0) >= :amount",
|
|
params={"amount": amount},
|
|
)
|
|
return rows > 0
|
|
|
|
|
|
def _refund_treasury(amount: int) -> None:
|
|
if amount <= 0:
|
|
return
|
|
_treasury_update(
|
|
set_clause=(
|
|
"balance = COALESCE(balance, 0) + :amount, "
|
|
"granted_total = COALESCE(granted_total, 0) - :amount"
|
|
),
|
|
where_clause="1 = 1",
|
|
params={"amount": amount},
|
|
)
|
|
|
|
|
|
def grant_status(farm: dict, now: datetime) -> dict:
|
|
week = _iso_week(now)
|
|
if farm.get("last_grant_week") == week:
|
|
return {"available": False, "amount": 0, "reason": "Grant already claimed this week."}
|
|
if _lvl(farm, "prestige") > economy.GRANT_MAX_PRESTIGE:
|
|
return {
|
|
"available": False,
|
|
"amount": 0,
|
|
"reason": f"Grants support farms up to prestige {economy.GRANT_MAX_PRESTIGE}.",
|
|
}
|
|
if int(farm.get("coins", 0)) >= economy.GRANT_WEALTH_CEILING:
|
|
return {
|
|
"available": False,
|
|
"amount": 0,
|
|
"reason": f"Grants support farms below {economy.GRANT_WEALTH_CEILING} coins.",
|
|
}
|
|
if _lvl(farm, "harvests_week") < economy.GRANT_MIN_WEEK_HARVESTS:
|
|
return {
|
|
"available": False,
|
|
"amount": 0,
|
|
"reason": (
|
|
f"Harvest at least {economy.GRANT_MIN_WEEK_HARVESTS} builds this week to qualify."
|
|
),
|
|
}
|
|
amount = economy.grant_amount(treasury_balance())
|
|
if amount <= 0:
|
|
return {
|
|
"available": False,
|
|
"amount": 0,
|
|
"reason": "The treasury is empty - refactor fees fill it.",
|
|
}
|
|
return {"available": True, "amount": amount, "reason": ""}
|
|
|
|
|
|
def claim_grant(user: dict) -> dict:
|
|
farm = ensure_farm(user["uid"])
|
|
now = _now()
|
|
status = grant_status(farm, now)
|
|
if not status["available"]:
|
|
raise GameError(status["reason"])
|
|
amount = status["amount"]
|
|
week = _iso_week(now)
|
|
if not _debit_treasury(amount):
|
|
raise GameError("The treasury is empty - refactor fees fill it.")
|
|
rows = conditional_update_farm(
|
|
farm["uid"],
|
|
set_clause=(
|
|
"coins = coins + :amount, "
|
|
"last_grant_week = :week, "
|
|
"lifetime_coins_earned = COALESCE(lifetime_coins_earned, 0) + :amount"
|
|
),
|
|
where_clause=(
|
|
"(last_grant_week IS NULL OR last_grant_week != :week) AND coins < :ceiling"
|
|
),
|
|
params={"amount": amount, "week": week, "ceiling": economy.GRANT_WEALTH_CEILING},
|
|
)
|
|
if rows == 0:
|
|
_refund_treasury(amount)
|
|
farm = get_farm(user["uid"])
|
|
if farm and farm.get("last_grant_week") == week:
|
|
raise GameError("Grant already claimed this week.")
|
|
raise GameError("Your farm changed - refresh and try again.")
|
|
return {"amount": amount, "week": week}
|