diff --git a/config.json b/config.json index d90c964..614ee07 100644 --- a/config.json +++ b/config.json @@ -2,7 +2,7 @@ "Difficulté": {"Value": "Normal", "Available": ["Facile", "Normal", "Difficile"]}, "Vie": {"Value": 3, "Available": [1,2,3,4,5,6,7,8,9,10]}, "Temps": {"Value": 180, "Available": [30,45,60,75,90,105,120,135,150,165,180,195,210,225,240,255,270,285,300,315,330,345,360,375,390,405,420,435,450,465,480,495,510,525,540,555,570,585,600]}, - "Bonus de temps": {"Value": 30, "Available": [0,10,20,30,40,50,60,70,80,90,100,110,120,130,140,150,160,170,180]}, + "Bonus de temps": {"Value": 40, "Available": [0,10,20,30,40,50,60,70,80,90,100,110,120,130,140,150,160,170,180]}, "Malus de temps": {"Value": 0, "Available": [0,5,10,15,20,25,30,35,40,45,50,55,60]}, "Module négli.": {"Value": 0, "Available": [0,1,2,3,4,5,6,7,8,9,10]}, "Mode daltonien": {"Value": "Aucun", "Available": ["Aucun", "Protanopie", "Deutéranopie", "Tritanopie"]}, diff --git a/config.pickle b/config.pickle index 125445e..6ba1046 100644 Binary files a/config.pickle and b/config.pickle differ diff --git a/main.pyw b/main.pyw index bd1ed64..5e6cc0e 100644 --- a/main.pyw +++ b/main.pyw @@ -4,6 +4,7 @@ import os import pickle import json import random +import math from PIL import Image, ImageTk ########## constante ########### @@ -12,6 +13,7 @@ PATH_ASSETS = "./assets/" ######## initialisation ######## Fen = Tk() +Fen.resizable(width = False, height = False) Fen.iconbitmap(PATH_ASSETS + "icon.ico") Fen.title("Emulateur - Bombe") classModule = {} # Dictionnaire qui va contenir tout les modules afin qu'ils puissent intéragir entre eux @@ -26,13 +28,14 @@ class AppClass(): # Classe du "moteur" du jeu self.load_settings() self.MainMenu() - + self.InfinityMode = False def MainMenu(self, selected = 0): # Niveau 1 MainMenu_Option = { "Lancer" : self.start, "Option" : self.settings, + "Mode Infini": self.start_infinity_mode, "Reinit. Option.": self.confirm_reinit_option, "Quitter" : self.leave, } # On créer un dictionnaire qui associe toute les options proposé à leur fonction respective. @@ -64,7 +67,6 @@ class AppClass(): # Classe du "moteur" du jeu def start(self): classModule["simon"].bind(UpCmd = "pass", DownCmd = "pass", LeftCmd = "pass", RightCmd = "pass") - self.Life = self.config["Vie"]["Value"] # On initialise le nombre de vie comme indiqué dans les paramètres for module in classModule: @@ -74,6 +76,12 @@ class AppClass(): # Classe du "moteur" du jeu # Initilisalisé tout les modules # Démmaré un chrono + def start_infinity_mode(self): + self.InfinityMode = True + self.start() + + + def settings(self, selected = 0): # On créer un dictionnaire qui associe toute les options proposé à leur fonction respective. SettingsMenu_Keys = list(self.config.keys()) # On créer une liste qui ne contient que les clé du dictionnaire, permettant d'utiliser des index numériques. diff --git a/module/button.py b/module/button.py index 41477ec..47356df 100644 --- a/module/button.py +++ b/module/button.py @@ -18,7 +18,7 @@ class button(): } } - self.frame = LabelFrame(Fen, text = "Button", width = 180, height = 180) # On créer une sous-fenêtre + self.frame = LabelFrame(Fen, text = "Bouton", width = 180, height = 180, borderwidth = 4) # On créer une sous-fenêtre self.frame.grid(row = 2, column = 3, sticky = "NEWS") # On l'affiche self.frame.grid_propagate(0) # Force le LabelFrame à ne pas changer de taille diff --git a/module/display.py b/module/display.py index 82186e7..9480dc7 100644 --- a/module/display.py +++ b/module/display.py @@ -1,8 +1,10 @@ class display(): def __init__(self): # Cette fonction est automatiquement éxécuter lors de la création de l'objet self.defuse = True # Ce module est toujours désamorçé. + self.InitInfinity = False # Vaut False si la partie en mode infinity est à sa première partie, si tous les modules sont alors désamoçé une fois, elle vaut True. + # Permet de ne lancer le chrono qu'une seule fois. - self.frame = LabelFrame(Fen, text = "Display", width = 180, height = 180) # On créer une sous-fenêtre + self.frame = LabelFrame(Fen, text = "Ecran d'affichage", width = 180, height = 180, borderwidth = 4) # On créer une sous-fenêtre self.frame.grid(row = 1, column = 1) # On l'affiche self.frame.grid_propagate(0) # Force le LabelFrame à ne pas changer de taille @@ -51,8 +53,10 @@ class display(): def start(self): self.PenalityAnimation = False self.DefuseAnimation = False - self.time = App.config["Temps"]["Value"] + 1 # En lanceant le chrono, une seconde est immédiatement supprimée - self.chrono() + + if self.InitInfinity == False: # Si le jeu n'a pas encore été lancé + self.time = App.config["Temps"]["Value"] + 1 # En lanceant le chrono, une seconde est immédiatement supprimée + self.chrono() def checkDefuse(self): @@ -64,9 +68,7 @@ class display(): _Stop += 1 if _Stop <= App.config["Module négli."]["Value"]: # Si tout les modules sont désamorcé - Fen.after_cancel(self.chrono_event) # On désactive le chrono self.write(random.choice(["GG", "Bravo", "Félicitation"])) - self.reset_all() else: @@ -86,6 +88,8 @@ class display(): Fen.after_cancel(self.chrono_event) # On désactive le chrono self.write(random.choice(["Perdu", "Dommage", "Try again"])) + self.InitInfinity = False + App.InfinityMode = False self.reset_all() @@ -95,7 +99,14 @@ class display(): def reset(self): # Cette fonction est appelé a chaque fin de partie pour réinitialiser ce module - self.label.config(foreground = "black", background = "SystemButtonFace") - Fen.after(7500, lambda: App.MainMenu()) # On laisse le joueur devant le message de victoire / défaite pendant 7.5 secondes + if App.InfinityMode == False: # Si l'on n'est pas en mode infini + Fen.after_cancel(self.chrono_event) # On désactive le chrono + self.label.config(foreground = "black", background = "SystemButtonFace") + + Fen.after(7500, lambda: App.MainMenu()) # On laisse le joueur devant le message de victoire / défaite pendant 7.5 secondes + + else: # Si l'on est en mode infini + self.InitInfinity = True # On a déjà fini le jeu une fois + Fen.after(1000, App.start) # On relance le jeu classModule["display"] = display() diff --git a/module/morse.py b/module/morse.py index c059af6..57ad9ca 100644 --- a/module/morse.py +++ b/module/morse.py @@ -23,7 +23,7 @@ class morse(): "V":"...-", "W":".--", "X":"-..-", "Y":"-.--", "Z":"--.." } - self.frame = LabelFrame(Fen, text = "Morse", width = 180, height = 180) # On créer une sous-fenêtre + self.frame = LabelFrame(Fen, text = "Morse", width = 180, height = 180, borderwidth = 4) # On créer une sous-fenêtre self.frame.grid(row = 2, column = 2, sticky = "NEWS") # On l'affiche self.frame.grid_propagate(0) # Force le LabelFrame à ne pas changer de taille @@ -38,6 +38,7 @@ class morse(): self.SelectButton.grid(row = 2, column = 1, sticky = "WE") self.SelectFen = Toplevel() # Créer une fenêtre secondaire. + self.SelectFen.resizable(width = False, height = False) self.SelectFen.iconbitmap(PATH_ASSETS + "icon.ico") # Change l'icone self.SelectFen.title("Emulateur - Morse") # Change le titre self.SelectFen.protocol('WM_DELETE_WINDOW', lambda: "pass") # Rend la fenêtre non fermable diff --git a/module/safe.py b/module/safe.py index 6ae1262..a50c097 100644 --- a/module/safe.py +++ b/module/safe.py @@ -26,27 +26,81 @@ class safe(): } - self.frame = LabelFrame(Fen, text = "Safe", width = 180, height = 180) # On créer une sous-fenêtre + self.frame = LabelFrame(Fen, text = "Coffre-fort", width = 180, height = 180, borderwidth = 4) # On créer une sous-fenêtre self.frame.grid(row = 1, column = 3, sticky = "NEWS") # On l'affiche self.frame.grid_propagate(0) # Force le LabelFrame à ne pas changer de taille self.frame.grid_columnconfigure(1, weight = 1) - self.frame.grid_rowconfigure(1, weight = 1) self.label = Label(self.frame, text = "", background = "lightgray", relief = SUNKEN, width = 2, height = 1) # On créer la led self.label.grid(row = 1, column = 1) - self.scale = Scale(self.frame, from_ = 1, to_ = 4, orient = HORIZONTAL) # On créer un scroller pour sélectionner une valeur entre 1 et 4 - self.scale.grid(row = 2, column = 1) + ########### + self.size_canvas = 90 - self.Valid_but = Button(self.frame, text = "Validé", background = "lightgreen", relief = RIDGE, width = 10) - self.Valid_but.grid(row = 3, column = 1) + self.canvas = Canvas(self.frame, width = self.size_canvas, height = self.size_canvas) + self.canvas.grid(row = 2, column = 1) + + self.mult_base = 6 + # Cercle sur lequel va tourner la base + self.cache_canvas = self.canvas.create_oval( + (self.size_canvas / 2) - (self.size_canvas / self.mult_base), # Ax + (self.size_canvas / 2) - (self.size_canvas / self.mult_base), # Ay + (self.size_canvas / 2) + (self.size_canvas / self.mult_base), # Bx + (self.size_canvas / 2) + (self.size_canvas / self.mult_base), # By + + fill = "gray12") + + # Cercle sur lequel va tourner le pic + + for index in range(1, 5): + self.canvas.create_arc( 2, self.size_canvas, # A(x, y) + self.size_canvas, 2, # B(x, y) + + start = 90 * (index), extent = 90, # ici en dégrée + fill = "lightgray", outline = "black", width = 1) + + + self.canvas.create_text((self.size_canvas / 2) + (self.size_canvas / 4.5) * round(math.cos((index - 1) * (math.pi / 2) + math.sqrt(2)/2 + math.pi/2)) + 2, + (self.size_canvas / 2) - (self.size_canvas / 4.5) * round(math.sin((index - 1) * (math.pi / 2) + math.sqrt(2)/2 + math.pi/2)) + 2, + text = str(index), font = ("Arial Black", 15), angle = 225 + 90 * (index - 1)) + + + ########## + + self.scale = Scale(self.frame, from_ = 0.01, to_ = 4, orient = HORIZONTAL, width = 10, showvalue = False, resolution = 0.01) # On créer un scroller pour sélectionner une valeur entre 1 et 4 + self.scale.grid(row = 3, column = 1, sticky = "S") + + self.Valid_but = Button(self.frame, text = "Valider", background = "lightgreen", relief = RIDGE, width = 10) + self.Valid_but.grid(row = 4, column = 1) + + self.position_curseur = 0.01 + self.Event = None + self.updateCanvas() + + def updateCanvas(self): + angle = (self.position_curseur - 1) / (4/(2*math.pi)) + math.pi + + + if self.Event != None: self.canvas.delete(self.Event) + self.Event = self.canvas.create_polygon((self.size_canvas / 2) - (self.size_canvas / self.mult_base) * math.sin(angle), + (self.size_canvas / 2) - (self.size_canvas / self.mult_base) * math.cos(angle), + + (self.size_canvas / 2) + (self.size_canvas / self.mult_base) * math.sin(angle), + (self.size_canvas / 2) + (self.size_canvas / self.mult_base) * math.cos(angle), + + (self.size_canvas / 2) + (self.size_canvas / 2) * math.cos(angle), + (self.size_canvas / 2) - (self.size_canvas / 2) * math.sin(angle), + + fill = "orange", outline = "black", width = 2) + + self.canvas.tag_raise(self.cache_canvas) def start(self): - self.defuse = False # Le module n'est pas désamorçer. + self.defuse = False # Le module n'est pas désamorçé. self.Step = 0 self.position_curseur = 0 @@ -63,21 +117,23 @@ class safe(): def zone_choice(self): # S'enclenche quand le joueur touche au curseur self.position_curseur = self.scale.get() # Valeur sélectionner avec le curseur - - if self.scale_zone[self.Step] == self.position_curseur: + self.updateCanvas() + if self.scale_zone[self.Step] == math.ceil(self.position_curseur): self.label.config(background = "yellow") else: self.label.config(background = "lightgray") + def check(self): Difficulty = App.config["Difficulté"]["Value"] Step_max = len(self.rules[Difficulty]) - if self.rules[Difficulty][self.Step + 1][self.scale_zone[self.Step]] == self.position_curseur: # Si le joueur à bien placé le curseur + if self.rules[Difficulty][self.Step + 1][self.scale_zone[self.Step]] == math.ceil(self.position_curseur): # Si le joueur à bien placé le curseur self.Step += 1 if self.Step >= Step_max: # Si à la dernière étape self.defuse = True classModule["display"].checkDefuse() + self.Valid_but.config(command = lambda: "pass") else: self.zone_choice() @@ -87,7 +143,7 @@ class safe(): def reset(self): self.label.config(background = "lightgray") # On éteint la LED - self.scale.config(command = lambda: "pass") # Désactive la mise à jour du curseur + self.scale.config(command = lambda x: "pass") # Désactive la mise à jour du curseur self.Valid_but.config(command = lambda: "pass") # Désactive le bouton diff --git a/module/simon.py b/module/simon.py index bf8db34..4eef253 100644 --- a/module/simon.py +++ b/module/simon.py @@ -21,12 +21,16 @@ class simon(): self.reset_color() - self.frame = LabelFrame(Fen, text = "Simon", width = 180, height = 180) # On créer une sous-fenêtre + self.frame = LabelFrame(Fen, text = "Simon", width = 180, height = 180, borderwidth = 4) # On créer une sous-fenêtre self.frame.grid(row = 2, column = 1, sticky = "NEWS") # On l'affiche self.frame.grid_propagate(0) # Force le LabelFrame à ne pas changer de taille + self.frame.grid_columnconfigure(0, weight = 1) + self.frame.grid_columnconfigure(4, weight = 1) + self.frame.grid_rowconfigure(0, weight = 1) + self.frame.grid_rowconfigure(4, weight = 1) self.dico_but = {} # On créer un dictionnaire qui va contenir les objets bouttons. diff --git a/module/wire.py b/module/wire.py index 7dff09c..63b0bc5 100644 --- a/module/wire.py +++ b/module/wire.py @@ -26,7 +26,7 @@ class wire(): } # Règles du manuel transcrite dans le code - self.frame = LabelFrame(Fen, text = "Wire", width = 180, height = 180) + self.frame = LabelFrame(Fen, text = "Fils", width = 180, height = 180, borderwidth = 4) self.frame.grid(row = 1, column = 2) # On l'affiche self.frame.grid_propagate(0) # Force le LabelFrame à ne pas changer de taille @@ -56,6 +56,7 @@ class wire(): self.defuse = False # Le module n'est pas désamorçer. self.Blink_Event = {} + for wire in self.dico_wire: # Pour chaque câbles, ... self.Blink_Event[wire] = None self.dico_wire[wire]["WIRE"].config(command = lambda led = "%s" % wire: self.cut_wire(led = led)) # ... On le rend sécable. @@ -115,7 +116,7 @@ class wire(): classModule["display"].PenalityLife() - if self.wire_errorTotal - self.wrong_cut == 0: # Si le joueur à tout désamorçer, en comptant les fils qu'ils n'auraient pas du coupé + if self.wire_errorTotal <= self.wrong_cut: # Si le joueur à tout désamorcé, en comptant les fils qu'ils n'auraient pas du coupé self.defuse = True classModule["display"].checkDefuse() for led in self.dico_wire: # On rend les câbles insécable de nouveau pour évité une nouvelle erreur