Refator eco code. Split into modules
This commit is contained in:
194
core/economy/fishing.py
Normal file
194
core/economy/fishing.py
Normal file
@@ -0,0 +1,194 @@
|
||||
"""Fishing minigame: catalogue, rolls, catch/sell flows."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
from datetime import timedelta
|
||||
|
||||
from ..pb_client import DatabaseError
|
||||
from .store import (
|
||||
COOLDOWNS, _cooldown_remaining, _commit, _is_jailed, _locked_by, _now,
|
||||
_prestige_mult, _txn, get_user,
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Fish catalogue
|
||||
# ---------------------------------------------------------------------------
|
||||
FISH_CATALOGUE: dict[str, dict] = {
|
||||
# id: { rarity, weight=(min_g, max_g), coins=(min, max), exp }
|
||||
"sarj": {"rarity": "common", "weight": (50, 500), "coins": (3, 18), "exp": 3},
|
||||
"ahven": {"rarity": "common", "weight": (80, 700), "coins": (5, 22), "exp": 3},
|
||||
"koger": {"rarity": "common", "weight": (100, 800), "coins": (5, 20), "exp": 3},
|
||||
"viidikas": {"rarity": "common", "weight": (10, 120), "coins": (2, 8), "exp": 2},
|
||||
"latikas": {"rarity": "uncommon", "weight": (300, 2500), "coins": (20, 70), "exp": 6},
|
||||
"karpkala": {"rarity": "uncommon", "weight": (500, 4000), "coins": (25, 80), "exp": 7},
|
||||
"linask": {"rarity": "uncommon", "weight": (200, 2000), "coins": (18, 60), "exp": 6},
|
||||
"haug": {"rarity": "rare", "weight": (500, 6000), "coins": (50, 180), "exp": 10},
|
||||
"angerjas": {"rarity": "rare", "weight": (200, 1800), "coins": (40, 120), "exp": 10},
|
||||
"siig": {"rarity": "rare", "weight": (200, 2000), "coins": (45, 130), "exp": 10},
|
||||
"forell": {"rarity": "epic", "weight": (400, 4500), "coins": (100, 280), "exp": 15},
|
||||
"koha": {"rarity": "epic", "weight": (600, 7000), "coins": (120, 300), "exp": 15},
|
||||
"tougjas": {"rarity": "epic", "weight": (400, 4000), "coins": (90, 250), "exp": 14},
|
||||
"lohe": {"rarity": "legendary","weight": (1500, 12000), "coins": (250, 700), "exp": 25},
|
||||
"vimb": {"rarity": "legendary","weight": (200, 1200), "coins": (200, 600), "exp": 25},
|
||||
}
|
||||
|
||||
FISH_RARITY_WEIGHTS: dict[str, int] = {
|
||||
"junk": 15,
|
||||
"common": 45,
|
||||
"uncommon": 22,
|
||||
"rare": 12,
|
||||
"epic": 5,
|
||||
"legendary": 1,
|
||||
}
|
||||
|
||||
|
||||
def roll_fish(rarity_bump: bool = False) -> tuple[str, int]:
|
||||
"""Roll a random fish. Returns (fish_id, weight_grams) or ('junk', 0).
|
||||
rarity_bump=True (kalavork item) shifts each catch one tier up.
|
||||
"""
|
||||
rarity_pool = list(FISH_RARITY_WEIGHTS.keys())
|
||||
weights = list(FISH_RARITY_WEIGHTS.values())
|
||||
chosen_rarity = random.choices(rarity_pool, weights=weights)[0]
|
||||
if chosen_rarity == "junk":
|
||||
return ("junk", 0)
|
||||
if rarity_bump:
|
||||
order = ["common", "uncommon", "rare", "epic", "legendary"]
|
||||
idx = order.index(chosen_rarity) if chosen_rarity in order else 0
|
||||
chosen_rarity = order[min(idx + 1, len(order) - 1)]
|
||||
fish_of_rarity = [k for k, v in FISH_CATALOGUE.items() if v["rarity"] == chosen_rarity]
|
||||
if not fish_of_rarity:
|
||||
return ("junk", 0)
|
||||
fish_id = random.choice(fish_of_rarity)
|
||||
fish = FISH_CATALOGUE[fish_id]
|
||||
weight = random.randint(fish["weight"][0], fish["weight"][1])
|
||||
return (fish_id, weight)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# /fish
|
||||
# ---------------------------------------------------------------------------
|
||||
@_locked_by(0)
|
||||
async def do_fish_start(user_id: int) -> dict:
|
||||
"""Check cooldown + jail, set cooldown. Call before starting the fishing minigame."""
|
||||
try:
|
||||
user = await get_user(user_id)
|
||||
except DatabaseError:
|
||||
return {"ok": False, "reason": "db_error"}
|
||||
if user.get("eco_banned"):
|
||||
return {"ok": False, "reason": "banned"}
|
||||
if jail := _is_jailed(user):
|
||||
return {"ok": False, "reason": "jailed", "remaining": jail}
|
||||
|
||||
fish_cd = timedelta(seconds=90) if "ussipurk" in user["items"] else COOLDOWNS["fish"]
|
||||
if cd := _cooldown_remaining(user, "fish", override_cd=fish_cd):
|
||||
return {"ok": False, "reason": "cooldown", "remaining": cd}
|
||||
|
||||
user["last_fish"] = _now().isoformat()
|
||||
await _commit(user_id, user)
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
@_locked_by(0)
|
||||
async def do_fish_resolve(user_id: int, fish_id: str, weight: int) -> dict:
|
||||
"""Add catch to inventory + update fish_book. Returns catch info incl. pre-calculated value."""
|
||||
user = await get_user(user_id)
|
||||
|
||||
if fish_id == "junk":
|
||||
_txn("FISH_JUNK", user=user_id)
|
||||
return {"ok": True, "type": "junk", "coins": 0, "exp": 0}
|
||||
|
||||
if fish_id not in FISH_CATALOGUE:
|
||||
return {"ok": False, "reason": "invalid_fish"}
|
||||
|
||||
fish = FISH_CATALOGUE[fish_id]
|
||||
min_c, max_c = fish["coins"]
|
||||
w_min, w_max = fish["weight"]
|
||||
weight_ratio = (weight - w_min) / max(1, w_max - w_min)
|
||||
base_coins = int(min_c + weight_ratio * (max_c - min_c))
|
||||
coin_mult, _ = _prestige_mult(user)
|
||||
value = int(base_coins * coin_mult)
|
||||
exp = fish["exp"]
|
||||
|
||||
book: dict = user.get("fish_book") or {}
|
||||
prev_count = book.get(fish_id, 0)
|
||||
book[fish_id] = prev_count + 1
|
||||
user["fish_book"] = book
|
||||
user["total_fish_caught"] = user.get("total_fish_caught", 0) + 1
|
||||
|
||||
inv: list = list(user.get("fish_inventory") or [])
|
||||
inv.append({"fish_id": fish_id, "weight": weight, "value": value})
|
||||
user["fish_inventory"] = inv
|
||||
|
||||
await _commit(user_id, user)
|
||||
_txn("FISH", user=user_id, fish=fish_id, weight=weight, value=value)
|
||||
|
||||
return {
|
||||
"ok": True,
|
||||
"type": "fish",
|
||||
"fish_id": fish_id,
|
||||
"weight": weight,
|
||||
"value": value,
|
||||
"exp": exp,
|
||||
"is_new": prev_count == 0,
|
||||
"total_caught": book[fish_id],
|
||||
}
|
||||
|
||||
|
||||
@_locked_by(0)
|
||||
async def do_fish_sell(user_id: int, indices: list[int] | None = None) -> dict:
|
||||
"""Sell fish from inventory. indices=None sells all. Returns coins earned."""
|
||||
user = await get_user(user_id)
|
||||
inv: list = list(user.get("fish_inventory") or [])
|
||||
if not inv:
|
||||
return {"ok": False, "reason": "empty"}
|
||||
|
||||
if indices is None:
|
||||
to_sell = inv
|
||||
remaining = []
|
||||
else:
|
||||
sell_idx = {
|
||||
(i if i >= 0 else len(inv) + i)
|
||||
for i in indices
|
||||
}
|
||||
sell_idx = {i for i in sell_idx if 0 <= i < len(inv)}
|
||||
to_sell = [inv[i] for i in sorted(sell_idx)]
|
||||
keep_idx = set(range(len(inv))) - sell_idx
|
||||
remaining = [inv[i] for i in sorted(keep_idx)]
|
||||
|
||||
if not to_sell:
|
||||
return {"ok": False, "reason": "empty"}
|
||||
|
||||
total_coins = sum(entry["value"] for entry in to_sell)
|
||||
user["fish_inventory"] = remaining
|
||||
user["balance"] = user.get("balance", 0) + total_coins
|
||||
user["lifetime_earned"] = user.get("lifetime_earned", 0) + total_coins
|
||||
user["peak_balance"] = max(user.get("peak_balance", 0), user["balance"])
|
||||
await _commit(user_id, user)
|
||||
_txn("FISH_SELL", user=user_id, count=len(to_sell), coins=f"+{total_coins}", bal=user["balance"])
|
||||
return {
|
||||
"ok": True,
|
||||
"coins": total_coins,
|
||||
"count": len(to_sell),
|
||||
"balance": user["balance"],
|
||||
}
|
||||
|
||||
|
||||
async def do_fishbook(user_id: int) -> dict:
|
||||
"""Return the user's fish book data including per-species inventory counts."""
|
||||
user = await get_user(user_id)
|
||||
book: dict = user.get("fish_book") or {}
|
||||
inv: list = user.get("fish_inventory") or []
|
||||
inv_counts: dict[str, int] = {}
|
||||
for entry in inv:
|
||||
fid = entry.get("fish_id", "")
|
||||
inv_counts[fid] = inv_counts.get(fid, 0) + 1
|
||||
return {
|
||||
"ok": True,
|
||||
"book": book,
|
||||
"inv_counts": inv_counts,
|
||||
"total_fish_caught": user.get("total_fish_caught", 0),
|
||||
"unique_caught": len(book),
|
||||
"total_species": len(FISH_CATALOGUE),
|
||||
}
|
||||
Reference in New Issue
Block a user