Compare commits

..

4 Commits

Author SHA1 Message Date
220f5759e9 Removed redundant "important function" call 2025-06-27 07:53:45 +01:00
bba51ebc8c Cleaned up code 2025-06-27 07:53:02 +01:00
904601c697 Added basic implementation of createCaptcha(), Needs to be cleaned up 2025-06-27 07:18:11 +01:00
ce771d26a3 Fixed typos 2025-06-27 07:17:39 +01:00
2 changed files with 80 additions and 34 deletions

View File

@ -1,16 +1,16 @@
[ [
{"file": "Noxlock-Free.otf", "alphabet": "abcdefghijklmnopqrstuvwxyz", "dificulty": 0.0}, {"file": "Noxlock-Free.otf", "alphabet": "abcdefghijklmnopqrstuvwxyz", "difficulty": 0.0},
{"file": "Chernobyl.otf", "alphabet": "abcdefghijklmnopqrstuvwxyz0123456789", "dificulty": 0.1}, {"file": "Chernobyl.otf", "alphabet": "abcdefghijklmnopqrstuvwxyz0123456789", "difficulty": 0.1},
{"file": "VIDEO PIRATE.ttf", "alphabet": "abcdefghijklmnopqrstuvwxyz", "dificulty": 0.1}, {"file": "VIDEO PIRATE.ttf", "alphabet": "abcdefghijklmnopqrstuvwxyz", "difficulty": 0.1},
{"file": "Vampire Wars.ttf", "alphabet": "abcdefghijklmnopqrstuvwxyz0123456789", "dificulty": 0.1}, {"file": "Vampire Wars.ttf", "alphabet": "abcdefghijklmnopqrstuvwxyz0123456789", "difficulty": 0.1},
{"file": "CloisterBlack.ttf", "alphabet": "0123456789", "dificulty": 0.1}, {"file": "CloisterBlack.ttf", "alphabet": "0123456789", "difficulty": 0.1},
{"file": "Noxlock-Free.otf", "alphabet": "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "dificulty": 0.2}, {"file": "Noxlock-Free.otf", "alphabet": "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "difficulty": 0.2},
{"file": "CloisterBlack.ttf", "alphabet": "abcdefghijklmnopqrstuvwxyz", "dificulty": 0.3}, {"file": "CloisterBlack.ttf", "alphabet": "abcdefghijklmnopqrstuvwxyz", "difficulty": 0.3},
{"file": "LEDLIGHT.otf", "alphabet": "abcdefghijklmnopqrstuvwxyz", "dificulty": 0.4}, {"file": "LEDLIGHT.otf", "alphabet": "abcdefghijklmnopqrstuvwxyz", "difficulty": 0.4},
{"file": "Flame on Black", "alphabet": "abcdefghijklmnopqrstuvwxyz0123456789!?/#<>", "dificulty": 0.5}, {"file": "Flame on Black.ttf", "alphabet": "abcdefghijklmnopqrstuvwxyz0123456789!?/#<>", "difficulty": 0.5},
{"file": "CloisterBlack.ttf", "alphabet": "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "dificulty": 0.6}, {"file": "CloisterBlack.ttf", "alphabet": "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "difficulty": 0.6},
{"file": "mevno2.ttf", "alphabet": "abcdefghijklmnopqrstuvwxyz", "dificulty": 0.8}, {"file": "mevno2.ttf", "alphabet": "abcdefghijklmnopqrstuvwxyz", "difficulty": 0.8},
{"file": "CloisterBlack.ttf", "alphabet": "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "dificulty": 0.8}, {"file": "CloisterBlack.ttf", "alphabet": "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "difficulty": 0.8},
{"file": "RoyalInitialen.ttf", "alphabet": "abcdefghijklmnopqrstuvwxyz", "dificulty": 0.8}, {"file": "RoyalInitialen.ttf", "alphabet": "abcdefghijklmnopqrstuvwxyz", "difficulty": 0.8},
{"file": "DeathMohawk_PERSONAL_USE_ONLY.otf", "alphabet": "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "dificulty": 1.0} {"file": "DeathMohawk_PERSONAL_USE_ONLY.otf", "alphabet": "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "difficulty": 1.0}
] ]

86
game.py
View File

@ -1,10 +1,13 @@
from PIL import Image, ImageDraw, ImageFont from PIL import Image, ImageDraw, ImageFont
import math as maths
import logging import logging
import pygame import pygame
import gameUtils import gameUtils
import NoPELib import NoPELib
import random import random
import json import json
import time
import os
def normalDist(difficulty): def normalDist(difficulty):
""" """
@ -22,6 +25,18 @@ def normalDist(difficulty):
# Cap it to be 0-1 again and return # Cap it to be 0-1 again and return
return min(max(v, 0), 1) return min(max(v, 0), 1)
def PIL2PG(pilImage: Image) -> pygame.Surface:
"""
Converts a PIL image to a Pygame surface.
"""
return pygame.image.fromstring(pilImage.tobytes(), pilImage.size, pilImage.mode)
class Font:
def __init__(self, data, fontSize):
self.font = ImageFont.truetype(os.path.join('./fonts/', data['file']), fontSize)
self.alphabet = data['alphabet']
self.difficulty = data['difficulty']
class Game(gameUtils.Game): class Game(gameUtils.Game):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
""" """
@ -32,7 +47,7 @@ class Game(gameUtils.Game):
self.pm (NoPELib.PlayerManager): This is where your players are stored. self.pm (NoPELib.PlayerManager): This is where your players are stored.
self.cfg (dict): Everything from the `game.toml` file. You can access it like this: self.details['title'] self.cfg (dict): Everything from the `game.toml` file. You can access it like this: self.details['title']
""" """
# Don't remove this. It does important things. :3 # Don't remove this. It does important things. :3
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@ -41,26 +56,69 @@ class Game(gameUtils.Game):
# The actual text in the captcha, used to check what the user typed # The actual text in the captcha, used to check what the user typed
self.currentCaptchaText = '' self.currentCaptchaText = ''
# The image of the captcha # The image of the captcha
self.currentCaptchaImg = '' self.currentCaptchaImg = pygame.Surface((0, 0))
self.fonts = {} self.fonts = []
self.Drawsurface = Image.new("RGB",(800,220),(255,255,255))
# I haven't finished this yet, you might want to create # I haven't finished this yet, you might want to create
# an object or something, I don't know. Keep in mind you # an object or something, I don't know. Keep in mind you
# have to load all of the font files for use later. # have to load all of the font files for use later.
with open(f'./fonts/fonts.json', 'r') as f: with open(f'./fonts/fonts.json', 'r') as f:
self.fontList = json.loads(f.read())#loads the fonts from the json (Why the fuck was the variable called 'j' before????) for fontData in json.loads(f.read()):
self.fonts.append(Font(fontData, 100))
#self.fontList = json.loads(f.read())#loads the fonts from the json (Why the fuck was the variable called 'j' before????)
#for fontData in j: #for fontData in j:
# self.fonts.update() # self.fonts.update()
def fontsByDifficulty(self, difficulty, width=0.3):
"""
Gets a list of fonts that fall within the specified difficulty.
"""
return [
font for font in self.fonts
if font.difficulty >= difficulty-width and font.difficulty <= difficulty+width
]
def createCaptcha(self): def createCaptcha(self):
""" """
Use PIL (https://pillow.readthedocs.io/en/stable/handbook/tutorial.html) Use PIL (https://pillow.readthedocs.io/en/stable/handbook/tutorial.html)
to draw the fonts, add noise, random shapes, transforms etc. based on to draw the fonts, add noise, random shapes, transforms etc. based on
self.gameDifficulty self.gameDifficulty
""" """
pass # Create a surface for that captcha
drawSurface = Image.new("RGB", (800,220), (255,255,255))
# Create a drawing object
draw = ImageDraw.Draw(drawSurface)
# Temporarily stores the current captcha text
captcha = ''
# Get a random cpatcha length
capLength = random.randint(3, 6)
for i in range(capLength):
# Calculate the base X position of this character
# TODO: Make this better, I'm not too happy with my implementation here.
x = self.size[0] / (capLength + 3)
x *= i
# Get the selected difficulty for this character
charDiff = normalDist(self.gameDifficulty)
# Pick a random font based on that difficulty
font = random.choice(self.fontsByDifficulty(charDiff))
# Pick a random character
char = random.choice(font.alphabet)
# Draw the selected character, with the selected font
draw.text((x, 10), char, font=font.font, fill=(0,0,0))
# Append the character to the captcha
captcha += char
# Store the correct captcha text
self.currentCaptchaText = captcha
# Store the created image
self.currentCaptchaImg = PIL2PG(drawSurface)
print(captcha)
def onEvent(self, event): def onEvent(self, event):
""" """
@ -83,21 +141,9 @@ class Game(gameUtils.Game):
Ran once per frame, put your drawing code and any Ran once per frame, put your drawing code and any
game logic that should be ran once per frame in here. game logic that should be ran once per frame in here.
""" """
# Don't remove this. It does important things. :3
super().update()
self.Drawsurface = Image.new("RGB",(800,220),(255,255,255)) #creates a surface to draw the fonts on
self.textTest = ImageFont.truetype("./fonts/"+self.fontList[2]["file"],200) #loads the font
self.draw = ImageDraw.Draw(self.Drawsurface) #creates an object to let us draw to the surface
self.draw.text((10,10),"Hello", font=self.textTest, fill=(0,0,0)) #actually draws the text
self.pygameConvert = pygame.image.fromstring(self.Drawsurface.tobytes(), self.Drawsurface.size, self.Drawsurface.mode) #converts the pillow image to a pygame image
#no, there wasn't an easier way I could find to achieve this, stab me
self.surf.fill((0, 0, 0)) #sets the background colour self.surf.fill((0, 0, 0)) #sets the background colour
self.surf.blit(gameUtils.centre(self.pygameConvert,self.size)) #draws the text to center of the screen self.surf.blit(gameUtils.centre(self.currentCaptchaImg, self.size)) #draws the text to center of the screen
#TODO: actually scale the text, however, more work needs to be done on the actual function of the game first #TODO: actually scale the text, however, more work needs to be done on the actual function of the game first
def close(self): def close(self):