Fix_1
This commit is contained in:
44
config.py
44
config.py
@@ -0,0 +1,44 @@
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
BOT_TOKEN = os.getenv("BOT_TOKEN")
|
||||
ADMIN_ID = os.getenv("ADMIN_ID")
|
||||
|
||||
# Стартовые значения
|
||||
INITIAL_BALANCE = 10_000
|
||||
INITIAL_SERVERS = 1
|
||||
INITIAL_COVERAGE_CUSTOMERS = 500
|
||||
INITIAL_MAX_CUSTOMERS = 500
|
||||
INITIAL_SPEED = 10
|
||||
INITIAL_CHANNEL_LEVEL = 1
|
||||
INITIAL_POWER_CAPACITY = 5.0
|
||||
INITIAL_NETWORK_CHANNEL_CAPACITY = 10 # Мбит/с (база)
|
||||
|
||||
# Параметры инфраструктуры
|
||||
SERVER_POWER = 2.0 # кВт/сервер
|
||||
SERVER_COST = 3_000
|
||||
SERVER_CAPACITY_ADD = 500
|
||||
CABLE_COST = 800
|
||||
CABLE_COVERAGE_ADD = 500
|
||||
BACKUP_CHANNEL_COST = 2_500
|
||||
BACKUP_CHANNEL_POWER_ADD = 100
|
||||
|
||||
# Тарифы (в ₡/день/клиент)
|
||||
TARIFFS = {
|
||||
"home": 10,
|
||||
"office": 30,
|
||||
"gamer": 50,
|
||||
"botfarm": 15
|
||||
}
|
||||
|
||||
# Уровни канала
|
||||
CHANNEL_LEVELS = {
|
||||
1: 10,
|
||||
2: 50,
|
||||
3: 100,
|
||||
4: 250,
|
||||
5: 500,
|
||||
6: 1000
|
||||
}
|
||||
41
database.py
41
database.py
@@ -1,8 +1,10 @@
|
||||
# database.py — работа с SQLite
|
||||
import sqlite3
|
||||
from typing import Optional, Dict, Any
|
||||
|
||||
DB_PATH = "data/db.sqlite3"
|
||||
|
||||
|
||||
def init_db():
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
cur = conn.cursor()
|
||||
@@ -32,14 +34,17 @@ def init_db():
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
||||
def get_player(user_id: int) -> Optional[Dict[str, Any]]:
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
cur = conn.cursor()
|
||||
cur.execute("SELECT * FROM players WHERE user_id = ?", (user_id,))
|
||||
row = cur.fetchone()
|
||||
conn.close()
|
||||
|
||||
if not row:
|
||||
return None
|
||||
|
||||
keys = [
|
||||
"user_id", "balance", "servers", "cables", "coverage_customers",
|
||||
"max_customers", "speed", "rating", "rating_threshold",
|
||||
@@ -49,6 +54,7 @@ def get_player(user_id: int) -> Optional[Dict[str, Any]]:
|
||||
]
|
||||
return dict(zip(keys, row))
|
||||
|
||||
|
||||
def update_player(user_id: int, updates: Dict[str, Any]):
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
cur = conn.cursor()
|
||||
@@ -58,15 +64,30 @@ def update_player(user_id: int, updates: Dict[str, Any]):
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
||||
def create_player_if_not_exists(user_id: int):
|
||||
player = get_player(user_id)
|
||||
if not player:
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
cur = conn.cursor()
|
||||
cur.execute("""
|
||||
INSERT INTO players (user_id, balance, servers, cables, coverage_customers, max_customers, speed, power_capacity, channel_capacity)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""", (user_id, INITIAL_BALANCE, INITIAL_SERVERS, 0, INITIAL_COVERAGE_CUSTOMERS,
|
||||
INITIAL_MAX_CUSTOMERS, INITIAL_SPEED, INITIAL_POWER_CAPACITY, INITIAL_NETWORK_CHANNEL_CAPACITY))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
if player:
|
||||
return
|
||||
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
cur = conn.cursor()
|
||||
cur.execute("""
|
||||
INSERT INTO players
|
||||
(user_id, balance, servers, cables, coverage_customers, max_customers, speed,
|
||||
power_capacity, network_channel_level, channel_capacity)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""", (
|
||||
user_id,
|
||||
10_000, # balance
|
||||
1, # servers
|
||||
0, # cables
|
||||
500, # coverage_customers
|
||||
500, # max_customers
|
||||
10, # speed
|
||||
5.0, # power_capacity
|
||||
1, # network_channel_level
|
||||
10 # channel_capacity
|
||||
))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
@@ -0,0 +1,74 @@
|
||||
from aiogram import types, Router
|
||||
from database import get_player, update_player
|
||||
from economy import sync_power
|
||||
from config import CABLE_COST, SERVER_COST, BACKUP_CHANNEL_COST, BACKUP_CHANNEL_POWER_ADD
|
||||
|
||||
router = Router()
|
||||
|
||||
@router.callback_query(lambda c: c.data == "build_cable")
|
||||
async def build_cable(callback: types.CallbackQuery):
|
||||
user_id = callback.from_user.id
|
||||
player = get_player(user_id)
|
||||
if player["balance"] < CABLE_COST:
|
||||
await callback.answer("❌ Не хватает средств!", show_alert=True)
|
||||
return
|
||||
|
||||
new_power = player["power_capacity"] + 2
|
||||
update_player(user_id, {
|
||||
"balance": player["balance"] - CABLE_COST,
|
||||
"power_capacity": new_power,
|
||||
"cables": player["cables"] + 1
|
||||
})
|
||||
await callback.message.edit_text(
|
||||
f"✅ Кабель проложен!\n"
|
||||
f"⚡ Лимит питания: {new_power} кВт\n"
|
||||
f"💰 Остаток: {player['balance'] - CABLE_COST} ₡"
|
||||
)
|
||||
await callback.answer("Кабель установлен 🛠️")
|
||||
|
||||
@router.callback_query(lambda c: c.data == "buy_server")
|
||||
async def buy_server(callback: types.CallbackQuery):
|
||||
user_id = callback.from_user.id
|
||||
player = get_player(user_id)
|
||||
if player["balance"] < SERVER_COST:
|
||||
await callback.answer("❌ Не хватает средств!", show_alert=True)
|
||||
return
|
||||
|
||||
new_servers = player["servers"] + 1
|
||||
new_power = new_servers * 2.0 # SERVER_POWER = 2.0 из config.py
|
||||
|
||||
update_player(user_id, {
|
||||
"balance": player["balance"] - SERVER_COST,
|
||||
"servers": new_servers,
|
||||
"max_customers": player["max_customers"] + 500,
|
||||
"power_capacity": new_power, # обновляем лимит
|
||||
"power_usage": player["servers"] * 2.0 # обновляем нагрузку (была на старом количестве)
|
||||
})
|
||||
|
||||
await callback.message.edit_text(
|
||||
f"✅ Сервер установлен!\n"
|
||||
f"🖥 Теперь: {new_servers} шт.\n"
|
||||
f"⚡ Потребление: {new_power:.1f}/{new_power:.1f} кВт"
|
||||
)
|
||||
await callback.answer("Сервер включён!")
|
||||
|
||||
@router.callback_query(lambda c: c.data == "buy_backup_channel")
|
||||
async def buy_backup_channel(callback: types.CallbackQuery):
|
||||
user_id = callback.from_user.id
|
||||
player = get_player(user_id)
|
||||
if player["balance"] < BACKUP_CHANNEL_COST:
|
||||
await callback.answer("❌ Не хватает средств!", show_alert=True)
|
||||
return
|
||||
|
||||
new_power = player["power_capacity"] + BACKUP_CHANNEL_POWER_ADD
|
||||
update_player(user_id, {
|
||||
"balance": player["balance"] - BACKUP_CHANNEL_COST,
|
||||
"power_capacity": new_power,
|
||||
"backup_channel_active": 0
|
||||
})
|
||||
await callback.message.edit_text(
|
||||
f"⚡ Резервный канал построен! ✅\n"
|
||||
f"Лимит питания: {new_power} кВт\n"
|
||||
f"💰 Остаток: {player['balance'] - BACKUP_CHANNEL_COST} ₡"
|
||||
)
|
||||
await callback.answer("Резерв готов!")
|
||||
@@ -1,7 +1,10 @@
|
||||
from aiogram import types
|
||||
from aiogram import types, Router
|
||||
from database import get_player, update_player
|
||||
from economy import calculate_channel_cost
|
||||
|
||||
router = Router() # ← ВАЖНО!
|
||||
|
||||
@router.callback_query(lambda c: c.data == "upgrade_channel")
|
||||
async def upgrade_channel(callback: types.CallbackQuery):
|
||||
user_id = callback.from_user.id
|
||||
player = get_player(user_id)
|
||||
@@ -17,7 +20,7 @@ async def upgrade_channel(callback: types.CallbackQuery):
|
||||
return
|
||||
|
||||
next_level = current_level + 1
|
||||
next_capacity = int(player["channel_capacity"] * 2.5) # +150% каждый уровень
|
||||
next_capacity = int(player["channel_capacity"] * 2.5)
|
||||
upgrade_hours = 4 * current_level
|
||||
|
||||
update_player(user_id, {
|
||||
@@ -50,7 +53,11 @@ async def speedup_channel(callback: types.CallbackQuery):
|
||||
await callback.answer("❌ Нет средств на ускорение", show_alert=True)
|
||||
return
|
||||
|
||||
new_end = max(0, int(__import__("time").time()) + (player["next_build_end_ts"] - int(__import__("time").time())) // 2)
|
||||
new_end = max(
|
||||
0,
|
||||
int(__import__("time").time()) +
|
||||
(player["next_build_end_ts"] - int(__import__("time").time())) // 2
|
||||
)
|
||||
|
||||
update_player(user_id, {
|
||||
"balance": player["balance"] - 500,
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
from aiogram import types
|
||||
# handlers/map.py
|
||||
from aiogram import types, Router
|
||||
from database import get_player
|
||||
|
||||
router = Router() # ← ВАЖНО! Регистрируем роутер
|
||||
|
||||
@router.callback_query(lambda c: c.data == "map")
|
||||
async def show_map(callback: types.CallbackQuery):
|
||||
player = get_player(callback.from_user.id)
|
||||
districts = [
|
||||
("🏠 Гараж (ваша база)", "✅ Подключён"),
|
||||
("🏢 Центральный район", "🟡 В процессе (15 мин)" if player["next_build_end_ts"] > 0 else "🔒 Недоступен"),
|
||||
("🏢 Центральный район", "🟡 В процессе" if player.get("next_build_end_ts", 0) > 0 else "🔒 Недоступен"),
|
||||
("🎮 Западный квартал", "🔒 Недоступен"),
|
||||
]
|
||||
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
from aiogram import types, Router
|
||||
from aiogram.filters import CommandStart
|
||||
from aiogram.types import WebAppInfo
|
||||
|
||||
from database import create_player_if_not_exists, get_player
|
||||
from economy import (
|
||||
calculate_daily_offline_earnings, calculate_effective_bandwidth,
|
||||
calculate_rating, calculate_daily_income
|
||||
calculate_effective_bandwidth, calculate_rating, calculate_client_retention,
|
||||
calculate_daily_income, calculate_daily_offline_earnings
|
||||
)
|
||||
from keyboards import get_main_menu
|
||||
|
||||
router = Router()
|
||||
|
||||
@@ -23,7 +20,6 @@ async def cmd_start(message: types.Message):
|
||||
player["balance"] += offline_earn
|
||||
player["total_income"] += offline_earn
|
||||
player["last_login_ts"] = int(__import__("time").time())
|
||||
get_player.cache_clear()
|
||||
update_player(user_id, {
|
||||
"balance": player["balance"],
|
||||
"total_income": player["total_income"],
|
||||
@@ -31,6 +27,8 @@ async def cmd_start(message: types.Message):
|
||||
})
|
||||
|
||||
effective_bw = calculate_effective_bandwidth(player)
|
||||
lost, churn_msg = calculate_client_retention(player)
|
||||
daily_income = calculate_daily_income(player)
|
||||
|
||||
status = ""
|
||||
if player["outage_end_ts"] > 0:
|
||||
@@ -44,13 +42,14 @@ async def cmd_start(message: types.Message):
|
||||
f"⚡ *Канал:* {player['channel_capacity']} → {effective_bw} Мбит/с\n"
|
||||
f"🔋 *Сеть:* {player['power_usage']:.1f}/{player['power_capacity']} кВт\n"
|
||||
f"🖥 *Серверы:* {player['servers']} (ёмкость: {player['max_customers']} клиентов)\n"
|
||||
f"📡 *Клиенты:* {player['coverage_customers']} (отток: {calculate_client_retention(player)[0]}/сутки)\n"
|
||||
f"📡 *Клиенты:* {player['coverage_customers']} (отток: {lost}/сутки)\n"
|
||||
f"💰 *Бюджет:* {player['balance']:,.0f} ₡\n"
|
||||
f"📊 *Доход/день:* {calculate_daily_income(player):,.0f} ₡\n"
|
||||
f"📊 *Доход/день:* {daily_income:,.0f} ₡\n"
|
||||
f"🌟 *Рейтинг:* {calculate_rating(player)}\n"
|
||||
f"{status}"
|
||||
f"{churn_msg}\n{status}"
|
||||
)
|
||||
|
||||
from keyboards import get_main_menu
|
||||
await message.answer(
|
||||
text,
|
||||
reply_markup=get_main_menu(player),
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
from aiogram import types
|
||||
# handlers/stats.py
|
||||
from aiogram import types, Router
|
||||
from database import get_player
|
||||
from economy import calculate_rating, calculate_effective_bandwidth
|
||||
|
||||
router = Router()
|
||||
|
||||
@router.callback_query(lambda c: c.data == "stats")
|
||||
async def stats(callback: types.CallbackQuery):
|
||||
player = get_player(callback.from_user.id)
|
||||
if not player:
|
||||
await callback.answer("❌ Игрок не найден", show_alert=True)
|
||||
return
|
||||
|
||||
bw = calculate_effective_bandwidth(player)
|
||||
daily = calculate_daily_income(player)
|
||||
|
||||
text = (
|
||||
f"📊 *Ваша статистика*\n\n"
|
||||
f"🔹 Канал: {player['network_channel_level']} → {bw} Мбит/с\n"
|
||||
f"🔹 Серверы: {player['servers']} шт. (ёмкость: {player['max_customers']})\n"
|
||||
f"🔹 Клиенты: {player['coverage_customers']} / {player['max_customers']}\n"
|
||||
f"🔹 Доход/день: {calculate_daily_income(player):,.0f} ₡\n"
|
||||
f"🔹 Доход/день: {daily:,.0f} ₡\n"
|
||||
f"🔹 Общий доход: {player['total_income']:,.0f} ₡\n"
|
||||
f"🔹 Рейтинг: {calculate_rating(player)} 🌟"
|
||||
)
|
||||
|
||||
58
main.py
58
main.py
@@ -1,16 +1,12 @@
|
||||
from aiogram import Bot, Dispatcher, types
|
||||
from aiogram import Bot, Dispatcher
|
||||
from aiogram.enums import ParseMode
|
||||
from aiogram.filters import Command
|
||||
from aiogram import Router
|
||||
import asyncio
|
||||
import logging
|
||||
import time
|
||||
|
||||
from config import BOT_TOKEN
|
||||
from database import init_db, get_player, update_player
|
||||
from economy import calculate_effective_bandwidth, handle_outage, sync_power
|
||||
from database import init_db
|
||||
from handlers.start import router as start_router
|
||||
from handlers.economy import router as economy_router
|
||||
from handlers.build import router as build_router
|
||||
from handlers.channel import router as channel_router
|
||||
from handlers.stats import router as stats_router
|
||||
@@ -19,53 +15,37 @@ from handlers.events import router as events_router
|
||||
|
||||
dp = Dispatcher()
|
||||
dp.include_router(start_router)
|
||||
dp.include_router(economy_router)
|
||||
dp.include_router(build_router)
|
||||
dp.include_router(channel_router)
|
||||
dp.include_router(stats_router)
|
||||
dp.include_router(map_router)
|
||||
dp.include_router(events_router)
|
||||
|
||||
# Периодическая проверка состояний (каждые 5 минут)
|
||||
@dp.message(Command("check"))
|
||||
async def check_state(message: types.Message):
|
||||
user_id = message.from_user.id
|
||||
player = get_player(user_id)
|
||||
if not player:
|
||||
await message.answer("❌ Игрок не найден")
|
||||
return
|
||||
@dp.message()
|
||||
async def echo(message: types.Message):
|
||||
if message.text == "/check":
|
||||
from database import get_player
|
||||
from economy import calculate_effective_bandwidth, handle_outage, sync_power
|
||||
player = get_player(message.from_user.id)
|
||||
if not player:
|
||||
await message.answer("❌ Игрок не найден")
|
||||
return
|
||||
|
||||
# Оффлайн доход + апгрейды
|
||||
player = handle_outage(player)
|
||||
player = sync_power(player)
|
||||
effective_bw = calculate_effective_bandwidth(player)
|
||||
player = handle_outage(player)
|
||||
player = sync_power(player)
|
||||
|
||||
# Обновление
|
||||
update_player(user_id, {
|
||||
"power_usage": player["power_usage"],
|
||||
"coverage_customers": player["coverage_customers"],
|
||||
"max_customers": player["max_customers"]
|
||||
})
|
||||
|
||||
status = ""
|
||||
if player["outage_end_ts"] > 0:
|
||||
status = f"\n⚠️ АВАРИЯ: Отключение до {player['outage_end_ts'] - int(__import__('time').time()) // 3600}ч"
|
||||
|
||||
await message.answer(
|
||||
f"⚡ Состояние проверено!\n"
|
||||
f"Канал: {player['channel_capacity']} → {effective_bw} Мбит/с\n"
|
||||
f"Лимит: {player['power_usage']:.1f}/{player['power_capacity']} кВт\n"
|
||||
f"Клиенты: {player['coverage_customers']} / {player['max_customers']}\n"
|
||||
f"{status}",
|
||||
parse_mode="Markdown"
|
||||
)
|
||||
await message.answer(
|
||||
f"⚡ Состояние проверено!\n"
|
||||
f"Канал: {player['channel_capacity']} → {calculate_effective_bandwidth(player)} Мбит/с\n"
|
||||
f"Лимит: {player['power_usage']:.1f}/{player['power_capacity']} кВт"
|
||||
)
|
||||
|
||||
async def main():
|
||||
init_db()
|
||||
bot = Bot(token=BOT_TOKEN, parse_mode=ParseMode.HTML)
|
||||
print("🤖 ISP Tycoon bot started...")
|
||||
await dp.start_polling(bot)
|
||||
|
||||
if __name__ == "__main__":
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
bot = Bot(token=BOT_TOKEN, parse_mode=ParseMode.HTML)
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user