192 lines
7.2 KiB
Python
192 lines
7.2 KiB
Python
import random
|
|
from datetime import datetime
|
|
from typing import Dict, Optional
|
|
from sqlalchemy.orm import Session
|
|
from database import User, UserRPU
|
|
|
|
# Стандартные веса редкостей
|
|
BASE_RARITY_WEIGHTS = {
|
|
"Consumer Grade": 10000,
|
|
"Industrial Grade": 5000,
|
|
"Mil-Spec": 2500,
|
|
"Mil-Spec Grade": 2500,
|
|
"Restricted": 625,
|
|
"Classified": 125,
|
|
"Covert": 25,
|
|
"Rare Special Item": 5,
|
|
"Extraordinary": 5
|
|
}
|
|
|
|
# Маппинг редкостей на поля в UserRPU
|
|
RARITY_TO_FIELD = {
|
|
"Consumer Grade": "consumer_multiplier",
|
|
"Industrial Grade": "industrial_multiplier",
|
|
"Mil-Spec": "mil_spec_multiplier",
|
|
"Mil-Spec Grade": "mil_spec_multiplier",
|
|
"Restricted": "restricted_multiplier",
|
|
"Classified": "classified_multiplier",
|
|
"Covert": "covert_multiplier",
|
|
"Rare Special Item": "rare_special_multiplier",
|
|
"Extraordinary": "rare_special_multiplier"
|
|
}
|
|
|
|
|
|
def get_user_rpu(db: Session, user_id: int) -> UserRPU:
|
|
"""Получает или создает настройки РПУ для пользователя"""
|
|
rpu = db.query(UserRPU).filter(UserRPU.user_id == user_id).first()
|
|
if not rpu:
|
|
rpu = UserRPU(user_id=user_id)
|
|
db.add(rpu)
|
|
db.commit()
|
|
db.refresh(rpu)
|
|
return rpu
|
|
|
|
|
|
def get_adjusted_weights(db: Session, user_id: int) -> Dict[str, float]:
|
|
"""
|
|
Получает веса редкостей с учетом РПУ пользователя.
|
|
НИЗКИЙ % РПУ = ПОВЫШЕННЫЕ шансы на редкое (везёт)
|
|
ВЫСОКИЙ % РПУ = ПОНИЖЕННЫЕ шансы на редкое (не везёт)
|
|
"""
|
|
rpu = get_user_rpu(db, user_id)
|
|
|
|
# Вычисляем общий уровень РПУ (0-100%)
|
|
rpu_level = calculate_rpu_level(rpu)
|
|
|
|
# Переворачиваем: низкий РПУ = высокий множитель для редких
|
|
# При 0% РПУ множитель для редких = 2.0 (очень везёт)
|
|
# При 50% РПУ множитель = 1.0 (обычно)
|
|
# При 100% РПУ множитель = 0.1 (совсем не везёт)
|
|
|
|
adjusted = {}
|
|
for rarity, base_weight in BASE_RARITY_WEIGHTS.items():
|
|
field = RARITY_TO_FIELD.get(rarity)
|
|
base_multiplier = getattr(rpu, field, 1.0) if field else 1.0
|
|
|
|
# Определяем "редкость" предмета (чем реже, тем больше индекс)
|
|
rarity_index = 0
|
|
if "Industrial" in rarity:
|
|
rarity_index = 1
|
|
elif "Mil-Spec" in rarity:
|
|
rarity_index = 2
|
|
elif "Restricted" in rarity:
|
|
rarity_index = 3
|
|
elif "Classified" in rarity:
|
|
rarity_index = 4
|
|
elif "Covert" in rarity:
|
|
rarity_index = 5
|
|
elif "Rare Special" in rarity or "Extraordinary" in rarity:
|
|
rarity_index = 6
|
|
|
|
# Чем выше РПУ, тем сильнее режем шансы на редкое
|
|
# Чем ниже РПУ, тем сильнее повышаем шансы на редкое
|
|
if rpu_level < 50:
|
|
# Везёт: повышаем шансы на редкое
|
|
luck_factor = 1.0 + ((50 - rpu_level) / 50) * rarity_index * 0.3
|
|
else:
|
|
# Не везёт: понижаем шансы на редкое
|
|
luck_factor = 1.0 - ((rpu_level - 50) / 50) * rarity_index * 0.2
|
|
|
|
luck_factor = max(0.1, min(3.0, luck_factor))
|
|
|
|
final_multiplier = base_multiplier * rpu.luck_multiplier * luck_factor
|
|
adjusted[rarity] = base_weight * final_multiplier
|
|
|
|
return adjusted
|
|
|
|
|
|
def calculate_rpu_level(rpu: UserRPU) -> float:
|
|
"""
|
|
Вычисляет общий уровень РПУ (0-100%).
|
|
0% = максимальное везение
|
|
100% = максимальное невезение
|
|
"""
|
|
multipliers = [
|
|
rpu.consumer_multiplier,
|
|
rpu.industrial_multiplier,
|
|
rpu.mil_spec_multiplier,
|
|
rpu.restricted_multiplier,
|
|
rpu.classified_multiplier,
|
|
rpu.covert_multiplier,
|
|
rpu.rare_special_multiplier
|
|
]
|
|
|
|
# Средний множитель
|
|
avg = sum(multipliers) / len(multipliers)
|
|
|
|
# Преобразуем в проценты: 0.1x = 100% РПУ (не везёт), 3.0x = 0% РПУ (везёт)
|
|
# 1.0x = 50% РПУ
|
|
if avg >= 1.0:
|
|
level = 50 - ((avg - 1.0) / 2.0) * 100
|
|
else:
|
|
level = 50 + ((1.0 - avg) / 0.9) * 50
|
|
|
|
return max(0, min(100, level))
|
|
|
|
|
|
def get_rpu_description(level: float) -> str:
|
|
"""Возвращает текстовое описание уровня РПУ"""
|
|
if level < 20:
|
|
return "🍀 Очень везучий"
|
|
elif level < 35:
|
|
return "😊 Везучий"
|
|
elif level < 45:
|
|
return "🙂 Немного везучий"
|
|
elif level < 55:
|
|
return "😐 Обычный"
|
|
elif level < 70:
|
|
return "🙁 Немного невезучий"
|
|
elif level < 85:
|
|
return "😟 Невезучий"
|
|
else:
|
|
return "💀 Проклятый"
|
|
|
|
|
|
def auto_adjust_rpu(db: Session, user_id: int):
|
|
"""Автоматическая подкрутка РПУ на основе статистики"""
|
|
rpu = get_user_rpu(db, user_id)
|
|
|
|
if not rpu.auto_adjust:
|
|
return
|
|
|
|
user = db.query(User).filter(User.id == user_id).first()
|
|
if not user:
|
|
return
|
|
|
|
# Анализируем статистику
|
|
if rpu.total_opened > 0:
|
|
avg_spent_per_case = rpu.total_spent / rpu.total_opened
|
|
|
|
# Если пользователь много тратит и мало получает - снижаем РПУ (даём везение)
|
|
if rpu.total_spent > 10000 and rpu.total_opened > 20:
|
|
# Снижаем РПУ на 5-15%
|
|
reduction = min(0.15, rpu.total_spent / 100000)
|
|
rpu.luck_multiplier = min(2.0, rpu.luck_multiplier + reduction)
|
|
|
|
# Если пользователь часто открывает кейсы - немного снижаем РПУ
|
|
if rpu.total_opened > 50:
|
|
rpu.classified_multiplier = min(1.5, rpu.classified_multiplier + 0.05)
|
|
rpu.covert_multiplier = min(1.3, rpu.covert_multiplier + 0.03)
|
|
|
|
# Ограничиваем множители
|
|
for field in ['consumer_multiplier', 'industrial_multiplier', 'mil_spec_multiplier',
|
|
'restricted_multiplier', 'classified_multiplier', 'covert_multiplier',
|
|
'rare_special_multiplier']:
|
|
value = getattr(rpu, field)
|
|
setattr(rpu, field, max(0.1, min(3.0, value)))
|
|
|
|
rpu.luck_multiplier = max(0.1, min(3.0, rpu.luck_multiplier))
|
|
rpu.last_adjustment = datetime.utcnow()
|
|
db.commit()
|
|
|
|
|
|
def update_rpu_stats(db: Session, user_id: int, spent: float, opened: int = 1):
|
|
"""Обновляет статистику РПУ после открытия кейсов"""
|
|
rpu = get_user_rpu(db, user_id)
|
|
rpu.total_spent += spent
|
|
rpu.total_opened += opened
|
|
db.commit()
|
|
|
|
# Авто-подкрутка если включена
|
|
if rpu.auto_adjust:
|
|
auto_adjust_rpu(db, user_id) |