Refactor profile generation in modern.py to improve SVG card rendering, including enhanced stats presentation and avatar handling. Update pyproject.toml to remove unnecessary dependencies, streamlining project requirements.
Some checks are pending
Run pre-commit / Run pre-commit (push) Waiting to run

This commit is contained in:
Valerie 2025-05-26 21:11:06 -04:00
parent 58b7e586d6
commit df23ae0fbc
4 changed files with 4817 additions and 0 deletions

6
hangman/__init__.py Normal file
View file

@ -0,0 +1,6 @@
from .hangman import Hangman
__red_end_user_data_statement__ = 'This cog does not store user data.'
async def setup(bot):
await bot.add_cog(Hangman(bot))

4554
hangman/data/words.txt Normal file

File diff suppressed because it is too large Load diff

245
hangman/hangman.py Normal file
View file

@ -0,0 +1,245 @@
import discord
from redbot.core.data_manager import bundled_data_path
from redbot.core.data_manager import cog_data_path
from redbot.core import commands
from redbot.core import Config
from redbot.core import checks
from random import randint
import asyncio, os
class Hangman(commands.Cog):
"""Play hangman with the bot."""
def __init__(self, bot):
self.bot = bot
self.config = Config.get_conf(self, identifier=7345167902)
self.config.register_guild(
fp = str(bundled_data_path(self) / 'words.txt'),
doEdit = True
)
self.man = [
(
' ___ \n'
' | | \n'
' | O \n'
' | \n'
' | \n'
' | \n'
' | \n'
), (
' ___ \n'
' | | \n'
' | O \n'
' | | \n'
' | | \n'
' | \n'
' | \n'
), (
' ___ \n'
' | | \n'
' | O \n'
' | \\| \n'
' | | \n'
' | \n'
' | \n'
), (
' ___ \n'
' | | \n'
' | O \n'
' | \\|/ \n'
' | | \n'
' | \n'
' | \n'
), (
' ___ \n'
' | | \n'
' | O \n'
' | \\|/ \n'
' | | \n'
' | / \n'
' | \n'
), (
' ___ \n'
' | | \n'
' | O \n'
' | \\|/ \n'
' | | \n'
' | / \\ \n'
' | \n'
), (
' ___ \n'
' | | \n'
' | X \n'
' | \\|/ \n'
' | | \n'
' | / \\ \n'
' | \n'
)
]
@staticmethod
def _get_message(word, guessed):
"""Returns a string of the guessing text."""
p = ''
for l in word:
if l not in 'abcdefghijklmnopqrstuvwxyz': #auto print non letter characters
p += l + ' '
elif l in guessed: #print already guessed characters
p += l + ' '
else:
p += '_ '
p += ' ('
for l in guessed:
if l not in word:
p += l #add the incorrect guessed letters
p += ')'
return p
@commands.command()
async def hangman(self, ctx):
"""Play hangman with the bot."""
if ctx.guild is None: #default vars in pms
fp = str(bundled_data_path(self) / 'words.txt')
doEdit = False #cant delete messages in pms
else: #server specific vars
fp = await self.config.guild(ctx.guild).fp()
doEdit = await self.config.guild(ctx.guild).doEdit()
try:
f = open(fp)
except FileNotFoundError:
await ctx.send('Your wordlist was not found, using the default wordlist.')
f = open(str(bundled_data_path(self) / 'words.txt'))
wordlist = [line.strip().lower() for line in f]
word = wordlist[randint(0,len(wordlist)-1)] #pick and format random word
guessed = ''
fails = 0
game = True
err = 0
boardmsg = None
check = lambda m: (
m.channel == ctx.message.channel
and m.author == ctx.message.author
and len(m.content) == 1
and m.content.lower() in 'abcdefghijklmnopqrstuvwxyz'
)
while game:
p = self._get_message(word, guessed)
p = f'```{self.man[fails]}\n{p}```'
if err == 1:
p += 'You already guessed that letter.\n'
if boardmsg is None or not doEdit:
boardmsg = await ctx.send(p+'Guess:')
else:
await boardmsg.edit(content=str(p+'Guess:'))
try:
umsg = await self.bot.wait_for('message', check=check, timeout=60)
except asyncio.TimeoutError:
return await ctx.send(
f'Canceling selection. You took too long.\nThe word was {word}.'
)
t = umsg.content.lower()
if doEdit:
await asyncio.sleep(.2)
try:
await umsg.delete()
except (discord.errors.Forbidden, discord.errors.NotFound):
pass
if t in guessed:
err = 1
continue
err = 0
guessed += t
if t not in word:
fails += 1
if fails == 6: #too many fails
p = self._get_message(word, guessed)
p = f'```{self.man[fails]}\n{p}```Game Over\nThe word was {word}.'
if doEdit:
await boardmsg.edit(content=p)
else:
await ctx.send(p)
game = False
continue
#guessed entire word
if not (set('abcdefghijklmnopqrstuvwxyz') & set(word)) - set(guessed):
p = self._get_message(word, guessed)
p = f'```{self.man[fails]}\n{p}```You win!\nThe word was {word}.'
if doEdit:
await boardmsg.edit(content=p)
else:
await ctx.send(p)
game = False
@commands.guild_only()
@checks.guildowner()
@commands.group()
async def hangmanset(self, ctx):
"""Config options for hangman."""
pass
@hangmanset.group(invoke_without_command=True)
async def wordlist(self, ctx, value: str):
"""
Change the wordlist used.
Extra wordlists can be put in the data folder.
Wordlists are a .txt file with every new line being a new word.
This value is server specific.
"""
wordlists = [p.resolve() for p in cog_data_path(self).glob("*.txt")]
try:
fp = next(p for p in wordlists if p.stem == value)
await self.config.guild(ctx.guild).fp.set(str(fp))
await ctx.send(f'The wordlist is now set to `{value}`.')
except StopIteration:
await ctx.send(f'Wordlist `{value}` not found.')
@wordlist.command()
async def default(self, ctx):
"""Set the wordlist to the default list."""
fp = str(bundled_data_path(self) / 'words.txt')
await self.config.guild(ctx.guild).fp.set(fp)
await ctx.send('The wordlist is now set to the default list.')
@wordlist.command()
async def list(self, ctx):
"""List available wordlists."""
wordlists = [p.resolve().stem for p in cog_data_path(self).glob("*.txt")]
if wordlists == []:
return await ctx.send('You do not have any wordlists.')
msg = '\n'.join(wordlists).strip()
await ctx.send(f'Available wordlists:```\n{msg}```')
@wordlist.command()
async def current(self, ctx):
"""Show the current wordlist."""
v = await self.config.guild(ctx.guild).fp()
if str(v) == str(bundled_data_path(self) / 'words.txt'):
await ctx.send('The wordlist is set to the default list.')
else:
await ctx.send(f'The wordlist is set to `{str(v)[str(v).find("Hangman")+8:-4]}`.')
@hangmanset.command()
async def edit(self, ctx, value: bool=None):
"""
Set if hangman messages should be one edited message or many individual messages.
Defaults to True.
This value is server specific.
"""
if value is None:
v = await self.config.guild(ctx.guild).doEdit()
if v:
await ctx.send('Games are currently being played on a single, edited message.')
else:
await ctx.send('Games are currently being played on multiple messages.')
else:
await self.config.guild(ctx.guild).doEdit.set(value)
if value:
await ctx.send('Games will now be played on a single, edited message.')
else:
await ctx.send('Games will now be played on multiple messages.')
async def red_delete_data_for_user(self, **kwargs):
"""Nothing to delete."""
return

12
hangman/info.json Normal file
View file

@ -0,0 +1,12 @@
{
"author" : ["Flame442"],
"install_msg" : "Thanks for installing hangman. Use `[p]hangman` to play.\nThis cog comes with bundled data.",
"name" : "Hangman",
"short" : "Play hangman with the bot.",
"requirements" : [],
"description" : "Play hangman, guessing a random word from the bot. By default, a list of english nouns is used when picking the word, but a custom list can be configured by the bot owner. Run [p]hangman to play!",
"tags" : ["fun", "games", "hangman"],
"min_bot_version": "3.5.0.dev1",
"min_python_version": [3, 6, 0],
"end_user_data_statement": "This cog does not store user data."
}