Добавил проект с учетом .gitignore

This commit is contained in:
2025-07-06 19:24:54 +03:00
parent 41ad5a5b92
commit e796892942
20 changed files with 6162 additions and 3 deletions

453
src/cogs/economy.py Normal file
View File

@@ -0,0 +1,453 @@
import disnake
from disnake.ext import commands
from disnake.ext import tasks
import requests
import numpy as np
import asyncio
import sys
import os
import copy
import datetime
import math
import random
import json
import shutil
from constants.global_constants import *
def setup(bot):
bot.add_cog(MainEconomyModule(bot))
class MainEconomyModule(commands.Cog):
def __init__(self, client):
self.client = client
self.DataBaseManager = client.DataBaseManager
@commands.Cog.listener()
async def on_ready(self):
self.krekchat = await self.client.fetch_guild(constants["krekchat"])
self.sponsors = [disnake.utils.get(self.krekchat.roles, id=i) for i in constants["sponsors"]]
self.me = disnake.utils.get(self.krekchat.roles, id=constants["me"])
print(f'KrekFunBot economy module activated')
@commands.slash_command(name = "статистика", description="Статистика отображает все данные о пользователе")
async def UserStatistic(self, ctx: disnake.AppCmdInter,
member: disnake.Member = commands.Param(description="Чью статистику хотите посмотреть?", name="участник", default=None)):
if not member:
member = ctx.author
if ctx.guild is None:
embed = disnake.Embed(title=f"Статистика **{member.name}**", description=f'')
elif member.nick != None:
embed = disnake.Embed(title=f"Статистика **{member.nick}**", description=f'')
else:
embed = disnake.Embed(title=f"Статистика **{member.name}**", description=f'')
embed.set_thumbnail(url=member.avatar)
await ctx.response.defer()
users_model = self.DataBaseManager.models['users'].m
rimagochi_users_model = self.DataBaseManager.models['rimagochi_users'].m
async with self.DataBaseManager.session() as session:
async with session.begin():
user = await session.get(users_model, member.id)
if user is None:
await self.client.ErrorOutHelper(send_function = ctx.edit_original_message, err_name = "Ошибка статистики").out(d="Такого пользователя нет в базе данных")
return
stmt = self.DataBaseManager.select(users_model).options(
self.DataBaseManager.selectinload(users_model.custom_roles),
self.DataBaseManager.joinedload(users_model.creation_role),
self.DataBaseManager.selectinload(users_model.prize_roles),
self.DataBaseManager.selectinload(users_model.sender_in_crumbs_transactions),
self.DataBaseManager.selectinload(users_model.recipient_in_crumbs_transactions),
self.DataBaseManager.joinedload(users_model.casino_account),
).where(
users_model.id == member.id
)
user = (await session.execute(stmt)).scalars().first()
stmt = self.DataBaseManager.select(rimagochi_users_model).options(
self.DataBaseManager.selectinload(rimagochi_users_model.animals),
self.DataBaseManager.selectinload(rimagochi_users_model.battle_slots_animals)
).where(
rimagochi_users_model.id == member.id
)
rimagochi_user = (await session.execute(stmt)).scalars().first()
embed.add_field(name=f"Модуль экономики", value=f"", inline=False)
embed.add_field(name=f"крошки", value=f"{user.crumbs}", inline=False)
embed.add_field(name=f"сообщения (в общем)", value=f"{user.summary_messages}", inline=False)
embed.add_field(name=f"минут в голосовом канале (в общем)", value=f"{user.summary_voice_activity/60}", inline=False)
embed.add_field(name=f"сообщения (после сброса)", value=f"{user.period_messages}", inline=False)
embed.add_field(name=f"минут в голосовом канале (после сброса)", value=f"{user.period_voice_activity/60}", inline=False)
embed.add_field(name=f"репутация", value=f"{user.carma}", inline=False)
embed.add_field(name=f"зарплата", value=f"{user.staff_salary}", inline=False)
embed.add_field(name=f"время получения последней ежедневной награды", value=f"<t:{int(user.last_daily_crumbs_date)}:F>", inline=False)
embed.add_field(name=f"время последней активности", value=f"<t:{int(user.last_activity_date)}:F>", inline=False)
embed.add_field(name=f"количество записей в истории об отправлениях (общая сумма)", value=f"{len(user.sender_in_crumbs_transactions)} ({sum([write.amount for write in user.sender_in_crumbs_transactions]+[0])})", inline=False)
embed.add_field(name=f"количество записей в истории о получениях (общая сумма)", value=f"{len(user.recipient_in_crumbs_transactions)} ({sum([write.amount for write in user.recipient_in_crumbs_transactions]+[0])})", inline=False)
embed.add_field(name=f"наличие записей в казино", value=f"{not user.casino_account is None}", inline=False)
if not user.casino_account is None:
embed.add_field(name=f"количество круток сегодня (может быть не актуальным)", value=f"{user.casino_account.spins_today_count}", inline=False)
embed.add_field(name=f"время последнего сброса лимитов", value=f"<t:{int(user.casino_account.last_reset_time)}:F>", inline=False)
embed.add_field(name=f"Ролевой модуль", value=f"", inline=False)
embed.add_field(name=f"количество кастомных ролей (общая стоимость)", value=f"{len(user.custom_roles)} ({sum([role.cost for role in user.custom_roles]+[0])})", inline=False)
embed.add_field(name=f"количество призовых ролей", value=f"{len(user.prize_roles)}", inline=False)
embed.add_field(name=f"созданная кастомная роль", value=(f"<@&{user.creation_role.id}>" if not user.creation_role is None else "None"), inline=False)
embed.add_field(name=f"Модуль rimagochi", value=f"", inline=False)
embed.add_field(name=f"наличие аккаунта rimagochi", value=f"{not rimagochi_user is None}", inline=False)
if not rimagochi_user is None:
embed.add_field(name=f"количество зверей", value=f"{len(rimagochi_user.animals)}", inline=False)
embed.add_field(name=f"количество генов", value=f"{sum([int(i) for i in rimagochi_user.genes.values()])}", inline=False)
embed.add_field(name=f"количество предметов", value=f"{sum([int(i) for i in rimagochi_user.items.values()])}", inline=False)
embed.add_field(name=f"количество побед", value=f"{rimagochi_user.wins}", inline=False)
await ctx.edit_original_message(embed=embed)
@commands.slash_command(description="Показывает топ участников сервера по заданному параметру (по умолчанию - уровень)", name="топ")
async def TopSlash(self, ctx: disnake.AppCmdInter, parameter: str = commands.Param(description="По какому критерию хотите увидеть топ?",
name="критерий", default = 'по уровню',
choices=['по уровню', 'по количеству сообщений', 'по времени в голосовых каналах', 'по количеству крошек'])):
await ctx.response.defer()
async with self.DataBaseManager.session() as session:
async with session.begin():
async with self.DataBaseManager.models['users'] as users_model:
order_by = None
match parameter:
case "по уровню":
order_by = [self.DataBaseManager.desc(users_model.period_messages + (users_model.period_voice_activity / 180))]
case "по количеству сообщений":
order_by = [self.DataBaseManager.desc(users_model.period_messages), self.DataBaseManager.desc(users_model.period_voice_activity)]
case "по времени в голосовых каналах":
order_by = [self.DataBaseManager.desc(users_model.period_voice_activity), self.DataBaseManager.desc(users_model.period_messages)]
case "по количеству крошек":
order_by = [self.DataBaseManager.desc(users_model.crumbs), self.DataBaseManager.desc(users_model.period_messages), self.DataBaseManager.desc(users_model.period_voice_activity)]
stmt = self.DataBaseManager.select(users_model).order_by(*order_by).limit(20)
users = (await session.execute(stmt)).scalars().all()
embed = disnake.Embed(title=f"Общий топ {parameter}", description=f'', colour=0x2F3136)
users_counter = 0
for user in users:
try:
member = await self.krekchat.fetch_member(user.id)
except disnake.NotFound:
continue
member_name = None
if member.nick != None:
member_name = member.nick
elif member.display_name != None:
member_name = member.display_name
else:
member_name = member.name
match parameter:
case "по уровню":
embed.add_field(name=f"{users_counter + 1}) {member_name}",
value=f"{member.mention} - {int(self.client.CalculateLevel(user.period_messages, user.period_voice_activity))} уровень",
inline=False)
case "по количеству сообщений":
embed.add_field(name=f"{users_counter + 1}) {member_name}",
value=f"{member.mention} - {user.period_messages} сообщений",
inline=False)
case "по времени в голосовых каналах":
embed.add_field(name=f"{users_counter + 1}) {member_name}",
value=f"{member.mention} - {int(user.period_voice_activity/60)} минут",
inline=False)
case "по количеству крошек":
embed.add_field(name=f"{users_counter + 1}) {member_name}",
value=f"{member.mention} - {int(user.crumbs)} крошек",
inline=False)
users_counter += 1
if users_counter >= 10:
break
await ctx.edit_original_message(embed=embed)
@commands.slash_command(name="ежедневная")
async def DailySlash(self, ctx):
pass
@DailySlash.sub_command(
description=f"Получайте награду в крошках каждый день",
name="награда")
async def DailyCrumbsSub(self, ctx: disnake.AppCmdInter):
await ctx.response.defer()
error_helper = self.client.ErrorOutHelper(send_function = ctx.edit_original_message, err_name = "Ошибка начисления ежедневной награды")
if ctx.guild is None:
await error_helper.out(d="Эта команда не работает в личных сообщениях!")
return
async with self.DataBaseManager.session() as session:
await self.client.UserUpdate(member = ctx.author, session = session)
async with session.begin():
async with self.DataBaseManager.models['users'] as users_model:
stmt = self.DataBaseManager.select(users_model).where(users_model.id == ctx.author.id).with_for_update()
user = (await session.execute(stmt)).scalars().first()
result = await user.claim_daily_crumbs(daily_constant = constants['dailycrumbs'], member = ctx.author, sponsor_roles = self.sponsors)
if result['success']:
history = self.DataBaseManager.models['transaction_history_crumbs'].m(recipient_id = ctx.author.id, amount = result['count'], description = f"Ежедневная награда за {result['date'].strftime('%d.%m.%Y')}")
session.add(history)
await ctx.edit_original_message(embed=disnake.Embed(description=result['output'], colour=0x2F3136))
return
else:
await error_helper.out(d=result['output'])
return
@commands.slash_command(name="история", description="Показывает историю транзакций")
async def HistoryCrumbsSlash(self, ctx: disnake.AppCmdInter):
pass
@HistoryCrumbsSlash.sub_command(description="Показывает историю транзакций", name="транзакций")
async def HistoryCrumbsSub(self, ctx: disnake.AppCmdInter, member: disnake.Member = commands.Param(
description="Чью историю хотите посмотреть?(только для администраторов)",
name="участник", default=None)):
if not (member != None and self.me in ctx.author.roles):
member = ctx.author
class HistoryButtons(disnake.ui.View):
def __init__(self, ctx, transactions, member, embed):
super().__init__(timeout=180)
self.transactions = transactions
self.ctx = ctx
self.embed = embed
self.member = member
self.page = 1
self.maxpage = len(transactions) if len(transactions) > 0 else 1
self.left.disabled = (self.page == 1)
self.right.disabled = (self.page == self.maxpage)
@disnake.ui.button(label="<", custom_id="left", style=disnake.ButtonStyle.secondary)
async def left(self, button, inter):
if inter.author != self.ctx.author:
return
self.page -= 1
self.left.disabled = (self.page == 1)
self.right.disabled = (self.page == self.maxpage)
self.embed = await EmbedHistoryChanger(self.transactions, self.embed, self.page, self.member)
await inter.response.edit_message(embed=self.embed, view=self)
@disnake.ui.button(label=">", custom_id="right", style=disnake.ButtonStyle.secondary)
async def right(self, button, inter):
if inter.author != self.ctx.author:
return
self.page += 1
self.left.disabled = (self.page == 1)
self.right.disabled = (self.page == self.maxpage)
self.embed = await EmbedHistoryChanger(self.transactions, self.embed, self.page, self.member)
await inter.response.edit_message(embed=self.embed, view=self)
async def on_timeout(self):
for child in self.children:
if isinstance(child, (disnake.ui.Button, disnake.ui.BaseSelect)):
child.disabled = True
await self.ctx.edit_original_message(view=self)
async def EmbedHistoryChanger(transactions, embed, selfpage, member):
embed.clear_fields()
if len(transactions) == 0:
embed.add_field(name=f"В истории пока ничего нет", value=f"", inline=False)
return embed
embed.add_field(name=f"", value=f"", inline=False)
page = transactions[selfpage - 1]
maxpage = len(transactions) if len(transactions) > 0 else 1
c = 1
for transaction in transactions[selfpage - 1]:
if transaction.recipient_id == member.id:
string = (
f"{c+5*(selfpage-1)}) <:A_g_wplus:606920277443608593> **{int(transaction.amount)} крошек** {f' (комиссия: {int(transaction.commission_fraction * 100)}%)'if transaction.commission_fraction != 0 else ''}\n"
f"{f'Отправитель: <@{transaction.sender_id}>' if not transaction.sender_id is None else ''}\n"
f"Время транзакции: <t:{int(transaction.transaction_time)}:f>\n"
f"> {transaction.description}"
)
else:
string = (
f"{c+5*(selfpage-1)}) <:A_g_wmins:606920287044239362> **{int(transaction.amount)} крошек** {f' (комиссия: {int(transaction.commission_fraction * 100)}%)'if transaction.commission_fraction != 0 else ''}\n"
f"{f'Получатель: <@{transaction.recipient_id}>' if not transaction.recipient_id is None else ''}\n"
f"Время транзакции: <t:{int(transaction.transaction_time)}:f>\n"
f"> {transaction.description}"
)
embed.add_field(name=f"", value=string, inline=False)
c += 1
embed.add_field(name=f"", value=f"Страница {selfpage}/{maxpage}", inline=False)
return embed
await ctx.response.defer(ephemeral = True)
embed = disnake.Embed(title=f'История транзакций {member.name}', description=f"", colour=0x2F3136)
async with self.DataBaseManager.session() as session:
async with session.begin():
async with self.DataBaseManager.models['transaction_history_crumbs'] as transaction_history_crumbs_model:
stmt = self.DataBaseManager.select(transaction_history_crumbs_model).where(
self.DataBaseManager.or_(
transaction_history_crumbs_model.sender_id == member.id,
transaction_history_crumbs_model.recipient_id == member.id
)
).order_by(self.DataBaseManager.desc(transaction_history_crumbs_model.id))
transactions = (await session.execute(stmt)).scalars().all()
readyarray = self.client.PartitioningEmbeder(transactions)
view = HistoryButtons(ctx, readyarray, member, embed)
embed = await EmbedHistoryChanger(readyarray, embed, 1, member)
await ctx.edit_original_message(embed=embed, view=view)
@commands.slash_command(name="казино",
description="Хотите иметь очень много крошек? Тогда, эта команда точно не для вас)")
async def CasinoSlash(self, ctx: disnake.AppCmdInter,
count: commands.Range[int, 1, ...] = commands.Param(description="Сколько крошек хотите поставить на кон?", name="ставка"),
possibility: commands.Range[int, 1, 99] = commands.Param(
description="Шанс на победу. Чем выше, тем меньше крошек вы получите после победы(целое число от 1 до 99)",
name="шанс", default=50),
quantity: int = commands.Param(
description=f"Количество круток(целое число от 1 до {constants['casinospinslimit']}({constants['casinospinslimit']*2} для спонсоров))",
name="количество", default=1)):
await ctx.response.defer()
error_helper = self.client.ErrorOutHelper(send_function = ctx.edit_original_message, err_name = "Ошибка казино")
if ctx.guild is None:
await error_helper.out(d="Эта команда не работает в личных сообщениях!")
return
def get_dynamic_fee(count: int) -> float:
if count < 1_000:
return 0
elif count < 5_000:
return 0.1
elif count < 10_000:
return 0.2
elif count < 25_000:
return 0.3
elif count < 50_000:
return 0.4
elif count < 75_000:
return 0.5
elif count < 100_000:
return 0.6
elif count < 125_000:
return 0.7
elif count < 150_000:
return 0.8
else:
return 0.9
def calculate_multiplier(possibility: float, count: int) -> float:
fee = get_dynamic_fee(count)
multiplier = ((0.909/possibility)-0.918)*(1-fee)
return multiplier*count
async with self.DataBaseManager.session() as session:
await self.client.CasinoUserUpdate(member = ctx.author, session = session)
async with session.begin():
users_model = self.DataBaseManager.models['users'].m
casino_account_model = self.DataBaseManager.models['casino_user_account'].m
stmt = self.DataBaseManager.select(users_model).where(users_model.id == ctx.author.id).with_for_update()
user = (await session.execute(stmt)).scalars().first()
stmt = self.DataBaseManager.select(casino_account_model).where(casino_account_model.id == ctx.author.id).with_for_update()
casino_user = (await session.execute(stmt)).scalars().first()
user_is_sponsor = await user.in_role(member = ctx.author, roles = self.sponsors)
casinospinslimit = constants['casinospinslimit']
if quantity <= 0:
await error_helper.out(d=f'Количество круток должно быть > 0')
return
if quantity > casinospinslimit * (user_is_sponsor + 1) and (not self.me in ctx.author.roles):
await error_helper.out(d=f'Вы не можете крутить казино больше {casinospinslimit * (user_is_sponsor + 1)} раз в день!')
return
if not 0 < possibility < 100:
await error_helper.out(d=f'Шанс должен быть от 1% до 99%')
return
possibility = possibility / 100
if count <= 0:
await error_helper.out(d=f'Ставка должна быть больше 0')
return
if user.crumbs < count * quantity:
await error_helper.out(d=f'Для такой ставки вам необходимо иметь {quantity*count} крошек')
return
now = datetime.datetime.now().timestamp()
if now - casino_user.last_reset_time >= 86400:
casino_user.spins_today_count = 0
casino_user.last_reset_time = now
if casino_user.spins_today_count + quantity > casinospinslimit * (user_is_sponsor + 1) and (not self.me in ctx.author.roles):
if casino_user.spins_today_count >= casinospinslimit * (user_is_sponsor + 1):
await error_helper.out(d=f'У вас не осталось круток, возобновление лимита будет <t:{casino_user.last_reset_time + 86400}:R>')
else:
await error_helper.out(d=f'У вас осталось только {casinospinslimit * (user_is_sponsor + 1) - (casino_user.spins_today_count)} круток, возобновление лимита будет <t:{casino_user.last_reset_time + 86400}:R>')
return
results = [random.random() < possibility for _ in range(quantity)]
totalwins = sum(results)
totalcrumbs = totalwins * calculate_multiplier(possibility, count) - (quantity - totalwins) * count
casino_user.spins_today_count += quantity
user.crumbs += totalcrumbs
if int(totalcrumbs)>0:
history = self.DataBaseManager.models['transaction_history_crumbs'].m(recipient_id = ctx.author.id, amount = int(totalcrumbs), description = f"Выигрыш в казино с шансом {int(possibility * 100)}% и ставкой {count} крошек ({totalwins} побед, {quantity-totalwins} поражений)")
session.add(history)
embed=disnake.Embed(title=f'Вы в плюсе!', description=f"Ваш выигрыш составил {int(totalcrumbs)}!", colour=0x2F3136)
elif int(totalcrumbs) == 0:
embed=disnake.Embed(title=f'Вы вышли в 0',description=f"", colour=0x2F3136)
else:
history = self.DataBaseManager.models['transaction_history_crumbs'].m(sender_id = ctx.author.id, amount = int(abs(totalcrumbs)), description = f"Проигрыш в казино с шансом {int(possibility * 100)}% и ставкой {count} крошек ({totalwins} побед, {quantity-totalwins} поражений)")
session.add(history)
embed=disnake.Embed(title=f'Вы в минусе(', description=f"Ваш проигрыш составил {int(-totalcrumbs)}", colour=0x2F3136)
embed.description += (f"\n-# У вас осталось {casinospinslimit * (user_is_sponsor + 1) - (casino_user.spins_today_count)} круток")
await ctx.edit_original_message(embed = embed)
@commands.slash_command(name="отдать")
async def GiveCrumbsSlash(self, ctx):
pass
@GiveCrumbsSlash.sub_command(description=f"Передайте свои крошки другому участнику сервера (комиссия {int(constants['givecrumbscommission']*100)}%)", name="крошки")
async def GiveCrumbsSub(self, ctx: disnake.AppCmdInter,
member: disnake.Member = commands.Param(description="Кому вы хотите перевести крошки?",
name="адресат"),
count: int = commands.Param(description="Сколько крошек вы хотите перевести?",
name="количество"),
comment: str = commands.Param(description="Комментарий к переводу", name="комментарий",
default="Перевод"),
commission: float = commands.Param(description="Доля комиссии(доступно только админам)",
name="комиссия", default=None)):
error_helper = self.client.ErrorOutHelper(send_function = ctx.response.send_message, err_name = "Ошибка перевода")
if ctx.guild is None:
await error_helper.out(d="Эта команда не работает в личных сообщениях!")
return
if comment != "Перевод":
comment = "Перевод | " + comment
if (commission == None) or (not self.me in ctx.author.roles):
commission = constants['givecrumbscommission']
if count <= 0:
await error_helper.out(d="Количество крошек должно быть больше 0")
return
users_model = self.DataBaseManager.models['users'].m
async with self.DataBaseManager.session() as session:
async with session.begin():
author_data = await session.get(users_model, ctx.author.id, with_for_update = True)
member_data = await session.get(users_model, member.id, with_for_update = True)
if author_data is None:
await error_helper.out(d=f'Вас нет в базе данных')
return
if member_data is None:
await error_helper.out(d=f'Такого пользователя нет в базе данных')
return
if author_data.crumbs - count < 0:
await error_helper.out(d=f'У вас не хватает крошек')
return
history_write = self.DataBaseManager.models["transaction_history_crumbs"].m(sender_id = ctx.author.id, recipient_id = member.id, commission_fraction = commission, description = comment, amount = count)
session.add(history_write)
author_data.crumbs -= count
member_data.crumbs += count * (1 - commission)
await ctx.response.send_message(embed=disnake.Embed(
description=f'{count} крошек успешно отправлено на счёт {member.mention}, комиссия составила {int(commission * 100)}%({int(count * commission)} крошек)',
colour=0x2F3136))