From 860b98f1a93788c4e7240db390102422e17238ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maty=C3=A1=C5=A1=20Caras?= Date: Wed, 4 May 2022 10:16:30 +0200 Subject: [PATCH] Complete fighting and squash bugs --- lib/fight.py | 53 ++++++++++++++++++++++++++++++++++++++++++---- lib/game.py | 56 ++++++++++++++++++++++++++++++------------------- lib/item.py | 9 ++++++++ lib/lang/cz.yml | 3 +++ lib/lang/en.yml | 5 ++++- lib/menu.py | 2 +- lib/save.py | 30 ++++++++++++++++++++++---- 7 files changed, 127 insertions(+), 31 deletions(-) create mode 100644 lib/item.py diff --git a/lib/fight.py b/lib/fight.py index 7dc2f24..1d7bc65 100644 --- a/lib/fight.py +++ b/lib/fight.py @@ -1,16 +1,16 @@ import math +from lib.menu import MenuManager + from .ascii import * from colorama import Fore import keyboard from random import randrange class FightHandler: - def __init__(self,message:str,name:str,hp:int,defense:int,attacks:dict,lang:dict,eq:dict,img:str="") -> None: + def __init__(self,message:str,name:str,hp:int,defense:int,attacks:dict,lang:dict,eq:dict,inv:list,img:str="") -> None: self.selected = 0 - keyboard.add_hotkey("up",self.up) - keyboard.add_hotkey("down",self.down) - keyboard.add_hotkey("enter",self.attack) + self.rebind() self.name = name self.max = hp # starting ENEMY HP self.hp = self.max # current ENEMY HP @@ -21,6 +21,7 @@ class FightHandler: self.lang = lang self.message = message self.equipped = eq + self.inventory = inv self.show() def up(self): @@ -40,6 +41,7 @@ class FightHandler: self.show() def show(self): + system("cls||clear") p = math.trunc(self.hp/self.max*10) h = "🟥"*p if str(p).endswith(".5"): @@ -57,6 +59,39 @@ class FightHandler: else: print(f" {selection}") + def make_selection(self) -> None: + if self.selected == 0: + self.attack() + elif self.selected == 1: + self.defend() + elif self.selected == 2: + self.show_inventory() + + def rebind(self): + keyboard.remove_all_hotkeys() + keyboard.add_hotkey("up",self.up) + keyboard.add_hotkey("down",self.down) + keyboard.add_hotkey("enter",self.make_selection) + + def show_inventory(self): # Basically `Game` show_inventory + system("cls||clear") + if len(self.inventory) == 0: + FightMenu([self.lang["return"]],f" {self.lang['inside_inv']} \n") + else: + s = "" + for i,item in enumerate(self.inventory): + if type(item) is not str: + if(i == len(self.inventory)): # last item + s += f"- {item.name}" + else: + s += f"- {item.name}\n" + else: + if(i == len(self.inventory)): # last item + s += f"- {item}" + else: + s += f"- {item}\n" + FightMenu([self.lang["return"]],f" {self.lang['inside_inv']} \n{s}") + def attack(self): p = randrange(len(self.attacks)) name = list(self.attacks[p].keys())[0] @@ -70,3 +105,13 @@ class FightHandler: def defend(self): self.message = self.lang["defended"] + +class FightMenu(MenuManager): + def __init__(self,selections:list,additional:str): + self.selected = 0 # current selection + self.selections = selections # available selections + self.additional = additional # additional text to display above the menu + keyboard.add_hotkey("up",self.up) + keyboard.add_hotkey("down",self.down) + keyboard.add_hotkey("enter",self.make_selection) + self.show_menu() \ No newline at end of file diff --git a/lib/game.py b/lib/game.py index b36a52e..1844fde 100644 --- a/lib/game.py +++ b/lib/game.py @@ -2,6 +2,7 @@ import yaml from yaml.loader import SafeLoader from colorama import Fore, Back import re +from lib.item import Item from lib.menu import HasItemDialogue, MenuManager from .save import SaveManager @@ -11,14 +12,15 @@ from time import sleep from os import system class Game: # the game class keeps information about the loaded game - def __init__(self,data:dict): + def __init__(self,data:dict,lang): self.name = data["meta"]["name"] # Game name self.author = data["meta"]["creator"] # Game creator self.current = "start" # Current prompt self.nodes = {} # All nodes self.inventory = [] # Player's inventory self.id = data["meta"]["id"] # Game ID - self.save = SaveManager(self.id) # saving + self.lang = lang # Language strings + self.save = SaveManager(self.id,self.lang) # saving self.equipped = {"weapon":None,"armor":None} # Items equipped by player self.enemies = {} # Enemies if "equippable" in data["meta"].keys(): @@ -134,10 +136,27 @@ class Game: # the game class keeps information about the loaded game elif "fight" in self.nodes[self.current].keys(): # Initiate a fight enemy = self.enemies[self.nodes[self.current]["fight"]] # TODO: Complete after fight actions - s = FightHandler(self.nodes[self.current]["text"],enemy["name"],enemy["hp"],enemy["def"],enemy["attacks"],self.lang,self.equipped) - while s.hp > 0: - s.show() + m = FightHandler(self.nodes[self.current]["text"],enemy["name"],enemy["hp"],enemy["def"],enemy["attacks"],self.lang,self.equipped,self.inventory) + input() + while m.hp > 0 and m.my > 0: + m.show() + m.rebind() # rebind due to MenuManager in show_inventory input() + system("cls||clear") + keyboard.remove_all_hotkeys() + if m.hp < 1: + # Enemy defeated + print(self.lang["defeated"].replace("$enemy",enemy["name"])) + sleep(5) + self.current = self.nodes[self.current]["actions"][0] # move to the first action + self.print_text() + return + else: + # Player defeated + print(self.lang["defeat"].replace("$enemy",enemy["name"])) + sleep(5) + self.print_text() + return else: m = MenuManager(actions_desc,self.parse_colors(self.nodes[self.current]["text"])) sel = m.selected @@ -161,10 +180,16 @@ class Game: # the game class keeps information about the loaded game else: s = "" for i,item in enumerate(self.inventory): - if(i == len(self.inventory)): # last item - s += f"- {item}" + if type(item) is Item: + if(i == len(self.inventory)): # last item + s += f"- {item.name}" + else: + s += f"- {item.name}\n" else: - s += f"- {item}\n" + if(i == len(self.inventory)): # last item + s += f"- {item}" + else: + s += f"- {item}\n" MenuManager([self.lang["return"]],f" {self.lang['inside_inv']} \n{s}") self.print_text() @@ -183,20 +208,9 @@ def load(file_path,lang): # starts to load the game from YAML try: with open(file_path) as f: data = yaml.load(f,Loader=SafeLoader) - g = Game(data) - g.lang = lang + g = Game(data,lang) return g except Exception as e: print(f"{Back.RED}{Fore.WHITE}ERROR{Fore.RESET}{Back.RESET}") print(e) - return None - -class Item: - def __init__(self,name:str,attack:int = 0,defense:int = 0) -> None: - self.name = name - if attack == 0 and defense > 0: - self.type = "armor" - else: - self.type = "weapon" - self.attack = attack - self.defense = defense \ No newline at end of file + return None \ No newline at end of file diff --git a/lib/item.py b/lib/item.py new file mode 100644 index 0000000..fab4c87 --- /dev/null +++ b/lib/item.py @@ -0,0 +1,9 @@ +class Item: + def __init__(self,name:str,attack:int = 0,defense:int = 0) -> None: + self.name = name + if attack == 0 and defense > 0: + self.type = "armor" + else: + self.type = "weapon" + self.attack = attack + self.defense = defense \ No newline at end of file diff --git a/lib/lang/cz.yml b/lib/lang/cz.yml index fb110fd..de839f9 100644 --- a/lib/lang/cz.yml +++ b/lib/lang/cz.yml @@ -29,6 +29,9 @@ defend: "Bránit se" enemydmg: "$name dostal zásah za $atk bodů!" playerdmg: "Nepřítel použil $name a poškodil tě za $atk bodů." defended: "Rozhodneš se bránit a nedostal jsi tak žádný zásah." +defeated: "Porazil jsi $enemy." +defeat: "$enemy tě zabil. Budeš to muset zkusit znovu." error_loading: 'Při načítání YAML souboru nastala chyba:' no_action: 'Chyba: žádná akce "$action" nenalezena v souboru hry' +no_comp: "VAROVÁNÍ: Tato uložená hra je pro starší verzi enginu a nemusí být kompatibilní!" \ No newline at end of file diff --git a/lib/lang/en.yml b/lib/lang/en.yml index 8314b32..0219d00 100644 --- a/lib/lang/en.yml +++ b/lib/lang/en.yml @@ -29,6 +29,9 @@ defend: "Defend" enemydmg: "$name took $atk damage!" playerdmg: "The enemy used $name to damage you by $atk" defended: "You decide to defend yourself and take no damage." +defeated: "You have defeated $enemy." +defeat: "$enemy has slain you. You'll have to try again." error_loading: 'An exception has occured while loading the game from the YAML file' -no_action: 'Error: No action "$action" found in the game file.' \ No newline at end of file +no_action: 'Error: No action "$action" found in the game file.' +no_comp: "WARNING: This save is for an older version of the engine and may not be compatible!" \ No newline at end of file diff --git a/lib/menu.py b/lib/menu.py index f572008..34e9e95 100644 --- a/lib/menu.py +++ b/lib/menu.py @@ -15,7 +15,7 @@ class MenuManager: self.show_menu() input() - def make_selection(self) -> int: + def make_selection(self) -> None: keyboard.remove_all_hotkeys() def up(self): diff --git a/lib/save.py b/lib/save.py index 79c6837..29c4f0c 100644 --- a/lib/save.py +++ b/lib/save.py @@ -1,22 +1,44 @@ -from os import path +from time import sleep +from os import path, system import yaml +from lib.game import Item + class SaveManager: # manages save and configuration files - def __init__(self,gid:str): + def __init__(self,gid:str,lang): self.id = gid # game ID self.currentPrompt = "" # Current prompt self.inventory = [] # Items in inventory + self.version = 1 + self.lang = lang def load(self): if(path.exists(f"./saves/{self.id}.yml")): with open(f"./saves/{self.id}.yml",encoding="utf-8") as f: data = yaml.load(f,Loader=yaml.SafeLoader) self.currentPrompt = data["currentPrompt"] - self.inventory = data["inventory"] + if(data["version"] < self.version): + system("cls||clear") + print(self.lang["no_comp"]) + sleep(5) + inv = [] + for item in data["inventory"]: + if type(item) is str: + inv.append(item) + else: + # Item class + inv.append(Item(item["name"],item["atk"],item["def"])) return True return False def save(self): - data = {"id":self.id,"currentPrompt":self.currentPrompt,"inventory":self.inventory} + inv = [] + for item in self.inventory: + if type(item) is str: + inv.append(item) + else: + # Item class + inv.append({"name":item.name,"atk":item.attack,"def":item.defense}) + data = {"id":self.id,"currentPrompt":self.currentPrompt,"inventory":self.inventory,"version":1} with open(f"./saves/{self.id}.yml",mode="w",encoding="utf-8") as f: yaml.dump(data,f)