1
0
Fork 0
mirror of synced 2024-06-30 12:10:26 +12:00

Changed directory before importing config file, to stop it from erroring out when looking for required files

This commit is contained in:
phxntxm 2016-08-17 15:46:20 -05:00
parent 556022abbc
commit 8919b1210c
4 changed files with 134 additions and 104 deletions

2
bot.py
View file

@ -6,6 +6,7 @@ import logging
import datetime import datetime
import pendulum import pendulum
import os import os
os.chdir(os.path.dirname(os.path.realpath(__file__)))
from discord.ext import commands from discord.ext import commands
from cogs.utils import config from cogs.utils import config
@ -30,7 +31,6 @@ extensions = ['cogs.interaction',
bot = commands.Bot(command_prefix=config.commandPrefix, description=config.botDescription, pm_help=None) bot = commands.Bot(command_prefix=config.commandPrefix, description=config.botDescription, pm_help=None)
discord_logger = logging.getLogger('discord') discord_logger = logging.getLogger('discord')
discord_logger.setLevel(logging.WARNING) discord_logger.setLevel(logging.WARNING)
os.chdir(os.path.dirname(os.path.realpath(__file__)))
log = logging.getLogger() log = logging.getLogger()
log.setLevel(logging.INFO) log.setLevel(logging.INFO)

View file

@ -124,8 +124,9 @@ class Hangman:
Due to the fact that I might not be able to delete a message, I will PM you and ask for the phrase you want. Due to the fact that I might not be able to delete a message, I will PM you and ask for the phrase you want.
The phrase needs to be under 30 characters""" The phrase needs to be under 30 characters"""
# Only have one hangman game per server, since anyone in a server (except the creator) can guess towards the current game # Only have one hangman game per server, since anyone
if self.games.get(ctx.message.server.id) != None: # In a server (except the creator) can guess towards the current game
if self.games.get(ctx.message.server.id) is not None:
await self.bot.say("Sorry but only one Hangman game can be running per server!") await self.bot.say("Sorry but only one Hangman game can be running per server!")
return return
@ -135,11 +136,13 @@ class Hangman:
# Doing this so that while we wait for the phrase, another one cannot be started. # Doing this so that while we wait for the phrase, another one cannot be started.
self.games[ctx.message.server.id] = "placeholder" self.games[ctx.message.server.id] = "placeholder"
# We want to send this message instead of just PM'ing the creator, as some people have PM's turned off/ don't pay attention to them # We want to send this message instead of just PM'ing the creator
# As some people have PM's turned off/ don't pay attention to them
await self.bot.say( await self.bot.say(
"I have just PM'd you {}, please respond there with the phrase you want to start a new hangman game with".format( "I have just PM'd you {}, please respond there with the phrase you want to start a new"
ctx.message.author.display_name)) " hangman game with".format(ctx.message.author.display_name))
# The only reason we save this variable, is so that we can retrieve the PrivateChannel for it, for use in our wait_for_message command # The only reason we save this variable, is so that we can retrieve
# The PrivateChannel for it, for use in our wait_for_message command
_msg = await self.bot.whisper("Please respond with the phrase you would like to use for your new hangman game\n" _msg = await self.bot.whisper("Please respond with the phrase you would like to use for your new hangman game\n"
"Please note that it must be under 30 characters long") "Please note that it must be under 30 characters long")
msg = await self.bot.wait_for_message(timeout=60.0, channel=_msg.channel, check=check) msg = await self.bot.wait_for_message(timeout=60.0, channel=_msg.channel, check=check)

View file

@ -30,7 +30,8 @@ class Mod:
"""This command can be used to set whether or not you want user notificaitons to show """This command can be used to set whether or not you want user notificaitons to show
This will save what channel you run this command in, that will be the channel used to send the notification to This will save what channel you run this command in, that will be the channel used to send the notification to
Provide on, yes, or true to set it on; otherwise it will be turned off""" Provide on, yes, or true to set it on; otherwise it will be turned off"""
# Join/Leave notifications can be kept separate from normal alerts, so we base this channel on it's own and not from alerts # Join/Leave notifications can be kept separate from normal alerts
# So we base this channel on it's own and not from alerts
# When mod logging becomes available, that will be kept to it's own channel if wanted as well # When mod logging becomes available, that will be kept to it's own channel if wanted as well
on_off = ctx.message.channel.id if re.search("(on|yes|true)", on_off.lower()) else None on_off = ctx.message.channel.id if re.search("(on|yes|true)", on_off.lower()) else None
notifications = config.get_content('user_notifications') or {} notifications = config.get_content('user_notifications') or {}
@ -126,10 +127,14 @@ class Mod:
setattr(perm_obj, permissions, True) setattr(perm_obj, permissions, True)
perm_value = perm_obj.value perm_value = perm_obj.value
# This next loop ensures the command given is valid. We need to loop through commands, as self.bot.commands only includes parent commands # This next loop ensures the command given is valid. We need to loop through commands
# So we are splitting the command in parts, looping through the commands and getting the subcommand based on the next part # As self.bot.commands only includes parent commands
# If we try to access commands of a command that isn't a group, we'll hit an AttributeError, meaning an invalid command was given # So we are splitting the command in parts, looping through the commands
# If we loop through and don't find anything, cmd will still be None, and we'll report an invalid was given as well # And getting the subcommand based on the next part
# If we try to access commands of a command that isn't a group
# We'll hit an AttributeError, meaning an invalid command was given
# If we loop through and don't find anything, cmd will still be None
# And we'll report an invalid was given as well
cmd = None cmd = None
for part in msg[0:len(msg) - 1]: for part in msg[0:len(msg) - 1]:
try: try:
@ -147,7 +152,8 @@ class Mod:
return return
# Two cases I use should never have custom permissions setup on them, is_owner for obvious reasons # Two cases I use should never have custom permissions setup on them, is_owner for obvious reasons
# The other case is if I'm using the default has_permissions case, which means I do not want to check custom permissions at all # The other case is if I'm using the default has_permissions case
# Which means I do not want to check custom permissions at all
# Currently the second case is only on adding and removing permissions, to avoid abuse on these # Currently the second case is only on adding and removing permissions, to avoid abuse on these
for check in cmd.checks: for check in cmd.checks:
if "is_owner" == check.__name__ or re.search("has_permissions", str(check)) is not None: if "is_owner" == check.__name__ or re.search("has_permissions", str(check)) is not None:
@ -159,7 +165,6 @@ class Mod:
.format(permissions, "\n".join(valid_perms))) .format(permissions, "\n".join(valid_perms)))
return return
custom_perms = config.get_content('custom_permissions') or {} custom_perms = config.get_content('custom_permissions') or {}
server_perms = custom_perms.get(ctx.message.server.id) or {} server_perms = custom_perms.get(ctx.message.server.id) or {}
# Save the qualified name, so that we don't get screwed up by aliases # Save the qualified name, so that we don't get screwed up by aliases
@ -181,8 +186,9 @@ class Mod:
return return
cmd = None cmd = None
# This is the same loop as the add command, we need this to get the command object so we can get the qualified_name # This is the same loop as the add command, we need this to get the
for part in msg[0:len(msg) - 1]: # command object so we can get the qualified_name
for part in command[0:len(command) - 1]:
try: try:
if cmd is None: if cmd is None:
cmd = self.bot.commands.get(part) cmd = self.bot.commands.get(part)

View file

@ -10,6 +10,7 @@ import random
class Board: class Board:
def __init__(self, player1, player2): def __init__(self, player1, player2):
# Our board just needs to be a 3x3 grid. To keep formatting nice, each one is going to be a space to start
self.board = [[' ', ' ', ' '], [' ', ' ', ' '], [' ', ' ', ' ']] self.board = [[' ', ' ', ' '], [' ', ' ', ' '], [' ', ' ', ' ']]
# Randomize who goes first when the board is created # Randomize who goes first when the board is created
@ -22,81 +23,73 @@ class Board:
self.X_turn = True self.X_turn = True
def full(self): def full(self):
# For this check we just need to see if there is a space anywhere, if there is then we're not full
for row in self.board: for row in self.board:
if ' ' in row: if ' ' in row:
return False return False
return True return True
def can_play(self, player): def can_play(self, player):
# Simple check to see if the player is the one that's up
if self.X_turn: if self.X_turn:
return player == self.challengers['x'] return player == self.challengers['x']
else: else:
return player == self.challengers['o'] return player == self.challengers['o']
def update(self, x, y): def update(self, x, y):
# If it's x's turn, we place an x, otherwise place an o
letter = 'x' if self.X_turn else 'o' letter = 'x' if self.X_turn else 'o'
# Make sure the place we're trying to update is blank, we can't override something
if self.board[x][y] == ' ': if self.board[x][y] == ' ':
self.board[x][y] = letter self.board[x][y] = letter
else: else:
return False return False
# If we were succesful in placing the piece, we need to switch whose turn it is
self.X_turn = not self.X_turn self.X_turn = not self.X_turn
return True return True
def check(self): def check(self):
# Checking all possiblities will be fun... # Checking all possiblities will be fun...
# First base off the top-left corner, see if any possiblities with that match # First base off the top-left corner, see if any possiblities with that match
# We need to also make sure that the place is not blank, so that 3 in a row that are blank doesn't cause a 'win'
# Top-left, top-middle, top right
if self.board[0][0] == self.board[0][1] and self.board[0][0] == self.board[0][2] and self.board[0][0] != ' ': if self.board[0][0] == self.board[0][1] and self.board[0][0] == self.board[0][2] and self.board[0][0] != ' ':
if self.board[0][0] == 'x': return self.challengers[self.board[0][0]]
return self.challengers['x'] # Top-left, middle-left, bottom-left
else:
return self.challengers['o']
if self.board[0][0] == self.board[1][0] and self.board[0][0] == self.board[2][0] and self.board[0][0] != ' ': if self.board[0][0] == self.board[1][0] and self.board[0][0] == self.board[2][0] and self.board[0][0] != ' ':
if self.board[0][0] == 'x': return self.challengers[self.board[0][0]]
return self.challengers['x'] # Top-left, middle, bottom-right
else:
return self.challengers['o']
if self.board[0][0] == self.board[1][1] and self.board[0][0] == self.board[2][2] and self.board[0][0] != ' ': if self.board[0][0] == self.board[1][1] and self.board[0][0] == self.board[2][2] and self.board[0][0] != ' ':
if self.board[0][0] == 'x': return self.challengers[self.board[0][0]]
return self.challengers['x']
else:
return self.challengers['o']
# Next check the top-right corner, not re-checking the last possiblity that included it # Next check the top-right corner, not re-checking the last possiblity that included it
# Top-right, middle-right, bottom-right
if self.board[0][2] == self.board[1][2] and self.board[0][2] == self.board[2][2] and self.board[0][2] != ' ': if self.board[0][2] == self.board[1][2] and self.board[0][2] == self.board[2][2] and self.board[0][2] != ' ':
if self.board[0][2] == 'x': return self.challengers[self.board[0][2]]
return self.challengers['x'] # Top-right, middle, bottom-left
else:
return self.challengers['o']
if self.board[0][2] == self.board[1][1] and self.board[0][2] == self.board[2][0] and self.board[0][2] != ' ': if self.board[0][2] == self.board[1][1] and self.board[0][2] == self.board[2][0] and self.board[0][2] != ' ':
if self.board[0][2] == 'x': return self.challengers[self.board[0][2]]
return self.challengers['x']
else:
return self.challengers['o']
# Next up, bottom-right corner, only one possiblity to check here, other two have been checked # Next up, bottom-right corner, only one possiblity to check here, other two have been checked
# Bottom-right, bottom-middle, bottom-left
if self.board[2][2] == self.board[2][1] and self.board[2][2] == self.board[2][0] and self.board[2][2] != ' ': if self.board[2][2] == self.board[2][1] and self.board[2][2] == self.board[2][0] and self.board[2][2] != ' ':
if self.board[2][2] == 'x': return self.challengers[self.board[2][2]]
return self.challengers['x']
else:
return self.challengers['o']
# No need to check the bottom-left, all posiblities have been checked now # No need to check the bottom-left, all posiblities have been checked now
# Base things off the middle now, as we only need the two 'middle' possiblites that aren't diagonal # Base things off the middle now, as we only need the two 'middle' possiblites that aren't diagonal
# Top-middle, middle, bottom-middle
if self.board[1][1] == self.board[0][1] and self.board[1][1] == self.board[2][1] and self.board[1][1] != ' ': if self.board[1][1] == self.board[0][1] and self.board[1][1] == self.board[2][1] and self.board[1][1] != ' ':
if self.board[1][1] == 'x': return self.challengers[self.board[1][1]]
return self.challengers['x'] # Left-middle, middle, right-middle
else:
return self.challengers['o']
if self.board[1][1] == self.board[1][0] and self.board[1][1] == self.board[1][2] and self.board[1][1] != ' ': if self.board[1][1] == self.board[1][0] and self.board[1][1] == self.board[1][2] and self.board[1][1] != ' ':
if self.board[1][1] == 'x': return self.challengers[self.board[1][1]]
return self.challengers['x']
else:
return self.challengers['o']
# Otherwise nothing has been found, return None # Otherwise nothing has been found, return None
return None return None
def __str__(self): def __str__(self):
# Simple formatting here when you look at it, enough spaces to even out where everything is
# Place whatever is at the grid in place, whether it's x, o, or blank
_board = " {} | {} | {}\n".format(self.board[0][0], self.board[0][1], self.board[0][2]) _board = " {} | {} | {}\n".format(self.board[0][0], self.board[0][1], self.board[0][2])
_board += "———————————————\n" _board += "———————————————\n"
_board += " {} | {} | {}\n".format(self.board[1][0], self.board[1][1], self.board[1][2]) _board += " {} | {} | {}\n".format(self.board[1][0], self.board[1][1], self.board[1][2])
@ -105,18 +98,9 @@ class Board:
return "```\n{}```".format(_board) return "```\n{}```".format(_board)
class TicTacToe: def update_records(winner, loser):
def __init__(self, bot): # This is the exact same formula as the battling update.
self.bot = bot # The only difference is I use the word "match" instead of "battle"
self.boards = {}
def create(self, server_id, player1, player2):
self.boards[server_id] = Board(player1, player2)
# Return whoever is x's so that we know who is going first
return self.boards[server_id].challengers['x']
def update_records(self, winner, loser):
matches = config.get_content('tictactoe') matches = config.get_content('tictactoe')
if matches is None: if matches is None:
matches = {winner.id: "1-0", loser.id: "0-1"} matches = {winner.id: "1-0", loser.id: "0-1"}
@ -157,6 +141,18 @@ class TicTacToe:
return config.save_content('tictactoe', matches) return config.save_content('tictactoe', matches)
class TicTacToe:
def __init__(self, bot):
self.bot = bot
self.boards = {}
def create(self, server_id, player1, player2):
self.boards[server_id] = Board(player1, player2)
# Return whoever is x's so that we know who is going first
return self.boards[server_id].challengers['x']
@commands.group(pass_context=True, aliases=['tic', 'tac', 'toe'], no_pm=True, invoke_without_command=True) @commands.group(pass_context=True, aliases=['tic', 'tac', 'toe'], no_pm=True, invoke_without_command=True)
@checks.custom_perms(send_messages=True) @checks.custom_perms(send_messages=True)
async def tictactoe(self, ctx, *, option: str): async def tictactoe(self, ctx, *, option: str):
@ -166,9 +162,12 @@ class TicTacToe:
Provide top, left, bottom, right, middle as you want to mark where to play on the board""" Provide top, left, bottom, right, middle as you want to mark where to play on the board"""
player = ctx.message.author player = ctx.message.author
board = self.boards.get(ctx.message.server.id) board = self.boards.get(ctx.message.server.id)
# Need to make sure the board exists before allowing someone to play
if not board: if not board:
await self.bot.say("There are currently no Tic-Tac-Toe games setup!") await self.bot.say("There are currently no Tic-Tac-Toe games setup!")
return return
# Now just make sure the person can play, this will fail if o's are up and x tries to play
# Or if someone else entirely tries to play
if not board.can_play(player): if not board.can_play(player):
await self.bot.say("You cannot play right now!") await self.bot.say("You cannot play right now!")
return return
@ -180,13 +179,14 @@ class TicTacToe:
left = re.search('left', option) left = re.search('left', option)
right = re.search('right', option) right = re.search('right', option)
# Check if what was given was valid # Just a bit of logic to ensure nothing that doesn't make sense is given
if top and bottom: if top and bottom:
await self.bot.say("That is not a valid location! Use some logic, come on!") await self.bot.say("That is not a valid location! Use some logic, come on!")
return return
if left and right: if left and right:
await self.bot.say("That is not a valid location! Use some logic, come on!") await self.bot.say("That is not a valid location! Use some logic, come on!")
return return
# Make sure at least something was given
if not top and not bottom and not left and not right and not middle: if not top and not bottom and not left and not right and not middle:
await self.bot.say("Please provide a valid location to play!") await self.bot.say("Please provide a valid location to play!")
return return
@ -200,30 +200,46 @@ class TicTacToe:
y = 0 y = 0
if right: if right:
y = 2 y = 2
# If middle was given and nothing else, we need the exact middle
if middle and not (top or bottom or left or right): if middle and not (top or bottom or left or right):
x = 1 x = 1
y = 1 y = 1
# If just top or bottom was given, we assume this means top-middle or bottom-middle
# We don't need to do anything fancy with top/bottom as it's already assigned, just assign middle
if (top or bottom) and not (left or right): if (top or bottom) and not (left or right):
y = 1 y = 1
# If just left or right was given, we assume this means left-middle or right-middle
# We don't need to do anything fancy with left/right as it's already assigned, just assign middle
elif (left or right) and not (top or bottom): elif (left or right) and not (top or bottom):
x = 1 x = 1
# If all checks have been made, x and y should now be defined correctly based on the matches, and we can go ahead and: # If all checks have been made, x and y should now be defined
# Correctly based on the matches, and we can go ahead and update the board
# We've already checked if the author can play, so there's no need to make any additional checks here
# board.update will handle which letter is placed
# If it returns false however, then someone has already played in that spot and nothing was updated
if not board.update(x, y): if not board.update(x, y):
await self.bot.say("Someone has already played there!") await self.bot.say("Someone has already played there!")
return return
# Next check if there's a winner
winner = board.check() winner = board.check()
if winner: if winner:
# Get the loser based on whether or not the winner is x's
# If the winner is x's, the loser is o's...obviously, and vice-versa
loser = board.challengers['x'] if board.challengers['x'] != winner else board.challengers['o'] loser = board.challengers['x'] if board.challengers['x'] != winner else board.challengers['o']
await self.bot.say("{} has won this game of TicTacToe, better luck next time {}".format(winner.display_name, await self.bot.say("{} has won this game of TicTacToe, better luck next time {}".format(winner.display_name,
loser.display_name)) loser.display_name))
# Handle updating ratings based on the winner and loser
self.update_records(winner, loser) update_records(winner, loser)
# This game has ended, delete it so another one can be made
del self.boards[ctx.message.server.id] del self.boards[ctx.message.server.id]
else: else:
# If no one has won, make sure the game is not full. If it has, delete the board and say it was a tie
if board.full(): if board.full():
await self.bot.say("This game has ended in a tie!") await self.bot.say("This game has ended in a tie!")
del self.boards[ctx.message.server.id] del self.boards[ctx.message.server.id]
# If no one has won, and the game has not ended in a tie, print the new updated board
# TODO: edit in place instead of printing?
else: else:
await self.bot.say(str(board)) await self.bot.say(str(board))
@ -232,12 +248,17 @@ class TicTacToe:
async def start_game(self, ctx, player2: discord.Member): async def start_game(self, ctx, player2: discord.Member):
"""Starts a game of tictactoe with another player""" """Starts a game of tictactoe with another player"""
player1 = ctx.message.author player1 = ctx.message.author
# For simplicities sake, only allow one game on a server at a time.
# Things can easily get confusing (on the server's end) if we allow more than one
if self.boards.get(ctx.message.server.id) is not None: if self.boards.get(ctx.message.server.id) is not None:
await self.bot.say("Sorry but only one Tic-Tac-Toe game can be running per server!") await self.bot.say("Sorry but only one Tic-Tac-Toe game can be running per server!")
return return
# Create the board and return who has been decided to go first
x_player = self.create(ctx.message.server.id, player1, player2) x_player = self.create(ctx.message.server.id, player1, player2)
fmt = "A tictactoe game has just started between {} and {}".format(player1.display_name, player2.display_name) fmt = "A tictactoe game has just started between {} and {}".format(player1.display_name, player2.display_name)
# Print the board too just because
fmt += str(self.boards[ctx.message.server.id]) fmt += str(self.boards[ctx.message.server.id])
# We don't need to do anything weird with assigning x_player to something, it is already a member object, just use it
fmt += "I have decided at random, and {} is going to be x's this game. It is your turn first!".format( fmt += "I have decided at random, and {} is going to be x's this game. It is your turn first!".format(
x_player.display_name) x_player.display_name)
await self.bot.say(fmt) await self.bot.say(fmt)