lot's of refactoring and packaging
This commit is contained in:
parent
9cdc8d742c
commit
eff057da8c
Binary file not shown.
Binary file not shown.
|
@ -3,6 +3,7 @@ from discord.ext import commands
|
||||||
|
|
||||||
|
|
||||||
class Developer(commands.Cog):
|
class Developer(commands.Cog):
|
||||||
|
"""This class is intended only for the developer, mainly for testing purposes"""
|
||||||
|
|
||||||
def __init__(self, bot):
|
def __init__(self, bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
|
@ -18,11 +19,10 @@ class Developer(commands.Cog):
|
||||||
|
|
||||||
@commands.command()
|
@commands.command()
|
||||||
async def ping(self, ctx):
|
async def ping(self, ctx):
|
||||||
print("pong")
|
print("pong", self.bot.owner_id, await self.bot.application_info())
|
||||||
|
print(await self.bot.is_owner(ctx.author))
|
||||||
await ctx.send("pong")
|
await ctx.send("pong")
|
||||||
|
|
||||||
# developer commands
|
|
||||||
|
|
||||||
async def is_dev(ctx):
|
async def is_dev(ctx):
|
||||||
if ctx.author.id == 461892912821698562:
|
if ctx.author.id == 461892912821698562:
|
||||||
return True
|
return True
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,18 @@
|
||||||
|
from abc import ABC
|
||||||
|
|
||||||
|
|
||||||
|
class Game(ABC):
|
||||||
|
|
||||||
|
name = "Game"
|
||||||
|
|
||||||
|
def __init__(self, bot, channel):
|
||||||
|
self.bot = bot
|
||||||
|
self.channel = channel
|
||||||
|
self.running = False
|
||||||
|
self.player_list = []
|
||||||
|
|
||||||
|
async def round(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def set_players(self):
|
||||||
|
pass
|
|
@ -0,0 +1,90 @@
|
||||||
|
"""This (abstract) module is a template for Discord Cog's for game specific channel commands"""
|
||||||
|
|
||||||
|
# standard library imports
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
|
# discord imports
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
|
||||||
|
# local imports
|
||||||
|
from ..send_message import Send_message
|
||||||
|
from .game import Game
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: take group as argument to add subcommands
|
||||||
|
|
||||||
|
class Game_cog(Send_message, commands.Cog):
|
||||||
|
"""This (abstract) class is are common function for the Game Cog's (setup-game, pre-game, in-game), mainly has checker functions"""
|
||||||
|
|
||||||
|
def __init__(self, bot, game_instances: Dict[discord.TextChannel, Game]):
|
||||||
|
self.bot = bot
|
||||||
|
self.game_instances = game_instances
|
||||||
|
|
||||||
|
async def setup_check(self, ctx):
|
||||||
|
if ctx.channel not in self.game_instances:
|
||||||
|
await self.send_wrong(ctx, f"The channel is not setup yet.")
|
||||||
|
return ctx.channel in self.game_instances
|
||||||
|
|
||||||
|
async def not_running_check(self, ctx):
|
||||||
|
if self.game_instances[ctx.channel].running:
|
||||||
|
await self.send_wrong(ctx, "Sorry! A game is already running")
|
||||||
|
return not self.game_instances[ctx.channel].running
|
||||||
|
|
||||||
|
async def running_check(self, ctx):
|
||||||
|
if not self.game_instances[ctx.channel].running:
|
||||||
|
await self.send_wrong(ctx, "No game is running")
|
||||||
|
return self.game_instances[ctx.channel].running
|
||||||
|
|
||||||
|
|
||||||
|
class Setup_game_cog(Game_cog):
|
||||||
|
"""This (abstract) class is a template for Discord Cog's for game specific channel commands for setting up the channel"""
|
||||||
|
|
||||||
|
async def setup(self, ctx, game: Game):
|
||||||
|
"""This function creates an game instance for this channel"""
|
||||||
|
if ctx.channel in self.game_instances:
|
||||||
|
await self.send_wrong(ctx, f"A game '{game.name}' is already setup in this channel")
|
||||||
|
else:
|
||||||
|
self.game_instances[ctx.channel] = game(self.bot, ctx.channel)
|
||||||
|
await self.send_friendly(ctx, f"This channel can now play: {game.name}")
|
||||||
|
|
||||||
|
async def reset(self, ctx):
|
||||||
|
"""This function deletes the game instance for this channel"""
|
||||||
|
if self.setup_check(ctx):
|
||||||
|
del self.game_instances[ctx.channel]
|
||||||
|
|
||||||
|
# TODO: better info message
|
||||||
|
async def info(self, ctx, game: Game):
|
||||||
|
"""Send information about the subcommands for the game"""
|
||||||
|
embed = discord.Embed(title="How to play?", description="You will need to set up the game and its information in a channel and start the game there. Afterwards the player mainly interact with the bot in DM.", color=0x00ffff)
|
||||||
|
embed.set_author(name=f"With this bot you can play {game.name}")
|
||||||
|
# embed.set_thumbnail(url="https://images-na.ssl-images-amazon.com/images/I/717GrDtFKCL._AC_SL1000_.jpg")
|
||||||
|
embed.add_field(name="$w game setup", value="Make this channel playable.", inline=False)
|
||||||
|
embed.add_field(name="$w game players", value="Set mentioned users as players", inline=False)
|
||||||
|
embed.add_field(name="$w game roles", value="Set the roles to play with", inline=False)
|
||||||
|
embed.add_field(name="$w game start", value="Play one round", inline=False)
|
||||||
|
embed.set_footer(text="Have fun!")
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
|
||||||
|
class Pre_game_cog(Game_cog):
|
||||||
|
"""This (abstract) class is a template for Discord Cog's for game specific channel commands for setting up the game rounds"""
|
||||||
|
async def cog_check(self, ctx):
|
||||||
|
return self.setup_check(ctx) and self.not_running_check(ctx)
|
||||||
|
|
||||||
|
async def players(self, ctx):
|
||||||
|
await self.game_instances[ctx.channel].set_players(ctx.message)
|
||||||
|
|
||||||
|
async def start(self, ctx):
|
||||||
|
self.game_instances[ctx.channel].game = self.bot.loop.create_task(self.game_instances[ctx.channel].round())
|
||||||
|
await self.game_instances[ctx.channel].game
|
||||||
|
|
||||||
|
|
||||||
|
class In_game_goc(Game_cog):
|
||||||
|
"""This (abstract) class is a template for Discord Cog's for game specific channel commands during the game"""
|
||||||
|
async def cog_check(self, ctx):
|
||||||
|
return self.setup_check(ctx) and self.running_check(ctx)
|
||||||
|
|
||||||
|
async def stop(self, ctx):
|
||||||
|
self.game_instances[ctx.channel].game.cancel()
|
||||||
|
await self.send_friendly(ctx, "Game canceled")
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,34 @@
|
||||||
|
# discord imports
|
||||||
|
from discord.ext import commands
|
||||||
|
|
||||||
|
# local imports
|
||||||
|
from ..game_cog import Game_cog
|
||||||
|
from .game import Werewolf_game
|
||||||
|
|
||||||
|
|
||||||
|
class Werewolf_cog(Game_cog):
|
||||||
|
"""This singleton class is a Discord Cog for the interaction in the werewolf game"""
|
||||||
|
|
||||||
|
@commands.group(invoke_without_command=True)
|
||||||
|
async def werewolf(self, ctx):
|
||||||
|
# TODO: isn't there a better way to have a default subcommand?
|
||||||
|
await ctx.invoke(self.bot.get_command('werewolf info'))
|
||||||
|
|
||||||
|
@werewolf.command()
|
||||||
|
async def info(self, ctx):
|
||||||
|
"""Send information about the subcommands for the game"""
|
||||||
|
await super().info(ctx, Werewolf_game)
|
||||||
|
|
||||||
|
@werewolf.command()
|
||||||
|
async def setup(self, ctx):
|
||||||
|
"""This function creates an game instance for this channel"""
|
||||||
|
await super().setup(ctx, Werewolf_game)
|
||||||
|
|
||||||
|
@werewolf.command()
|
||||||
|
async def reset(self, ctx):
|
||||||
|
"""This function deletes the game instance for this channel"""
|
||||||
|
await super().reset(ctx)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
bot.add_cog(Werewolf_cog(bot, None))
|
|
@ -2,11 +2,13 @@ from random import shuffle
|
||||||
import time
|
import time
|
||||||
import asyncio
|
import asyncio
|
||||||
import discord
|
import discord
|
||||||
from werewolf_roles import Role, Doppelganger, Werewolf, Minion, Mason, Seer, Robber, Troublemaker, Drunk, Insomniac, Tanner, Hunter, No_role
|
from .roles import Role, Doppelganger, Werewolf, Minion, Mason, Seer, Robber, Troublemaker, Drunk, Insomniac, Tanner, Hunter, No_role
|
||||||
from werewolf_players import Player, No_player
|
from .players import Player, No_player
|
||||||
|
|
||||||
|
|
||||||
class Game:
|
class Werewolf_game:
|
||||||
|
|
||||||
|
name = "One Night Ultimate Werewolf"
|
||||||
|
|
||||||
def __init__(self, bot, channel):
|
def __init__(self, bot, channel):
|
||||||
self.running = False
|
self.running = False
|
|
@ -1,6 +1,6 @@
|
||||||
import functools
|
import functools
|
||||||
from fuzzywuzzy import fuzz
|
from fuzzywuzzy import fuzz
|
||||||
from werewolf_players import No_player
|
from .players import No_player
|
||||||
|
|
||||||
|
|
||||||
class Role:
|
class Role:
|
|
@ -0,0 +1,18 @@
|
||||||
|
# discord import
|
||||||
|
import discord
|
||||||
|
|
||||||
|
|
||||||
|
class Send_message:
|
||||||
|
"""This (abstract) class for sending formatted messages"""
|
||||||
|
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
async def send_embed(self, ctx, desc, color):
|
||||||
|
await ctx.send(embed=discord.Embed(description=desc, color=color))
|
||||||
|
|
||||||
|
async def send_friendly(self, ctx, desc):
|
||||||
|
await self.send_embed(ctx, desc, 0x00ff00)
|
||||||
|
|
||||||
|
async def send_wrong(self, ctx, desc):
|
||||||
|
await self.send_embed(ctx, desc, 0xff8000)
|
|
@ -1,124 +1,43 @@
|
||||||
|
"""
|
||||||
|
This is the main module of the Discord Bot
|
||||||
|
|
||||||
|
Mainly loads the Cog's and starts the bot
|
||||||
|
"""
|
||||||
|
|
||||||
|
__version__ = '0.3'
|
||||||
|
__author__ = 'Bibin Muttappillil'
|
||||||
|
|
||||||
|
# standard library imports
|
||||||
import os
|
import os
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
import functools
|
|
||||||
import asyncio
|
# discord imports
|
||||||
import discord
|
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from werewolf_game import Game as Werewolf_Game
|
|
||||||
|
|
||||||
|
|
||||||
|
# Token stuff
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
TOKEN = os.getenv('DISCORD_TOKEN')
|
TOKEN = os.getenv('DISCORD_TOKEN')
|
||||||
if TOKEN is None:
|
if TOKEN is None:
|
||||||
print("Missing discord token!")
|
print("Missing discord token!")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
|
bot = commands.Bot(command_prefix=commands.when_mentioned_or('$w '))
|
||||||
|
|
||||||
PREFIX = '$w '
|
bot.load_extension('package.developer')
|
||||||
bot = commands.Bot(command_prefix=commands.when_mentioned_or(PREFIX))
|
bot.load_extension('package.games.werewolf.cog')
|
||||||
bot.remove_command('help')
|
|
||||||
|
|
||||||
bot.load_extension('developer')
|
|
||||||
|
|
||||||
|
|
||||||
@bot.command()
|
|
||||||
async def load(ctx, extension):
|
|
||||||
bot.load_extension(f'{extension}')
|
|
||||||
|
|
||||||
|
|
||||||
@bot.command()
|
|
||||||
async def unload(ctx, extension):
|
|
||||||
bot.unload_extension(f'{extension}')
|
|
||||||
|
|
||||||
|
|
||||||
@bot.command()
|
@bot.command()
|
||||||
|
@commands.is_owner()
|
||||||
async def reload(ctx, extension):
|
async def reload(ctx, extension):
|
||||||
bot.reload_extension(f'{extension}')
|
bot.reload_extension(f'{extension}')
|
||||||
|
|
||||||
|
|
||||||
# TODO: better help message
|
|
||||||
@bot.command()
|
|
||||||
async def help(ctx):
|
|
||||||
embed = discord.Embed(title="How to play?", description="You will need to set up the game and its information in a channel and start the game there. Afterwards the player mainly interact with the bot in DM.", color=0x00ffff)
|
|
||||||
embed.set_author(name="With this bot you can play One Night Ultimate Werewolf")
|
|
||||||
# embed.set_thumbnail(url="https://images-na.ssl-images-amazon.com/images/I/717GrDtFKCL._AC_SL1000_.jpg")
|
|
||||||
embed.add_field(name="$w game setup", value="Make this channel playable.", inline=False)
|
|
||||||
embed.add_field(name="$w game players", value="Set mentioned users as players", inline=False)
|
|
||||||
embed.add_field(name="$w game roles", value="Set the roles to play with", inline=False)
|
|
||||||
embed.add_field(name="$w game start", value="Play one round", inline=False)
|
|
||||||
embed.set_footer(text="Have fun!")
|
|
||||||
await ctx.send(embed=embed)
|
|
||||||
|
|
||||||
|
|
||||||
# TODO: interaction COG
|
|
||||||
async def send_embed(ctx, desc, color):
|
|
||||||
await ctx.send(embed=discord.Embed(description=desc, color=color))
|
|
||||||
|
|
||||||
|
|
||||||
async def send_friendly(ctx, desc):
|
|
||||||
await send_embed(ctx, desc, 0x00ff00)
|
|
||||||
|
|
||||||
|
|
||||||
async def send_wrong(ctx, desc):
|
|
||||||
await send_embed(ctx, desc, 0xff8000)
|
|
||||||
|
|
||||||
|
|
||||||
# TODO: (general) game COG
|
|
||||||
# game commands
|
|
||||||
|
|
||||||
game_instances = {}
|
|
||||||
|
|
||||||
|
|
||||||
@bot.group()
|
|
||||||
async def game(ctx):
|
|
||||||
if ctx.invoked_subcommand is None:
|
|
||||||
await send_wrong(ctx, 'Invalid sub command passed...')
|
|
||||||
|
|
||||||
|
|
||||||
@game.command()
|
|
||||||
async def setup(ctx):
|
|
||||||
if ctx.channel in game_instances:
|
|
||||||
await send_wrong(ctx, "Game already setup in this channel")
|
|
||||||
else:
|
|
||||||
game_instances[ctx.channel] = Werewolf_Game(bot, ctx.channel)
|
|
||||||
await send_friendly(ctx, "This channel can now play Werewolf")
|
|
||||||
|
|
||||||
|
|
||||||
# checker annotations
|
# checker annotations
|
||||||
# TODO: replace with discord.py error handling?
|
# TODO: replace with discord.py error handling?
|
||||||
|
|
||||||
def channel_setup(command):
|
'''
|
||||||
@functools.wraps(command)
|
|
||||||
async def wrapper(ctx, *args, **kwargs):
|
|
||||||
if ctx.channel not in game_instances:
|
|
||||||
await send_wrong(ctx, f"No game setup yet. Use {PREFIX}game setup")
|
|
||||||
else:
|
|
||||||
await command(ctx, *args, **kwargs)
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
|
|
||||||
def game_not_running(command):
|
|
||||||
@functools.wraps(command)
|
|
||||||
@channel_setup
|
|
||||||
async def wrapper(ctx, *args, **kwargs):
|
|
||||||
if game_instances[ctx.channel].running:
|
|
||||||
await send_wrong(ctx, "Sorry! A game is already running")
|
|
||||||
else:
|
|
||||||
await command(ctx, *args, **kwargs)
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
|
|
||||||
def game_running(command):
|
|
||||||
@functools.wraps(command)
|
|
||||||
@channel_setup
|
|
||||||
async def wrapper(ctx, *args, **kwargs):
|
|
||||||
if not game_instances[ctx.channel].running:
|
|
||||||
await send_wrong(ctx, "No game is running")
|
|
||||||
else:
|
|
||||||
await command(ctx, *args, **kwargs)
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
|
|
||||||
def error_handling(command):
|
def error_handling(command):
|
||||||
@functools.wraps(command)
|
@functools.wraps(command)
|
||||||
async def wrapper(ctx, *args, **kwargs):
|
async def wrapper(ctx, *args, **kwargs):
|
||||||
|
@ -129,30 +48,9 @@ def error_handling(command):
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
await send_wrong(ctx, "Error: I got bored waiting for your input")
|
await send_wrong(ctx, "Error: I got bored waiting for your input")
|
||||||
return wrapper
|
return wrapper
|
||||||
|
'''
|
||||||
|
|
||||||
|
'''
|
||||||
@game.command()
|
|
||||||
@game_not_running
|
|
||||||
@error_handling
|
|
||||||
async def start(ctx):
|
|
||||||
game_instances[ctx.channel].game = bot.loop.create_task(game_instances[ctx.channel].round())
|
|
||||||
await game_instances[ctx.channel].game
|
|
||||||
|
|
||||||
|
|
||||||
@game.command()
|
|
||||||
@game_running
|
|
||||||
@channel_setup
|
|
||||||
async def stop(ctx):
|
|
||||||
game_instances[ctx.channel].game.cancel()
|
|
||||||
await send_friendly(ctx, "Game canceled")
|
|
||||||
|
|
||||||
|
|
||||||
@game.command()
|
|
||||||
@game_not_running
|
|
||||||
@error_handling
|
|
||||||
async def players(ctx):
|
|
||||||
await game_instances[ctx.channel].set_players(ctx.message)
|
|
||||||
|
|
||||||
|
|
||||||
# TODO: (specifig game) werewolf COG
|
# TODO: (specifig game) werewolf COG
|
||||||
|
|
||||||
|
@ -175,10 +73,6 @@ async def minutes(ctx, i):
|
||||||
@error_handling
|
@error_handling
|
||||||
async def time(ctx):
|
async def time(ctx):
|
||||||
await send_friendly(ctx, game_instances[ctx.channel].remaining_time_string())
|
await send_friendly(ctx, game_instances[ctx.channel].remaining_time_string())
|
||||||
|
'''
|
||||||
|
|
||||||
# TODO: developer COG
|
|
||||||
# smaller commands
|
|
||||||
|
|
||||||
|
|
||||||
bot.run(TOKEN)
|
bot.run(TOKEN)
|
||||||
|
|
Loading…
Reference in New Issue