from cmu_112_graphics import * import random import math import sqlite3 import time #Establishing connection with the database con = sqlite3.connect('pastWins.db') #Creating cursor to execute commands cur = con.cursor() #Creating new table or accessing existing table in DB cur.execute('''CREATE TABLE IF NOT EXISTS pastwins ( seed int, diff text, time int)''') #This function makes a 2d list of the specified size #Taken from notes def make2dList(rows, cols): return [ ([1] * cols) for row in range(rows) ] ########################################## # Monster Class ########################################## class Monster(): #Holds list of all monsters monsterList = [[],[]] pass #Unkillable Entity(Green) class theEntity(Monster): #intialization of different attributes def __init__(self, app): self.speed = 4 self.spawn = [1,1] self.curPos = self.spawn self.color = 'green' imageWidth, imageHeight = app.width, app.height Monster.monsterList[0].append(self) self.damage = 25 self.alive = True #Other killable monsters(Yelloe) class otherMonsters(Monster): #intialization of different attributes def __init__(self, app): self.speed = 2 #Determines spawnpoint randomly in maze while True: randX, randY = random.randrange(0, len(app.map)), random.randrange(0, len(app.map[0])) if (randX, randY) != (app.playX, app.playY) and app.map[randX][randY] == 0: self.spawn = [randX, randY] break self.health = 100 self.color = 'yellow' self.curPos = self.spawn Monster.monsterList[1].append(self) self.damage = 5 self.alive = True #this function prints a monster as an x def __repr__(self): return f'x' ########################################## # Monster Functions ########################################## #This function positions the monsters in the maze def setEnemies(app): for monsterType in Monster.monsterList: for enemy in monsterType: (enemyX, enemyY) = enemy.curPos if enemy.alive : if app.map[enemyX][enemyY] == 0: app.map[enemyX][enemyY] = enemy else: app.map[enemyX][enemyY] = 0 ########################################## # Maze Class ########################################## #Maze Class class Maze(): #Intializing what path, wall and end are path = 0 wall = 1 end = 3 #Intializing and Creating maze, randomly def __init__(self, rows, cols): self.rows = rows self.cols = cols self.maze = make2dList(rows, cols) # I used Prims Algorithm in order to create my maze randomly #This algorithm, created by Vojtěch Jarník, it starts from point (1,1) #And fans outwards walls = [] startRow, startCol = 1,1 walls.append([startRow, startCol, startRow, startCol]) while len(walls) != 0: currentWall = walls.pop(random.randint(0, len(walls) -1)) x, y = currentWall[2], currentWall[3] if self.maze[x][y] == 1: self.maze[currentWall[0]][currentWall[1]] = self.maze[x][y] = 0 if x < self.cols - 2 and self.maze[x+2][y] == 1: walls.append([x+1, y, x+2, y]) if y < self.rows - 2 and self.maze[x][y+2] == 1: walls.append([x, y+1, x, y+2]) if x >= 2 and self.maze[x-2][y] == 1: walls.append([x-1, y, x-2, y]) if y >= 2 and self.maze[x][y-2] == 1: walls.append([x, y-1, x, y-2]) #This section makes sure that the last column and last row is all ones #as well as it sets a exit self.maze.append([1] * cols) for row in self.maze: row.append(1) for col in range(len(self.maze[0]) - 1, 0, -1): if self.maze[len(self.maze) - 2][col] == 0: self.maze[len(self.maze) - 1][col] = Maze.end self.end = self.maze[len(self.maze) - 1][col] break ########################################## # Button Functions ########################################## #This function changes mode to help/howto mode def helpMode(app): print('hi') app.mode = 'howTo' #This function changes mode to gameMode with easy difficulty #It also intializes the other necessary components for the game def easyMode(app): app.mode = 'gameMode' app.playX, app.playY = 1,1 app.playerAngle = 0 app.difficulty = 'easy' app.map = mazeGeneration(app) app.startTime = time.time() app.X, app.Y = app.width//2, app.height//2 disableSelect() #This function changes mode to gameMode with medium difficulty #It also intializes the other necessary components for the game def mediumMode(app): app.mode = 'gameMode' app.playX, app.playY = 1,1 app.playerAngle = 0 app.difficulty = 'medium' app.map = mazeGeneration(app) app.startTime = time.time() app.X, app.Y = app.width//2, app.height//2 disableSelect() #This function changes mode to gameMode with hard difficulty #It also intializes the other necessary components for the game def hardMode(app): app.mode = 'gameMode' app.playX, app.playY =1,1 app.playerAngle = 0 app.difficulty = 'hard' app.map = mazeGeneration(app) app.startTime = time.time() app.X, app.Y = app.width//2, app.height//2 disableSelect() #Changes the mode to past Wins mode def pastWinsMode(app): app.mode = 'pastWins' disableSelect() #This function changes mode to gameMode with hard difficulty #It sets the seed and difficulty to the one selected #It also intializes the other necessary components for the game def playAgain(app, seed, difficulty): app.mode = 'gameMode' app.playX, app.playY = 1,1 app.playerAngle = 0 app.difficulty = difficulty random.seed(seed) app.seedInt = seed app.map = mazeGeneration(app) app.startTime = time.time() app.X, app.Y = app.width//2, app.height//2 disableSelect() #This function disables the buttons on the play again screen def disablePlay(): for button in myButtons.myButtons: if 'Play' in button: myButtons.myButtons[button]['drawing'] = False #This function enables the buttons on the select screen def enableSelect(): myButtons.myButtons['Easy']['drawing'] = True myButtons.myButtons['Medium']['drawing'] = True myButtons.myButtons['Hard']['drawing'] = True myButtons.myButtons['Help']['drawing'] = True myButtons.myButtons['Seed']['drawing'] = True myButtons.myButtons['Past Wins']['drawing'] = True #This function disables the buttons on the select screen def disableSelect(): myButtons.myButtons['Easy']['drawing'] = False myButtons.myButtons['Medium']['drawing'] = False myButtons.myButtons['Hard']['drawing'] = False myButtons.myButtons['Help']['drawing'] = False myButtons.myButtons['Seed']['drawing'] = False myButtons.myButtons['Past Wins']['drawing'] = False #Changes mode to select mode def selectMode(app): app.mode = 'selectMode' myButtons.myButtons['Start']['drawing'] = False #This function allows the user to input a chosen seed if desired def seedInput(app): seedInt = app.getUserInput('SEED') if seedInt == None: pass elif seedInt.isdigit(): app.seedInt = seedInt random.seed(int(seedInt)) else: app.showMessage('Seed Must Be Integer') ########################################## # Button Class ########################################## #Button Class class myButtons(): #Dictiionary that contains all buttons used myButtons = {} #intialization of button attributes def __init__(self, text, x1, y1, x2, y2, buttonCommand, commandArgs = None, commandArgs2 = None, commandArgs3 = None, intColor = 'black', chColor = 'white', ): self.topCorner = (x1,y1) self.botCorner = (x2,y2) self.name = text self.intColor = intColor self.chColor = chColor self.command = buttonCommand #TBH Idk why I used dictionarys inside of a dictionary #Looking back on it I think it was kinda useless #because I can access the buttons using 'button.attribute' #Too late now, ¯\_(ツ)_/¯ myButtons.myButtons[text] = {'topCorner': self.topCorner, 'botCorner': self.botCorner, 'intialColor': self.intColor, 'changeColor': self.chColor, 'command': self.command, 'commandArgs': commandArgs, 'commandArgs2': commandArgs2, 'commandArgs3': commandArgs3, 'hovering': False, 'drawing': True} #This function draws all the buttons that need to be on screen def drawButtons(app, canvas): for button in myButtons.myButtons: #Accessing necessary attributes topCorner = myButtons.myButtons[button]['topCorner'] botCorner = myButtons.myButtons[button]['botCorner'] name = button intColor = myButtons.myButtons[button]['intialColor'] chColor = myButtons.myButtons[button]['changeColor'] if myButtons.myButtons[button]['drawing'] == False: continue #Buttons were supposed to change color when hovered over #Doesn't work though, (-__-) if myButtons.myButtons[button]['hovering'] == False: canvas.create_rectangle(topCorner[0], topCorner[1], botCorner[0], botCorner[1], fill = intColor, outline = 'white') elif myButtons.myButtons[button]['hovering'] == True: canvas.create_rectangle(topCorner[0], topCorner[1], botCorner[0], botCorner[1], fill = chColor) #drawing buttons midpoint = ((topCorner[0] + botCorner[0])//2, (topCorner[1] + botCorner[1])//2) fontSize = min(int((botCorner[1] - topCorner[1])*0.22), int((botCorner[0] - topCorner[0])*0.22)) canvas.create_text(midpoint[0], midpoint[1], text = name, font = f'Times {fontSize} bold', fill = 'white') ########################################## # Start Screen Mode ########################################## #This function draws the elements of the start screen def startScreen_redrawAll(app, canvas): #Background canvas.create_rectangle(0,0, app.width, app.height, fill = 'black') start = app.width//3, app.height//3 #Start Button myButtons('Start', start[0]//2, start[1], start[0] * 2.5, start[1] * 2, selectMode, commandArgs =app) #Calls drawButtons so they can be seen drawButtons(app, canvas) pass #This function was supposed to help change the button color #When it was being hovered over #The hovering feature doesn't work, but idk if deleting this function will break my code def mouseOnButton(app, event): for button in myButtons.myButtons: topCorner = myButtons.myButtons[button]['topCorner'] botCorner = myButtons.myButtons[button]['botCorner'] if topCorner[0] <= event.x <= botCorner[0] and topCorner[1] <= event.y <= botCorner[1]: myButtons.myButtons[button]['hovering'] == True else: myButtons.myButtons[button]['hovering'] == False #This function checks if mouse has been moved def startScreen_mouseMoved(app, event ): mouseOnButton(app, event ) #This function checks if mouse has been pressed def startScreen_mousePressed(app, event): buttonPressed(app, event) #This function sees if the cursor is clicking on one of the active buttons def buttonPressed(app, event): for button in myButtons.myButtons: topCorner = myButtons.myButtons[button]['topCorner'] botCorner = myButtons.myButtons[button]['botCorner'] buttonCommand = myButtons.myButtons[button]['command'] commandArgs = myButtons.myButtons[button]['commandArgs'] commandArgs2 = myButtons.myButtons[button]['commandArgs2'] commandArgs3 = myButtons.myButtons[button]['commandArgs3'] if topCorner[0] <= event.x <= botCorner[0] and topCorner[1] <= event.y <= botCorner[1]: if commandArgs2 == None: buttonCommand(commandArgs) else: buttonCommand(commandArgs, commandArgs2, commandArgs3) ########################################## # Select Mode ########################################## #This function draws the elements of the select screen def selectMode_redrawAll(app, canvas): #Background canvas.create_rectangle(0,0,app.width, app.height, fill = 'black') #A bunch of variables to help position the buttons buttonX = app.width//3 dy = app.height//6 butDif = 20 seedX, seedY = app.width - app.width * 0.97, app.height - app.height * 0.90 topButtonY = seedY + butDif #Easy, Medium, Hard, PastWins, Seed, Help Button intialization myButtons('Easy', buttonX, topButtonY, buttonX * 2, topButtonY + dy, easyMode, commandArgs =app) myButtons('Medium', buttonX, topButtonY + dy + butDif, buttonX * 2, topButtonY + 2*dy + butDif, mediumMode, commandArgs =app) myButtons('Hard', buttonX, topButtonY + 2*dy + 2 * butDif, buttonX * 2, topButtonY + 3*dy + 2 * butDif, hardMode, commandArgs =app) myButtons('Past Wins', buttonX, topButtonY + 3*dy + 3 * butDif, buttonX * 2, topButtonY + 4*dy + 3 * butDif, pastWinsMode, commandArgs = app ) myButtons('Seed', seedX, seedY + butDif, buttonX - butDif, seedY + butDif + dy//1.5, seedInput, commandArgs =app) myButtons('Help', app.width - (buttonX - butDif), seedY + butDif, app.width - seedX , seedY + butDif + dy//1.5, helpMode, commandArgs =app) #Draws Active buttons drawButtons(app, canvas) #This displays the active seed canvas.create_text(seedX, seedY, text = f'SEED: {app.seedInt}', anchor = 'sw', font = f'Arial {app.height//20} bold', fill = 'white') #Checks if mouse has been moved def selectMode_mouseMoved(app, event ): mouseOnButton(app, event ) #Checks if mouse has been pressed and if so is it pressing a button def selectMode_mousePressed(app, event): buttonPressed(app, event) ########################################## # Map Mode ########################################## #This function draws the map def mapMode_redrawAll(app, canvas): rows, cols = len(app.map), len(app.map[0]) #Drawing cells of the maze for row in range(rows): for col in range(cols): #Variables to determine position of cells leftUpX = (app.width// cols) * col leftUpY = (app.height// rows) * row dx = app.width// cols dy = app.height// rows #Determining color if app.map[row][col] == 1: color = 'black' elif (row, col) == (1,1): color = 'grey' elif app.map[row][col] == 3: color = 'blue' elif isinstance(app.map[row][col], otherMonsters): color = 'yellow' elif isinstance(app.map[row][col], theEntity): color = 'green' else: color = 'white' #Drawing Rectangle canvas.create_rectangle(leftUpX, leftUpY,leftUpX + dx,leftUpY + dy, fill = color) if (int(app.playX), int(app.playY)) == (row, col): #This draws the player Icon with a line showing direction canvas.create_oval(leftUpX, leftUpY,leftUpX + dx,leftUpY + dy, fill = 'yellow') midPointX, midPointY = leftUpX + dx//2, leftUpY + dy//2 up, down = math.cos(app.playerAngle), math.sin(app.playerAngle) sidePointX, sidePointY = midPointX + down * dx//2, midPointY + up * dy//2, canvas.create_line(midPointX, midPointY, sidePointX, sidePointY, width = 5) #Checks if key is pressed and if 'm' key is pressed, this function returns to game mode def mapMode_keyPressed(app, event): if event.key == 'm': app.mode = 'gameMode' #Starts app def appStarted(app): app.seedInt = None app.mode = 'startScreen' app.difficulty = '' app.timerDelay = 1000 app.entityCnt = 0 app.entityTimer = 0 app.monsterCnt = 0 app.monsterCoords = [] app.playerHealth = 100 app.playerDamage = 11.34 app.enemyMoveCnt = 0 app.entityMoveCnt = 0 ########################################## # Game Mode ########################################## #Turns r g b values in color hexcode string #Taken from notes def rgbString(r, g, b): # Don't worry about the :02x part, but for the curious, # it says to use hex (base 16) with two digits. return f'#{r:02x}{g:02x}{b:02x}' #Draw Health Bar for player def drawHealthBar(app, canvas): healthState = int((app.playerHealth/100)*147) canvas.create_rectangle(20,20, 150, 50, fill = 'white') canvas.create_rectangle(23,23, healthState, 47, fill = 'green') canvas.create_text(28, 28, text = 'Health', font = 'Arial 15 bold', anchor = 'nw') #Draws Cursor def drawCursor(app, canvas): canvas.create_line(app.X, app.Y - 20, app.X, app.Y - 5, width = 2) canvas.create_line(app.X, app.Y + 20, app.X, app.Y + 5, width = 2) canvas.create_line(app.X - 5, app.Y, app.X - 20, app.Y , width = 2) canvas.create_line(app.X + 5, app.Y, app.X + 20, app.Y , width = 2) #This function draws elements of the gamemode def gameMode_redrawAll(app, canvas): canvas.create_rectangle(0, 0, app.width, app.height, fill = 'black') mazeDraw(app, canvas) drawHealthBar(app, canvas) drawCursor(app, canvas) #This function determines if a monster(not the entity) has been shot def shotDetection(app, event): for i in range(400): #Variables that help determine intial position and intial distance of ray iAngle = (i/400) * 60 curRot = app.playerAngle + math.radians(iAngle - 30) x, y = app.playX, app.playY sinI, cosI = (0.02* math.sin(curRot)), (0.02* math.cos(curRot)) n = 0 isMonster = False, (None, None) #this loop goes until the ray hits a wall #in order to determine how far the wall is while True: x, y = x + cosI, y + sinI n += 1 #This if statement ensures that the loop eventually breaks #however it is not entirely necessary since the mazes have been designed to always have #walls around them if int(x) >= len(app.map) or int(y) >= len(app.map[0]): break #Checks if something has been hit if app.map[int(x)][int(y)] != 0: #Checks if that something is a monster if isinstance(app.map[int(x)][int(y)], otherMonsters): isMonster = True, (int(x), int(y)) break try: newX = (iAngle/60) * app.width widthSize = app.width//275 #If ray is hitting monster this if statement #checks if the mouse is at the same position if so monster has been hit if isMonster[0]: if newX - widthSize <= event.x <= newX + widthSize: monsterX, monsterY = isMonster[1] app.map[monsterX][monsterY].health -= app.playerDamage except: pass #This function removes any dead monsters #and changes the colors of the monsters when they have been hit def deleteDeadMonsters(): for monster in Monster.monsterList[1]: if 50 <= monster.health <= 99.99: monster.color = 'orange' elif 0.1 <= monster.health <= 49.99: monster.color = 'red' elif monster.health < 0: monster.alive = False #Checks if mouse has been pressed #If o checks if any monsters were hit def gameMode_mousePressed(app, event): shotDetection(app, event) deleteDeadMonsters() setEnemies(app) #This function draws the maze #This function is very similar to shotDetection #I didn't really use a specfic algorithm, just adjusted it till it worked ¯\_(ツ)_/¯ def mazeDraw(app, canvas): #This list is used in order to create the lines between each block colors = [] for i in range(400): #A bunch of variables to determine intial position of ray color = 0 iAngle = (i/400) * 60 curRot = app.playerAngle + math.radians(iAngle - 30) x, y = app.playX, app.playY sinI, cosI = (0.02* math.sin(curRot)), (0.02* math.cos(curRot)) n = 0 #loop runs till ray hits something while True: x, y = x + cosI, y + sinI n += 1 #This if exists for same reason as its equivalent in shotDetection #However it serves more of a purpose in this function #Stops runtime error from happing and theoretically allows player to leave maze if int(x) >= len(app.map) or int(y) >= len(app.map[0]): break #Checks that ray has hit something if app.map[int(x)][int(y)] != 0: height = 1 / (0.02 * n) #Depending on what has been hit and where, color is augmented if app.map[int(x)][int(y)] == 3: color = 'white' elif isinstance(app.map[int(x)][int(y)], Monster): color = app.map[int(x)][int(y)].color elif int(x) % 3 == 0 and int(y) % 2 == 0: color = rgbString(100,100,100) elif int(x) % 3 == 1 and int(y) % 2 == 0: color = rgbString(101,101,101) elif int(x) % 3 == 2 and int(y) % 2 == 0: color = rgbString(99,99,99) elif int(x) % 3 == 0 and int(y) % 2 == 1: color = rgbString(98,98,98) elif int(x) % 3 == 1 and int(y) % 2 == 1: color = rgbString(102,102,102) elif int(x) % 3 == 2 and int(y) % 2 == 1: color = rgbString(103,103,103) break try: #This part makes the black outline between blocks colors.append(color) if i >=1: if colors[i - 1] != colors[i]: color = 'black' #variables for position and length of ray's line newX = (iAngle/60) * app.width newY = int(height*app.height * 0.70) widthSize = app.width//275 #Drawing ray's line canvas.create_line(int(newX), app.height//2 - newY, int(newX), app.height//2 + newY, fill=color, width = widthSize) except: pass #Checks if key has been pressed def gameMode_keyPressed(app, event): #this are here in case a b=move is illegal, then app.playX, app.playY, app.playerAngle #can be set back to them x,y = app.playX, app.playY curAngle = app.playerAngle #checks if WASD has been pressed and adjusts player position accordingly if event.key == 'w': app.playX, app.playY = (app.playX + 0.3* math.cos(app.playerAngle)), \ (app.playY + 0.3* math.sin(app.playerAngle)) if not legalMove(app): app.playX, app.playY = x,y if event.key == 's': app.playX, app.playY = (app.playX - 0.3* math.cos(app.playerAngle)), \ (app.playY - 0.3* math.sin(app.playerAngle)) if not legalMove(app): app.playX, app.playY = x,y if event.key == 'd': app.playerAngle += 90 app.playX, app.playY = (app.playX + 0.1* math.cos(app.playerAngle)), \ (app.playY + 0.1* math.sin(app.playerAngle)) app.playerAngle -= 90 if not legalMove(app): app.playX, app.playY = x, y if event.key == 'a': app.playerAngle -= 90 app.playX, app.playY = (app.playX + 0.1* math.cos(app.playerAngle)), \ (app.playY + 0.1* math.sin(app.playerAngle)) app.playerAngle += 90 if not legalMove(app): app.playX, app.playY = x, y #Switches to map mode if m is pressed if event.key == 'm': app.mode = 'mapMode' #Resets to beginging if r is pressed if event.key == 'r': app.playX, app.playY = 1,1 #Instantly kills player if k is pressed if event.key == 'k': app.playerHealth = 0 if event.key == 'v': app.map[int(app.playX)][int(app.playY)] = 3 #Checks if player is at the exit if app.map[int(app.playX)][int(app.playY)] == 3: app.mode = 'winScreen' #Calculates total time taken to complete the maze app.endTime = int(time.time() - app.startTime) #inserts Seed, Time, Difficulty in SQL table if player has won if app.seedInt != None and not seedDiffInTable(app.seedInt, app.difficulty): insertNewSeed(app) elif app.seedInt != None and seedDiffInTable(app.seedInt, app.difficulty): updateSeed(app) #Returns amount of rows in database def lenDB(): cnt = 0 for row in cur.execute('SELECT * FROM pastwins'): cnt += 1 return cnt #Prints values of the database row by row def printDB(): for row in cur.execute('SELECT * FROM pastwins'): print(row[0], row[1], row[2]) #this function inserts the seed, difficulty, and time taken into database def insertNewSeed(app): cur.execute(f"INSERT INTO pastwins VALUES ({app.seedInt}, '{app.difficulty}', {app.endTime})") con.commit() #This function updates db if seed and difficulty already exists in database def updateSeed(app): cur.execute(f'DELETE FROM as c WHERE c.seed = {app.seedInt}') cur.execute(f"INSERT INTO pastwins VALUES ({app.seedInt}, '{app.difficulty}', {app.endTime})") con.commit() ##This functiion checks if a seed and difficulty are alreasy in the database def seedDiffInTable(seedInt, difficulty): for row in cur.execute('SELECT * FROM pastwins'): if row[0] == seedInt and row[1] == difficulty: return True return False #Finds distance between 2 points def distance(x1,y1,x2,y2): xDiff = (x1-x2)**2 yDiff = (y1-y2)**2 return math.sqrt(xDiff + yDiff) #Checks if a possible move is legal for an enemy def legalEnemyMove(app, enemy, move): newX, newY = enemy.curPos[0] + move[0], enemy.curPos[1] + move[1] if app.map[newX][newY] != 0 or (newX, newY) == (app.playX, app.playY): return False return True #Inflicts damage to the player def damagePlayer(enemy, app): enemyX, enemyY = enemy.curPos for xDir in (-1,0,1): for yDir in (-1,0,1): if (xDir, yDir) != 0: if enemyX + xDir == int(app.playX) and enemyY + yDir == int(app.playY): app.playerHealth -= enemy.damage return #this functio moves the player def moveEnemy(enemy, app): #First this function finds enemy's current position currentX, currentY = enemy.curPos moveDists = [] #Checks distance from all possible moves to the player and puts them in a list for xDir in (-1,0,1): for yDir in (-1,0,1): if (xDir, yDir) != (0,0): curDist = distance(app.playX, app.playY, currentX + xDir, currentY + yDir) moveDists.append(((xDir, yDir), curDist)) #This embedded function simply returns the second element of a list #This is used as a key for the sort def shortDist(e): return e[1] #Sorting list moveDists.sort(key = shortDist) #This function moves through the list of distances to find the move that would move #The enemy closest to the player for move in moveDists: if legalEnemyMove(app, enemy, move[0]): app.map[enemy.curPos[0]][enemy.curPos[1]] = 0 enemy.curPos[0], enemy.curPos[1] = (enemy.curPos[0] + move[0][0], \ enemy.curPos[1] + move[0][1]) return #Checks if mouse has been moved def gameMode_mouseMoved(app, event): #sets app.X, app.Y in order to draw the cursor app.X, app.Y = event.x, event.y #Changes app.playerAngle based on x in order to allow for pan app.playerAngle = (event.x/app.width) * 10 #Returns how many monsters(not including the entity) are alive def monstersAlive(): cnt = 0 for monster in Monster.monsterList[1]: if monster.alive: cnt += 1 return cnt #this function activates when timer goes off def gameMode_timerFired(app): #Checks if player is dead if app.playerHealth < 1: app.mode = 'loseScreen' #Spawns entity after 10 seconds if app.entityCnt == 10 and len(Monster.monsterList[0]) == 0: theEntity(app) else: app.entityCnt += 1 #Spawns other monsters if app.monsterCnt == 5: if monstersAlive() < len(app.map)//2 and app.enemyMoveCnt % 3 == 0: otherMonsters(app) else: app.monsterCnt += 1 #This moves all the monsters using a base timer of 3 seconds if app.enemyMoveCnt % 3 == 0: for monsterType in Monster.monsterList: for enemy in monsterType: if type(enemy) == theEntity and app.entityTimer == enemy.speed: moveEnemy(enemy, app) app.entityTimer = 0 elif type(enemy) == theEntity: app.entityTimer +=1 #Makes 40% of all monsters move when allowed to if type(enemy) == otherMonsters and random.randint(0,10) > 6: moveEnemy(enemy, app) #This function damages a player if an enemy is close enough for monsterType in Monster.monsterList: for enemy in monsterType: damagePlayer(enemy, app) #if enemy's health is less than 1/ dead this switches mode to lose screen if app.playerHealth < 1: app.mode = 'loseScreen' #Sets Enemies in maze after movement setEnemies(app) #Checks if a players movbe is legal def legalMove(app): #if walking into wall NOT a legal move, everything is is allowed if app.map[int(app.playX)][int(app.playY)] == 1: return False return True # if app.map[int(app.playX)][int(app.playY)] == 0 or app.map[int(app.playX)][int(app.playY)] == 3: # return True # return False #Generates maze based on difficulty chosed def mazeGeneration(app): hardMazeSize = 35 mediumMazeSize = 20 easyMazeSize = 6 maze = [] if app.difficulty == 'easy': maze = Maze(easyMazeSize, easyMazeSize) elif app.difficulty == 'medium': maze = Maze(mediumMazeSize,mediumMazeSize) elif app.difficulty == 'hard': maze = Maze(hardMazeSize,hardMazeSize) return maze.maze #Draws elements of WinScreen def winScreen_redrawAll(app, canvas): fontSize = app.height//20 canvas.create_rectangle(0,0, app.width, app.height, fill = 'black') canvas.create_text(app.width//2, app.height//6, text = 'YOU WON', font = f'Times {fontSize} bold', anchor = 'n', fill = 'white') canvas.create_text(app.width//2 , app.height//3 + app.height//6, text = f'Time Elapsed: {app.endTime}s', font = f'Times {fontSize} bold', anchor = 'n', fill = 'white') if app.seedInt != None: canvas.create_text(app.width//2, 2 * app.height//3 + app.height//6, text = f'Seed: {app.seedInt} has been added to Past Wins', font = f'Times {fontSize} bold', anchor = 'n', fill = 'white') #Draws Elements of howTo/help screen def howTo_redrawAll(app, canvas): canvas.create_rectangle(0,0, app.width, app.height, fill = 'black') canvas.create_text(app.width//3 - 15, app.height//5, text = 'Controls \n \ Forward - W\n \ Back - S\n \ Left - A\n \ Right - D\n \ Map - M\n \ Kill any monsters(yellow)\n \ and escape the unkillable entity(green)\n \ and reach the exit to win.', font = f'Times {app.height//25} bold', anchor = 'nw', fill = 'white') canvas.create_text(2 *app.width //3, 4 * app.height//5,text ='Press R to Return', font = f'Times {app.height//25} bold', anchor = 'nw', fill = 'white') #Checka if key has been pressed def pastWins_keyPressed(app, event): #If r has been pressed returns mode to select mode if event.key == 'r': app.mode = 'selectMode' enableSelect() disablePlay() if event.key == 'a': print(lenDB()) #This function draws the table with values in Database #It also creates buttons which allow the player to play that #difficulty and seed again def tableInfo(app, canvas): rows = lenDB() + 1 fontSize = int((app.height//rows) * 0.15) for row in range(rows): #variables that help determine where rectangles should be leftUpX = 0 leftUpY = (app.height// rows) * row botDownX = app.width botDownY = (app.height// rows) * (row + 1) canvas.create_rectangle(leftUpX, leftUpY, botDownX, botDownY, fill = 'black', outline = 'white') for col in range(4): #More variables that help determine where rectangles should be leftX = app.width//4 * col rightX = leftX + app.width//4 canvas.create_rectangle(leftX + 15, leftUpY + 15, rightX - 15, botDownY - 15, fill = 'white') #This if statements draw the headers if row == 0: if (row,col) == (0,0): canvas.create_text((leftX + rightX)//2, (leftUpY + botDownY)//2, text = 'Seed', font = f'Arial {fontSize} bold', fill = 'grey') elif(row, col) == (0,1): canvas.create_text((leftX + rightX)//2, (leftUpY + botDownY)//2, text = 'Difficulty', font = f'Arial {fontSize} bold', fill = 'grey') elif(row, col) == (0,2): canvas.create_text((leftX + rightX)//2, (leftUpY + botDownY)//2, text = 'Time', font = f'Arial {fontSize} bold', fill = 'grey') elif (row, col) == (0,3): canvas.create_text((leftX + rightX)//2, (leftUpY + botDownY)//2, text = 'Click', font = f'Arial {fontSize} bold', fill = 'grey') #Puts information from database into the drawn table dy = 1 for row in cur.execute('SELECT * FROM pastwins'): for i in range(len(row) + 1): #Variables for determining midpoint of rectangles midY = (app.height//rows * dy) + (app.height//rows)//2 midX = ((app.width//4) * i) + (app.width//4)//2 #Drawing buttons in last column if i == 3: myButtons(f'Play Again \n {row[0], row[1]}', midX - (app.width//4)//2, midY - (app.height//rows)//2, midX + (app.width//4)//2, midY + (app.height//rows)//2, playAgain, commandArgs = app, commandArgs2 = row[0], commandArgs3 = row[1]) elif i == 2: canvas.create_text(midX, midY, text = f'{row[i]}s', font = f'Arial {fontSize} bold') else: canvas.create_text(midX, midY, text = f'{row[i]}', font = f'Arial {fontSize} bold') dy += 1 #Draws elements of past wins screen def pastWins_redrawAll(app, canvas): tableInfo(app, canvas) drawButtons(app, canvas) #Checks if mouse has been pressed on past wins screen #Also checks if button was pressed def pastWins_mousePressed(app, event): buttonPressed(app, event) #Checks if ky has been pressed def howTo_keyPressed(app, event): if event.key == 'r': app.mode = 'selectMode' #Draws elements of losing screen def loseScreen_redrawAll(app, canvas): canvas.create_text(app.width//2, 30, text = 'YOU DIED', font = 'Times 40 bold', anchor = 'n', fill = 'Black') #Runs the app runApp(width=600, height=500) con.close()