root před 1 rokem
rodič
revize
b13dc7aaac

+ 56 - 30
bot/commands/admin.py

@@ -3,12 +3,11 @@ from discord import app_commands
 from discord.ext import commands
 from discord.ui import ChannelSelect
 
-#from common.logging import report
-from common.settings import check_ignore
+from common.logging import report
 from query.guild import set_output_channel
 
 
-class View(discord.ui.View):
+class SelectOutputChannel(discord.ui.View):
 	def __init__(self, pg):
 		super().__init__()
 		self.pg = pg
@@ -17,28 +16,48 @@ class View(discord.ui.View):
 	async def select_channels(self, interaction: discord.Interaction, select: ChannelSelect):
 		await set_output_channel(self.pg, interaction.guild_id, select.values[0].id)
 		return await interaction.response.send_message(f'You selected {select.values[0].mention}')
-class Select(discord.ui.Select):
-	def __init__(self, pg, channels):
-		self.pg = pg
-		print(channels)
-		options = []
-		for channel in channels:
-			options.append(discord.SelectOption(label=str(channel.name),emoji="👌",description=str(channel.category)),)
-		print(options)
-		#options=[
-		#	discord.SelectOption(label="Option 1",emoji="👌",description="This is option 1!"),
-		#	discord.SelectOption(label="Option 2",emoji="✨",description="This is option 2!"),
-		#	discord.SelectOption(label="Option 3",emoji="🎭",description="This is option 3!")
-		#	]
-		super().__init__(placeholder="Select an option",max_values=1,min_values=1,options=options)
-	async def callback(self, interaction: discord.Interaction):
-		await set_output_channel(self.pg, interaction.guild_id, 971796738484625468)
-		await interaction.response.send_message(content=f"Your choice is {self.values[0]}!", ephemeral=True)
-
-class SelectView(discord.ui.View):
-	def __init__(self, pg, channels, *, timeout = 180):
-		super().__init__(timeout=timeout)
-		self.add_item(Select(pg, channels))
+
+
+# class SelectOutputChannel(discord.ui.Select):
+# 	def __init__(self, pg, channels):
+# 		self.pg = pg
+# 		options = []
+# 		for channel in channels:
+# 			options.append(discord.SelectOption(label=str(channel.name),emoji="👌",description=str(channel.category)),)
+# 		super().__init__(placeholder="Select an option",max_values=1,min_values=1,options=options)
+# 	async def callback(self, interaction: discord.Interaction):
+# 		await set_output_channel(self.pg, interaction.guild_id, 971796738484625468)
+# 		await interaction.response.send_message(content=f"Your choice is {self.values[0]}!", ephemeral=True)
+
+
+# class SelectInteract(discord.ui.Select):
+# 	def __init__(self, pg):
+# 		self.pg = pg
+# 	options = [
+# 		discord.SelectOption(label="Option 1", emoji=":x:", description="Disabled"),
+# 		discord.SelectOption(label="Option 2", emoji=":white_square_button:", description="Defer to default"),
+# 		discord.SelectOption(label="Option 3", emoji=":white_check_mark:", description="Enabled")
+# 	]
+# 	super().__init__(placeholder="Select an option", max_values=1, min_values=1, options=options)
+# 	async def callback(self, interaction: discord.Interaction):
+# 		await interaction.response.send_message(content=f"Your choice is {self.values[0]}!", ephemeral=True)
+#
+# class SelectGames(discord.ui.Select):
+# 	def __init__(self, pg, channels):
+# 		self.pg = pg
+# 	options = [
+# 		discord.SelectOption(label="Option 1", emoji=":x:", description="Disabled"),
+# 		discord.SelectOption(label="Option 2", emoji=":white_square_button:", description="Defer to default"),
+# 		discord.SelectOption(label="Option 3", emoji=":white_check_mark:", description="Enabled")
+# 	]
+# 	super().__init__(placeholder="Select an option", max_values=1, min_values=1, options=options)
+# 	async def callback(self, interaction: discord.Interaction):
+# 		await interaction.response.send_message(content=f"Your choice is {self.values[0]}!", ephemeral=True)
+
+# class SelectView(discord.ui.View):
+# 	def __init__(self, pg, channels, *, timeout = 180):
+# 		super().__init__(timeout=timeout)
+# 		self.add_item(SelectOutputChannel(pg, channels))
 
 
 class Admin(commands.Cog):
@@ -54,12 +73,8 @@ class Admin(commands.Cog):
 	@commands.has_guild_permissions(administrator=True)
 	async def guildsettings(self, interaction: discord.Interaction):
 
-		# Halt on ignore list.
-		if await check_ignore(self.bot.pg, interaction.user):
-			return
-
 		#await ctx.send("Menus!", view=SelectView(self.bot.pg, ctx.guild.channels))
-		await interaction.response.send_message("Menus!", view=View(self.bot.pg), ephemeral=True)
+		await interaction.response.send_message("Menus!", view=SelectOutputChannel(self.bot.pg), ephemeral=True)
 
 
 	@commands.command(
@@ -88,5 +103,16 @@ class Admin(commands.Cog):
 		await ctx.send(content=f"Synced {len(synced)} commands to this guild", ephemeral=True)
 
 
+	@app_commands.command(
+		name="status",
+		description="Change status.",
+	)
+	async def status(self, interaction: discord.Interaction, message: str) -> None:
+
+		await self.bot.change_presence(activity=discord.Game(name=message))
+		await interaction.response.send_message(content=":white_check_mark:")
+		await report(self.bot, f" has set my status to `{message}`.", user=interaction.user)
+
+
 async def setup(bot: commands.Bot):
 	await bot.add_cog(Admin(bot))

+ 11 - 11
bot/commands/angels.py

@@ -5,23 +5,23 @@ from discord.utils import get
 async def setup(bot: commands.Bot):
 	await bot.add_cog(AngelCommands(bot))
 
+def check_if_home_guild(interaction):
+	return interaction.guild.id == 962355492850638939
+
 class AngelCommands(commands.Cog):
-	"""Administrative functionality."""
 
 	def __init__(self, bot: commands.Bot):
 		self.bot = bot
 
-	@commands.command(
+	@discord.app_commands.command(
+		name="ungreeted",
 		description="List ungreeted users",
-		brief="Show a list of users that have not been granted the @fan role",
-		help="Generates list of users not in the @fan role"
 	)
 	@commands.has_guild_permissions(manage_roles=True)
-	@commands.guild_only()
+	@commands.check(check_if_home_guild)
 	async def ungreeted(self, interaction: discord.Interaction):
-		if interaction.guild.id == 962355492850638939: # Only in the Angels guild.
-			not_fanned = []
-			for member in interaction.guild.members:	# For loop for each guild member.
-				if not get(member.roles, id=962382104816140398):
-					not_fanned.append(f"{member.mention}|{member.nick}")
-			await interaction.send_message(content=not_fanned, ephemeral=True)
+		not_fanned = []
+		for member in interaction.guild.members:	# For loop for each guild member.
+			if not get(member.roles, id=962382104816140398) and not member.bot:
+				not_fanned.append(f"{member.mention} | {member.name}")
+		await interaction.response.send_message(content=not_fanned)

+ 199 - 189
bot/commands/games.py

@@ -1,10 +1,10 @@
 from discord.ext import commands
 import discord
+from discord import app_commands
 import random
 from typing import Optional
 from query.user import is_ignored, get_level, get_xp, level_up, get_ability_points_spent, increment_all_coin, get_coin, get_karma, get_theft_skill, get_random_player
-#from local_settings import COMMAND_PREFIX
-from common.settings import check_ignore
+from common.settings import check_ignore_interaction
 
 
 async def setup(bot: commands.Bot):
@@ -17,190 +17,200 @@ class Games(commands.Cog):
 	def __init__(self, bot: commands.Bot):
 		self.bot = bot
 
-	# @commands.command(
-	# 	description="Check the level for a player.",
-	# 	brief="Get player level",
-	# 	help="View game level of player."
-	# )
-	# async def level(self, ctx: commands.Context, user: Optional[discord.User]):
-	# 	# Halt on ignore list or games channel settings.
-	# 	if await check_ignore(self.bot.pg, ctx.author, ctx.channel):
-	# 		return
-	#
-	# 	if not user:
-	# 		user = ctx.author
-	# 	level = await get_level(self.bot.pg, user.id)
-	#
-	# 	if level == 0:
-	# 		if ctx.author == user:
-	# 			await ctx.send(f"You are not playing, join the game with `/levelup`")
-	# 		else:
-	# 			await ctx.send(f"`{user}` is not playing.")
-	# 	else:
-	# 		xp_spent, total_xp = await get_xp(self.bot.pg, user.id)
-	# 		ability_points_spent = await get_ability_points_spent(self.bot.pg, user.id)
-	# 		coin = await get_coin(self.bot.pg, user.id)
-	# 		karma = await get_karma(self.bot.pg, user.id)
-	# 		if ctx.author == user:
-	# 			await ctx.send(f"You rank at level **{level}**. (exp **{xp_spent}**/{total_xp} | abp **{ability_points_spent}**/{level * 3} | coin **{coin}** | karma **{karma}**)")
-	# 		else:
-	# 			await ctx.send(f"`{user}` ranks at level **{level}**. (**{xp_spent}**/{total_xp} | abp **{ability_points_spent}**/{level * 3}) | coin **{coin}** | karma **{karma}**")
-	#
-	# @commands.command(
-	# 	description="Check the experience points for a player.",
-	# 	brief="Get player xp",
-	# 	help="View amount of XP a game player has."
-	# )
-	# async def xp(self, ctx: commands.Context, user: Optional[discord.User]):
-	# 	# Halt on ignore list or games channel settings.
-	# 	if await check_ignore(self.bot.pg, ctx.author, ctx.channel):
-	# 		return
-	#
-	# 	if not user:
-	# 		xp_spent, total_xp = await get_xp(self.bot.pg, ctx.author.id)
-	# 		level = await get_level(self.bot.pg, ctx.author.id)
-	# 		threshold = (level + 1) * 50 + xp_spent
-	# 		if threshold < total_xp - xp_spent:
-	# 			await ctx.send(f"You have spent {xp_spent} experience points of your {total_xp} total and can gain 3 ability points for {threshold} xp.")
-	# 		else:
-	# 			await ctx.send(f"You have spent {xp_spent} experience points of your {total_xp} total and require {threshold - (total_xp - xp_spent)} xp to `/levelup`.")
-	# 	else:
-	# 		xp_spent, total_xp = await get_xp(self.bot.pg, user.id)
-	# 		level = await get_level(self.bot.pg, user.id)
-	# 		threshold = (level + 1) * 50 + xp_spent
-	# 		if threshold < total_xp - xp_spent:
-	# 			await ctx.send(f"`{user}` has spent {xp_spent} of {total_xp} experience points and can level up for {threshold} xp.")
-	# 		else:
-	# 			await ctx.send(f"`{user}` has spent {xp_spent} of {total_xp} experience points and requires {threshold - (total_xp - xp_spent)} xp to level up.")
-	#
-	# @commands.command(
-	# 	description="Attempt to gain a level.",
-	# 	brief="Level up",
-	# 	help="Try to rank up a level in the game by spending XP."
-	# )
-	# async def levelup(self, ctx: commands.Context):
-	# 	# Halt on ignore list or games channel settings.
-	# 	if await check_ignore(self.bot.pg, ctx.author, ctx.channel):
-	# 		return
-	#
-	# 	xp_spent, total_xp = await get_xp(self.bot.pg, ctx.author.id)
-	# 	xp_available = total_xp - xp_spent
-	# 	level = await get_level(self.bot.pg, ctx.author.id)
-	# 	threshold = (level + 1) * 50 + xp_spent
-	# 	if xp_available < threshold:
-	# 		await ctx.send(f"Not yet, you require {threshold - xp_available} more XP to level up.")
-	# 	else:
-	# 		await level_up(self.bot.pg, ctx.author.id, threshold)
-	# 		await ctx.send(f"You have gained three ability points climbed the ranks for {threshold} XP, leaving you {xp_available - threshold} remaining.")
-	# 		await increment_all_coin(self.bot.pg)
-	#
-	# @commands.command(
-	# 	description="Rob another player",
-	# 	brief="Rob a player",
-	# 	help="Pursuit a robbery."
-	# )
-	# async def rob(self, ctx: commands.Context):
-	# 	# Halt on ignore list or games channel settings.
-	# 	if await check_ignore(self.bot.pg, ctx.author, ctx.channel):
-	# 		return
-	#
-	# 	if get_theft_skill(self.bot.pg, ctx.author.id < 1):
-	# 		await ctx.send("You do not have the `Theft` skill.")
-	# 		return
-	#
-	# 	victim_id = get_random_player(self.bot.pg)
-	# 	await ctx.send(f"You have decided to rob{self.bot.get_user(victim_id)}, unfortunately crime has not been invited yet.")
-	#
-	# @commands.command(
-	# 	description="Simulate dice rolls.",
-	# 	brief="Roll dice",
-	# 	help="Roll two dice."
-	# )
-	# async def dice(self, ctx: commands.Context, amount: Optional[int], sides: Optional[int]):
-	# 	# Halt on ignore list or games channel settings.
-	# 	if await check_ignore(self.bot.pg, ctx.author, ctx.channel):
-	# 		return
-	#
-	# 	if not amount:
-	# 		amount = 2
-	# 	if not sides:
-	# 		sides = 6
-	#
-	# 	if amount < 1:
-	# 		await ctx.send("You want me to roll less than one die? How!?")
-	# 	elif amount > 25:
-	# 		await ctx.send("I can not hold so many dice at one time.")
-	# 	elif sides < 2:
-	# 		await ctx.send("A die has physical minimum of 2 sides. Don't ask for impossible objects.")
-	# 	elif sides > 256:
-	# 		await ctx.send("My tiny hands can not handle such large dice. Even if both are virtual.")
-	# 	else:
-	# 		embed = discord.Embed(title = "Dice roll", description=f"Rolling {amount} dice, with {sides} sides.")
-	# 		while amount > 0:
-	# 			embed.insert_field_at(0, name=f"Die {amount}", value=random.randint(1, sides), inline=True)
-	# 			amount -= 1
-	# 		await ctx.send(embed=embed)
-	#
-	# @commands.command(
-	# 	description="Ask the magic 8-ball.",
-	# 	brief="Pose question",
-	# 	help="Simulate the iconic 8-ball gimmic.",
-	# 	name="8ball"
-	# )
-	# async def eightball(self, ctx: commands.Context, *, question: str = None):
-	# 	# Halt on ignore list or games channel settings.
-	# 	if await check_ignore(self.bot.pg, ctx.author, ctx.channel):
-	# 		return
-	#
-	# 	if not question:
-	# 		messages = [
-	# 			"Don't forget to ask a question...",
-	# 			"Hey, that's not a question!",
-	# 			"What would you like to know?",
-	# 			"You want me to predict nothing?",
-	# 			"Are you intentionally not asking a question?",
-	# 			"Ask a question you tease!",
-	# 			"You will die alone.",
-	# 		]
-	# 	elif question.strip().count(" ") == 0:
-	# 		messages = [
-	# 			"What?",
-	# 			"That is not a question",
-	# 			"Can you use more than one word?",
-	# 			"What is the question?",
-	# 			"Sorry?"
-	# 		]
-	# 	elif question.strip()[-1] != "?":
-	# 		messages = [
-	# 			"Did you forget to end with a question mark?",
-	# 			"Is that a statement or question?",
-	# 			"Don't questions usually end with a question mark?",
-	# 			"Don't forget to use punctuation."
-	# 		]
-	# 	else:
-	# 		messages = [
-	# 			"Yes.",
-	# 			"No.",
-	# 			"Affirmative.",
-	# 			"No way!",
-	# 			"Negative.",
-	# 			"Positive.",
-	# 			"Correct.",
-	# 			"Incorrect.",
-	# 			"Likely",
-	# 			"Unlikely",
-	# 			"Maybe.",
-	# 			"Definately!",
-	# 			"Perhaps?",
-	# 			"Most indubitably.",
-	# 			"Does the pope shit in the woods?",
-	# 			"When hell freezes over.",
-	# 			"Only between 9 and 5.",
-	# 			"Only just before you die.",
-	# 			"ERROR: Probability failure.",
-	# 			"Ask again later.",
-	# 			"I don't know.",
-	# 			"Unpredictable.",
-	# 			"Unknown",
-	# 		]
-	# 	await ctx.send(random.choice(messages))
+	@app_commands.command(
+		name="level",
+		description="Check the level for a player.",
+	)
+	async def level(self, interaction: discord.Interaction, user: Optional[discord.User]) -> None:
+		# Keep interaction alive longer then 3 seconds to give the bot time to respond.
+		await interaction.response.defer()
+
+		# Halt on ignore list or games channel settings.
+		if await check_ignore_interaction(self.bot.pg, interaction, games=True):
+			return
+
+		if not user:
+			user = interaction.user
+		level = await get_level(self.bot.pg, user.id)
+
+		if level == 0:
+			if interaction.user == user:
+				await interaction.followup.send(f"You are not playing, join the game with `/levelup`")
+			else:
+				await interaction.followup.send(f"`{user}` is not playing.")
+		else:
+			xp_spent, total_xp = await get_xp(self.bot.pg, user.id)
+			ability_points_spent = await get_ability_points_spent(self.bot.pg, user.id)
+			coin = await get_coin(self.bot.pg, user.id)
+			karma = await get_karma(self.bot.pg, user.id)
+			if interaction.user == user:
+				await interaction.followup.send(f"You rank at level **{level}**. (exp **{xp_spent}**/{total_xp} | abp **{ability_points_spent}**/{level * 3} | coin **{coin}** | karma **{karma}**)")
+			else:
+				await interaction.followup.send(f"`{user}` ranks at level **{level}**. (**{xp_spent}**/{total_xp} | abp **{ability_points_spent}**/{level * 3}) | coin **{coin}** | karma **{karma}**")
+
+	@app_commands.command(
+		name="xp",
+		description="Check the experience points for a player.",
+	)
+	async def xp(self, interaction: discord.Interaction, user: Optional[discord.User]) -> None:
+		# Keep interaction alive longer then 3 seconds to give the bot time to respond.
+		await interaction.response.defer()
+
+		# Halt on ignore list or games channel settings.
+		if await check_ignore_interaction(self.bot.pg, interaction, games=True):
+			return
+
+		if not user:
+			xp_spent, total_xp = await get_xp(self.bot.pg, interaction.user.id)
+			level = await get_level(self.bot.pg, interaction.user.id)
+			threshold = (level + 1) * 50 + xp_spent
+			if threshold < total_xp - xp_spent:
+				await interaction.followup.send(f"You have spent {xp_spent} experience points of your {total_xp} total and can gain 3 ability points for {threshold} xp.")
+			else:
+				await interaction.followup.send(f"You have spent {xp_spent} experience points of your {total_xp} total and require {threshold - (total_xp - xp_spent)} xp to `/levelup`.")
+		else:
+			xp_spent, total_xp = await get_xp(self.bot.pg, user.id)
+			level = await get_level(self.bot.pg, user.id)
+			threshold = (level + 1) * 50 + xp_spent
+			if threshold < total_xp - xp_spent:
+				await interaction.followup.send(f"`{user}` has spent {xp_spent} of {total_xp} experience points and can level up for {threshold} xp.")
+			else:
+				await interaction.followup.send(f"`{user}` has spent {xp_spent} of {total_xp} experience points and requires {threshold - (total_xp - xp_spent)} xp to level up.")
+
+	@app_commands.command(
+		name="levelup",
+		description="Attempt to gain a level.",
+	)
+	async def levelup(self, interaction: discord.Interaction) -> None:
+		# Halt on ignore list or games channel settings.
+		if await check_ignore_interaction(self.bot.pg, interaction, games=True):
+			return
+
+		xp_spent, total_xp = await get_xp(self.bot.pg, interaction.user.id)
+		xp_available = total_xp - xp_spent
+		level = await get_level(self.bot.pg, interaction.user.id)
+		threshold = (level + 1) * 50 + xp_spent
+		if xp_available < threshold:
+			await interaction.followup.send(f"Not yet, you require {threshold - xp_available} more XP to level up.")
+		else:
+			await level_up(self.bot.pg, interaction.user.id, threshold)
+			await interaction.send_message(f"You have gained three ability points climbed the ranks for {threshold} XP, leaving you {xp_available - threshold} remaining.")
+			await increment_all_coin(self.bot.pg)
+
+	@app_commands.command(
+		name="rob",
+		description="Rob another player",
+	)
+	async def rob(self, interaction: discord.Interaction) -> None:
+		# Halt on ignore list or games channel settings.
+		if await check_ignore_interaction(self.bot.pg, interaction, games=True):
+			return
+
+		if await get_theft_skill(self.bot.pg, interaction.user.id < 1):
+			await interaction.followup.send("You do not have the `Theft` skill.")
+			return
+
+		victim_id = get_random_player(self.bot.pg)
+		await interaction.send_message(f"You have decided to rob{self.bot.get_user(victim_id)}, unfortunately crime has not been invited yet.")
+
+	@app_commands.command(
+		name="dice",
+		description="Simulate dice rolls.",
+	)
+	async def dice(self, interaction: discord.Interaction, amount: Optional[int], sides: Optional[int]) -> None:
+
+		# Keep interaction alive longer then 3 seconds to give the bot time to respond.
+		await interaction.response.defer()
+
+		print(f"Extras: {interaction.extras}")
+		print(f"Message: {interaction.message}")
+		print(f"Data: {interaction.data}")
+
+		# Halt on ignore list or games channel settings.
+		if await check_ignore(self.bot.pg, interaction, games=True):
+			return
+
+		if not amount:
+			amount = 2
+		if not sides:
+			sides = 6
+
+		if amount < 1:
+			await interaction.followup.send("You want me to roll less than one die? How!?")
+		elif amount > 25:
+			await interaction.followup.send("I can not hold so many dice at one time.")
+		elif sides < 2:
+			await interaction.followup.send("A die has physical minimum of 2 sides. Don't ask for impossible objects.")
+		elif sides > 256:
+			await interaction.followup.send("My tiny hands can not handle such large dice. Even if both are virtual.")
+		else:
+			embed = discord.Embed(title = "Dice roll", description=f"Rolling {amount} dice, with {sides} sides.")
+			while amount > 0:
+				embed.insert_field_at(0, name=f"Die {amount}", value=random.randint(1, sides), inline=True)
+				amount -= 1
+			await interaction.followup.send(embed=embed)
+
+	@app_commands.command(
+		name="8ball",
+		description="Ask the magic 8-ball.",
+	)
+	async def eightball(self, interaction: discord.Interaction, question: str = None) -> None:
+		theorem = f"{interaction.user.mention} asked: `{question}`"
+		await interaction.response.send_message(theorem)
+
+		# Halt on ignore list or games channel settings.
+		if await check_ignore(self.bot.pg, interaction, games=True):
+			return
+
+		if not question:
+			messages = [
+				"Don't forget to ask a question...",
+				"Hey, that's not a question!",
+				"What would you like to know?",
+				"You want me to predict nothing?",
+				"Are you intentionally not asking a question?",
+				"Ask a question you tease!",
+				"You will die alone.",
+			]
+		elif question.strip().count(" ") == 0:
+			messages = [
+				"What?",
+				"That is not a question",
+				"Can you use more than one word?",
+				"What is the question?",
+				"Sorry?"
+			]
+		elif question.strip()[-1] != "?":
+			messages = [
+				"Did you forget to end with a question mark?",
+				"Is that a statement or question?",
+				"Don't questions usually end with a question mark?",
+				"Don't forget to use punctuation."
+			]
+		else:
+			messages = [
+				"Yes.",
+				"No.",
+				"Affirmative.",
+				"No way!",
+				"Negative.",
+				"Positive.",
+				"Correct.",
+				"Incorrect.",
+				"Likely",
+				"Unlikely",
+				"Maybe.",
+				"Definately!",
+				"Perhaps?",
+				"Most indubitably.",
+				"Does the pope shit in the woods?",
+				"When hell freezes over.",
+				"Only between 9 and 5.",
+				"Only just before you die.",
+				"ERROR: Probability failure.",
+				"Ask again later.",
+				"I don't know.",
+				"Unpredictable.",
+				"Unknown",
+			]
+		await interaction.edit_original_response(content=f"{theorem}\n**{random.choice(messages)}**")

+ 18 - 47
bot/commands/general.py

@@ -1,40 +1,33 @@
 from discord.ext import commands
 import discord
 from discord import app_commands
-#import time
+import time
 from typing import Optional
 #from query.channel import get_interact
 from query.user import ignore_user, unignore_user, is_ignored
 from common.logging import report
 #from local_settings import OUTPUT_CHANNEL
-from common.settings import check_ignore
-
+from common.settings import check_ignore_interaction
 
 async def setup(bot: commands.Bot) -> None:
 	await bot.add_cog(GeneralCommands(bot))
 
-
 class GeneralCommands(commands.Cog):
 	"""General functionality."""
 
 	def __init__(self, bot: commands.Bot) -> None:
 		self.bot = bot
 
-	# @commands.command(
-	# 	description="Get the bot's current websocket and API latency.",
-	# 	brief="Test latency",
-	# 	help="Test latency by polling the gateway and API."
-	# )
-	# async def ping(self, ctx: commands.Context):
-	# 	# Halt on ignore list.
-	# 	if await check_ignore(self.bot.pg, ctx.author):
-	# 		return
-	#
-	# 	start_time = time.time()
-	# 	message = await ctx.send(f"Pong!\nGateway heartbeat in {round(self.bot.latency * 1000)}ms.")
-	# 	end_time = time.time()
-	#
-	# 	await ctx.send(f"API roundtrip latency {round((end_time - start_time) * 1000)}ms.")
+	@app_commands.command(
+		name="ping",
+		description="Get the bot's current websocket and API latency.",
+	)
+	async def ping(self, interaction: discord.Interaction) -> None:
+		start_time = time.time()
+		# message = await ctx.send(f"Pong!\nGateway heartbeat in {round(self.bot.latency * 1000)}ms.")
+		end_time = time.time()
+
+		await interaction.response.send_message(f"API roundtrip latency {round((end_time - start_time) * 1000)}ms.", ephemeral=True)
 
 	# @commands.command(
 	# 	description="Send a message",
@@ -44,7 +37,7 @@ class GeneralCommands(commands.Cog):
 	# )
 	# async def msg(self, ctx: commands.Context, channel: Optional[discord.TextChannel], user: Optional[discord.User], *, message: str = None):
 	# 	# Halt on ignore list.
-	# 	if await check_ignore(self.bot.pg, ctx.author):
+	# 	if await check_ignore_interaction(self.bot.pg, interaction):
 	# 		return
 	#
 	# 	#print(ctx.author.permissions_in(self.bot.get_channel(OUTPUT_CHANNEL)).send_messages)
@@ -68,31 +61,18 @@ class GeneralCommands(commands.Cog):
 	# 		await ctx.send(message)
 	# 		await report(self.bot, f"`{ctx.author}` has sent {message} locally.", ctx.guild)
 
-	# @commands.command(
-	# 	description="Change status.",
-	# 	brief="Set status",
-	# 	help="Update the bot's status."
-	# )
-	# async def status(self, ctx: commands.Context, *, text: str):
-	# 	# Halt on ignore list.
-	# 	if await check_ignore(self.bot.pg, ctx.author):
-	# 		return
-	#
-	# 	await self.bot.change_presence(activity=discord.Game(name=text))
-	# 	await report(self.bot, f"`{ctx.author}` has set my status to `{text}`.")
-
 	@app_commands.command(
 		name="ignoreme",
 		description="Get ignored.",
 	)
 	async def ignoreme(self, interaction: discord.Interaction) -> None:
 		# Halt on ignore list.
-		if await check_ignore(self.bot.pg, interaction.user):
+		if await check_ignore_interaction(self.bot.pg, interaction):
 			return
 
 		await ignore_user(self.bot.pg, interaction.user.id)
 		await interaction.response.send_message(f"To revert this use the `/unignoreme` command.")
-		await report(self.bot, f"`{ctx.author}` has requested to be ignored.")
+		await report(self.bot, " has requested to be ignored.", user=interaction.user)
 
 	@app_commands.command(
 		name="unignoreme",
@@ -101,20 +81,15 @@ class GeneralCommands(commands.Cog):
 	async def unignoreme(self, interaction: discord.Interaction) -> None:
 		await unignore_user(self.bot.pg, interaction.user.id)
 		await interaction.response.send_message(f"I shall now interact with you again where my channel settings allow it.")
-		await report(self.bot, f"`{interaction.user}` has requested to be un-ignored.")
+		await report(self.bot, " has requested to be un-ignored.", user=interaction.user)
 
 	@app_commands.command(
 		name="isignored",
 		description="Ignore status for user.",
 	)
-	# @commands.command(
-	# 	description="Ignore status for user.",
-	# 	brief="Check if user is ingored",
-	# 	help="Verify if the user is being ignored."
-	# )
 	async def isignored(self, interaction: discord.Interaction, user: Optional[discord.User]) -> None:
 		# Halt on ignore list.
-		if await check_ignore(self.bot.pg, interaction.user):
+		if await check_ignore_interaction(self.bot.pg, interaction.user):
 			return
 
 		if not user:
@@ -123,8 +98,4 @@ class GeneralCommands(commands.Cog):
 		if await is_ignored(self.bot.pg, user.id):
 			await interaction.response.send_message(f"I am ignoring `{user}`.")
 		else:
-			await interaction.response.send_message(f"I am not ignoring `{user}`.")
-
-	@app_commands.command(name="echo1", description="Echo a message")
-	async def echo1(self, inter: discord.Interaction, message: str) -> None:
-		await inter.response.send_message(message)
+			await interaction.response.send_message(f"I am not ignoring `{user}`.")

+ 0 - 7
bot/common/datetime.py

@@ -1,7 +0,0 @@
-import datetime
-
-def min10min(before):
-	return before - datetime.timedelta(minutes=10)
-
-def plus10min(after):
-	return after + datetime.timedelta(minutes=10)

+ 19 - 8
bot/common/logging.py

@@ -3,12 +3,23 @@ from typing import Optional
 from local_settings import OUTPUT_CHANNEL
 from query.guild import get_output_channel
 
-async def report(bot, message, guild: Optional[discord.Guild]=None):
-    channel = bot.get_channel(int(OUTPUT_CHANNEL))
-    if guild:
-        message = f"**{guild}** | {message}"
-        try: channel = bot.get_channel(get_output_channel(guild.id))
-        except:
-            pass
+async def report(bot, message, user: Optional[discord.User]=None, guild: Optional[discord.Guild]=None, guild_id: Optional[int]=None, channel: Optional[discord.TextChannel]=None) -> None:
+    output_channel = bot.get_channel(int(OUTPUT_CHANNEL))
+    prefix = ""
+    if guild or guild_id:
+        if guild_id:
+            guild = bot.get_guild(guild_id)
+        prefix += f"**{guild}**"
+    if channel:
+        prefix += f"/**{channel.mention}** - "
+    if user:
+        prefix += f"`{user}`|**{user.display_name}**: "
 
-    await channel.send(message)
+    await output_channel.send(prefix + message)
+
+    # Send to local guild
+    try:
+        guild_output_channel = bot.get_channel(get_output_channel(guild.id))
+        await output_channel.send(prefix + message)
+    except:
+        pass

+ 56 - 12
bot/common/settings.py

@@ -1,13 +1,57 @@
+from typing import Optional
+
+import discord
 from query.user import is_ignored
-from query.channel import get_games
-
-async def check_ignore(pg, user, games_channel=None):
-	# Ignore user if on the ignore list.
-	if await is_ignored(pg, user.id):
-		return True
-
-	# Ignore if games are disabled for channel.
-	if games_channel:  # Invoked by a game command.
-		if not await get_games(pg, games_channel.id):  # Warn if games are off.
-			user.send(f"Games are disabled in {games_channel}, ask an admin to enable them.")
-			return True
+from query.channel import get_channel_games, get_channel_interact
+from query.guild import get_guild_games, get_guild_interact
+
+
+# Ignore user if on the ignore list.
+async def check_userignore(pg, user_id):
+	if await is_ignored(pg, user_id):
+		return True	# Confirm ignore
+
+async def check_interact(pg, channel):
+	# Respond if interaction is enabled for channel.
+	if channel and await get_channel_interact(pg, channel.id):
+		return False  # Deny ignore
+
+	# Ignore if interactions are disabled for channel or guild.
+	if channel and await get_channel_interact(pg, channel.id) == False or interaction.guild and await get_guild_interact(pg, channel.id) == False:
+		return True  # Confirm ignore
+
+async def check_ignore_interaction(pg, interaction: discord.Interaction, games: Optional[bool]=False, interact: Optional[bool]=False):
+
+	# Ignore user if they have requested to be ignored:
+	if await check_userignore(pg, interaction.user.id):
+		return True	# Confirm ignore
+
+	# Game setting check
+	if games:
+
+		# Respond if games enabled for channel.
+		if interaction.channel and await get_channel_games(pg, interaction.channel.id):
+			return False	# Deny ignore
+
+		# Ignore if games are disabled for channel or guild.
+		if interaction.channel and await get_channel_games(pg, interaction.channel.id) == False or interaction.guild and await get_guild_games(pg, interaction.guild.id) == False:
+			await interaction.response.send_message(f"An admin of **{interaction.guild}** has disabled games in {interaction.channel.mention}.", ephemeral=True)
+			return True	# Confirm ignore
+
+		# Respond if channel & faction games are not disabled.
+		else:
+			return False	# Deny ignore
+
+	# Interact settings check:
+	if interact:
+		return await check_interact(pg, interaction.channel)
+
+async def check_ignore_message(pg, message: discord.Message, interact: Optional[bool] = False):
+
+	# Check if user has requested to be ignored:
+	if await check_userignore(pg, message.author.id):
+		True	# Confirm ignore
+
+	# Interact settings check:
+	if interact:
+		return await check_interact(pg, message.channel)

+ 1 - 1
bot/events/angels.py

@@ -19,7 +19,7 @@ class AngelEvents(commands.Cog):
 				source_channel = self.bot.get_channel(message.reference.channel_id)
 				if source_channel:
 					source_invite = await source_channel.create_invite(unique=False, reason="Linking back to discord of which news is being repeated.")
-					await news_channel.send(f"{message.author.mention} [{message.system_content.partition()[2]}]({source_invite})")
+					await news_channel.send(f"{message.author.mention} [{message.system_content.partition()[2]}]({source_invite.url})")
 				else:
 					await news_channel.send(f"{message.author.mention} {message.system_content.partition(' ')[2]}")
 			else:

+ 36 - 25
bot/events/general.py

@@ -2,10 +2,11 @@ import logging, discord, asyncpg, random, sys, datetime
 
 from discord.ext import commands
 from query.guild import update_guild, get_report_deleted, get_output_channel, get_report_edited
-from query.channel import insert_channel, get_interact
+from query.channel import insert_channel, get_channel_interact
 from query.channel_user import upsert_total_messages
 from query.user import create_user, created_invite, created_integration, member_updated, user_updated, member_banned, member_unbanned, presence_updated, message_edited, message_deleted, reacted, event_created, event_joined, thread_created, joined_thread, deleted_invite, member_joined, unreacted, event_parted, thread_deleted, left_thread
 from common.logging import report
+from common.settings import check_ignore_interaction, check_ignore_message
 
 async def setup(bot: commands.Bot):
 	await bot.add_cog(GeneralEvents(bot))
@@ -21,12 +22,14 @@ class GeneralEvents(commands.Cog):
 	@commands.Cog.listener()
 	async def on_raw_app_command_permissions_update(self, payload):
 		logging.info(f"Application command permissions are updated: {payload}")
-		await report(self.bot, f"Application command permissions are updated: {payload}", payload.guild)
+		await report(self.bot, f"Application command permissions are updated: {payload}", guild=payload.guild)
 
 	@commands.Cog.listener()
 	async def on_app_command_completion(self, interaction, command):
-		logging.info(f"Application command completion: {interaction} - {command}")
-		await report(self.bot, f"Application command completion: {interaction} - {command}", interaction.guild)
+		logging.info(f"{interaction.guild} {interaction.channel} {interaction.user}: {interaction.message}")
+		for parameter in interaction.command.parameters:
+			print(parameter)
+		await report(self.bot, f"Executed: {interaction.command.name} {interaction.command.extras}", user=interaction.user, guild=interaction.guild, channel=interaction.channel)
 
 	@commands.Cog.listener()
 	async def on_connect(self):
@@ -74,18 +77,19 @@ class GeneralEvents(commands.Cog):
 	@commands.Cog.listener()
 	async def on_guild_unavailable(self, guild: discord.Guild):
 		logging.info(f"Guild unavailable: {guild}")
-		await report(self.bot, f"Guild unavailable: `{guild}`")
+		await report(self.bot, f"Guild unavailable: `{guild}`", guild=guild)
 
 	@commands.Cog.listener()
 	async def on_guild_join(self, guild: discord.Guild):
 		await update_guild(self.bot.pg, guild)
 		logging.info(f"Joined guild {guild}")
-		await report(self.bot, f"Joined guild [`{guild}`]({await guild.channels[0].create_invite(unique=False)}).")
+		invite = await guild.channels[0].create_invite(unique=False)
+		await report(self.bot, f"Joined Discord guild [`{guild}`]({invite.url}).", guild=guild)
 
 	@commands.Cog.listener()
 	async def on_guild_remove(self, guild: discord.Guild):
 		logging.info(f"Guild removed: {guild}")
-		await report(self.bot, f"Guild removed `{guild}`.")
+		await report(self.bot, f"Guild removed `{guild}`.", guild=guild)
 
 	@commands.Cog.listener()
 	async def on_invite_create(self, invite: discord.Invite):
@@ -108,7 +112,7 @@ class GeneralEvents(commands.Cog):
 		await member_updated(self.bot.pg, before.id)
 
 	@commands.Cog.listener()
-	async def on_user_update(self, before):
+	async def on_user_update(self, before, after):
 		await user_updated(self.bot.pg, before.id)
 
 	@commands.Cog.listener()
@@ -139,15 +143,19 @@ class GeneralEvents(commands.Cog):
 				except asyncpg.exceptions.ForeignKeyViolationError:
 					await update_guild(self.bot.pg, message.guild)
 		elif self.bot.user != message.author:	# Not a guild message and not from bot.
-			await report(self.bot, f"`{message.author}`: {message.content}")
+			await report(self.bot, message.content, user=message.author)
 		
-		# Do not respond to one self.
+		# Do not respond to one self.	TODO: check if this is still required.
 		if self.bot.user == message.author:
-			pass
+			return
+
+		# Do not respond if interaction are disabled:
+		if await check_ignore_message(self.bot.pg, message, interact=True):
+			return
 
 		# Respond when mentioned
 		if self.bot.user.mentioned_in(message):
-			if isinstance(message.channel, discord.channel.DMChannel) or await get_interact(self.bot.pg, message.channel.id):
+			if isinstance(message.channel, discord.channel.DMChannel) or await get_channel_interact(self.bot.pg, message.channel.id): # TODO add this to commno.settings to be checked also against the guild settings.
 
 				# Only respond every X seconds in public places.
 				if message.guild:  # Ignore DM's
@@ -190,6 +198,10 @@ class GeneralEvents(commands.Cog):
 					":zany_face: :space_invader: :mechanical_leg: :performing_arts: :robot:",
 					":black_joker: :black_joker: :black_joker:",
 					"Want to come back to my place?",
+					"Oega.",
+					"Oega!",
+					"OEGA",
+					"OEGA!!!",
 				]
 				await message.reply(random.choice(messages))
 
@@ -198,57 +210,56 @@ class GeneralEvents(commands.Cog):
 		await message_edited(self.bot.pg, before.author.id)
 		if before.guild:
 			if await get_report_edited(self.bot.pg, before.guild.id) and get_output_channel(self.bot.pg, before.guild.id):
-				report(self.bot, before.guild.id, f"Message from {before.author}, in {before.channel} edited from {before.content} to {after.content}")
+				await report(self.bot, before.guild.id, f"Message from {before.author}, in {before.channel} edited from {before.content} to {after.content}", user=before.author, guild=before.guild, channel=before.channel)
 
 	@commands.Cog.listener()
 	async def on_message_delete(self, message: discord.Message):
 		await message_deleted(self.bot.pg, message.author.id)
 		if await get_report_deleted(self.bot.pg, message.guild.id):
-			report(self.bot, message.guild_id,
-				   f"Message from {message.author}, in {message.channel} deleted: {message}")
+			report(self.bot, message.guild_id, f"Message from {message.author}, in {message.channel} deleted: {message}", guild=message.guild, channel=message.channel)
 
 		# !snipe
 		self.last_deleted_msg = message
 
 	@commands.Cog.listener()
 	async def on_raw_member_remove(self, payload):
-		report(self.bot, f"{payload.user} has left {payload.guild_id}")
+		await report(self.bot, f"{payload.user} has left the Discord guild.", user=payload.user, guild_id=payload.guild_id)
 
 	@commands.Cog.listener()
 	async def on_reaction_add(self, reaction, user):
-		reacted(self.bot.pg, user.id)
+		await reacted(self.bot.pg, user.id)
 
 	@commands.Cog.listener()
 	async def on_reaction_remove(self, reaction, user):
-		unreacted(self.bot.pg, user.id)
+		await unreacted(self.bot.pg, user.id)
 
 	@commands.Cog.listener()
 	async def on_scheduled_event_create(self, event):
-		event_created(self.bot.pg, event.creator.id)
+		await event_created(self.bot.pg, event.creator.id)
 
 	@commands.Cog.listener()
 	async def on_scheduled_event_user_add(self, event, user):
-		event_joined(self.bot.pg, user.id)
+		await event_joined(self.bot.pg, user.id)
 
 	@commands.Cog.listener()
 	async def on_scheduled_event_user_remove(self, event, user):
-		event_parted(self.bot.pg, user.id)
+		await event_parted(self.bot.pg, user.id)
 
 	@commands.Cog.listener()
 	async def on_thread_create(self, thread):
-		thread_created(self.bot.pg, thread.owner.id)
+		await thread_created(self.bot.pg, thread.owner.id)
 
 	@commands.Cog.listener()
 	async def on_thread_delete(self, thread):
-		thread_deleted(self.bot.pg, thread.owner.id)
+		await thread_deleted(self.bot.pg, thread.owner.id)
 
 	@commands.Cog.listener()
 	async def on_thread_member_join(self, member: discord.User):
-		joined_thread(self.bot.pg, member.id)
+		await joined_thread(self.bot.pg, member.id)
 
 	@commands.Cog.listener()
 	async def on_thread_member_remove(self, member: discord.User):
-		left_thread(self.bot.pg, member.id)
+		await left_thread(self.bot.pg, member.id)
 
 	# @commands.command(name="snipe")
 	# async def snipe(self, ctx: commands.Context):  # Undelete last deleted message

+ 13 - 5
bot/main.py

@@ -4,20 +4,24 @@ from discord.ext import commands
 import asyncpg, asyncio
 
 
+# Called when the database does not seem to exist.
 def sql_db_does_not_exist():
 	logging.error("Database does not exist. Doublecheck if it has been created, and the user has access.")
 	quit()
 
+# Called when SQL authentication fails.
 def sql_authentication_error():
 	logging.error("Database authentication failed. Doublecheck username & password, and if the user has been created.")
 	quit()
 
+# Called on settings issue.
 def hint_quit():  # Hint how to edit the settings and quit
 	logging.info("")
 	logging.info("    edit local_settings.py")
 	logging.info("")
 	quit()
 
+# Called when settings file is not present.
 def missing_config():  # Copy or create settings file if missing
 	logging.basicConfig(level=logging.DEBUG)
 	if not os.path.exists("local_settings.py"):
@@ -49,6 +53,7 @@ def missing_config():  # Copy or create settings file if missing
 	logging.info("Configure the settings:")
 	hint_quit()
 
+# Issue with specific setting
 def correct_setting(setting):  # Hint to correct specific setting and quit
 	logging.info("Correct the %s in local_settings.py", setting)
 	hint_quit()
@@ -71,7 +76,9 @@ async def main():
 	intents = discord.Intents.default()
 	intents.message_content = True
 	intents.invites = True
+	intents.members = True
 
+	# Try being a bot
 	try:
 		bot = commands.Bot(
 			command_prefix="/",
@@ -82,19 +89,20 @@ async def main():
 	except AttributeError:
 		missing_config()
 
-	# Load extensions
-	default_extensions = [
+	# Extensions
+	default_extensions = [	# Define cogs
 		"commands.admin",
 		"commands.games",
 		"commands.general",
 		"commands.angels",
-		"events.general",
+		"events.general", # Causes an errror on any slash command, even commands from other cogs
 		"events.angels",
 	]
 	for ext in default_extensions:
 		logging.info(f"Loading extension: {ext}")
-		await bot.load_extension(ext)
+		await bot.load_extension(ext)	# Load cog
 
+	# Database connection
 	async def create_db_pool():	 # Connect to database
 		try:
 			bot.pg = await asyncpg.create_pool(
@@ -116,7 +124,7 @@ async def main():
 	# Create database tables if they do not exist
 	from query.initialise_database import init_db, check_db
 	try:
-		await check_db(bot.pg)
+		await check_db(bot.pg)	# TODO: Create a better check
 	except asyncpg.exceptions.UndefinedTableError:
 		logging.info("User table does not exists, assuming empty database. Populating database...")
 		await init_db(bot.pg)

+ 5 - 3
bot/query/channel.py

@@ -1,8 +1,10 @@
 async def insert_channel(pg, channel_id, guild_id):
 	await pg.execute("INSERT INTO channel(channel_id, guild) VALUES($1, $2)", channel_id, guild_id)
 
-async def get_interact(pg, channel_id):
+
+async def get_channel_interact(pg, channel_id):
 	return await pg.fetchval("SELECT interact FROM channel WHERE channel_id=$1::bigint", channel_id)
 
-async def get_games(pg, channel_id):
-	return await pg.fetchval("SELECT games FROM channel WHERE channel_id=$1::bigint", channel_id)
+
+async def get_channel_games(pg, channel_id):
+	return await pg.fetchval("SELECT games FROM channel WHERE channel_id=$1::bigint", channel_id)

+ 13 - 1
bot/query/guild.py

@@ -3,14 +3,26 @@ async def update_guild(pg, guild):
 	for chan in guild.text_channels:
 		await pg.execute("INSERT INTO channel(channel_id, guild) VALUES($1, $2) ON CONFLICT DO NOTHING", chan.id, guild.id)
 
+
 async def get_output_channel(pg, guild_id):
 	return await pg.fetchval("SELECT output_channel FROM guild WHERE guild_id = $1", guild_id)
 
+
 async def set_output_channel(pg, guild_id, value):
 	return await pg.execute("UPDATE guild SET output_channel = $1 WHERE guild_id = $2 ", value, guild_id)
 
+
 async def get_report_deleted(pg, guild_id):
 	return await pg.fetchval("SELECT report_deleted FROM guild WHERE guild_id = $1", guild_id)
 
+
 async def get_report_edited(pg, guild_id):
-	return await pg.fetchval("SELECT report_edited FROM guild WHERE guild_id = $1", guild_id)
+	return await pg.fetchval("SELECT report_edited FROM guild WHERE guild_id = $1", guild_id)
+
+
+async def get_guild_games(pg, guild_id):
+	return await pg.fetchval("SELECT games FROM guild WHERE guild_id=$1::bigint", guild_id)
+
+
+async def get_guild_interact(pg, guild_id):
+	return await pg.fetchval("SELECT interact FROM guild WHERE guild_id=$1::bigint", guild_id)

+ 0 - 19
bot/query/guild_access_token.py

@@ -1,19 +0,0 @@
-import datetime, asyncpg
-from common.datetime import min10min
-from query.guild import update_guild
-
-async def get_active_token(pg, guild_id):
-	return await pg.fetchrow("SELECT * FROM guild_access_token WHERE guild=$1 AND created > $2", guild_id, min10min(datetime.datetime.now()))
-
-async def upsert_token(pg, guild_id, user_id, token):
-	print(token)
-	print("INSERT INTO guild_access_token(guild, \"user\", token) VALUES($1, $2, $3)", guild_id, user_id, token)
-
-	try:
-		await pg.execute("INSERT INTO guild_access_token(guild, \"user\", token) VALUES($1, $2, $3)", guild_id, user_id, [token])
-		
-		# ON CONFLICT() DO UPDATE SET \"user\"=$1 AND token=$2", user_id, token)
-	except asyncpg.exceptions.ForeignKeyViolationError:
-		await update_guild(self.bot.pg, message.guild)
-		await pg.execute("INSERT INTO guild_access_token(guild, \"user\", token) VALUES($1, $2, $3)", guild_id, user_id, token)
-		# ON CONFLICT() DO UPDATE SET \"user\"=$1 AND token=$2", user_id, token)

+ 4 - 2
bot/query/initialise_database.py

@@ -6,7 +6,9 @@ async def init_db(pg):
                 guild_id BIGINT UNIQUE NOT NULL, \
                 output_channel BIGINT REFERENCES channel (channel_id),\
                 report_deleted BOOL DEFAULT FALSE, \
-                report_edited BOOL DEFAULT FALSE\
+                report_edited BOOL DEFAULT FALSE, \
+                games BOOL DEFAULT NULL, \
+                interact BOOL DEFAULT NULL\
             )\
         ",
         "CREATE TABLE IF NOT EXISTS \
@@ -15,7 +17,7 @@ async def init_db(pg):
                 channel_id BIGINT UNIQUE NOT NULL, \
                 guild BIGINT REFERENCES guild (guild_id), \
                 interact BOOL DEFAULT FALSE, \
-                games BOOL DEFAULT FALSE\
+                games BOOL DEFAULT NULL\
             )\
         ",
         "CREATE TABLE IF NOT EXISTS \