Merge pull request #102 from NikolajDanger/PEP-fixin

Pep fixin
This commit is contained in:
Nikolaj Gade
2022-01-28 13:35:04 +01:00
committed by GitHub
27 changed files with 1586 additions and 1843 deletions

1
.gitignore vendored
View File

@ -157,6 +157,7 @@ gwendolyn/resources/star_wars/destinyPoints.txt
gwendolyn/resources/plex/
gwendolyn/resources/games/hilo/
gwendolyn/resources/games/blackjack_tables/
gwendolyn/resources/games/images/
gwendolyn/resources/games/old_images/
gwendolyn/resources/games/connect_four_boards/
gwendolyn/resources/games/hex_boards/

View File

@ -52,26 +52,6 @@ class BlackjackCog(commands.Cog):
"""Enter the game of blackjack with a bet."""
await self.bot.games.blackjack.enter_game(ctx, bet)
@cog_ext.cog_subcommand(**params["blackjack_stand"])
async def blackjack_stand(self, ctx, hand=""):
"""Stand on your hand in blackjack."""
await self.bot.games.blackjack.stand(ctx, hand)
@cog_ext.cog_subcommand(**params["blackjack_hit"])
async def blackjack_hit(self, ctx, hand=0):
"""Hit on your hand in blackjack."""
await self.bot.games.blackjack.hit(ctx, hand)
@cog_ext.cog_subcommand(**params["blackjack_double"])
async def blackjack_double(self, ctx, hand=0):
"""Double in blackjack."""
await self.bot.games.blackjack.double(ctx, hand)
@cog_ext.cog_subcommand(**params["blackjack_split"])
async def blackjack_split(self, ctx, hand=0):
"""Split your hand in blackjack."""
await self.bot.games.blackjack.split(ctx, hand)
@cog_ext.cog_subcommand(**params["blackjack_hilo"])
async def blackjack_hilo(self, ctx):
"""Get the hilo value for the deck in blackjack."""

View File

@ -18,13 +18,13 @@ class LookupCog(commands.Cog):
@cog_ext.cog_slash(**params["spell"])
async def spell(self, ctx, query):
"""Look up a spell."""
await self.bot.lookup_funcs.spellFunc(ctx, query)
await self.bot.lookup_funcs.spell_func(ctx, query)
# Looks up a monster
@cog_ext.cog_slash(**params["monster"])
async def monster(self, ctx, query):
"""Look up a monster."""
await self.bot.lookup_funcs.monsterFunc(ctx, query)
await self.bot.lookup_funcs.monster_func(ctx, query)
def setup(bot):

View File

@ -1,6 +1,7 @@
"""Contains the MiscCog, which deals with miscellaneous commands."""
from discord.ext import commands # Has the cog class
from discord_slash import cog_ext # Used for slash commands
from discord_slash.context import SlashContext
from gwendolyn.utils import get_params # pylint: disable=import-error
@ -19,77 +20,77 @@ class MiscCog(commands.Cog):
self.nerd_shit = bot.other.nerd_shit
@cog_ext.cog_slash(**params["ping"])
async def ping(self, ctx):
async def ping(self, ctx: SlashContext):
"""Send the bot's latency."""
await ctx.send(f"Pong!\nLatency is {round(self.bot.latency * 1000)}ms")
@cog_ext.cog_slash(**params["stop"])
async def stop(self, ctx):
async def stop(self, ctx: SlashContext):
"""Stop the bot."""
await self.bot.stop(ctx)
@cog_ext.cog_slash(**params["help"])
async def help_command(self, ctx, command=""):
async def help_command(self, ctx: SlashContext, command=""):
"""Get help for commands."""
await self.bot.other.helpFunc(ctx, command)
@cog_ext.cog_slash(**params["thank"])
async def thank(self, ctx):
async def thank(self, ctx: SlashContext):
"""Thank the bot."""
await ctx.send("You're welcome :blush:")
@cog_ext.cog_slash(**params["hello"])
async def hello(self, ctx):
async def hello(self, ctx: SlashContext):
"""Greet the bot."""
await self.bot.other.helloFunc(ctx)
@cog_ext.cog_slash(**params["roll"])
async def roll(self, ctx, dice="1d20"):
async def roll(self, ctx: SlashContext, dice="1d20"):
"""Roll dice."""
await self.bot.other.rollDice(ctx, dice)
@cog_ext.cog_slash(**params["image"])
async def image(self, ctx):
async def image(self, ctx: SlashContext):
"""Get a random image from Bing."""
await self.bot.other.imageFunc(ctx)
@cog_ext.cog_slash(**params["movie"])
async def movie(self, ctx):
async def movie(self, ctx: SlashContext):
"""Get a random movie from the Plex server."""
await self.bot.other.movieFunc(ctx)
@cog_ext.cog_slash(**params["name"])
async def name(self, ctx):
async def name(self, ctx: SlashContext):
"""Generate a random name."""
await self.generators.nameGen(ctx)
@cog_ext.cog_slash(**params["tavern"])
async def tavern(self, ctx):
async def tavern(self, ctx: SlashContext):
"""Generate a random tavern name."""
await self.generators.tavernGen(ctx)
@cog_ext.cog_slash(**params["wiki"])
async def wiki(self, ctx, page=""):
async def wiki(self, ctx: SlashContext, wiki_page=""):
"""Get a page on a fandom wiki."""
await self.bot.other.findWikiPage(ctx, page)
@cog_ext.cog_slash(**params["add_movie"])
async def add_movie(self, ctx, movie):
async def add_movie(self, ctx: SlashContext, movie):
"""Search for a movie and add it to the Plex server."""
await self.plex.request_movie(ctx, movie)
@cog_ext.cog_slash(**params["add_show"])
async def add_show(self, ctx, show):
async def add_show(self, ctx: SlashContext, show):
"""Search for a show and add it to the Plex server."""
await self.plex.request_show(ctx, show)
@cog_ext.cog_slash(**params["downloading"])
async def downloading(self, ctx, parameters="-d"):
async def downloading(self, ctx: SlashContext, parameters="-d"):
"""Get the current downloading torrents."""
await self.plex.downloading(ctx, parameters)
@cog_ext.cog_slash(**params["wolf"])
async def wolf(self, ctx, query):
async def wolf(self, ctx: SlashContext, query):
"""Perform a search on Wolfram Alpha."""
await self.nerd_shit.wolfSearch(ctx, query)

11
gwendolyn/exceptions.py Normal file
View File

@ -0,0 +1,11 @@
"""Exceptions for Gwendolyn"""
class GameNotInDatabase(Exception):
def __init__(self, game: str, channel: str):
self.message = f"There is no {game} game in channel {channel}"
super().__init__(self.message)
class InvalidInteraction(Exception):
def __init__(self, custom_id: str, decoded: str):
self.message = f"{custom_id = }, {decoded = }"
super().__init__(self.message)

File diff suppressed because it is too large Load Diff

View File

@ -22,12 +22,46 @@ create_actionrow)
from discord_slash.model import ButtonStyle
from gwendolyn.utils import encode_id
from .game_base import BoardGame
ROWCOUNT = 6
COLUMNCOUNT = 7
def _encode_board_string(board: list):
string = [str(i) for row in board for i in row]
class ConnectFour():
while len(string) > 0 and string[0] == "0":
string = string[1:]
if string == "":
string = "0"
dec = 0
for i, digit in enumerate(string[::-1]):
dec += (3**i)*int(digit)
return str(dec)
def _decode_board_string(board_string: str):
dec = int(board_string)
string = []
while dec:
string.append(str(dec % 3))
dec = dec // 3
while len(string) < ROWCOUNT * COLUMNCOUNT:
string.append("0")
string = string[::-1]
board = [
[int(x) for x in string[i*COLUMNCOUNT:i*COLUMNCOUNT+COLUMNCOUNT]]
for i in range(ROWCOUNT)]
return board
class ConnectFour(BoardGame):
"""
Deals with connect four commands and logic.
@ -41,8 +75,7 @@ class ConnectFour():
def __init__(self, bot):
"""Initialize the class."""
self.bot = bot
self.draw = DrawConnectFour(bot)
super().__init__(bot, "connectfour", DrawConnectFour)
self.get_name = self.bot.database_funcs.get_name
# pylint: disable=invalid-name
self.AISCORES = {
@ -57,39 +90,6 @@ class ConnectFour():
}
# pylint: enable=invalid-name
def _encode_board_string(self, board: list):
string = [str(i) for row in board for i in row]
while len(string) > 0 and string[0] == "0":
string = string[1:]
if string == "":
string = "0"
dec = 0
for i, digit in enumerate(string[::-1]):
dec += (3**i)*int(digit)
return str(dec)
def _decode_board_string(self, board_string: str):
dec = int(board_string)
string = []
while dec:
string.append(str(dec % 3))
dec = dec // 3
while len(string) < ROWCOUNT * COLUMNCOUNT:
string.append("0")
string = string[::-1]
board = [
[int(x) for x in string[i*COLUMNCOUNT:i*COLUMNCOUNT+COLUMNCOUNT]]
for i in range(ROWCOUNT)]
return board
async def start(self, ctx: SlashContext,
opponent: Union[int, discord.User]):
"""
@ -106,128 +106,90 @@ class ConnectFour():
searches when minimaxing.
"""
await self.bot.defer(ctx)
user = ctx.author.id
channel = str(ctx.channel_id)
started_game = False
can_start = True
opponent_info = await self._test_opponent(ctx, opponent)
if not opponent_info:
return
if isinstance(opponent, int):
# Opponent is Gwendolyn
if opponent in range(1, 6):
difficulty = int(opponent)
difficulty_text = f" with difficulty {difficulty}"
opponent = self.bot.user.id
else:
send_message = "Difficulty doesn't exist"
log_message = "They challenged a difficulty that doesn't exist"
can_start = False
elif isinstance(opponent, discord.User):
if opponent.bot:
# User has challenged a bot
if opponent == self.bot.user:
# It was Gwendolyn
difficulty = 3
difficulty_text = f" with difficulty {difficulty}"
opponent = self.bot.user.id
else:
send_message = "You can't challenge a bot!"
log_message = "They tried to challenge a bot"
can_start = False
else:
# Opponent is another player
if ctx.author != opponent:
opponent = opponent.id
difficulty = 5
difficulty_text = ""
else:
send_message = "You can't play against yourself"
log_message = "They tried to play against themself"
can_start = False
difficulty = opponent_info[0]
difficulty_text = opponent_info[1]
if can_start:
board = [[0 for _ in range(COLUMNCOUNT)] for _ in range(ROWCOUNT)]
players = [user, opponent]
random.shuffle(players)
board = [[0 for _ in range(COLUMNCOUNT)] for _ in range(ROWCOUNT)]
players = [ctx.author.id, opponent]
random.shuffle(players)
self.draw.draw_image(channel, board, 0, [0,0], "", players)
self.draw.draw_image(channel, board, players, [0, [0,0], ""], players)
gwendolyn_turn = (players[0] == self.bot.user.id)
started_game = True
opponent_name = self.get_name(f"#{opponent}")
turn_name = self.get_name(f"#{players[0]}")
opponent_name = self.get_name(f"#{opponent}")
turn_name = self.get_name(f"#{players[0]}")
started_text = "Started game against {}{}.".format(
opponent_name,
difficulty_text
)
turn_text = f"It's {turn_name}'s turn"
send_message = f"{started_text} {turn_text}"
log_message = "They started a game"
self.bot.log(log_message)
await ctx.send(send_message)
started_text = "Started game against {}{}.".format(
opponent_name,
difficulty_text
)
turn_text = f"It's {turn_name}'s turn"
await ctx.send(f"{started_text} {turn_text}")
self.bot.log("They started a game")
# Sets the whole game in motion
if started_game:
boards_path = "gwendolyn/resources/games/connect_four_boards/"
file_path = f"{boards_path}board{ctx.channel_id}.png"
image_message = await ctx.send(file=discord.File(file_path))
board_string = self._encode_board_string(board)
if gwendolyn_turn:
await self._connect_four_ai(
ctx, board_string, players, difficulty, image_message.id
)
else:
buttons = []
for i in range(7):
custom_id = encode_id(
[
"connectfour",
"place",
str(players[0]),
board_string,
str(i),
str(players[0]),
str(players[1]),
str(difficulty),
str(image_message.id)
]
)
buttons.append(create_button(
style=ButtonStyle.blue,
label=str(i+1),
custom_id=custom_id,
disabled=(board[0][i] != 0)
))
boards_path = "gwendolyn/resources/games/connect_four_boards/"
file_path = f"{boards_path}board{ctx.channel_id}.png"
image_message = await ctx.send(file=discord.File(file_path))
board_string = _encode_board_string(board)
if (players[0] == self.bot.user.id):
await self._connect_four_ai(
ctx, board_string, players, difficulty, image_message.id
)
else:
buttons = []
for i in range(7):
custom_id = encode_id(
[
"connectfour",
"end",
"place",
str(players[0]),
board_string,
str(i),
str(players[0]),
str(players[1]),
str(difficulty),
str(image_message.id)
]
)
buttons.append(create_button(
style=ButtonStyle.red,
label="Surrender",
custom_id=custom_id
style=ButtonStyle.blue,
label=str(i+1),
custom_id=custom_id,
disabled=(board[0][i] != 0)
))
action_rows = []
for x in range(((len(buttons)-1)//4)+1):
row_buttons = buttons[
(x*4):(min(len(buttons),x*4+4))
]
action_rows.append(create_actionrow(*row_buttons))
custom_id = encode_id(
[
"connectfour",
"end",
str(players[0]),
str(players[1]),
str(image_message.id)
]
)
buttons.append(create_button(
style=ButtonStyle.red,
label="Surrender",
custom_id=custom_id
))
await image_message.edit(
components=action_rows
)
action_rows = []
for x in range(((len(buttons)-1)//4)+1):
row_buttons = buttons[
(x*4):(min(len(buttons),x*4+4))
]
action_rows.append(create_actionrow(*row_buttons))
await image_message.edit(
components=action_rows
)
async def place_piece(self, ctx: ComponentContext, board_string: str,
column: int, players: list[int], difficulty: int,
@ -246,7 +208,7 @@ class ConnectFour():
user_name = self.get_name(f"#{placer}")
placed_piece = False
board = self._decode_board_string(board_string)
board = _decode_board_string(board_string)
board = self._place_on_board(board, player_number, column)
if board is None:
@ -300,7 +262,7 @@ class ConnectFour():
if game_won:
self._end_game(winner, players, difficulty)
else:
board_string = self._encode_board_string(board)
board_string = _encode_board_string(board)
if gwendolyn_turn:
await self._connect_four_ai(
ctx, board_string, players, difficulty, image_message.id
@ -513,7 +475,7 @@ class ConnectFour():
self.bot.log("Figuring out best move")
board = self._decode_board_string(board_string)
board = _decode_board_string(board_string)
player = players.index(self.bot.user.id)+1
scores = [-math.inf for _ in range(COLUMNCOUNT)]
@ -748,7 +710,7 @@ class DrawConnectFour():
White, but with the alpha set to win_bar_alpha.
"""
def __init__(self, bot):
def __init__(self, bot, game):
"""Initialize the class."""
self.bot = bot
self.get_name = self.bot.database_funcs.get_name
@ -797,8 +759,8 @@ class DrawConnectFour():
# pylint: enable=invalid-name
# Draws the whole thing
def draw_image(self, channel: str, board: list, winner: int,
win_coordinates: list, win_direction: str, players: list):
def draw_image(self, channel: str, board: list, players: list,
win_info: list):
"""
Draw an image of the connect four board.
@ -815,8 +777,8 @@ class DrawConnectFour():
self._draw_pieces(drawer, board)
if winner != 0:
self._draw_win(background, win_coordinates, win_direction)
if win_info[0] != 0:
self._draw_win(background, win_info[1], win_info[2])
self._draw_footer(drawer, players)

View File

@ -0,0 +1,309 @@
"""Base class for the games."""
import random
from typing import Union
from discord import File, User
from discord.abc import Messageable
from discord_slash.utils.manage_components import (create_button,
create_actionrow)
from discord_slash.context import InteractionContext as IntCont
from PIL import ImageFont, Image, ImageDraw
from gwendolyn.exceptions import GameNotInDatabase
from gwendolyn.utils import encode_id
class GameBase():
"""The base class for the games."""
def __init__(self, bot, game_name: int, drawer):
"""Initialize the class."""
self.bot = bot
self.long_strings = self.bot.long_strings
self.resources = "gwendolyn/resources/games/"
self.game_name = game_name
self.draw = drawer(bot, self)
def _get_action_rows(self, buttons: list[tuple[str, list]]):
self.bot.log("Generation action rows")
button_objects = []
for label, data, style in buttons:
custom_id = encode_id([self.game_name] + data)
button_objects.append(create_button(
style=style,
label=label,
custom_id=custom_id
))
action_rows = []
for i in range(((len(button_objects)-1)//5)+1):
action_rows.append(create_actionrow(*button_objects[i*5:i*5+5]))
return action_rows
async def _send_image(self, channel: Messageable,
buttons: list[tuple[str, list]] = None, delete=True):
self.draw.draw(str(channel.id))
file_path = f"{self.resources}images/{self.game_name}{channel.id}.png"
old_image = await channel.send(
file=File(file_path), delete_after=120 if delete else None)
if buttons is not None and len(buttons) < 25:
await old_image.edit(components = self._get_action_rows(buttons))
return old_image
class DatabaseGame(GameBase):
"""The base class for the games."""
def __init__(self, bot, game_name, drawer):
"""Initialize the class."""
super().__init__(bot, game_name, drawer)
self.database = self.bot.database
self.old_images_path = f"{self.resources}old_images/{self.game_name}"
def access_document(self, channel: str, collection_name: str="games",
raise_missing_error: bool=True):
collection = self.bot.database[f"{self.game_name} {collection_name}"]
game = collection.find_one({"_id": channel})
if game is None and raise_missing_error:
raise GameNotInDatabase(self.game_name, channel)
return game
def _test_document(self, channel: str, collection_name: str="games"):
collection = self.bot.database[f"{self.game_name} {collection_name}"]
game = collection.find_one({"_id": channel})
return game is not None
def _update_document(self, channel: str, updater: dict,
collection_name: str="games"):
self.database[f"{self.game_name} {collection_name}"].update_one(
{"_id": channel},
updater,
upsert=True
)
def _delete_document(self, channel: str, collection_name: str="games"):
self.database[f"{self.game_name} {collection_name}"].delete_one(
{"_id": channel}
)
def _insert_document(self, data: dict, collection_name: str="games"):
self.database[f"{self.game_name} {collection_name}"].insert_one(data)
async def _delete_old_image(self, channel: Messageable):
with open(self.old_images_path + str(channel.id), "r") as file_pointer:
old_image = await channel.fetch_message(int(file_pointer.read()))
await old_image.delete()
async def _send_image(self, channel: Messageable,
buttons: list[tuple[str, list]] = None, delete=True):
old_image = await super()._send_image(channel, buttons, delete)
with open(self.old_images_path + str(channel.id), "w") as file_pointer:
file_pointer.write(str(old_image.id))
async def _start_new(self, channel: Messageable, new_game: dict,
buttons: list[tuple[str, list]] = None):
self._insert_document(new_game)
await self._send_image(channel, buttons)
async def _end_game(self, channel: Messageable):
await self._delete_old_image(channel)
await self._send_image(channel, delete=False)
self._delete_document(str(channel.id))
class CardGame(DatabaseGame):
"""The class for card games."""
def __init__(self, bot, game_name, drawer, deck_used):
"""Initialize the class."""
super().__init__(bot, game_name, drawer)
self.decks_used = deck_used
def _shuffle_cards(self, channel: str):
self.bot.log(f"Shuffling cards for {self.game_name}")
with open(f"{self.resources}deck_of_cards.txt", "r") as file_pointer:
deck = file_pointer.read()
all_decks = deck.split("\n") * self.decks_used
random.shuffle(all_decks)
self._update_document(
channel,
{"$set": {"_id": channel, "cards": all_decks}},
"cards"
)
def _draw_card(self, channel: str):
"""
Draw a card from the stack.
*Parameters*
------------
channel: str
The id of the channel the card is drawn in.
"""
self.bot.log("drawing a card")
drawn_card = self.access_document(channel, "cards")["cards"][0]
self._update_document(channel, {"$pop": {"cards": -1}}, "cards")
return drawn_card
class BoardGame(GameBase):
async def _test_opponent(self, ctx: IntCont, opponent: Union[int, User]):
if isinstance(opponent, int):
# Opponent is Gwendolyn
if opponent in range(1, 6):
difficulty = int(opponent)
difficulty_text = f" with difficulty {difficulty}"
opponent = self.bot.user.id
else:
await ctx.send("Difficulty doesn't exist")
self.bot.log("They challenged a difficulty that doesn't exist")
return False
elif isinstance(opponent, User):
if opponent.bot:
# User has challenged a bot
if opponent == self.bot.user:
# It was Gwendolyn
difficulty = 3
difficulty_text = f" with difficulty {difficulty}"
opponent = self.bot.user.id
else:
await ctx.send("You can't challenge a bot!")
self.bot.log("They tried to challenge a bot")
return False
else:
# Opponent is another player
if ctx.author != opponent:
opponent = opponent.id
difficulty = 5
difficulty_text = ""
else:
await ctx.send("You can't play against yourself")
self.bot.log("They tried to play against themself")
return False
return difficulty, difficulty_text
class BaseDrawer():
"""Class for drawing games."""
def __init__(self, bot, game: GameBase):
self.bot = bot
self.game = game
self.fonts_path = "gwendolyn/resources/fonts/"
self.font_name = "futura-bold"
self.resources = game.resources
game_name = game.game_name
self.default_image = f"{self.resources}default_images/{game_name}.png"
self.images_path = f"{self.resources}images/{game_name}"
def _draw_image(self, game: dict, table: Image.Image):
pass
def draw(self, channel: str):
game = self.game.access_document(channel)
image = Image.open(self.default_image)
self._draw_image(game, image)
self._save_image(image, channel)
def _get_font(self, size: int, font_name: str = None):
if font_name is None:
font_name = self.font_name
return ImageFont.truetype(f"{self.fonts_path}{font_name}.ttf", size)
def _adjust_font(self, max_font_size: int, text: str, max_text_size: int,
font_name: str = None):
font_size = max_font_size
font = self._get_font(font_size, font_name)
text_width = font.getsize(text)[0]
while text_width > max_text_size:
font_size -= 1
font = self._get_font(font_size, font_name)
text_width = font.getsize(text)[0]
return font, font_size
def _save_image(self, image: Image.Image, channel: str):
self.bot.log("Saving image")
image.save(f"{self.images_path}{channel}.png")
def _draw_shadow_text(self, text: str, colors: list[tuple[int, int, int]],
font_size: int):
font = self._get_font(font_size)
offset = font_size//20
shadow_offset = font_size//10
text_size = list(font.getsize(text))
text_size[0] += 1 + (offset * 2)
text_size[1] += 1 + (offset * 2) + shadow_offset
image = Image.new("RGBA", tuple(text_size), (0, 0, 0, 0))
text_image = ImageDraw.Draw(image)
for color_index, color in enumerate(colors[:-1]):
color_offset = offset//(color_index+1)
if color_index == 0:
color_shadow_offset = shadow_offset
else:
color_shadow_offset = 0
for i in range(4):
x_pos = [-1,1][i % 2] * color_offset
y_pos = [-1,1][(i//2) % 2] * color_offset + color_shadow_offset
position = (offset + x_pos, offset + y_pos)
text_image.text(position, text, fill=color, font=font)
text_image.text((offset, offset), text, fill=colors[-1], font=font)
return image
class CardDrawer(BaseDrawer):
def __init__(self, bot, game: GameBase):
super().__init__(bot, game)
self.cards_path = f"{self.resources}cards/"
# pylint: disable=invalid-name
self.CARD_WIDTH = 691
self.CARD_HEIGHT = 1065
self.CARD_BORDER = 100
self.CARD_OFFSET = 125
# pylint: enable=invalid-name
def _set_card_size(self, wanted_card_width: int):
ratio = wanted_card_width / self.CARD_WIDTH
self.CARD_WIDTH = wanted_card_width
self.CARD_HEIGHT = int(self.CARD_HEIGHT * ratio)
self.CARD_BORDER = int(self.CARD_BORDER * ratio)
self.CARD_OFFSET = int(self.CARD_OFFSET * ratio)
def _draw_cards(self, hand: list[str], hidden_cards: int = 0):
image_width = (self.CARD_BORDER * 2) + self.CARD_WIDTH
image_width += (self.CARD_OFFSET * (len(hand)-1))
image_size = (image_width, (self.CARD_BORDER * 2) + self.CARD_HEIGHT)
background = Image.new("RGBA", image_size, (0, 0, 0, 0))
for i, card in enumerate(hand):
position = (
self.CARD_BORDER + (self.CARD_OFFSET*i),
self.CARD_BORDER
)
if i + hidden_cards < len(hand):
card_image = Image.open(f"{self.cards_path}{card.upper()}.png")
else:
card_image = Image.open(f"{self.cards_path}red_back.png")
card_image = card_image.resize(
(self.CARD_WIDTH, self.CARD_HEIGHT),
resample=Image.BILINEAR
)
background.paste(card_image, position, card_image)
return background

View File

@ -8,13 +8,13 @@ Deals with commands and logic for hangman games.
DrawHangman()
Draws the image shown to the player.
"""
import os
import datetime # Used for generating the game id
import string # string.ascii_uppercase used
import math # Used by DrawHangman(), mainly for drawing circles
import random # Used to draw poorly
import requests # Used for getting the word in Hangman.start()
import discord # Used for discord.file and type hints
import os
from discord_slash.utils.manage_components import (create_button,
create_actionrow)
@ -50,10 +50,10 @@ class Hangman():
The parameters to pass to every api call.
"""
self.bot = bot
self.__draw = DrawHangman(bot)
self.__API_url = "https://api.wordnik.com/v4/words.json/randomWords?" # pylint: disable=invalid-name
self._draw = DrawHangman(bot)
self._API_url = "https://api.wordnik.com/v4/words.json/randomWords?" # pylint: disable=invalid-name
api_key = self.bot.credentials["wordnik_key"]
self.__APIPARAMS = { # pylint: disable=invalid-name
self._APIPARAMS = { # pylint: disable=invalid-name
"hasDictionaryDef": True,
"minCorpusCount": 5000,
"maxCorpusCount": -1,
@ -78,7 +78,7 @@ class Hangman():
word = "-"
while "-" in word or "." in word:
response = requests.get(self.__API_url, params=self.__APIPARAMS)
response = requests.get(self._API_url, params=self._APIPARAMS)
word = list(response.json()[0]["word"].upper())
self.bot.log("Found the word \""+"".join(word)+"\"")
@ -87,7 +87,7 @@ class Hangman():
remaining_letters = list(string.ascii_uppercase)
self.__draw.draw_image(game_id, 0, word, guessed, [])
self._draw.draw_image(game_id, 0, word, guessed, [])
send_message = f"{ctx.author.display_name} started a game of hangman."
@ -219,7 +219,7 @@ class Hangman():
send_message = "Guessed {}. There were {} {}s in the word."
send_message = send_message.format(guess, correct_guess, guess)
self.__draw.draw_image(game_id, misses, word, guessed, guessed_letters)
self._draw.draw_image(game_id, misses, word, guessed, guessed_letters)
if misses == 6:
send_message += self.bot.long_strings["Hangman lost game"]
@ -325,36 +325,36 @@ class DrawHangman():
FONT
SMALLFONT
"""
self.__bot = bot
self._bot = bot
# pylint: disable=invalid-name
self.__CIRCLESIZE = 120
self.__LINEWIDTH = 12
self._CIRCLESIZE = 120
self._LINEWIDTH = 12
self.__BODYSIZE = 210
self.__LIMBSIZE = 60
self.__ARMPOSITION = 60
self._BODYSIZE = 210
self._LIMBSIZE = 60
self._ARMPOSITION = 60
self.__MANX = (self.__LIMBSIZE*2)
self.__MANY = (self.__CIRCLESIZE+self.__BODYSIZE+self.__LIMBSIZE)
MANPADDING = self.__LINEWIDTH*4
self.__MANX += MANPADDING
self.__MANY += MANPADDING
self._MANX = (self._LIMBSIZE*2)
self._MANY = (self._CIRCLESIZE+self._BODYSIZE+self._LIMBSIZE)
MANPADDING = self._LINEWIDTH*4
self._MANX += MANPADDING
self._MANY += MANPADDING
self.__LETTERLINELENGTH = 90
self.__LETTERLINEDISTANCE = 30
self._LETTERLINELENGTH = 90
self._LETTERLINEDISTANCE = 30
self.__GALLOWX, self.__GALLOWY = 360, 600
self.__PHI = 1-(1 / ((1 + 5 ** 0.5) / 2))
self._GALLOWX, self._GALLOWY = 360, 600
self._PHI = 1-(1 / ((1 + 5 ** 0.5) / 2))
LETTERSIZE = 75 # Wrong guesses letter size
WORDSIZE = 70 # Correct guesses letter size
FONTPATH = "gwendolyn/resources/fonts/comic-sans-bold.ttf"
self.__FONT = ImageFont.truetype(FONTPATH, LETTERSIZE)
self.__SMALLFONT = ImageFont.truetype(FONTPATH, WORDSIZE)
self._FONT = ImageFont.truetype(FONTPATH, LETTERSIZE)
self._SMALLFONT = ImageFont.truetype(FONTPATH, WORDSIZE)
# pylint: enable=invalid-name
def __deviate(self, pre_deviance: int, pre_deviance_accuracy: int,
def _deviate(self, pre_deviance: int, pre_deviance_accuracy: int,
position_change: float, maxmin: int,
max_acceleration: float):
random_deviance = random.uniform(-position_change, position_change)
@ -371,14 +371,14 @@ class DrawHangman():
deviance = -maxmin
return deviance, deviance_accuracy
def __bad_circle(self):
circle_padding = (self.__LINEWIDTH*3)
image_width = self.__CIRCLESIZE+circle_padding
def _bad_circle(self):
circle_padding = (self._LINEWIDTH*3)
image_width = self._CIRCLESIZE+circle_padding
image_size = (image_width, image_width)
background = Image.new("RGBA", image_size, color=(0, 0, 0, 0))
drawer = ImageDraw.Draw(background, "RGBA")
middle = (self.__CIRCLESIZE+(self.__LINEWIDTH*3))/2
middle = (self._CIRCLESIZE+(self._LINEWIDTH*3))/2
deviance_x = 0
deviance_y = 0
deviance_accuracy_x = 0
@ -387,96 +387,96 @@ class DrawHangman():
degrees_amount = 360 + random.randint(-10, 30)
for degree in range(degrees_amount):
deviance_x, deviance_accuracy_x = self.__deviate(
deviance_x, deviance_accuracy_x = self._deviate(
deviance_x,
deviance_accuracy_x,
self.__LINEWIDTH/100,
self.__LINEWIDTH,
self._LINEWIDTH/100,
self._LINEWIDTH,
0.03
)
deviance_y, deviance_accuracy_y = self.__deviate(
deviance_y, deviance_accuracy_y = self._deviate(
deviance_y,
deviance_accuracy_y,
self.__LINEWIDTH/100,
self.__LINEWIDTH,
self._LINEWIDTH/100,
self._LINEWIDTH,
0.03
)
radians = math.radians(degree+start)
circle_x = (math.cos(radians) * (self.__CIRCLESIZE/2))
circle_y = (math.sin(radians) * (self.__CIRCLESIZE/2))
circle_x = (math.cos(radians) * (self._CIRCLESIZE/2))
circle_y = (math.sin(radians) * (self._CIRCLESIZE/2))
position_x = middle + circle_x - (self.__LINEWIDTH/2) + deviance_x
position_y = middle + circle_y - (self.__LINEWIDTH/2) + deviance_y
position_x = middle + circle_x - (self._LINEWIDTH/2) + deviance_x
position_y = middle + circle_y - (self._LINEWIDTH/2) + deviance_y
circle_position = [
(position_x, position_y),
(position_x+self.__LINEWIDTH, position_y+self.__LINEWIDTH)
(position_x+self._LINEWIDTH, position_y+self._LINEWIDTH)
]
drawer.ellipse(circle_position, fill=(0, 0, 0, 255))
return background
def __bad_line(self, length: int, rotated: bool = False):
def _bad_line(self, length: int, rotated: bool = False):
if rotated:
width, height = length+self.__LINEWIDTH*3, self.__LINEWIDTH*3
width, height = length+self._LINEWIDTH*3, self._LINEWIDTH*3
else:
width, height = self.__LINEWIDTH*3, length+self.__LINEWIDTH*3
width, height = self._LINEWIDTH*3, length+self._LINEWIDTH*3
background = Image.new("RGBA", (width, height), color=(0, 0, 0, 0))
drawer = ImageDraw.Draw(background, "RGBA")
possible_deviance = int(self.__LINEWIDTH/3)
possible_deviance = int(self._LINEWIDTH/3)
deviance_x = random.randint(-possible_deviance, possible_deviance)
deviance_y = 0
deviance_accuracy_x = 0
deviance_accuracy_y = 0
for pixel in range(length):
deviance_x, deviance_accuracy_x = self.__deviate(
deviance_x, deviance_accuracy_x = self._deviate(
deviance_x,
deviance_accuracy_x,
self.__LINEWIDTH/1000,
self.__LINEWIDTH,
self._LINEWIDTH/1000,
self._LINEWIDTH,
0.004
)
deviance_y, deviance_accuracy_y = self.__deviate(
deviance_y, deviance_accuracy_y = self._deviate(
deviance_y,
deviance_accuracy_y,
self.__LINEWIDTH/1000,
self.__LINEWIDTH,
self._LINEWIDTH/1000,
self._LINEWIDTH,
0.004
)
if rotated:
position_x = self.__LINEWIDTH + pixel + deviance_x
position_y = self.__LINEWIDTH + deviance_y
position_x = self._LINEWIDTH + pixel + deviance_x
position_y = self._LINEWIDTH + deviance_y
else:
position_x = self.__LINEWIDTH + deviance_x
position_y = self.__LINEWIDTH + pixel + deviance_y
position_x = self._LINEWIDTH + deviance_x
position_y = self._LINEWIDTH + pixel + deviance_y
circle_position = [
(position_x, position_y),
(position_x+self.__LINEWIDTH, position_y+self.__LINEWIDTH)
(position_x+self._LINEWIDTH, position_y+self._LINEWIDTH)
]
drawer.ellipse(circle_position, fill=(0, 0, 0, 255))
return background
def __draw_man(self, misses: int, seed: str):
def _draw_man(self, misses: int, seed: str):
random.seed(seed)
man_size = (self.__MANX, self.__MANY)
man_size = (self._MANX, self._MANY)
background = Image.new("RGBA", man_size, color=(0, 0, 0, 0))
if misses >= 1:
head = self.__bad_circle()
paste_x = (self.__MANX-(self.__CIRCLESIZE+(self.__LINEWIDTH*3)))//2
head = self._bad_circle()
paste_x = (self._MANX-(self._CIRCLESIZE+(self._LINEWIDTH*3)))//2
paste_position = (paste_x, 0)
background.paste(head, paste_position, head)
if misses >= 2:
body = self.__bad_line(self.__BODYSIZE)
paste_x = (self.__MANX-(self.__LINEWIDTH*3))//2
paste_position = (paste_x, self.__CIRCLESIZE)
body = self._bad_line(self._BODYSIZE)
paste_x = (self._MANX-(self._LINEWIDTH*3))//2
paste_position = (paste_x, self._CIRCLESIZE)
background.paste(body, paste_position, body)
if misses >= 3:
@ -487,30 +487,30 @@ class DrawHangman():
random.seed(seed)
for limb in limbs:
limb_drawing = self.__bad_line(self.__LIMBSIZE, True)
x_position = (self.__MANX-(self.__LINEWIDTH*3))//2
limb_drawing = self._bad_line(self._LIMBSIZE, True)
x_position = (self._MANX-(self._LINEWIDTH*3))//2
if limb[1] == "a":
rotation = random.randint(-45, 45)
shift = math.sin(math.radians(rotation))
line_length = self.__LIMBSIZE+(self.__LINEWIDTH*3)
line_length = self._LIMBSIZE+(self._LINEWIDTH*3)
compensation = int(shift*line_length)
limb_drawing = limb_drawing.rotate(rotation, expand=1)
y_position = self.__CIRCLESIZE + self.__ARMPOSITION
y_position = self._CIRCLESIZE + self._ARMPOSITION
if limb == "ra":
compensation = min(-compensation, 0)
else:
x_position -= self.__LIMBSIZE
x_position -= self._LIMBSIZE
compensation = min(compensation, 0)
y_position += compensation
else:
rotation = random.randint(-15, 15)
y_position = self.__CIRCLESIZE+self.__BODYSIZE-self.__LINEWIDTH
y_position = self._CIRCLESIZE+self._BODYSIZE-self._LINEWIDTH
if limb == "rl":
limb_drawing = limb_drawing.rotate(rotation-45, expand=1)
else:
x_position += -limb_drawing.size[0]+self.__LINEWIDTH*3
x_position += -limb_drawing.size[0]+self._LINEWIDTH*3
limb_drawing = limb_drawing.rotate(rotation+45, expand=1)
paste_position = (x_position, y_position)
@ -518,11 +518,11 @@ class DrawHangman():
return background
def __bad_text(self, text: str, big: bool, color: tuple = (0, 0, 0, 255)):
def _bad_text(self, text: str, big: bool, color: tuple = (0, 0, 0, 255)):
if big:
font = self.__FONT
font = self._FONT
else:
font = self.__SMALLFONT
font = self._SMALLFONT
width, height = font.getsize(text)
img = Image.new("RGBA", (width, height), color=(0, 0, 0, 0))
drawer = ImageDraw.Draw(img, "RGBA")
@ -530,59 +530,59 @@ class DrawHangman():
drawer.text((0, 0), text, font=font, fill=color)
return img
def __draw_gallows(self):
gallow_size = (self.__GALLOWX, self.__GALLOWY)
def _draw_gallows(self):
gallow_size = (self._GALLOWX, self._GALLOWY)
background = Image.new("RGBA", gallow_size, color=(0, 0, 0, 0))
bottom_line = self.__bad_line(int(self.__GALLOWX * 0.75), True)
bottom_line_x = int(self.__GALLOWX * 0.125)
bottom_line_y = self.__GALLOWY-(self.__LINEWIDTH*4)
bottom_line = self._bad_line(int(self._GALLOWX * 0.75), True)
bottom_line_x = int(self._GALLOWX * 0.125)
bottom_line_y = self._GALLOWY-(self._LINEWIDTH*4)
paste_position = (bottom_line_x, bottom_line_y)
background.paste(bottom_line, paste_position, bottom_line)
line_two = self.__bad_line(self.__GALLOWY-self.__LINEWIDTH*6)
line_two_x = int(self.__GALLOWX*(0.75*self.__PHI))
line_two_y = self.__LINEWIDTH*2
line_two = self._bad_line(self._GALLOWY-self._LINEWIDTH*6)
line_two_x = int(self._GALLOWX*(0.75*self._PHI))
line_two_y = self._LINEWIDTH*2
paste_position = (line_two_x, line_two_y)
background.paste(line_two, paste_position, line_two)
top_line = self.__bad_line(int(self.__GALLOWY*0.30), True)
paste_x = int(self.__GALLOWX*(0.75*self.__PHI))-self.__LINEWIDTH
paste_position = (paste_x, self.__LINEWIDTH*3)
top_line = self._bad_line(int(self._GALLOWY*0.30), True)
paste_x = int(self._GALLOWX*(0.75*self._PHI))-self._LINEWIDTH
paste_position = (paste_x, self._LINEWIDTH*3)
background.paste(top_line, paste_position, top_line)
last_line = self.__bad_line(int(self.__GALLOWY*0.125))
paste_x += int(self.__GALLOWY*0.30)
background.paste(last_line, (paste_x, self.__LINEWIDTH*3), last_line)
last_line = self._bad_line(int(self._GALLOWY*0.125))
paste_x += int(self._GALLOWY*0.30)
background.paste(last_line, (paste_x, self._LINEWIDTH*3), last_line)
return background
def __draw_letter_lines(self, word: str, guessed: list, misses: int):
letter_width = self.__LETTERLINELENGTH+self.__LETTERLINEDISTANCE
def _draw_letter_lines(self, word: str, guessed: list, misses: int):
letter_width = self._LETTERLINELENGTH+self._LETTERLINEDISTANCE
image_width = letter_width*len(word)
image_size = (image_width, self.__LETTERLINELENGTH+self.__LINEWIDTH*3)
image_size = (image_width, self._LETTERLINELENGTH+self._LINEWIDTH*3)
letter_lines = Image.new("RGBA", image_size, color=(0, 0, 0, 0))
for i, letter in enumerate(word):
line = self.__bad_line(self.__LETTERLINELENGTH, True)
paste_x = i*(self.__LETTERLINELENGTH+self.__LETTERLINEDISTANCE)
paste_position = (paste_x, self.__LETTERLINELENGTH)
line = self._bad_line(self._LETTERLINELENGTH, True)
paste_x = i*(self._LETTERLINELENGTH+self._LETTERLINEDISTANCE)
paste_position = (paste_x, self._LETTERLINELENGTH)
letter_lines.paste(line, paste_position, line)
if guessed[i]:
letter_drawing = self.__bad_text(letter, True)
letter_width = self.__FONT.getsize(letter)[0]
letter_x = i*(self.__LETTERLINELENGTH+self.__LETTERLINEDISTANCE)
letter_drawing = self._bad_text(letter, True)
letter_width = self._FONT.getsize(letter)[0]
letter_x = i*(self._LETTERLINELENGTH+self._LETTERLINEDISTANCE)
letter_x -= (letter_width//2)
letter_x += (self.__LETTERLINELENGTH//2)+(self.__LINEWIDTH*2)
letter_x += (self._LETTERLINELENGTH//2)+(self._LINEWIDTH*2)
letter_lines.paste(
letter_drawing,
(letter_x, 0),
letter_drawing
)
elif misses == 6:
letter_drawing = self.__bad_text(letter, True, (242, 66, 54))
letter_width = self.__FONT.getsize(letter)[0]
letter_x = i*(self.__LETTERLINELENGTH+self.__LETTERLINEDISTANCE)
letter_drawing = self._bad_text(letter, True, (242, 66, 54))
letter_width = self._FONT.getsize(letter)[0]
letter_x = i*(self._LETTERLINELENGTH+self._LETTERLINEDISTANCE)
letter_x -= (letter_width//2)
letter_x += (self.__LETTERLINELENGTH//2)+(self.__LINEWIDTH*2)
letter_x += (self._LETTERLINELENGTH//2)+(self._LINEWIDTH*2)
letter_lines.paste(
letter_drawing,
(letter_x, 0),
@ -591,7 +591,7 @@ class DrawHangman():
return letter_lines
def __shortest_dist(self, positions: list, new_position: tuple):
def _shortest_dist(self, positions: list, new_position: tuple):
shortest_dist = math.inf
for i, j in positions:
x_distance = abs(i-new_position[0])
@ -601,18 +601,18 @@ class DrawHangman():
shortest_dist = dist
return shortest_dist
def __draw_misses(self, guesses: list, word: str):
def _draw_misses(self, guesses: list, word: str):
background = Image.new("RGBA", (600, 400), color=(0, 0, 0, 0))
pos = []
for guess in guesses:
if guess not in word:
placed = False
while not placed:
letter = self.__bad_text(guess, True)
w, h = self.__FONT.getsize(guess)
letter = self._bad_text(guess, True)
w, h = self._FONT.getsize(guess)
x = random.randint(0, 600-w)
y = random.randint(0, 400-h)
if self.__shortest_dist(pos, (x, y)) > 70:
if self._shortest_dist(pos, (x, y)) > 70:
pos.append((x, y))
background.paste(letter, (x, y), letter)
placed = True
@ -628,27 +628,27 @@ class DrawHangman():
channel: str
The id of the channel the game is in.
"""
self.__bot.log("Drawing hangman image")
self._bot.log("Drawing hangman image")
random.seed(game_id)
background = Image.open("gwendolyn/resources/paper.jpg")
gallow = self.__draw_gallows()
man = self.__draw_man(misses, game_id)
gallow = self._draw_gallows()
man = self._draw_man(misses, game_id)
random.seed(game_id)
letter_line_parameters = [word, guessed, misses]
letter_lines = self.__draw_letter_lines(*letter_line_parameters)
letter_lines = self._draw_letter_lines(*letter_line_parameters)
random.seed(game_id)
misses = self.__draw_misses(list(guessed_letters), word)
misses = self._draw_misses(list(guessed_letters), word)
background.paste(gallow, (100, 100), gallow)
background.paste(man, (300, 210), man)
background.paste(letter_lines, (120, 840), letter_lines)
background.paste(misses, (600, 150), misses)
misses_text = self.__bad_text("MISSES", False)
misses_text = self._bad_text("MISSES", False)
misses_text_width = misses_text.size[0]
background.paste(misses_text, (850-misses_text_width//2, 50), misses_text)

View File

@ -4,22 +4,162 @@ import discord
from gwendolyn.utils import cap
STATS = [
"strength",
"dexterity",
"constitution",
"intelligence",
"wisdom",
"charisma"
]
def mod(statistic):
"""Calculates D&D modifier."""
modifier = math.floor((statistic-10)/2)
if modifier >= 0:
modifier = "+"+str(modifier)
return modifier
class LookupFuncs():
def __init__(self, bot):
self.bot = bot
self.saves = ["strength_save","dexterity_save","constitution_save","intelligence_save","wisdom_save","charisma_save"]
self.abilities = ["acrobatics","animal_handling","arcana","athletics","deception","history","insight","intimidation","investigation","medicine","nature","perception","performance","persuasion","religion","sleight_of_hand","stealth","survival"]
self.saves = [
"strength_save",
"dexterity_save",
"constitution_save",
"intelligence_save",
"wisdom_save",
"charisma_save"
]
self.abilities = [
"acrobatics",
"animal_handling",
"arcana",
"athletics",
"deception",
"history",
"insight",
"intimidation",
"investigation",
"medicine",
"nature",
"perception",
"performance",
"persuasion",
"religion",
"sleight_of_hand",
"stealth",
"survival"
]
# Calculates D&D stat modifier
def modifier(self, statistic):
mods = math.floor((statistic-10)/2)
if mods >= 0:
mods = "+"+str(mods)
return(str(mods))
def _format_monster(self, monster):
# Looks at the information about the monster and
# returns that information in separate variables,
# allowing Gwendolyn to know where to separate
# the messages
types = monster["type"]
if monster["subtype"] != "":
types += " ("+monster["subtype"]+")"
stats = []
for stat in STATS:
value = monster[stat]
stats.append(f"**{cap(stat[:3])}:** {value} ({mod(value)})")
stats = "\t".join(stats[:3]) + "\n" + "\t".join(stats[3:])
saving_throws = []
for save in self.saves:
if save in monster:
value = monster[save]
if monster[save] >= 0:
saving_throws.append(f"{cap(save[:3])} +{value}")
else:
saving_throws.append(f"{cap(save[:3])} {value}")
if saving_throws:
saving_throws = f"\n**Saving Throws:** {', '.join(saving_throws)}"
else:
saving_throws = ""
skills = []
for skill in self.abilities:
if skill in monster:
skill_name = cap(skill.replace("_"," "))
if monster[skill] >= 0:
skills.append(f"{skill_name} +{monster[skill]}")
else:
skills.append(f"{skill_name} {monster[skill]}")
if skills:
skills = f"\n**Skills:** {', '.join(skills)}"
else:
skills = ""
vulnerabilities = monster["damage_vulnerabilities"]
if vulnerabilities != "":
vulnerabilities = "\n**Damage Vulnerabilities** "+vulnerabilities
resistances = monster["damage_resistances"]
if resistances != "":
resistances = "\n**Damage Resistances** "+resistances
immunities = monster["damage_immunities"]
if immunities != "":
immunities = "\n**Damage Immunities** "+immunities
c_immunities = monster["condition_immunities"]
if c_immunities != "":
c_immunities = "\n**Condition Immunities** "+c_immunities
special_abilities = ""
if "special_abilities" in monster:
for ability in monster["special_abilities"]:
special_abilities += "\n\n***"+ability["name"]+".*** "+ability["desc"]
act = ""
if "actions" in monster:
for action in monster["actions"]:
act += "\n\n***"+action["name"]+".*** "+action["desc"]
react = ""
if "reactions" in monster:
for reaction in monster["reactions"]:
react += "\n\n***"+reaction["name"]+".*** "+reaction["desc"]
legendaryActions = ""
if "legendary_actions" in monster:
for action in monster["legendary_actions"]:
legendaryActions += "\n\n***"+action["name"]+".*** "+action["desc"]
hit_dice = monster["hit_dice"]
dice_amount = int(monster["hit_dice"].replace("d"," ").split()[0])
con_mod = math.floor((monster['constitution']-10)/2)
if con_mod < 0:
hit_dice += f" - {abs(con_mod) * dice_amount}"
elif con_mod > 0:
hit_dice += (f" + {con_mod * dice_amount}")
new_part = "\n--------------------"
monster_type = f"*{monster['size']} {types}, {monster['alignment']}*"
basic_info = "\n**Armor Class** "+str(monster["armor_class"])+"\n**Hit Points** "+str(monster["hit_points"])+" ("+hit_dice+")\n**Speed **"+monster["speed"]+new_part+"\n"
info = (monster_type+new_part+basic_info+stats+new_part+saving_throws+skills+vulnerabilities+resistances+immunities+c_immunities+"\n**Senses** "+monster["senses"]+"\n**Languages** "+monster["languages"]+"\n**Challenge** "+monster["challenge_rating"])
monster_info = [(info, monster['name']),
(special_abilities, "Special Abilities"),
(act, "Actions"),
(react, "Reactions"),
(legendaryActions, "Legendary Actions")]
self.bot.log("Returning monster information")
return monster_info
# Looks up a monster
async def monsterFunc(self, ctx, query):
async def monster_func(self, ctx, query):
query = cap(query)
self.bot.log("Looking up "+query)
@ -27,124 +167,41 @@ class LookupFuncs():
if len(query) < 2:
self.bot.log("Monster name too short")
await ctx.send("I don't know that monster...")
return
# Opens "monsters.json"
monster_file_path = "gwendolyn/resources/lookup/monsters.json"
with open(monster_file_path,"r", encoding="utf-8") as file_pointer:
data = json.load(file_pointer)
for monster in data:
if "name" in monster and str(query) == monster["name"]:
self.bot.log("Found it!")
monster_info = self._format_monster(monster)
# Sends the received information. Separates into separate messages if
# there is too much text
await ctx.send(f"Result for \"{query}\"")
for text, title in monster_info:
if text != "":
if len(text) < 2000:
em = discord.Embed(title = title, description = text, colour=0xDEADBF)
await ctx.channel.send(embed = em)
else:
index = text[:2000].rfind(".")+1
em1 = discord.Embed(title = title, description = text[:index], colour=0xDEADBF)
await ctx.channel.send(embed = em1)
em2 = discord.Embed(title = "", description = text[index+1:], colour=0xDEADBF)
await ctx.channel.send(embed = em2)
break
else:
# Opens "monsters.json"
data = json.load(open('gwendolyn/resources/lookup/monsters.json', encoding = "utf8"))
for monster in data:
if "name" in monster and str(query) == monster["name"]:
self.bot.log("Found it!")
# Looks at the information about the monster and returns that information
# in separate variables, allowing Gwendolyn to know where to separate
# the messages
if monster["subtype"] != "":
types = (monster["type"]+" ("+monster["subtype"]+")")
else:
types = monster["type"]
con_mod = math.floor((monster["constitution"]-10)/2)
hit_dice = monster["hit_dice"]
stats = ("**Str:** "+str(monster["strength"])+" ("+self.modifier(monster["strength"])+")\t**Dex:** "+str(monster["dexterity"])+" ("+self.modifier(monster["dexterity"])+")\t**Con:** "+str(monster["constitution"])+" ("+self.modifier(monster["constitution"])+")\n**Int: **"+str(monster["intelligence"])+" ("+self.modifier(monster["intelligence"])+")\t**Wis: **"+str(monster["wisdom"])+" ("+self.modifier(monster["wisdom"])+")\t**Cha: **"+str(monster["charisma"])+" ("+self.modifier(monster["charisma"])+")")
saving_throws = ""
for save in self.saves:
if save in monster:
if monster[save] >= 0:
saving_throws += " "+cap(save[:3])+" +"+str(monster[save])+","
else:
saving_throws += " "+cap(save[:3])+" "+str(monster[save])+","
if saving_throws != "":
saving_throws = "\n**Saving Throws**"+saving_throws[:-1]
skills = ""
for skill in self.abilities:
if skill in monster:
if monster[skill] >= 0:
skills += " "+cap(skill.replace("_"," "))+" +"+str(monster[skill])+","
else:
skills += " "+cap(skill.replace("_"," "))+" "+str(monster[skill])+","
if skills != "":
skills = "\n**Skills**"+skills[:-1]
vulnerabilities = monster["damage_vulnerabilities"]
if vulnerabilities != "":
vulnerabilities = "\n**Damage Vulnerabilities** "+vulnerabilities
resistances = monster["damage_resistances"]
if resistances != "":
resistances = "\n**Damage Resistances** "+resistances
immunities = monster["damage_immunities"]
if immunities != "":
immunities = "\n**Damage Immunities** "+immunities
c_immunities = monster["condition_immunities"]
if c_immunities != "":
c_immunities = "\n**Condition Immunities** "+c_immunities
specialAbilities = ""
if "special_abilities" in monster:
for ability in monster["special_abilities"]:
specialAbilities += "\n\n***"+ability["name"]+".*** "+ability["desc"]
act = ""
if "actions" in monster:
for action in monster["actions"]:
act += "\n\n***"+action["name"]+".*** "+action["desc"]
react = ""
if "reactions" in monster:
for reaction in monster["reactions"]:
react += "\n\n***"+reaction["name"]+".*** "+reaction["desc"]
legendaryActions = ""
if "legendary_actions" in monster:
for action in monster["legendary_actions"]:
legendaryActions += "\n\n***"+action["name"]+".*** "+action["desc"]
if con_mod < 0:
hit_dice += (" - "+str(con_mod * int(monster["hit_dice"].replace("d"," ").split()[0])*(-1)))
if con_mod > 0:
hit_dice += (" + "+str(con_mod * int(monster["hit_dice"].replace("d"," ").split()[0])))
new_part = "\n--------------------"
monster_type = monster["size"]+" "+types+", "+monster["alignment"]+"*"
basic_info = "\n**Armor Class** "+str(monster["armor_class"])+"\n**Hit Points** "+str(monster["hit_points"])+" ("+hit_dice+")\n**Speed **"+monster["speed"]+new_part+"\n"
info = (monster_type+new_part+basic_info+stats+new_part+saving_throws+skills+vulnerabilities+resistances+immunities+c_immunities+"\n**Senses** "+monster["senses"]+"\n**Languages** "+monster["languages"]+"\n**Challenge** "+monster["challenge_rating"])
monsterInfo = [(info, query),
(specialAbilities, "Special Abilities"),
(act, "Actions"),
(react, "Reactions"),
(legendaryActions, "Legendary Actions")]
self.bot.log("Returning monster information")
# Sends the received information. Separates into separate messages if
# there is too much text
await ctx.send(f"Result for \"{query}\"")
for text, title in monsterInfo:
if text != "":
if len(text) < 2000:
em = discord.Embed(title = title, description = text, colour=0xDEADBF)
await ctx.channel.send(embed = em)
else:
index = text[:2000].rfind(".")+1
em1 = discord.Embed(title = title, description = text[:index], colour=0xDEADBF)
await ctx.channel.send(embed = em1)
em2 = discord.Embed(title = "", description = text[index+1:], colour=0xDEADBF)
await ctx.channel.send(embed = em2)
break
else:
self.bot.log("Monster not in database")
await ctx.send("I don't know that monster...")
self.bot.log("Monster not in database")
await ctx.send("I don't know that monster...")
# Looks up a spell
async def spellFunc(self, ctx, query):
async def spell_func(self, ctx, query):
query = cap(query)
self.bot.log("Looking up "+query)

View File

@ -15,9 +15,10 @@ class Generators():
yield (corpus[i], corpus[i+1], corpus[i+2])
# Generates a random name
async def nameGen(self, ctx):
async def name_gen(self, ctx):
# Makes a list of all names from "names.txt"
names = open('gwendolyn/resources/names.txt', encoding='utf8').read()
with open("gwendolyn/resources/names.txt", "r", encoding='utf8') as file_pointer:
names = file_pointer.read()
corpus = list(names)
# Makes a list of pairs
@ -28,13 +29,13 @@ class Generators():
# Makes a dictionary of all letters that come after all other letters
for letter_1, letter_2 in pairs:
if letter_1 in letter_dict.keys():
if letter_1 in letter_dict:
letter_dict[letter_1].append(letter_2)
else:
letter_dict[letter_1] = [letter_2]
for letter_1, letter_2, letter_3 in triplets:
if letter_1+letter_2 in letter_dict.keys():
if letter_1+letter_2 in letter_dict:
letter_dict[letter_1+letter_2].append(letter_3)
else:
letter_dict[letter_1+letter_2] = [letter_3]
@ -60,7 +61,7 @@ class Generators():
done = False
# Creates the name one letter at a time
while done == False:
while not done:
if random.randint(1,10) > 1:
try:
new_letter = random.choice(letter_dict[chain[-2]+chain[-1]])
@ -79,15 +80,15 @@ class Generators():
await ctx.send(gen_name)
# Generates a random tavern name
async def tavernGen(self, ctx):
async def tavern_gen(self, ctx):
# _lists first parts, second parts and third parts of tavern names
fp = ["The Silver","The Golden","The Staggering","The Laughing","The Prancing","The Gilded","The Running","The Howling","The Slaughtered","The Leering","The Drunken","The Leaping","The Roaring","The Frowning","The Lonely","The Wandering","The Mysterious","The Barking","The Black","The Gleaming","The Tap-Dancing","The Sad","The Sexy","The Artificial","The Groovy","The Merciful","The Confused","The Pouting","The Horny","The Okay","The Friendly","The Hungry","The Handicapped","The Fire-breathing","The One-Eyed","The Psychotic","The Mad","The Evil","The Idiotic","The Trusty","The Busty"]
sp = ["Eel","Dolphin","Dwarf","Pegasus","Pony","Rose","Stag","Wolf","Lamb","Demon","Goat","Spirit","Horde","Jester","Mountain","Eagle","Satyr","Dog","Spider","Star","Dad","Rat","Jeremy","Mouse","Unicorn","Pearl","Ant","Crab","Penguin","Octopus","Lawyer","Ghost","Toad","Handjob","Immigrant","SJW","Dragon","Bard","Sphinx","Soldier","Salmon","Owlbear","Kite","Frost Giant","Arsonist"]
tp = [" Tavern"," Inn","","","","","","","","",""]
first_part = ["The Silver","The Golden","The Staggering","The Laughing","The Prancing","The Gilded","The Running","The Howling","The Slaughtered","The Leering","The Drunken","The Leaping","The Roaring","The Frowning","The Lonely","The Wandering","The Mysterious","The Barking","The Black","The Gleaming","The Tap-Dancing","The Sad","The Sexy","The Artificial","The Groovy","The Merciful","The Confused","The Pouting","The Horny","The Okay","The Friendly","The Hungry","The Handicapped","The Fire-breathing","The One-Eyed","The Psychotic","The Mad","The Evil","The Idiotic","The Trusty","The Busty"]
second_part = ["Eel","Dolphin","Dwarf","Pegasus","Pony","Rose","Stag","Wolf","Lamb","Demon","Goat","Spirit","Horde","Jester","Mountain","Eagle","Satyr","Dog","Spider","Star","Dad","Rat","Jeremy","Mouse","Unicorn","Pearl","Ant","Crab","Penguin","Octopus","Lawyer","Ghost","Toad","Handjob","Immigrant","SJW","Dragon","Bard","Sphinx","Soldier","Salmon","Owlbear","Kite","Frost Giant","Arsonist"]
third_part = [" Tavern"," Inn","","","","","","","","",""]
# Picks one of each
genTav = random.choice(fp)+" "+random.choice(sp)+random.choice(tp)
self.bot.log("Generated "+genTav)
gen_tav = random.choice(first_part)+" "+random.choice(second_part)+random.choice(third_part)
self.bot.log("Generated "+gen_tav)
# Return the name
await ctx.send(genTav)
await ctx.send(gen_tav)

View File

@ -1,4 +1,8 @@
import discord, discord_slash, wolframalpha, requests, os
import os
import requests
import discord
import wolframalpha
from PIL import Image, ImageDraw, ImageFont
class NerdShit():
@ -6,9 +10,9 @@ class NerdShit():
"""Runs misc commands."""
self.bot = bot
async def wolfSearch(self,ctx,content):
async def wolf_search(self,ctx,content):
await self.bot.defer(ctx)
fnt = ImageFont.truetype('gwendolyn/resources/fonts/times-new-roman.ttf', 20)
font = ImageFont.truetype('gwendolyn/resources/fonts/times-new-roman.ttf', 20)
self.bot.log("Requesting data")
bot = wolframalpha.Client(self.bot.credentials["wolfram_alpha_key"])
res = bot.query(content)
@ -19,33 +23,33 @@ class NerdShit():
if int(res.numpods) > 0:
for pod in res.pods:
titles += [pod.title]
for x, sub in enumerate(pod.subpods):
for i, sub in enumerate(pod.subpods):
pods += [sub]
if x > 0:
if i > 0:
titles += [""]
podChunks = [pods[x:x+2] for x in range(0, len(pods), 2)]
titleChucks = [titles[x:x+2] for x in range(0, len(titles), 2)]
pod_chunks = [pods[x:x+2] for x in range(0, len(pods), 2)]
title_chunks = [titles[x:x+2] for x in range(0, len(titles), 2)]
await ctx.send(f"Response for \"{content}\"")
for x, chunk in enumerate(podChunks):
for i, chunk in enumerate(pod_chunks):
width = 0
for title in titleChucks[x]:
width = max(width,fnt.getsize(title)[0])
for title in title_chunks[i]:
width = max(width,font.getsize(title)[0])
height = 5
heights = []
for count, pod in enumerate(chunk):
heights += [height]
width = max(width,int(pod.img['@width']))
if titleChucks[x][count] == "":
placeFor_text = 0
if title_chunks[i][count] == "":
place_for_text = 0
else:
placeFor_text = 30
height += int(pod.img["@height"]) + 10 + placeFor_text
place_for_text = 30
height += int(pod.img["@height"]) + 10 + place_for_text
width += 10
height += 5
wolfImage = Image.new("RGB",(width,height),color=(255,255,255))
wolf_image = Image.new("RGB",(width,height),color=(255,255,255))
for count, pod in enumerate(chunk):
response = requests.get(pod.img["@src"])
@ -53,25 +57,25 @@ class NerdShit():
file.write(response.content)
file.close()
old_image = Image.open("gwendolyn/resources/wolfTemp.png")
oldSize = old_image.size
if titleChucks[x][count] == "":
placeFor_text = 0
old_size = old_image.size
if title_chunks[i][count] == "":
place_for_text = 0
else:
placeFor_text = 30
newSize = (width,int(oldSize[1]+10+placeFor_text))
new_image = Image.new("RGB",newSize,color=(255,255,255))
new_image.paste(old_image, (int((int(oldSize[0]+10)-oldSize[0])/2),int(((newSize[1]-placeFor_text)-oldSize[1])/2)+placeFor_text))
if titleChucks[x][count] != "":
d = ImageDraw.Draw(new_image,"RGB")
d.text((5,7),titleChucks[x][count],font=fnt,fill=(150,150,150))
place_for_text = 30
new_size = (width,int(old_size[1]+10+place_for_text))
new_image = Image.new("RGB",new_size,color=(255,255,255))
new_image.paste(old_image, (int((int(old_size[0]+10)-old_size[0])/2),int(((new_size[1]-place_for_text)-old_size[1])/2)+place_for_text))
if title_chunks[i][count] != "":
drawer = ImageDraw.Draw(new_image,"RGB")
drawer.text((5,7),title_chunks[i][count],font=font,fill=(150,150,150))
wolfImage.paste(new_image,(0,heights[count]))
wolf_image.paste(new_image,(0,heights[count]))
new_image.close()
old_image.close()
count += 1
wolfImage.save("gwendolyn/resources/wolf.png")
wolfImage.close()
wolf_image.save("gwendolyn/resources/wolf.png")
wolf_image.close()
await ctx.channel.send(file = discord.File("gwendolyn/resources/wolf.png"))
os.remove("gwendolyn/resources/wolf.png")

View File

@ -1,24 +1,24 @@
import imdb # Used in movieFunc
import random # Used in movieFunc
import discord # Used in movieFunc
import datetime # Used in helloFunc
import urllib # Used in imageFunc
import ast
import imdb # Used in movieFunc
import discord # Used in movieFunc
import lxml # Used in imageFunc
import fandom # Used in findWikiPage
import d20 # Used in rollDice
import ast
from .plex import Plex
from .nerd_shit import NerdShit
from .generators import Generators
from gwendolyn.utils import cap
fandom.set_lang("da")
fandom.set_wiki("senkulpa")
class MyStringifier(d20.MarkdownStringifier):
def _str_expression(self, node):
if node.comment == None:
if node.comment is None:
result_text = "Result"
else:
result_text = node.comment.capitalize()
@ -33,23 +33,23 @@ class Other():
self.generators = Generators(self.bot)
# Picks a random movie and returns information about it
async def movieFunc(self, ctx):
async def movie_func(self, ctx):
await self.bot.defer(ctx)
self.bot.log("Creating IMDb object")
imdbClient = imdb.IMDb()
imdb_client = imdb.IMDb()
self.bot.log("Picking a movie")
with open("gwendolyn/resources/movies.txt", "r") as f:
movie_list = f.read().split("\n")
with open("gwendolyn/resources/movies.txt", "r") as file_pointer:
movie_list = file_pointer.read().split("\n")
movie_name = random.choice(movie_list)
self.bot.log(f"Searching for {movie_name}")
searchResult = imdbClient.search_movie(movie_name)
search_result = imdb_client.search_movie(movie_name)
self.bot.log("Getting the data")
movie = searchResult[0]
imdbClient.update(movie)
movie = search_result[0]
imdb_client.update(movie)
self.bot.log("Successfully ran /movie")
@ -63,13 +63,13 @@ class Other():
await ctx.send(embed = embed)
# Responds with a greeting of a time-appropriate maner
async def helloFunc(self, ctx):
def time_in_range(start, end, x):
# Return true if x is in the range [start, end]
async def hello_func(self, ctx):
def time_in_range(start, end, i):
# Return true if i is in the range [start, end]
if start <= end:
return start <= x <= end
return start <= i <= end
else:
return start <= x or x <= end
return start <= i or i <= end
author = ctx.author.display_name
now = datetime.datetime.now()
@ -87,31 +87,22 @@ class Other():
await ctx.send(send_message)
# Finds a random picture online
async def imageFunc(self, ctx):
async def image_func(self, ctx):
# Picks a type of camera, which decides the naming scheme
cams = ("one","two","three","four")
cam = random.choice(cams)
self.bot.log("Chose cam type "+cam)
if cam == "one":
a = str(random.randint(0 ,9))
b = str(random.randint(0,9))
c = str(random.randint(0,9))
d = str(random.randint(0,9))
search = ("img_"+a+b+c+d)
search = f"img_{''.join([random.randint(0,9) for _ in range(4)])}"
elif cam == "two":
a = str(random.randint(2012,2016))
b = str(random.randint(1,12)).zfill(2)
c = str(random.randint(1,29)).zfill(2)
search = ("IMG_"+a+b+c)
year = str(random.randint(2012,2016))
month = str(random.randint(1,12)).zfill(2)
day = str(random.randint(1,29)).zfill(2)
search = f"IMG_{year}{month}{day}"
elif cam == "three":
a = str(random.randint(1,500)).zfill(4)
search = ("IMAG_"+a)
search = f"IMAG_{str(random.randint(1,500)).zfill(4)}"
elif cam == "four":
a = str(random.randint(0,9))
b = str(random.randint(0,9))
c = str(random.randint(0,9))
d = str(random.randint(0,9))
search = ("DSC_"+a+b+c+d)
search = f"DSC_{''.join([random.randint(0,9) for _ in range(4)])}"
self.bot.log("Searching for "+search)
@ -127,37 +118,37 @@ class Other():
# Picks an image
number = random.randint(1,len(images))-1
image = ast.literal_eval(str(images[number]))
imageUrl = image["murl"]
image_url = image["murl"]
self.bot.log("Picked image number "+str(number))
# Returns the image
self.bot.log("Successfully returned an image")
await ctx.send(imageUrl)
await ctx.send(image_url)
# Finds a page from the Senkulpa Wikia
async def findWikiPage(self, ctx, search : str):
async def find_wiki_page(self, ctx, search : str):
await self.bot.defer(ctx)
foundPage = False
found_page = False
if search != "":
self.bot.log("Trying to find wiki page for "+search)
searchResults = fandom.search(search)
if len(searchResults) > 0:
foundPage = True
searchResult = searchResults[0]
search_results = fandom.search(search)
if len(search_results) > 0:
found_page = True
search_result = search_results[0]
else:
self.bot.log("Couldn't find the page")
await ctx.send("Couldn't find page")
else:
foundPage = True
found_page = True
self.bot.log("Searching for a random page")
searchResult = fandom.random()
search_result = fandom.random()
if foundPage:
self.bot.log(f"Found page \"{searchResult[0]}\"")
page = fandom.page(pageid = searchResult[1])
if found_page:
self.bot.log(f"Found page \"{search_result[0]}\"")
page = fandom.page(pageid = search_result[1])
content = page.summary
images = page.images
@ -173,24 +164,24 @@ class Other():
await ctx.send(embed = embed)
async def rollDice(self, ctx, rollString):
async def roll_dice(self, ctx, roll_string):
user = ctx.author.display_name
while len(rollString) > 1 and rollString[0] == " ":
rollString = rollString[1:]
while len(roll_string) > 1 and roll_string[0] == " ":
roll_string = roll_string[1:]
roll = d20.roll(rollString, allow_comments=True, stringifier=MyStringifier())
roll = d20.roll(roll_string, allow_comments=True, stringifier=MyStringifier())
await ctx.send(f"{user} :game_die:\n{roll}")
async def helpFunc(self, ctx, command):
async def help_func(self, ctx, command):
if command == "":
with open("gwendolyn/resources/help/help.txt",encoding="utf-8") as f:
text = f.read()
em = discord.Embed(title = "Help", description = text,colour = 0x59f442)
await ctx.send(embed = em)
with open("gwendolyn/resources/help/help.txt",encoding="utf-8") as file_pointer:
text = file_pointer.read()
embed = discord.Embed(title = "Help", description = text,colour = 0x59f442)
await ctx.send(embed = embed)
else:
self.bot.log(f"Looking for help-{command}.txt",str(ctx.channel_id))
with open(f"gwendolyn/resources/help/help-{command}.txt",encoding="utf-8") as f:
text = f.read()
em = discord.Embed(title = command.capitalize(), description = text,colour = 0x59f442)
await ctx.send(embed = em)
with open(f"gwendolyn/resources/help/help-{command}.txt",encoding="utf-8") as file_pointer:
text = file_pointer.read()
embed = discord.Embed(title = command.capitalize(), description = text,colour = 0x59f442)
await ctx.send(embed = embed)

View File

@ -6,18 +6,18 @@ class StarWarsChar():
def __init__(self, bot):
self.bot = bot
def getChar_name(self, user : str):
def get_char_name(self, user : str):
self.bot.log("Getting name for "+self.bot.database_funcs.get_name(user)+"'s character")
userCharacter = self.bot.database["starwars characters"].find_one({"_id":user})
user_character = self.bot.database["starwars characters"].find_one({"_id":user})
if userCharacter != None:
self.bot.log("Name is "+userCharacter["Name"])
return userCharacter["Name"]
if user_character != None:
self.bot.log("Name is "+user_character["Name"])
return user_character["Name"]
else:
self.bot.log("Just using "+self.bot.database_funcs.get_name(user))
return self.bot.database_funcs.get_name(user)
def setUpDict(self, cmd : dict):
def set_up_dict(self, cmd : dict):
self.bot.log("Setting up a dictionary in a nice way")
if bool(cmd):
keys = list(cmd)
@ -26,24 +26,24 @@ class StarWarsChar():
if isinstance(values[0],dict):
return ", ".join(values)
else:
for x, key in enumerate(keys):
for i, key in enumerate(keys):
if type(key) is list:
if x%3 != 2:
result += "**" + key + "**" + ": " + ", ".join(values[x]) + " "
if i%3 != 2:
result += "**" + key + "**" + ": " + ", ".join(values[i]) + " "
else:
result += "**" + key + "**" + ": " + ", ".join(values[x]) + "\n"
result += "**" + key + "**" + ": " + ", ".join(values[i]) + "\n"
else:
if x%3 != 2:
result += "**" + key + "**" + ": " + str(values[x]) + " "
if i%3 != 2:
result += "**" + key + "**" + ": " + str(values[i]) + " "
else:
result += "**" + key + "**" + ": " + str(values[x]) + "\n"
result += "**" + key + "**" + ": " + str(values[i]) + "\n"
self.bot.log("Returning a dictionary, but well formatted")
return result
else:
self.bot.log("Couldn't find anything")
return "There doesn't seem to be anything here..."
def lookUp(self, data : dict, key : str, cmd : str = ""):
def look_up(self, data : dict, key : str, cmd : str = ""):
if cmd == " ":
cmd = ""
elif cmd != "":
@ -57,7 +57,7 @@ class StarWarsChar():
self.bot.log(key+" exists")
if cmd == "":
if type(data[key]) is dict and key != "Weapons":
return self.setUpDict(data[key])
return self.set_up_dict(data[key])
elif key == "Weapons":
self.bot.log("Does this even get used? I'm too scared to delete it")
if bool(data[key]):
@ -85,21 +85,21 @@ class StarWarsChar():
if type(data[key]) is int:
try:
newValue = data[key] + int(cmd)
data[key] = newValue
new_value = data[key] + int(cmd)
data[key] = new_value
self.bot.log("Added "+cmd+" to "+key)
return data
except:
self.bot.log("Couldn't add "+cmd+" to "+key)
return "Can't add that"
elif type(data[key]) is list:
try:
data[key].append(cmd)
self.bot.log("Added "+cmd+" to "+key)
return data
except:
self.bot.log("Couldn't add "+cmd+" to "+key)
return "Can't add that"
try:
data[key].append(cmd)
self.bot.log("Added "+cmd+" to "+key)
return data
except:
self.bot.log("Couldn't add "+cmd+" to "+key)
return "Can't add that"
else:
self.bot.log("Yeah, I can't add that to "+key)
return "Can't add that"
@ -116,21 +116,21 @@ class StarWarsChar():
if type(data[key]) is int:
try:
newValue = data[key] - int(cmd)
data[key] = newValue
new_value = data[key] - int(cmd)
data[key] = new_value
self.bot.log("Subtracted "+cmd+" from "+key)
return data
except:
self.bot.log("Couldn't subtract "+cmd+" from "+key)
return "Can't remove that"
elif type(data[key]) is list:
try:
data[key].remove(cmd)
self.bot.log("Removed "+cmd+" from "+key)
return data
except:
self.bot.log("Couldn't remove "+cmd+" from "+key)
return "Can't remove that"
try:
data[key].remove(cmd)
self.bot.log("Removed "+cmd+" from "+key)
return data
except:
self.bot.log("Couldn't remove "+cmd+" from "+key)
return "Can't remove that"
else:
self.bot.log("Yeah, I can't remove/subtract that from "+key)
return "Can't remove that"
@ -139,20 +139,20 @@ class StarWarsChar():
cmd = cmd[1:]
if type(data[key]) is dict:
newKey = cmd.split(" ")[0]
cmd = cmd[len(newKey):]
new_key = cmd.split(" ")[0]
cmd = cmd[len(new_key):]
if cmd != "":
while cmd[0] == " ":
cmd = cmd[1:]
if cmd == "":
break
self.bot.log("Looking up "+newKey+" in "+key)
lookUpResult = self.lookUp(data[key],newKey,cmd)
if type(lookUpResult) is dict:
data[key] = lookUpResult
self.bot.log("Looking up "+new_key+" in "+key)
look_up_result = self.look_up(data[key],new_key,cmd)
if type(look_up_result) is dict:
data[key] = look_up_result
return data
else:
return lookUpResult
return look_up_result
elif type(data[key]) != list:
self.bot.log("Trying to change "+key+" to "+cmd)
try:
@ -193,23 +193,23 @@ class StarWarsChar():
if cmd == "":
self.bot.log("Returning "+search)
return self.setUpDict(data[search])
return self.set_up_dict(data[search])
else:
newKey = cmd.split(" ")[0]
cmd = cmd[len(newKey):]
new_key = cmd.split(" ")[0]
cmd = cmd[len(new_key):]
if cmd != "":
while cmd[0] == " ":
cmd = cmd[1:]
if cmd == "":
break
lookUpResult = self.lookUp(data[search],newKey,cmd)
if type(lookUpResult) is dict:
data[search] = lookUpResult
look_up_result = self.look_up(data[search],new_key,cmd)
if type(look_up_result) is dict:
data[search] = look_up_result
return data
else:
return lookUpResult
return look_up_result
def characterSheet(self,character : dict):
def character_sheet(self,character : dict):
self.bot.log("Setting up a character sheet for "+character["Name"])
divider = "--------------------\n"
name = character["Name"]
@ -219,8 +219,8 @@ class StarWarsChar():
text1 = "**Species**: "+character["Species"]+"\n**Career**: "+character["Career"]+"\n**Specialization Trees**: "+", ".join(character["Specialization-trees"])+textf+"\n**Soak**: "+str(character["Soak"])
text2 = "\n\n**Wounds**: "+str(character["Wounds"])+"/"+str(character["Wound-threshold"])+"\n**Strain**: "+str(character["Strain"])+"/"+str(character["Strain-threshold"])
text3 = self.setUpDict(character["Characteristics"])
text4 = self.setUpDict(character["Skills"])
text3 = self.set_up_dict(character["Characteristics"])
text4 = self.set_up_dict(character["Skills"])
text5 = ""
text6 = ""
text7 = ""
@ -240,7 +240,7 @@ class StarWarsChar():
return name, text1+text2+"\n\n"+text3+divider+text4+"\n"+divider+text5+text6+text7+text8
def char_data(self,user : str,cmd : str):
userCharacter = self.bot.database["starwars characters"].find_one({"_id":user})
user_character = self.bot.database["starwars characters"].find_one({"_id":user})
key = string.capwords(cmd.split(" ")[0])
cmd = cmd[len(key):]
@ -253,23 +253,23 @@ class StarWarsChar():
break
self.bot.log("Looking for "+self.bot.database_funcs.get_name(user)+"'s character")
if userCharacter != None:
if user_character != None:
self.bot.log("Found it! Looking for "+key+" in the data")
if key in userCharacter:
if key in user_character:
self.bot.log("Found it!")
if type(userCharacter[key]) is dict:
if type(user_character[key]) is dict:
self.bot.log("It's a dictionary!")
if cmd == "":
self.bot.log("Retrieving data")
if key == "Weapons":
if bool(userCharacter[key]):
if bool(user_character[key]):
self.bot.log("Returning a list of weapons")
return ", ".join(list(userCharacter[key]))
return ", ".join(list(user_character[key]))
else:
self.bot.log("The character doesn't have any weapons. Which is probably for the best. Like, who just walks around with weapons?")
return "There doesn't seem to be anything there..."
else:
return self.setUpDict(userCharacter[key])
return self.set_up_dict(user_character[key])
elif cmd[0] == "+":
self.bot.log("Gonna add something!!!")
try:
@ -287,7 +287,7 @@ class StarWarsChar():
self.bot.log("Adding "+cmd[0]+" to "+key)
self.bot.database["starwars characters"].update_one({"_id":user},
{"$set": {key+"."+cmd[0] : cmd[1]}})
return cmd[0]+" added to "+key+" for " + userCharacter["Name"]
return cmd[0]+" added to "+key+" for " + user_character["Name"]
elif key == "Obligations" and "," in cmd:
cmd = cmd.split(",")
@ -300,17 +300,17 @@ class StarWarsChar():
except:
self.bot.log("Fucked that up")
return "Wrong data type"
return cmd[0]+" added to "+key+" for " + userCharacter["Name"]
return cmd[0]+" added to "+key+" for " + user_character["Name"]
elif key == "Weapons":
with open("gwendolyn/resources/star_wars/starwarstemplates.json", "r") as f:
templates = json.load(f)
newWeapon = templates["Weapon"]
with open("gwendolyn/resources/star_wars/starwarstemplates.json", "r") as file_pointer:
templates = json.load(file_pointer)
new_weapon = templates["Weapon"]
self.bot.log("Adding "+cmd+" to "+key)
self.bot.database["starwars characters"].update_one({"_id":user},
{"$set": {key+"."+cmd : newWeapon}})
{"$set": {key+"."+cmd : new_weapon}})
return cmd+" added to weapons for " + userCharacter["Name"]
return cmd+" added to weapons for " + user_character["Name"]
else:
self.bot.log("That's not happening")
@ -328,11 +328,11 @@ class StarWarsChar():
if key == "Talents" or key == "Force-powers" or key == "Weapons" or key == "Obligations":
self.bot.log("Trying to remove "+cmd+" from "+key)
if cmd in userCharacter[key]:
if cmd in user_character[key]:
self.bot.database["starwars characters"].update_one({"_id":user},
{"$unset": {cmd}})
self.bot.log("I did that")
return cmd+" removed from "+key+" from "+userCharacter["Name"]
return cmd+" removed from "+key+" from "+user_character["Name"]
else:
self.bot.log("Welp. I fucked that up")
return "Can't remove that"
@ -343,27 +343,27 @@ class StarWarsChar():
else:
self.bot.log("Looking up "+cmd+" in "+key)
if key == "Talents" or key == "Force-powers":
newKey = cmd
newcmd = ""
new_key = cmd
new_cmd = ""
else:
newKey = string.capwords(cmd.split(" ")[0])
newcmd = cmd[len(newKey):]
new_key = string.capwords(cmd.split(" ")[0])
new_cmd = cmd[len(new_key):]
lookUpResult = self.lookUp(userCharacter[key],newKey,newcmd)
look_up_result = self.look_up(user_character[key],new_key,new_cmd)
if type(lookUpResult) is dict:
if type(look_up_result) is dict:
self.bot.database["starwars characters"].update_one({"_id":user},
{"$set": {key : lookUpResult}})
return "Changed " + userCharacter["Name"] + "'s " + key
{"$set": {key : look_up_result}})
return "Changed " + user_character["Name"] + "'s " + key
else:
return lookUpResult
return look_up_result
else:
if cmd == "":
self.bot.log("Retrieving data")
if type(userCharacter[key]) is list:
return key+":\n"+", ".join(userCharacter[key])
if type(user_character[key]) is list:
return key+":\n"+", ".join(user_character[key])
else:
return userCharacter[key]
return user_character[key]
elif cmd[0] == '+':
self.bot.log("Adding")
try:
@ -374,21 +374,21 @@ class StarWarsChar():
self.bot.log("Error message")
return "Can't do that"
if type(userCharacter[key]) is int:
if type(user_character[key]) is int:
try:
self.bot.log("Adding "+cmd+" to "+key)
self.bot.database["starwars characters"].update_one({"_id":user},
{"$inc": {key : int(cmd)}})
return "Added " + cmd + " to " + userCharacter["Name"] + "'s " + key
return "Added " + cmd + " to " + user_character["Name"] + "'s " + key
except:
self.bot.log("BITCH SANDWICH")
return "Can't add that"
elif type(userCharacter[key]) is list:
elif type(user_character[key]) is list:
try:
self.bot.log("Adding "+cmd+" to "+key)
self.bot.database["starwars characters"].update_one({"_id":user},
{"$push": {key : cmd}})
return "Added " + cmd + " to " + userCharacter["Name"] + "'s " + key
return "Added " + cmd + " to " + user_character["Name"] + "'s " + key
except:
self.bot.log("tstststststs")
return "Can't add that"
@ -405,16 +405,16 @@ class StarWarsChar():
self.bot.log("lalalala ")
return "Can't do that"
if type(userCharacter[key]) is int:
if type(user_character[key]) is int:
try:
self.bot.log("Subtracting "+cmd+" from "+key)
self.bot.database["starwars characters"].update_one({"_id":user},
{"$inc": {key : -int(cmd)}})
return "Subtracted " + cmd + " from " + userCharacter["Name"] + "'s " + key
return "Subtracted " + cmd + " from " + user_character["Name"] + "'s " + key
except:
self.bot.log("Tried it. Didn't want to")
return "Can't remove that"
elif type(userCharacter[key]) is list:
elif type(user_character[key]) is list:
try:
self.bot.log("removing "+cmd+" from "+key)
try:
@ -423,7 +423,7 @@ class StarWarsChar():
except:
self.bot.log("They can only remove stuff that's actually in the list")
return "Not in list"
return "Removed " + cmd + " from " + userCharacter["Name"] + "'s " + key
return "Removed " + cmd + " from " + user_character["Name"] + "'s " + key
except:
self.bot.log("nah")
return "Can't remove that"
@ -432,20 +432,20 @@ class StarWarsChar():
return "Can't remove that"
else:
self.bot.log("Changing "+key+" to "+cmd)
if type(userCharacter[key]) is int:
if type(user_character[key]) is int:
try:
self.bot.database["starwars characters"].update_one({"_id":user},
{"$set": {key : int(cmd)}})
except:
self.bot.log("I don't wanna tho")
return "Can't do that"
elif type(userCharacter[key]) is str:
elif type(user_character[key]) is str:
self.bot.database["starwars characters"].update_one({"_id":user},
{"$set": {key : cmd}})
else:
self.bot.log("I don't wanna tho")
return "Can't do that"
return "Changed " + userCharacter["Name"] + "'s " + key +" to " + cmd
return "Changed " + user_character["Name"] + "'s " + key +" to " + cmd
else:
self.bot.log(key+" isn't in there")
return "Couldn't find that data. Are you sure you spelled it correctly?"
@ -453,32 +453,32 @@ class StarWarsChar():
self.bot.log(user+" doesn't have a character")
return "You don't have a character. You can make one with /starwarscharacter"
def replaceSpaces(self,cmd : str):
withSpaces = ["Specialization Trees","Wound Threshold","Strain Threshold","Defense - Ranged","Defense - Melee","Force Rating","Core Worlds","Outer Rim","Piloting - Planetary","Piloting - Space","Ranged - Heavy","Ranged - Light","Lightsaber Characteristic","Critical Injuries","Force Powers"]
withoutSpaces = ["Specialization-trees","Wound-threshold","Strain-threshold","Defense-ranged","Defense-melee","Force-rating","Core-worlds","Outer-rim","Piloting-planetary","Piloting-space","Ranged-heavy","Ranged-light","Lightsaber-characteristic","Critical-injuries","Force-powers"]
def replace_spaces(self,cmd : str):
with_spaces = ["Specialization Trees","Wound Threshold","Strain Threshold","Defense - Ranged","Defense - Melee","Force Rating","Core Worlds","Outer Rim","Piloting - Planetary","Piloting - Space","Ranged - Heavy","Ranged - Light","Lightsaber Characteristic","Critical Injuries","Force Powers"]
without_spaces = ["Specialization-trees","Wound-threshold","Strain-threshold","Defense-ranged","Defense-melee","Force-rating","Core-worlds","Outer-rim","Piloting-planetary","Piloting-space","Ranged-heavy","Ranged-light","Lightsaber-characteristic","Critical-injuries","Force-powers"]
for x, value in enumerate(withoutSpaces):
cmd = cmd.replace(withSpaces[x],value)
for i, value in enumerate(without_spaces):
cmd = cmd.replace(with_spaces[i],value)
return cmd
def replaceWithSpaces(self,cmd : str):
withSpaces = ["Specialization Trees","Wound Threshold","Strain Threshold","Defense - Ranged","Defense - Melee","Force Rating","Core Worlds","Outer Rim","Piloting - Planetary","Piloting - Space","Ranged - Heavy","Ranged - light","Lightsaber Characteristic","Critical Injuries","Force Powers"]
withoutSpaces = ["Specialization-trees","Wound-threshold","Strain-threshold","Defense-ranged","Defense-melee","Force-rating","Core-worlds","Outer-rim","Piloting-planetary","Piloting-space","Ranged-heavy","Ranged-light","Lightsaber-characteristic","Critical-injuries","Force-powers"]
def replace_with_spaces(self,cmd : str):
with_spaces = ["Specialization Trees","Wound Threshold","Strain Threshold","Defense - Ranged","Defense - Melee","Force Rating","Core Worlds","Outer Rim","Piloting - Planetary","Piloting - Space","Ranged - Heavy","Ranged - light","Lightsaber Characteristic","Critical Injuries","Force Powers"]
without_spaces = ["Specialization-trees","Wound-threshold","Strain-threshold","Defense-ranged","Defense-melee","Force-rating","Core-worlds","Outer-rim","Piloting-planetary","Piloting-space","Ranged-heavy","Ranged-light","Lightsaber-characteristic","Critical-injuries","Force-powers"]
for x, value in enumerate(withoutSpaces):
cmd = cmd.replace(value,withSpaces[x])
for i, value in enumerate(without_spaces):
cmd = cmd.replace(value,with_spaces[i])
return cmd
async def parseChar(self, ctx, parameters : str):
async def parse_char(self, ctx, parameters : str):
user = f"#{ctx.author.id}"
cmd = string.capwords(parameters.replace("+","+ ").replace("-","- ").replace(",",", "))
returnEmbed = False
return_embed = False
cmd = self.replaceSpaces(cmd)
cmd = self.replace_spaces(cmd)
userCharacter = self.bot.database["starwars characters"].find_one({"_id":user})
user_character = self.bot.database["starwars characters"].find_one({"_id":user})
if cmd == " ":
cmd = ""
@ -490,17 +490,17 @@ class StarWarsChar():
if cmd == "":
if userCharacter != None:
title, text = self.characterSheet(userCharacter)
text = self.replaceWithSpaces(text)
returnEmbed = True
if user_character != None:
title, text = self.character_sheet(user_character)
text = self.replace_with_spaces(text)
return_embed = True
else:
self.bot.log("Makin' a character for "+self.bot.database_funcs.get_name(user))
with open("gwendolyn/resources/star_wars/starwarstemplates.json", "r") as f:
templates = json.load(f)
newChar = templates["Character"]
newChar["_id"] = user
self.bot.database["starwars characters"].insert_one(newChar)
with open("gwendolyn/resources/star_wars/starwarstemplates.json", "r") as file_pointer:
templates = json.load(file_pointer)
new_char = templates["Character"]
new_char["_id"] = user
self.bot.database["starwars characters"].insert_one(new_char)
await ctx.send("Character for " + self.bot.database_funcs.get_name(user) + " created")
else:
if cmd == "Purge":
@ -508,22 +508,21 @@ class StarWarsChar():
self.bot.database["starwars characters"].delete_one({"_id":user})
await ctx.send("Character for " + self.bot.database_funcs.get_name(user) + " deleted")
else:
await ctx.send(self.replaceWithSpaces(str(self.char_data(user,cmd))))
await ctx.send(self.replace_with_spaces(str(self.char_data(user,cmd))))
if returnEmbed:
em = discord.Embed(title = title, description = text, colour=0xDEADBF)
await ctx.send(embed = em)
if return_embed:
embed = discord.Embed(title = title, description = text, colour=0xDEADBF)
await ctx.send(embed = embed)
def lightsaberChar(self,user : str):
userCharacter = self.bot.database["starwars characters"].find_one({"_id":user})
def lightsaber_char(self,user : str):
user_character = self.bot.database["starwars characters"].find_one({"_id":user})
if userCharacter != None:
return userCharacter["Lightsaber-characteristic"]
if user_character != None:
return user_character["Lightsaber-characteristic"]
def userHasChar(self,user : str):
userCharacter = self.bot.database["starwars characters"].find_one({"_id":user})
return userCharacter != None
def user_has_char(self,user : str):
user_character = self.bot.database["starwars characters"].find_one({"_id":user})
return user_character != None

View File

@ -2,27 +2,27 @@ class StarWarsDestiny():
def __init__(self, bot):
self.bot = bot
def destinyNew(self, num : int):
def destiny_new(self, num : int):
self.bot.log("Creating a new destiny pool with "+str(num)+" players")
roll, diceResults = self.bot.star_wars.roll.roll(0,0,0,0,0,0,num)
roll, dice_results = self.bot.star_wars.roll.roll(0,0,0,0,0,0,num)
roll = "".join(sorted(roll))
with open("gwendolyn/resources/star_wars/destinyPoints.txt","wt") as f:
f.write(roll)
with open("gwendolyn/resources/star_wars/destinyPoints.txt","wt") as file_pointer:
file_pointer.write(roll)
return "Rolled for Destiny Points and got:\n"+self.bot.star_wars.roll.diceResultToEmoji(diceResults)+"\n"+self.bot.star_wars.roll.resultToEmoji(roll)
return "Rolled for Destiny Points and got:\n"+self.bot.star_wars.roll.diceResultToEmoji(dice_results)+"\n"+self.bot.star_wars.roll.resultToEmoji(roll)
def destinyUse(self, user : str):
with open("gwendolyn/resources/star_wars/destinyPoints.txt","rt") as f:
points = f.read()
def destiny_use(self, user : str):
with open("gwendolyn/resources/star_wars/destinyPoints.txt","rt") as file_pointer:
points = file_pointer.read()
if user == "Nikolaj":
self.bot.log("Trying to use a dark side destiny point")
if 'B' in points:
points = points.replace("B","L",1)
points = "".join(sorted(points))
with open("gwendolyn/resources/star_wars/destinyPoints.txt","wt") as f:
f.write(points)
with open("gwendolyn/resources/star_wars/destinyPoints.txt","wt") as file_pointer:
file_pointer.write(points)
self.bot.log("Did it")
return "Used a dark side destiny point. Destiny pool is now:\n"+self.bot.star_wars.roll.resultToEmoji(points)
else:
@ -33,15 +33,15 @@ class StarWarsDestiny():
if 'L' in points:
points = points.replace("L","B",1)
points = "".join(sorted(points))
with open("gwendolyn/resources/star_wars/destinyPoints.txt","wt") as f:
f.write(points)
with open("gwendolyn/resources/star_wars/destinyPoints.txt","wt") as file_pointer:
file_pointer.write(points)
self.bot.log("Did it")
return "Used a light side destiny point. Destiny pool is now:\n"+self.bot.star_wars.roll.resultToEmoji(points)
else:
self.bot.log("There were no dark side destiny points")
return "No light side destiny points"
async def parseDestiny(self, ctx, cmd : str):
async def parse_destiny(self, ctx, cmd : str):
user = f"#{ctx.author.id}"
if cmd != "":
while cmd[0] == ' ':
@ -51,22 +51,22 @@ class StarWarsDestiny():
if cmd == "":
self.bot.log("Retrieving destiny pool info")
with open("gwendolyn/resources/star_wars/destinyPoints.txt","rt") as f:
send_message = self.bot.star_wars.roll.resultToEmoji(f.read())
with open("gwendolyn/resources/star_wars/destinyPoints.txt","rt") as file_pointer:
send_message = self.bot.star_wars.roll.resultToEmoji(file_pointer.read())
else:
commands = cmd.upper().split(" ")
if commands[0] == "N":
if len(commands) > 1:
send_message = self.destinyNew(int(commands[1]))
send_message = self.destiny_new(int(commands[1]))
else:
send_message = "You need to give an amount of players"
elif commands[0] == "U":
send_message = self.destinyUse(user)
send_message = self.destiny_use(user)
else:
send_message = "I didn't quite understand that"
message_list = send_message.split("\n")
await ctx.send(message_list[0])
if len(message_list) > 1:
for messageItem in message_list[1:]:
await ctx.channel.send(messageItem)
for message_item in message_list[1:]:
await ctx.channel.send(message_item)

View File

@ -13,43 +13,43 @@ class StarWarsRoll():
# Rolls the specified dice
def roll(self, abi : int = 1, prof : int = 0, dif : int = 3, cha : int = 0, boo : int = 0, setb : int = 0, force : int = 0):
result = ""
diceResult = []
dice_result = []
for _ in range(abi):
choice = random.choice(["","S","S","SS","A","A","SA","AA"])
result += choice
diceResult.append("abi"+choice)
dice_result.append("abi"+choice)
for _ in range(prof):
choice = random.choice(["","S","S","SS","SS","A","SA","SA","SA","AA","AA","R"])
result += choice
diceResult.append("prof"+choice)
dice_result.append("prof"+choice)
for _ in range(dif):
choice = random.choice(["","F","FF","H","H","H","HH","FH"])
result += choice
diceResult.append("dif"+choice)
dice_result.append("dif"+choice)
for _ in range(cha):
choice = random.choice(["","F","F","FF","FF","H","H","FH","FH","HH","HH","D"])
result += choice
diceResult.append("cha"+choice)
dice_result.append("cha"+choice)
for _ in range(boo):
choice = random.choice(["","","S","SA","AA","A"])
result += choice
diceResult.append("boo"+choice)
dice_result.append("boo"+choice)
for _ in range(setb):
choice = random.choice(["","","F","F","H","H"])
result += choice
diceResult.append("setb"+choice)
dice_result.append("setb"+choice)
for _ in range (force):
choice = random.choice(["B","B","B","B","B","B","BB","L","L","LL","LL","LL"])
result += choice
diceResult.append("force"+choice)
dice_result.append("force"+choice)
return result, diceResult
return result, dice_result
# Lets dice cancel each other out
def simplify(self, result : str):
@ -78,9 +78,9 @@ class StarWarsRoll():
return simp
# Returns emoji that symbolize the dice results
def diceResultToEmoji(self, diceResults : list):
def dice_result_to_emoji(self, dice_results : list):
emoji = ""
for result in diceResults:
for result in dice_results:
if result == "abiA":
emoji += "<:abil1a:695267684476125264> "
elif result == "abiSA":
@ -167,7 +167,7 @@ class StarWarsRoll():
return emoji
# Returns emoji that symbolize the results of the dice rolls
def resultToEmoji(self, result : str):
def result_to_emoji(self, result : str):
emoji = ""
for char in result:
if char == 'S':
@ -190,7 +190,7 @@ class StarWarsRoll():
return emoji
# Converts emoji into letters
def emojiToResult(self, emoji : str):
def emoji_to_result(self, emoji : str):
result = ""
for char in emoji:
if char == "<:light:691010089905029171>":
@ -201,7 +201,7 @@ class StarWarsRoll():
return result
# Returns emoji that symbolize the dice
def diceToEmoji(self, dice : list):
def dice_to_emoji(self, dice : list):
emoji = ""
for _ in range(dice[0]):
@ -222,7 +222,7 @@ class StarWarsRoll():
return emoji
# Rolls for obligation
def obligationRoll(self):
def obligation_roll(self):
self.bot.log("Rolling for obligation")
data = self.bot.database["starwarscharacters"]
@ -239,40 +239,40 @@ class StarWarsRoll():
return random.choice(table)
# Rolls for critical injury
async def critRoll(self, ctx, addington : int):
dd = "<:difficulty:690973992470708296>"
sd = "<:setback:690972157890658415>"
bd = "<:boost:690972178216386561>"
async def crit_roll(self, ctx, addington : int):
difficulty_die = "<:difficulty:690973992470708296>"
setback_die = "<:setback:690972157890658415>"
boost_die = "<:boost:690972178216386561>"
roll = random.randint(1,100) + addington
injuries = [
"**Minor nick**: The target suffers 1 strain, "+dd] * 5 + [
"**Slowed down**: The target can only act during the last allied initiative slot this turn, "+dd] * 5 + [
"**Sudden Jolt**: The target drops whatever is in hand, "+dd] * 5 + [
"**Distracted**: The target cannot perform a Free maneuver during his next turn, "+dd] * 5 + [
"**Off-Balance**: The target adds "+sd+" to his next skill check, "+dd] * 5 + [
"**Discouraging Wound**: Flip one light side Destiny point to a dark side Destiny point (reverse if NPC), "+dd] * 5 + [
"**Stunned**: The target is staggered until the end of his next turn, "+dd] * 5 + [
"**Stinger**: Increase the difficulty of next check by one, "+dd] * 5 + [
"**Bowled Over**: The target is knocked prone and suffers 1 strain, "+dd+dd] * 5 + [
"**Head Ringer**: The target increases the difficulty of all Intellect and Cunning checks by one until the end of the encounter, "+dd+dd] * 5 + [
"**Fearsome Wound**: The target increases the difficulty of all Presence and Willpower checks by one until the end of the encounter, "+dd+dd] * 5 + [
"**Agonizing Wound**: The target increases the difficulty of all Brawn and Agility checks by one until the end of the encounter, "+dd+dd] * 5 + [
"**Slightly Dazed**: The target is disoriented until the end of the encounter, "+dd+dd] * 5 + [
"**Scattered Senses**: The target removes all "+bd+" from skill checks until the end of the encounter, "+dd+dd] * 5 + [
"**Hamstrung**: The target loses his free maneuver until the end of the encounter, "+dd+dd] * 5 + [
"**Overpowered**: The target leaves himself open, and the attacker may immediately attempt another free attack agains him, using the exact same pool as the original, "+dd+dd] * 5 + [
"**Winded**: Until the end of the encounter, the target cannot voluntarily suffer strain to activate any abilities or gain additional maneuvers, "+dd+dd] * 5 + [
"**Compromised**: Incerase difficulty of all skill checks by one until the end of the encounter, "+dd+dd] * 5 + [
"**At the brink**: The target suffers 1 strain each time he performs an action, "+dd+dd+dd] * 5 + [
"**Crippled**: One of the target's limbs (selected by the GM) is crippled until healed or replaced. Increase difficulty of all checks that require use of that limb by one, "+dd+dd+dd] * 5 + [
"**Maimed**: One of the target's limbs (selected by the GM) is permanently lost. Unless the target has a cybernetic replacement, the target cannot perform actions that would require the use of that limb. All other actions gain "+sd+", "+dd+dd+dd] * 5 + [
"**Minor nick**: The target suffers 1 strain, "+difficulty_die] * 5 + [
"**Slowed down**: The target can only act during the last allied initiative slot this turn, "+difficulty_die] * 5 + [
"**Sudden Jolt**: The target drops whatever is in hand, "+difficulty_die] * 5 + [
"**Distracted**: The target cannot perform a Free maneuver during his next turn, "+difficulty_die] * 5 + [
"**Off-Balance**: The target adds "+setback_die+" to his next skill check, "+difficulty_die] * 5 + [
"**Discouraging Wound**: Flip one light side Destiny point to a dark side Destiny point (reverse if NPC), "+difficulty_die] * 5 + [
"**Stunned**: The target is staggered until the end of his next turn, "+difficulty_die] * 5 + [
"**Stinger**: Increase the difficulty of next check by one, "+difficulty_die] * 5 + [
"**Bowled Over**: The target is knocked prone and suffers 1 strain, "+difficulty_die+difficulty_die] * 5 + [
"**Head Ringer**: The target increases the difficulty of all Intellect and Cunning checks by one until the end of the encounter, "+difficulty_die+difficulty_die] * 5 + [
"**Fearsome Wound**: The target increases the difficulty of all Presence and Willpower checks by one until the end of the encounter, "+difficulty_die+difficulty_die] * 5 + [
"**Agonizing Wound**: The target increases the difficulty of all Brawn and Agility checks by one until the end of the encounter, "+difficulty_die+difficulty_die] * 5 + [
"**Slightly Dazed**: The target is disoriented until the end of the encounter, "+difficulty_die+difficulty_die] * 5 + [
"**Scattered Senses**: The target removes all "+boost_die+" from skill checks until the end of the encounter, "+difficulty_die+difficulty_die] * 5 + [
"**Hamstrung**: The target loses his free maneuver until the end of the encounter, "+difficulty_die+difficulty_die] * 5 + [
"**Overpowered**: The target leaves himself open, and the attacker may immediately attempt another free attack agains him, using the exact same pool as the original, "+difficulty_die+difficulty_die] * 5 + [
"**Winded**: Until the end of the encounter, the target cannot voluntarily suffer strain to activate any abilities or gain additional maneuvers, "+difficulty_die+difficulty_die] * 5 + [
"**Compromised**: Incerase difficulty of all skill checks by one until the end of the encounter, "+difficulty_die+difficulty_die] * 5 + [
"**At the brink**: The target suffers 1 strain each time he performs an action, "+difficulty_die+difficulty_die+difficulty_die] * 5 + [
"**Crippled**: One of the target's limbs (selected by the GM) is crippled until healed or replaced. Increase difficulty of all checks that require use of that limb by one, "+difficulty_die+difficulty_die+difficulty_die] * 5 + [
"**Maimed**: One of the target's limbs (selected by the GM) is permanently lost. Unless the target has a cybernetic replacement, the target cannot perform actions that would require the use of that limb. All other actions gain "+setback_die+", "+difficulty_die+difficulty_die+difficulty_die] * 5 + [
"HI"] * 5 + [
"**Temporarily Lame**: Until this critical injury is healed, the target cannot perform more than one maneuver during his turn, "+dd+dd+dd] * 5 + [
"**Blinded**: The target can no longer see. Upgrade the difficulty of all checks twice. Upgrade the difficulty of perception checks three times, "+dd+dd+dd] * 5 + [
"**Knocked Senseless**: The target is staggered for the remainder of the encounter, "+dd+dd+dd] * 5 + [
"**Temporarily Lame**: Until this critical injury is healed, the target cannot perform more than one maneuver during his turn, "+difficulty_die+difficulty_die+difficulty_die] * 5 + [
"**Blinded**: The target can no longer see. Upgrade the difficulty of all checks twice. Upgrade the difficulty of perception checks three times, "+difficulty_die+difficulty_die+difficulty_die] * 5 + [
"**Knocked Senseless**: The target is staggered for the remainder of the encounter, "+difficulty_die+difficulty_die+difficulty_die] * 5 + [
"GI"] * 5 + [
"**Bleeding Out**: Every round, the target suffers 1 wound and 1 strain at the beginning of his turn. For every five wounds he suffers beyond his wound threshold, he suffers one additional critical injury. (If he suffers this one again, roll again), "+dd+dd+dd+dd] * 10 + [
"**The End is Nigh**: The target will die after the last initiative slot during the next round, "+dd+dd+dd+dd] * 10 + [
"**Bleeding Out**: Every round, the target suffers 1 wound and 1 strain at the beginning of his turn. For every five wounds he suffers beyond his wound threshold, he suffers one additional critical injury. (If he suffers this one again, roll again), "+difficulty_die+difficulty_die+difficulty_die+difficulty_die] * 10 + [
"**The End is Nigh**: The target will die after the last initiative slot during the next round, "+difficulty_die+difficulty_die+difficulty_die+difficulty_die] * 10 + [
"**Dead**: U B Dead :("]
if roll >= len(injuries):
@ -282,56 +282,56 @@ class StarWarsRoll():
if results == "HI":
characteristic = random.choice(["brawn"] * 3 + ["agility"] * 3 + ["intellect", "cunning", "presence"])
results = "**Horrific Injury**: Until this criticil injury is healed, treat the target's "+characteristic+" as if it's one lower, "+dd+dd+dd
results = "**Horrific Injury**: Until this criticil injury is healed, treat the target's "+characteristic+" as if it's one lower, "+difficulty_die+difficulty_die+difficulty_die
if results == "GI":
characteristic = random.choice(["brawn"] * 3 + ["agility"] * 3 + ["intellect", "cunning", "presence"])
results = "**Gruesome Injury**: The target's "+characteristic+" is permanently one lower, "+dd+dd+dd+dd
results = "**Gruesome Injury**: The target's "+characteristic+" is permanently one lower, "+difficulty_die+difficulty_die+difficulty_die+difficulty_die
send_message = "Roll: "+str(roll)+"\nInjury:\n"+results
message_list = send_message.split("\n")
await ctx.send(message_list[0])
if len(message_list) > 1:
for messageItem in message_list[1:]:
await ctx.channel.send(messageItem)
for message_item in message_list[1:]:
await ctx.channel.send(message_item)
# Parses the command into something the other functions understand
async def parseRoll(self, ctx, cmd : str = ""):
async def parse_roll(self, ctx, cmd : str = ""):
user = f"#{ctx.author.id}"
cmd = re.sub(' +',' ',cmd.upper()) + " "
if cmd[0] == " ":
cmd = cmd[1:]
cmd = self.bot.star_wars.character.replaceSpaces(string.capwords(cmd))
commands = cmd.split(" ")
validCommand = False
valid_command = False
if commands[0] == "":
rollParameters = [1,0,3,0,0,0,0]
roll_parameters = [1,0,3,0,0,0,0]
else:
rollParameters = [0,0,0,0,0,0,0]
roll_parameters = [0,0,0,0,0,0,0]
if string.capwords(commands[0]) == "Obligations":
send_message = self.obligationRoll()
send_message = self.obligation_roll()
elif string.capwords(commands[0]) in skill_data:
self.bot.log("Oh look! This guy has skills!")
if self.bot.star_wars.character.userHasChar(user):
self.bot.log("They have a character. That much we know")
skillLevel = self.bot.star_wars.character.char_data(user,"Skills " + string.capwords(commands[0]))
skill_level = self.bot.star_wars.character.char_data(user,"Skills " + string.capwords(commands[0]))
if string.capwords(commands[0]) == "Lightsaber":
self.bot.log("The skill is lightsaber")
charLevel = self.bot.star_wars.character.char_data(user,"Characteristics " + self.bot.star_wars.character.lightsaberChar(user))
char_level = self.bot.star_wars.character.char_data(user,"Characteristics " + self.bot.star_wars.character.lightsaberChar(user))
else:
charLevel = self.bot.star_wars.character.char_data(user,"Characteristics " + skill_data[string.capwords(commands[0])])
char_level = self.bot.star_wars.character.char_data(user,"Characteristics " + skill_data[string.capwords(commands[0])])
abilityDice = abs(charLevel-skillLevel)
proficiencyDice = min(skillLevel,charLevel)
ability_dice = abs(char_level-skill_level)
proficiency_dice = min(skill_level,char_level)
commands = [str(abilityDice)] + [str(proficiencyDice)] + commands[1:]
commands = [str(ability_dice)] + [str(proficiency_dice)] + commands[1:]
self.bot.log("Converted skill to dice")
validCommand = True
valid_command = True
else:
self.bot.log("Okay, no they don't i guess")
send_message = "You don't have a user. You can make one with /starwarscharacter"
@ -343,49 +343,49 @@ class StarWarsRoll():
else:
send_message = "Did you mean \"Piloting - Planetary\" or \"Piloting - Space\""
else:
validCommand = True
valid_command = True
if validCommand:
if valid_command:
self.bot.log("Converting commands to dice")
for x, command in enumerate(commands):
for i, command in enumerate(commands):
if command != "":
command = command.upper()
if command[0] == "A":
rollParameters[0] = int(command.replace("A",""))
roll_parameters[0] = int(command.replace("A",""))
elif command[0] == "P":
rollParameters[1] = int(command.replace("P",""))
roll_parameters[1] = int(command.replace("P",""))
elif command[0] == "D":
rollParameters[2] = int(command.replace("D",""))
roll_parameters[2] = int(command.replace("D",""))
elif command[0] == "C":
rollParameters[3] = int(command.replace("C",""))
roll_parameters[3] = int(command.replace("C",""))
elif command[0] == "B":
rollParameters[4] = int(command.replace("B",""))
roll_parameters[4] = int(command.replace("B",""))
elif command[0] == "S":
rollParameters[5] = int(command.replace("S",""))
roll_parameters[5] = int(command.replace("S",""))
elif command[0] == "F":
rollParameters[6] = int(command.replace("F",""))
roll_parameters[6] = int(command.replace("F",""))
else:
rollParameters[x] = int(command)
roll_parameters[i] = int(command)
self.bot.log("Rolling "+str(rollParameters))
rollResults, diceResults = self.roll(rollParameters[0],rollParameters[1],rollParameters[2],rollParameters[3],rollParameters[4],rollParameters[5],rollParameters[6])
self.bot.log("Rolling "+str(roll_parameters))
roll_results, dice_results = self.roll(roll_parameters[0],roll_parameters[1],roll_parameters[2],roll_parameters[3],roll_parameters[4],roll_parameters[5],roll_parameters[6])
simplified = self.simplify(rollResults)
simplified = self.simplify(roll_results)
name = self.bot.star_wars.character.getChar_name(user)
self.bot.log("Returns results and simplified results")
if simplified == "":
send_message = name + " rolls: " + "\n" + self.diceResultToEmoji(diceResults) + "\nEverything cancels out!"
send_message = name + " rolls: " + "\n" + self.dice_result_to_emoji(dice_results) + "\nEverything cancels out!"
else:
send_message = name + " rolls: " + "\n" + self.diceResultToEmoji(diceResults) + "\n" + self.resultToEmoji(simplified)
send_message = name + " rolls: " + "\n" + self.dice_result_to_emoji(dice_results) + "\n" + self.result_to_emoji(simplified)
message_list = send_message.split("\n")
await ctx.send(message_list[0])
if len(message_list) > 1:
for messageItem in message_list[1:]:
if messageItem == "":
for message_item in message_list[1:]:
if message_item == "":
self.bot.log("Tried to send empty message")
else:
await ctx.channel.send(messageItem)
await ctx.channel.send(message_item)

View File

@ -94,7 +94,7 @@ class Gwendolyn(commands.Bot):
if filename.endswith(".py"):
self.load_extension(f"gwendolyn.cogs.{filename[:-3]}")
def log(self, messages, channel: str = "", level: int = 20):
def log(self, messages, channel: str = "", level: int = 20): # pylint:disable=no-self-use
"""Log a message. Described in utils/util_functions.py."""
log_this(messages, channel, level)

View File

Before

Width:  |  Height:  |  Size: 529 KiB

After

Width:  |  Height:  |  Size: 529 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@ -7,7 +7,7 @@
"Blackjack double": "Adding another {} GwendoBucks to {}'s bet and drawing another card.",
"Blackjack different cards": "You can only split if your cards have the same value",
"Blackjack split": "Splitting {}'s hand into 2. Adding their original bet to the second hand. You can use \"/blackjack hit/stand/double 1\" and \"/blackjack hit/stand/double 2\" to play the different hands.",
"Blackjack started": "Blackjack game started. Use \"/blackjack bet [amount]\" to enter the game within the next 30 seconds.",
"Blackjack started": "Blackjack game started. Use the buttons or \"/blackjack bet [amount]\" to enter the game within the next 30 seconds.",
"Blackjack going on": "There's already a blackjack game going on. Try again in a few minutes.",
"Stock value": "The current {} stock is valued at **{}** GwendoBucks",
"Stock parameters": "You must give both a stock name and an amount of GwendoBucks you wish to spend.",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 610 KiB

View File

@ -45,68 +45,16 @@
"name" : "cards",
"description" : "Get a count of the cards used in blackjack games"
},
"blackjack_double" : {
"base" : "blackjack",
"name" : "double",
"description" : "Double your bet in blackjack",
"options" : [
{
"name" : "hand",
"description" : "The number of the hand to double your bet on",
"type" : 4,
"required" : "false"
}
]
},
"blackjack_hilo" : {
"base" : "blackjack",
"name" : "hilo",
"description" : "Get the current hi-lo value for the cards used in blackjack games"
},
"blackjack_hit" : {
"base" : "blackjack",
"name" : "hit",
"description" : "Hit on your hand in blackjack",
"options" : [
{
"name" : "hand",
"description" : "The number of the hand to hit if you've split",
"type" : 4,
"required" : "false"
}
]
},
"blackjack_shuffle" : {
"base" : "blackjack",
"name" : "shuffle",
"description" : "Shuffle the cards used in blackjack games"
},
"blackjack_split" : {
"base" : "blackjack",
"name" : "split",
"description" : "Split your hand in blackjack",
"options" : [
{
"name" : "hand",
"description" : "The number of the hand to split, in case you've already split once",
"type" : 4,
"required" : "false"
}
]
},
"blackjack_stand" : {
"base" : "blackjack",
"name" : "stand",
"description" : "Stand on your hand in blackjack",
"options" : [
{
"name" : "hand",
"description" : "The number of the hand to stand if you've split",
"type" : 4,
"required" : "false"
}
]
},
"blackjack_start" : {
"base" : "blackjack",
"name" : "start",

View File

@ -15,6 +15,7 @@ from discord.ext import commands # Used to compare errors with command
from discord_slash.context import SlashContext, ComponentContext
from gwendolyn.utils.util_functions import decode_id
from gwendolyn.exceptions import InvalidInteraction
class EventHandler():
@ -62,9 +63,11 @@ class EventHandler():
self.bot.log(log_message, str(ctx.channel_id), level=25)
async def on_component(self, ctx: ComponentContext):
"""Handle component interaction."""
info = decode_id(ctx.custom_id)
self.bot.log(f"Component action with info {info}")
channel = ctx.origin_message.channel
channel = ctx.channel
author = str(ctx.author_id)
if info[0].lower() == "plex":
if info[1].lower() == "movie":
@ -73,6 +76,7 @@ class EventHandler():
info[2],
not isinstance(channel, discord.DMChannel)
)
return
elif info[1].lower() == "show":
await self.bot.other.plex.add_show(
@ -80,18 +84,20 @@ class EventHandler():
info[2],
not isinstance(channel, discord.DMChannel)
)
else:
raise InvalidInteraction(ctx.custom_id, info)
elif info[0].lower() == "hangman":
if str(ctx.author_id) == info[2]:
if info[1].lower() == "guess":
await self.bot.games.hangman.guess(ctx, *info[3:])
elif info[1].lower() == "end":
await self.bot.games.hangman.stop(ctx, *info[3:])
elif info[0].lower() == "hangman" and author == info[2]:
if info[1].lower() == "guess":
await self.bot.games.hangman.guess(ctx, *info[3:])
elif info[1].lower() == "end":
await self.bot.games.hangman.stop(ctx, *info[3:])
else:
raise InvalidInteraction(ctx.custom_id, info)
elif info[0].lower() == "connectfour":
connect_four = self.bot.games.connect_four
if info[1].lower() == "place" and str(ctx.author_id) == info[2]:
params = [
if info[1].lower() == "place" and author == info[2]:
await connect_four.place_piece(
ctx,
info[3],
int(info[4]),
@ -99,14 +105,17 @@ class EventHandler():
int(info[7]),
ctx.author_id,
int(info[8])
]
await connect_four.place_piece(*params)
if info[1].lower() == "end":
if str(ctx.author_id) in [info[2], info[3]]:
params = [
ctx, [int(info[2]), int(info[3])], info[4], info[5]
]
await connect_four.surrender(*params)
)
elif info[1].lower() == "end" and author in [info[2], info[3]]:
await connect_four.surrender(
ctx, [int(info[2]), int(info[3])], info[4], info[5]
)
else:
raise InvalidInteraction(ctx.custom_id, info)
elif info[0].lower() == "blackjack":
await self.bot.games.blackjack.decode_interaction(ctx, info[1:])
else:
raise InvalidInteraction(ctx.custom_id, info)

View File

@ -139,7 +139,7 @@ class DatabaseFuncs():
old_images_path = "gwendolyn/resources/games/old_images/"
file_path = old_images_path + f"connect_four{channel.id}"
if os.path.isfile(file_path):
with open(file_path, "r") as file_pointer:
with open(file_path, "r", encoding="utf-8") as file_pointer:
old_image = int(file_pointer.read())
else:
old_image = 0

View File

@ -16,12 +16,12 @@ Contains utility functions used by parts of the bot.
new_string: str) -> str
emoji_to_command(emoji: str) -> str
"""
import string
import json # Used by long_strings(), get_params() and make_files()
import logging # Used for logging
import os # Used by make_files() to check if files exist
import sys # Used to specify printing for logging
import imdb # Used to disable logging for the module
import string
BASE_37 = ":" + string.digits + string.ascii_uppercase
@ -109,7 +109,7 @@ def get_options():
options: dict
The options of the bot.
"""
with open("options.txt", "r") as file_pointer:
with open("options.txt", "r", encoding="utf-8") as file_pointer:
data = sanitize(file_pointer.read(), True)
options = {}
@ -128,7 +128,7 @@ def get_credentials():
credentials: dict
The credentials used by the bot.
"""
with open("credentials.txt", "r") as file_pointer:
with open("credentials.txt", "r", encoding="utf-8") as file_pointer:
data = sanitize(file_pointer.read())
credentials = {}
@ -155,7 +155,8 @@ def long_strings():
data: dict
The long strings and their keys.
"""
with open("gwendolyn/resources/long_strings.json", "r") as file_pointer:
long_strings_path = "gwendolyn/resources/long_strings.json"
with open(long_strings_path, "r", encoding="utf-8") as file_pointer:
data = json.load(file_pointer)
return data
@ -170,7 +171,8 @@ def get_params():
params: dict
The parameters for every slash command.
"""
with open("gwendolyn/resources/slash_parameters.json", "r") as file_pointer:
path = "gwendolyn/resources/slash_parameters.json"
with open(path, "r", encoding="utf-8") as file_pointer:
slash_parameters = json.load(file_pointer)
options = get_options()
@ -256,14 +258,14 @@ def make_files():
"""Create json file if it doesn't exist."""
if not os.path.isfile(path):
log_this(path.split("/")[-1]+" didn't exist. Making it now.")
with open(path, "w") as file_pointer:
with open(path, "w", encoding="utf-8") as file_pointer:
json.dump(content, file_pointer, indent=4)
def make_txt_file(path, content):
"""Create txt file if it doesn't exist."""
if not os.path.isfile(path):
log_this(path.split("/")[-1]+" didn't exist. Making it now.")
with open(path, "w") as file_pointer:
with open(path, "w", encoding="utf-8") as file_pointer:
file_pointer.write(content)
def directory(path):
@ -272,7 +274,8 @@ def make_files():
os.makedirs(path)
log_this("The "+path.split("/")[-1]+" directory didn't exist")
with open("gwendolyn/resources/starting_files.json") as file_pointer:
file_path = "gwendolyn/resources/starting_files.json"
with open(file_path, "r", encoding="utf-8") as file_pointer:
data = json.load(file_pointer)
for path, content in data["json"].items():

View File

@ -1,5 +1,5 @@
aiohttp==3.7.4.post0
async-timeout==3.0.1
aiohttp==3.8.1
async-timeout==4.0.2
attrs==21.2.0
beautifulsoup4==4.9.3
cachetools==4.2.2
@ -19,10 +19,10 @@ idna==3.2
IMDbPY==2021.4.18
jaraco.context==4.0.0
lark-parser==0.9.0
lxml==4.6.3
lxml==4.7.1
more-itertools==8.8.0
multidict==5.1.0
Pillow==8.3.1
Pillow==9.0.0
pymongo==3.12.0
requests==2.26.0
setuptools==57.4.0