413 lines
14 KiB
Python
413 lines
14 KiB
Python
import asyncio
|
|
import logging
|
|
from copy import deepcopy
|
|
|
|
import discord
|
|
from redbot.core import Config, bank
|
|
from collections import namedtuple
|
|
|
|
from .cache import OldMessageTypeManager
|
|
from .utils import is_input_unsupported, min_int, max_int
|
|
|
|
user_defaults = {
|
|
"Pending_Credits": 0,
|
|
"Membership": {"Name": "Basic", "Assigned": False},
|
|
"Played": {
|
|
"Allin": 0,
|
|
"Blackjack": 0,
|
|
"Coin": 0,
|
|
"Craps": 0,
|
|
"Cups": 0,
|
|
"Dice": 0,
|
|
"Hilo": 0,
|
|
"War": 0,
|
|
"Double": 0,
|
|
},
|
|
"Won": {
|
|
"Allin": 0,
|
|
"Blackjack": 0,
|
|
"Coin": 0,
|
|
"Craps": 0,
|
|
"Cups": 0,
|
|
"Dice": 0,
|
|
"Hilo": 0,
|
|
"War": 0,
|
|
"Double": 0,
|
|
},
|
|
"Cooldowns": {
|
|
"Allin": 0,
|
|
"Blackjack": 0,
|
|
"Coin": 0,
|
|
"Craps": 0,
|
|
"Cups": 0,
|
|
"Dice": 0,
|
|
"Hilo": 0,
|
|
"War": 0,
|
|
"Double": 0,
|
|
},
|
|
}
|
|
|
|
guild_defaults = {
|
|
"use_old_style": False,
|
|
"Memberships": {},
|
|
"Settings": {
|
|
"Global": False,
|
|
"Casino_Name": "Redjumpman's",
|
|
"Casino_Open": True,
|
|
"Payout_Switch": False,
|
|
"Payout_Limit": 10000,
|
|
},
|
|
"Games": {
|
|
"Allin": {
|
|
"Access": 0,
|
|
"Cooldown": 43200,
|
|
"Min": None,
|
|
"Max": None,
|
|
"Multiplier": None,
|
|
"Open": True,
|
|
},
|
|
"Blackjack": {
|
|
"Access": 0,
|
|
"Cooldown": 5,
|
|
"Min": 50,
|
|
"Max": 500,
|
|
"Multiplier": 2.0,
|
|
"Open": True,
|
|
},
|
|
"Coin": {
|
|
"Access": 0,
|
|
"Cooldown": 5,
|
|
"Max": 10,
|
|
"Min": 10,
|
|
"Multiplier": 1.5,
|
|
"Open": True,
|
|
},
|
|
"Craps": {
|
|
"Access": 0,
|
|
"Cooldown": 5,
|
|
"Max": 500,
|
|
"Min": 50,
|
|
"Multiplier": 2.0,
|
|
"Open": True,
|
|
},
|
|
"Cups": {
|
|
"Access": 0,
|
|
"Cooldown": 5,
|
|
"Max": 100,
|
|
"Min": 25,
|
|
"Multiplier": 1.8,
|
|
"Open": True,
|
|
},
|
|
"Dice": {
|
|
"Access": 0,
|
|
"Cooldown": 5,
|
|
"Max": 100,
|
|
"Min": 25,
|
|
"Multiplier": 1.8,
|
|
"Open": True,
|
|
},
|
|
"Hilo": {
|
|
"Access": 0,
|
|
"Cooldown": 5,
|
|
"Min": 25,
|
|
"Max": 75,
|
|
"Multiplier": 1.7,
|
|
"Open": True,
|
|
},
|
|
"Double": {
|
|
"Access": 0,
|
|
"Cooldown": 5,
|
|
"Min": 10,
|
|
"Max": 250,
|
|
"Multiplier": None,
|
|
"Open": True,
|
|
},
|
|
"War": {"Access": 0, "Cooldown": 5, "Min": 25, "Max": 75, "Multiplier": 1.5, "Open": True},
|
|
},
|
|
}
|
|
|
|
member_defaults = deepcopy(user_defaults)
|
|
global_defaults = deepcopy(guild_defaults)
|
|
global_defaults["Settings"]["Global"] = True
|
|
|
|
|
|
_DataNamedTuple = namedtuple("Casino", "foo")
|
|
_DataObj = _DataNamedTuple(foo=None)
|
|
|
|
|
|
log = logging.getLogger("red.jumper-plugins.casino")
|
|
|
|
|
|
class Database:
|
|
|
|
config: Config = Config.get_conf(_DataObj, 5074395001, force_registration=True)
|
|
|
|
def __init__(self):
|
|
self.config.register_guild(**guild_defaults)
|
|
self.config.register_global(schema_version=1, **global_defaults)
|
|
self.config.register_member(**member_defaults)
|
|
self.config.register_user(**user_defaults)
|
|
self.old_message_cache = OldMessageTypeManager(config=self.config, enable_cache=True)
|
|
self.migration_task: asyncio.Task = None
|
|
self.cog_ready_event: asyncio.Event = asyncio.Event()
|
|
|
|
async def data_schema_migration(self, from_version: int, to_version: int):
|
|
if from_version == to_version:
|
|
self.cog_ready_event.set()
|
|
return
|
|
if from_version < 2 <= to_version:
|
|
try:
|
|
async with self.config.all() as casino_data:
|
|
temp = deepcopy(casino_data)
|
|
global_payout = casino_data["Settings"]["Payout_Limit"]
|
|
if is_input_unsupported(global_payout):
|
|
casino_data["Settings"]["Payout_Limit"] = await bank.get_max_balance()
|
|
for g, g_data in temp["Games"].items():
|
|
for g_data_key, g_data_value in g_data.items():
|
|
if g_data_key in ["Access", "Cooldown", "Max", "Min", "Multiplier"]:
|
|
if is_input_unsupported(g_data_value):
|
|
if g_data_value < min_int:
|
|
g_data_value_new = min_int
|
|
else:
|
|
g_data_value_new = max_int
|
|
casino_data["Games"][g][g_data_key] = g_data_value_new
|
|
async with self.config._get_base_group(self.config.GUILD).all() as casino_data:
|
|
temp = deepcopy(casino_data)
|
|
for guild_id, guild_data in temp.items():
|
|
if (
|
|
"Settings" in temp[guild_id]
|
|
and "Payout_Limit" in temp[guild_id]["Settings"]
|
|
):
|
|
guild_payout = casino_data[guild_id]["Settings"]["Payout_Limit"]
|
|
if is_input_unsupported(guild_payout):
|
|
casino_data[guild_id]["Settings"][
|
|
"Payout_Limit"
|
|
] = await bank.get_max_balance(
|
|
guild_payout, guild=discord.Object(id=int(guild_id))
|
|
)
|
|
if "Games" in temp[guild_id]:
|
|
for g, g_data in temp[guild_id]["Games"].items():
|
|
for g_data_key, g_data_value in g_data.items():
|
|
if g_data_key in [
|
|
"Access",
|
|
"Cooldown",
|
|
"Max",
|
|
"Min",
|
|
"Multiplier",
|
|
]:
|
|
if is_input_unsupported(g_data_value):
|
|
if g_data_value < min_int:
|
|
g_data_value_new = min_int
|
|
else:
|
|
g_data_value_new = max_int
|
|
casino_data[guild_id]["Games"][g][
|
|
g_data_key
|
|
] = g_data_value_new
|
|
await self.config.schema_version.set(2)
|
|
except Exception as e:
|
|
log.exception(
|
|
"Fatal Exception during Data migration to Scheme 2, Casino cog will not be loaded.",
|
|
exc_info=e,
|
|
)
|
|
raise
|
|
self.cog_ready_event.set()
|
|
|
|
async def casino_is_global(self):
|
|
"""Checks to see if the casino is storing data on
|
|
a per server basis or globally."""
|
|
return await self.config.Settings.Global()
|
|
|
|
async def get_data(self, ctx, player=None):
|
|
"""
|
|
|
|
:param ctx: Context object
|
|
:param player: Member or user object
|
|
:return: Database that corresponds to the given data.
|
|
|
|
Returns the appropriate config category based on the given
|
|
data, and wheater or not the casino is global.
|
|
"""
|
|
if await self.casino_is_global():
|
|
if player is None:
|
|
return self.config
|
|
else:
|
|
return self.config.user(player)
|
|
else:
|
|
if player is None:
|
|
return self.config.guild(ctx.guild)
|
|
else:
|
|
return self.config.member(player)
|
|
|
|
async def get_all(self, ctx, player):
|
|
"""
|
|
|
|
:param ctx: Context Object
|
|
:param player: Member or user object
|
|
:return: Tuple with two dictionaries
|
|
|
|
Returns a dictionary representation of casino's settings data
|
|
and the player data.
|
|
"""
|
|
settings = await self.get_data(ctx)
|
|
player_data = await self.get_data(ctx, player=player)
|
|
return await settings.all(), await player_data.all()
|
|
|
|
async def _wipe_casino(self, ctx):
|
|
"""
|
|
Wipes all the casino data available
|
|
|
|
:param ctx: context object
|
|
:return: None
|
|
|
|
This wipes everything, including member/user data.
|
|
"""
|
|
await self.config.clear_all()
|
|
msg = "{0.name} ({0.id}) wiped all casino data.".format(ctx.author)
|
|
await ctx.send(msg)
|
|
|
|
async def _reset_settings(self, ctx):
|
|
"""
|
|
Resets only the settings data.
|
|
"""
|
|
data = await self.get_data(ctx)
|
|
await data.Settings.clear()
|
|
msg = ("{0.name} ({0.id}) reset all casino settings.").format(ctx.author)
|
|
await ctx.send(msg)
|
|
|
|
async def _reset_memberships(self, ctx):
|
|
"""
|
|
Resets all the information pertaining to memberships
|
|
"""
|
|
data = await self.get_data(ctx)
|
|
await data.Memberships.clear()
|
|
msg = ("{0.name} ({0.id}) cleared all casino memberships.").format(ctx.author)
|
|
await ctx.send(msg)
|
|
|
|
async def _reset_games(self, ctx):
|
|
"""
|
|
Resets all game settings, such as multipliers and bets.
|
|
"""
|
|
data = await self.get_data(ctx)
|
|
await data.Games.clear()
|
|
msg = ("{0.name} ({0.id}) restored casino games to default settings.").format(ctx.author)
|
|
await ctx.send(msg)
|
|
|
|
async def _reset_all_settings(self, ctx):
|
|
"""
|
|
Resets all settings, but retains all player data.
|
|
"""
|
|
await self._reset_settings(ctx)
|
|
await self._reset_memberships(ctx)
|
|
await self._reset_games(ctx)
|
|
await self._reset_cooldowns(ctx)
|
|
|
|
async def _reset_player_stats(self, ctx, player):
|
|
"""
|
|
:param ctx: Context object
|
|
:param player: user or member object
|
|
:return: None
|
|
|
|
Resets a player's win / played stats.
|
|
|
|
"""
|
|
data = await self.get_data(ctx, player=player)
|
|
await data.Played.clear()
|
|
await data.Won.clear()
|
|
|
|
msg = ("{0.name} ({0.id}) reset all stats for {1.name} ({1.id}).").format(ctx.author, player)
|
|
await ctx.send(msg)
|
|
|
|
async def _reset_player_all(self, ctx, player):
|
|
"""
|
|
|
|
:param ctx: context object
|
|
:param player: user or member object
|
|
:return: None
|
|
|
|
Resets all data belonging to the user, including stats and memberships.
|
|
"""
|
|
data = await self.get_data(ctx, player=player)
|
|
await data.clear()
|
|
|
|
msg = ("{0.name} ({0.id}) reset all data for {1.name} ({1.id}).").format(ctx.author, player)
|
|
await ctx.send(msg)
|
|
|
|
async def _reset_player_cooldowns(self, ctx, player):
|
|
"""
|
|
|
|
:param ctx: context object
|
|
:param player: user or member object
|
|
:return: None
|
|
|
|
Resets all game cooldowns for a player.
|
|
"""
|
|
data = await self.get_data(ctx, player=player)
|
|
await data.Cooldowns.clear()
|
|
|
|
msg = ("{0.name} ({0.id}) reset all cooldowns for {1.name} ({1.id}).").format(ctx.author, player)
|
|
await ctx.send(msg)
|
|
|
|
async def _reset_cooldowns(self, ctx):
|
|
"""
|
|
Resets all game cooldowns for every player in the database.
|
|
"""
|
|
if await self.casino_is_global():
|
|
for player in await self.config.all_users():
|
|
user = discord.Object(id=player)
|
|
await self.config.user(user).Cooldowns.clear()
|
|
msg = ("{0.name} ({0.id}) reset all global cooldowns.").format(ctx.author)
|
|
else:
|
|
for player in await self.config.all_members(ctx.guild):
|
|
user = discord.Object(id=player)
|
|
await self.config.member(user).Cooldowns.clear()
|
|
msg = ("{0.name} ({0.id}) reset all cooldowns on {1.name}.").format(ctx.author, ctx.guild)
|
|
|
|
await ctx.send(msg)
|
|
|
|
async def change_mode(self, mode):
|
|
"""
|
|
|
|
:param mode: String, must be local or global.
|
|
:return: None
|
|
|
|
Toggles how data is stored for casino between local and global.
|
|
When switching modes, all perviously stored data will be deleted.
|
|
"""
|
|
if mode == "global":
|
|
await self.config.clear_all_members()
|
|
await self.config.clear_all_guilds()
|
|
await self.config.Settings.Global.set(True)
|
|
else:
|
|
await self.config.clear_all_users()
|
|
await self.config.clear_all_globals()
|
|
await self.config.Settings.Global.set(False)
|
|
|
|
async def _update_cooldown(self, ctx, game, time):
|
|
player_data = await self.get_data(ctx, player=ctx.author)
|
|
await player_data.set_raw("Cooldowns", game, value=time)
|
|
|
|
async def _get_player_membership(self, ctx, player):
|
|
"""
|
|
|
|
:param ctx: context object
|
|
:param player: user or member object
|
|
:return: Membership name and a dictionary with the perks
|
|
|
|
Performs a lookup on the user and the created memberhips for casino.
|
|
If the user has a memberhip that was deleted, it will return the
|
|
default basic membership. It will also set their new membership to the
|
|
default.
|
|
"""
|
|
basic = {"Reduction": 0, "Access": 0, "Color": "grey", "Bonus": 1}
|
|
player_data = await self.get_data(ctx, player=player)
|
|
name = await player_data.Membership.Name()
|
|
if name == "Basic":
|
|
return name, basic
|
|
|
|
data = await self.get_data(ctx)
|
|
memberships = await data.Memberships.all()
|
|
try:
|
|
return name, memberships[name]
|
|
except KeyError:
|
|
await player_data.Membership.set({"Name": "Basic", "Assigned": False})
|
|
return "Basic", basic
|