from typing import Optional from sqlalchemy.orm import Session from database import Achievement, UserAchievement, ActivityFeed from datetime import datetime import json # ─── Определения достижений ───────────────────────────────────────────────── ACHIEVEMENT_DEFS = [ { "name": "first_case", "title": "Первый шаг", "description": "Открой свой первый кейс", "icon": "📦", "category": "cases", "requirement_type": "open_cases", "requirement_value": 1, "reward_amount": 100, "sort_order": 1, }, { "name": "case_collector_10", "title": "Коллекционер", "description": "Открой 10 кейсов", "icon": "📦", "category": "cases", "requirement_type": "open_cases", "requirement_value": 10, "reward_amount": 250, "sort_order": 2, }, { "name": "case_collector_100", "title": "Заядлый коллекционер", "description": "Открой 100 кейсов", "icon": "📦", "category": "cases", "requirement_type": "open_cases", "requirement_value": 100, "reward_amount": 1000, "sort_order": 3, }, { "name": "case_collector_1000", "title": "Одержимый", "description": "Открой 1000 кейсов", "icon": "💎", "category": "cases", "requirement_type": "open_cases", "requirement_value": 1000, "reward_amount": 5000, "sort_order": 4, }, { "name": "first_contract", "title": "Обменщик", "description": "Выполни первый контракт обмена", "icon": "🔄", "category": "contracts", "requirement_type": "contracts", "requirement_value": 1, "reward_amount": 200, "sort_order": 5, }, { "name": "contract_master", "title": "Мастер контрактов", "description": "Выполни 50 контрактов обмена", "icon": "🔄", "category": "contracts", "requirement_type": "contracts", "requirement_value": 50, "reward_amount": 2000, "sort_order": 6, }, { "name": "first_upgrade", "title": "Рисковый", "description": "Попробуй апгрейд в первый раз", "icon": "🆙", "category": "upgrade", "requirement_type": "upgrade_attempts", "requirement_value": 1, "reward_amount": 100, "sort_order": 7, }, { "name": "upgrade_winner", "title": "Везунчик", "description": "Выиграй 10 апгрейдов", "icon": "🍀", "category": "upgrade", "requirement_type": "upgrade_wins", "requirement_value": 10, "reward_amount": 1500, "sort_order": 8, }, { "name": "rare_finder", "title": "Охотник за редким", "description": "Выбей предмет редкости Covert или Rare Special", "icon": "🔴", "category": "cases", "requirement_type": "rare_item", "requirement_value": 1, "reward_amount": 500, "sort_order": 9, }, { "name": "knife_collector", "title": "Ножевод", "description": "Выбей нож или перчатки", "icon": "🔪", "category": "cases", "requirement_type": "knife", "requirement_value": 1, "reward_amount": 2000, "sort_order": 10, }, { "name": "big_spender", "title": "Транжира", "description": "Потрать 10000 ₽ на кейсы", "icon": "💰", "category": "general", "requirement_type": "total_spent", "requirement_value": 10000, "reward_amount": 1000, "sort_order": 11, }, { "name": "whale", "title": "Кит", "description": "Потрать 100000 ₽ на кейсы", "icon": "🐋", "category": "general", "requirement_type": "total_spent", "requirement_value": 100000, "reward_amount": 10000, "sort_order": 12, }, { "name": "slot_winner", "title": "Джекпот", "description": "Собери 3 одинаковых символа в слот-машине", "icon": "🎰", "category": "cases", "requirement_type": "slot_match", "requirement_value": 1, "reward_amount": 1000, "sort_order": 13, }, { "name": "rich_100k", "title": "Богач", "description": "Накопи 100000 ₽ на балансе", "icon": "🤑", "category": "general", "requirement_type": "balance_100k", "requirement_value": 1, "reward_amount": 5000, "sort_order": 14, }, { "name": "slots_10", "title": "Слото-фанат", "description": "Сыграй 10 раундов в слот-машине", "icon": "🎰", "category": "cases", "requirement_type": "slot_plays", "requirement_value": 10, "reward_amount": 500, "sort_order": 15, }, { "name": "crash_first", "title": "Крэш-тестер", "description": "Сыграй в Crash в первый раз", "icon": "💥", "category": "crash", "requirement_type": "crash_plays", "requirement_value": 1, "reward_amount": 100, "sort_order": 16, }, { "name": "crash_pro", "title": "Крэш-профи", "description": "Сыграй 50 раундов в Crash", "icon": "💥", "category": "crash", "requirement_type": "crash_plays", "requirement_value": 50, "reward_amount": 2000, "sort_order": 17, }, { "name": "crash_5x", "title": "Смельчак", "description": "Выведи деньги на множителе x5 или выше в Crash", "icon": "🚀", "category": "crash", "requirement_type": "crash_cashout_5x", "requirement_value": 1, "reward_amount": 1500, "sort_order": 18, }, { "name": "inventory_50", "title": "Собиратель", "description": "Собери 50 предметов в инвентаре", "icon": "🎒", "category": "general", "requirement_type": "inventory_count", "requirement_value": 50, "reward_amount": 500, "sort_order": 19, }, ] def seed_achievements(db: Session): """Создаёт достижения в БД если их ещё нет""" existing = db.query(Achievement).count() if existing > 0: return for defn in ACHIEVEMENT_DEFS: ach = Achievement(**defn) db.add(ach) db.commit() def get_or_create_user_achievement(db: Session, user_id: int, achievement_id: int) -> UserAchievement: ua = db.query(UserAchievement).filter( UserAchievement.user_id == user_id, UserAchievement.achievement_id == achievement_id ).first() if not ua: ua = UserAchievement(user_id=user_id, achievement_id=achievement_id) db.add(ua) db.commit() db.refresh(ua) return ua def check_achievement(db: Session, user_id: int, achievement_name: str, current_value: int) -> Optional[dict]: """Проверяет и разблокирует достижение. Возвращает dict с инфой если разблокировано.""" ach = db.query(Achievement).filter(Achievement.name == achievement_name).first() if not ach: return None ua = get_or_create_user_achievement(db, user_id, ach.id) if ua.unlocked_at: return None ua.progress = min(current_value, ach.requirement_value) if current_value >= ach.requirement_value: ua.unlocked_at = datetime.utcnow() # Награда from database import User user = db.query(User).filter(User.id == user_id).first() if user: user.balance += ach.reward_amount db.commit() # Запись в ленту активности activity = ActivityFeed( user_id=user_id, username=user.username if user else "unknown", activity_type="achievement", message=f"🏆 Получено достижение: {ach.title}", data_json=json.dumps({ "achievement_name": ach.name, "achievement_title": ach.title, "achievement_icon": ach.icon, }) ) db.add(activity) db.commit() return { "name": ach.name, "title": ach.title, "icon": ach.icon, "reward": ach.reward_amount } db.commit() return None def check_open_cases_achievements(db: Session, user_id: int): from database import CaseOpening count = db.query(CaseOpening).filter(CaseOpening.user_id == user_id).count() results = [] for ach_name in ["first_case", "case_collector_10", "case_collector_100", "case_collector_1000"]: r = check_achievement(db, user_id, ach_name, count) if r: results.append(r) return results def check_contracts_achievements(db: Session, user_id: int): from database import Contract count = db.query(Contract).filter(Contract.user_id == user_id).count() results = [] for ach_name in ["first_contract", "contract_master"]: r = check_achievement(db, user_id, ach_name, count) if r: results.append(r) return results def check_upgrade_achievements(db: Session, user_id: int): from database import Upgrade attempts = db.query(Upgrade).filter(Upgrade.user_id == user_id).count() wins = db.query(Upgrade).filter(Upgrade.user_id == user_id, Upgrade.success == True).count() results = [] r1 = check_achievement(db, user_id, "first_upgrade", attempts) if r1: results.append(r1) r2 = check_achievement(db, user_id, "upgrade_winner", wins) if r2: results.append(r2) return results def check_rare_item_achievement(db: Session, user_id: int, rarity: str): results = [] if rarity in ("Covert", "Extraordinary", "Rare Special Item"): r = check_achievement(db, user_id, "rare_finder", 1) if r: results.append(r) return results def check_knife_achievement(db: Session, user_id: int, item_data: dict): from backend import is_knife, is_gloves results = [] if is_knife(item_data) or is_gloves(item_data): r = check_achievement(db, user_id, "knife_collector", 1) if r: results.append(r) return results def check_spent_achievements(db: Session, user_id: int, total_spent: float): results = [] r1 = check_achievement(db, user_id, "big_spender", int(total_spent)) if r1: results.append(r1) r2 = check_achievement(db, user_id, "whale", int(total_spent)) if r2: results.append(r2) return results def check_balance_achievement(db: Session, user_id: int): from database import User user = db.query(User).filter(User.id == user_id).first() if user and user.balance >= 100000: r = check_achievement(db, user_id, "rich_100k", 1) if r: return [r] return [] def check_slot_match_achievement(db: Session, user_id: int): results = [] r = check_achievement(db, user_id, "slot_winner", 1) if r: results.append(r) return results def check_slot_plays_achievements(db: Session, user_id: int): from database import CaseOpening slot_count = db.query(CaseOpening).filter( CaseOpening.user_id == user_id, CaseOpening.case_name.ilike("%slot%") ).count() results = [] r = check_achievement(db, user_id, "slots_10", slot_count) if r: results.append(r) return results def check_inventory_achievement(db: Session, user_id: int): from database import InventoryItem count = db.query(InventoryItem).filter(InventoryItem.user_id == user_id).count() results = [] r = check_achievement(db, user_id, "inventory_50", count) if r: results.append(r) return results def get_user_achievements(db: Session, user_id: int) -> list: """Возвращает все достижения пользователя с прогрессом""" all_ach = db.query(Achievement).order_by(Achievement.sort_order).all() result = [] for ach in all_ach: ua = db.query(UserAchievement).filter( UserAchievement.user_id == user_id, UserAchievement.achievement_id == ach.id ).first() result.append({ "id": ach.id, "name": ach.name, "title": ach.title, "description": ach.description, "icon": ach.icon, "category": ach.category, "requirement_type": ach.requirement_type, "requirement_value": ach.requirement_value, "reward_amount": ach.reward_amount, "progress": ua.progress if ua else 0, "unlocked": ua.unlocked_at is not None if ua else False, "unlocked_at": ua.unlocked_at.isoformat() if ua and ua.unlocked_at else None, }) return result