From 111e918c937f249eddfdc4fe034217d75991ca2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maty=C3=A1=C5=A1=20Caras?= Date: Tue, 5 Apr 2022 11:59:11 +0200 Subject: [PATCH 1/5] Work on item checking --- games/example.yml | 17 +++++++++++++++++ lib/game.py | 14 ++++++++++++-- lib/menu.py | 25 +++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/games/example.yml b/games/example.yml index 80932f4..76cd6d2 100644 --- a/games/example.yml +++ b/games/example.yml @@ -22,7 +22,24 @@ game: # here goes all the game logic description: "Order beer" text: "You order some &ebeer" add_inventory: "Beer" # add something to inventory + actions: + - do_something nothing: description: "Do nothing" text: "You sit and wait..." + do_something: + description: "Continue" + text: "You start to feel bored." + actions: + - drink + - leave + drink: + has_item: ["Beer"] # item names are case-sensitive + description: "Drink beer" + text: "You take a sip of your cold &eBeer" + actions: + - leave + leave: + description: "Leave" + text: "You decide to leave." diff --git a/lib/game.py b/lib/game.py index a3172e4..09ce019 100644 --- a/lib/game.py +++ b/lib/game.py @@ -3,7 +3,7 @@ from yaml.loader import SafeLoader from colorama import Fore, Back import re -from lib.menu import MenuManager +from lib.menu import HasItemDialogue, MenuManager from .save import SaveManager from .ascii import AsciiAnimation from time import sleep @@ -76,13 +76,23 @@ class Game: # the game class keeps information about the loaded game self.nodes[self.current]["text"] = self.nodes[self.current]["text"].replace("{"+animated.group(0)+"}","") # remove the animated text from the text prompt if("actions" in self.nodes[self.current].keys()): actions_desc = [] + need_item = [] for option in self.nodes[self.current]["actions"]: try: actions_desc.append(self.nodes[option]["description"]) + if "has_item" in self.nodes[option].keys(): + need_item.append(self.nodes[option]["has_item"]) + else: + need_item.append(None) except: print(f"{Back.RED}{Fore.WHITE}{self.lang['no_action'].replace('$action',option)}{Fore.RESET}") exit(1) - m = MenuManager(actions_desc,self.parse_colors(self.nodes[self.current]["text"])) + m = "" + if((element == None for element in need_item) is False): + # we need to check if user has item + m = HasItemDialogue(self.nodes[self.current]["actions"],self.parse_colors(self.nodes[self.current]["text"]),self.inventory,need_item) + else: + m = MenuManager(self.nodes[self.current]["actions"],self.parse_colors(self.nodes[self.current]["text"])) sel = m.selected if "add_item" in self.nodes[self.current]: # if there is an add_inventory key in the node, # add item to inventory diff --git a/lib/menu.py b/lib/menu.py index fe224e6..ae06ab8 100644 --- a/lib/menu.py +++ b/lib/menu.py @@ -41,3 +41,28 @@ class MenuManager: print(f"{Fore.RED}->{Fore.RESET} {selection}") else: print(f" {selection}") + +class HasItemDialogue(MenuManager): + ''' + Custom handler for dialogue, that requires to check if the user has an item + ''' + def __init__(self, selections: list, additional: str,inv:list,need_item:list): + self.inventory = inv + self.need_items = need_item + super().__init__(selections, additional) + + def show_menu(self): + print(self.additional) + for i,selection in enumerate(self.selections): + if(self.need_items[i] != None and self.need_items[i] not in self.inv): + # user does not have the needed item + if(self.selected == i): + print(f"{Fore.RED}-> {Fore.CYAN}{selection}{Fore.RESET} (Need '{self.need_items[i]}')") + else: + print(f" {Fore.CYAN}{selection}{Fore.RESET}") + else: + # we don't need to change color for an item user doesn't have + if(self.selected == i): + print(f"{Fore.RED}->{Fore.RESET} {selection}") + else: + print(f" {selection}") From 997475aef1a8fcae7f4422becc9478d6334553b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maty=C3=A1=C5=A1=20Caras?= Date: Wed, 6 Apr 2022 09:42:47 +0200 Subject: [PATCH 2/5] Hopefully item checking is complete --- games/example.yml | 5 ++++- lib/game.py | 26 ++++++++++++++++++-------- lib/lang/cz.yml | 1 + lib/lang/en.yml | 1 + lib/menu.py | 16 ++++++++++++++-- 5 files changed, 38 insertions(+), 11 deletions(-) diff --git a/games/example.yml b/games/example.yml index 76cd6d2..8728446 100644 --- a/games/example.yml +++ b/games/example.yml @@ -21,12 +21,15 @@ game: # here goes all the game logic beer: description: "Order beer" text: "You order some &ebeer" - add_inventory: "Beer" # add something to inventory + add_item: "Beer" # add something to inventory actions: - do_something nothing: description: "Do nothing" text: "You sit and wait..." + actions: + - drink + - leave do_something: description: "Continue" text: "You start to feel bored." diff --git a/lib/game.py b/lib/game.py index 09ce019..05a3fc9 100644 --- a/lib/game.py +++ b/lib/game.py @@ -70,13 +70,22 @@ class Game: # the game class keeps information about the loaded game def print_text(self): # Prints out the current prompt system("cls||clear") + if "add_item" in self.nodes[self.current].keys(): # if there is an add_inventory key in the node, + # add item to inventory + item = self.nodes[self.current]['add_item'] + self.inventory.append(item) + print(self.inventory) + system("clear||cls") + print(f"{self.lang['acquire'].replace('$item',f'{Fore.CYAN}{item}{Fore.RESET}')}") + sleep(3) + system("clear||cls") animated = re.search(r"(?!{).+(?=})",self.nodes[self.current]["text"]) # find the animated text if(animated != None): self.print_animated(animated.group(0)) self.nodes[self.current]["text"] = self.nodes[self.current]["text"].replace("{"+animated.group(0)+"}","") # remove the animated text from the text prompt if("actions" in self.nodes[self.current].keys()): - actions_desc = [] - need_item = [] + actions_desc = [] # has descriptions of text prompts, so that we don't need to find them in MenuManager + need_item = [] # helps implement a check for needing an item for option in self.nodes[self.current]["actions"]: try: actions_desc.append(self.nodes[option]["description"]) @@ -88,15 +97,16 @@ class Game: # the game class keeps information about the loaded game print(f"{Back.RED}{Fore.WHITE}{self.lang['no_action'].replace('$action',option)}{Fore.RESET}") exit(1) m = "" - if((element == None for element in need_item) is False): + if(all(element == None for element in need_item) is False): # we need to check if user has item - m = HasItemDialogue(self.nodes[self.current]["actions"],self.parse_colors(self.nodes[self.current]["text"]),self.inventory,need_item) + m = HasItemDialogue(actions_desc,self.parse_colors(self.nodes[self.current]["text"]),self.inventory,need_item) + print(self.inventory) + while need_item[m.selected] != None and all(element not in self.inventory for element in need_item[m.selected]): # until user selects an available prompt, re-prompt again + m = HasItemDialogue(actions_desc,self.parse_colors(self.nodes[self.current]["text"]),self.inventory,need_item) else: - m = MenuManager(self.nodes[self.current]["actions"],self.parse_colors(self.nodes[self.current]["text"])) + m = MenuManager(actions_desc,self.parse_colors(self.nodes[self.current]["text"])) sel = m.selected - if "add_item" in self.nodes[self.current]: # if there is an add_inventory key in the node, - # add item to inventory - self.inventory.append(self.nodes[self.current]["add_inventory"]) + self.current = self.nodes[self.current]["actions"][sel] self.save.currentPrompt = self.current # save the current prompt self.print_text() diff --git a/lib/lang/cz.yml b/lib/lang/cz.yml index 8c3d22e..fb6a532 100644 --- a/lib/lang/cz.yml +++ b/lib/lang/cz.yml @@ -9,6 +9,7 @@ quit: 'Vypnout' quitting: 'Vypínám' continue: 'Pokračovat' new_game: 'Nová hra' +acquire: 'Získal jsi $item' lang: 'Jazyk' back: 'Zpět' diff --git a/lib/lang/en.yml b/lib/lang/en.yml index c4c8615..c3aa17a 100644 --- a/lib/lang/en.yml +++ b/lib/lang/en.yml @@ -9,6 +9,7 @@ quit: 'Quit' quitting: 'Quitting' continue: 'Continue' new_game: 'New game' +acquire: 'You acquired $item' lang: 'Language' back: 'Back' diff --git a/lib/menu.py b/lib/menu.py index ae06ab8..f572008 100644 --- a/lib/menu.py +++ b/lib/menu.py @@ -35,6 +35,7 @@ class MenuManager: self.show_menu() def show_menu(self): + system("cls||clear") print(self.additional) for selection in self.selections: if(self.selected == self.selections.index(selection)): @@ -47,17 +48,26 @@ class HasItemDialogue(MenuManager): Custom handler for dialogue, that requires to check if the user has an item ''' def __init__(self, selections: list, additional: str,inv:list,need_item:list): + system("cls||clear") self.inventory = inv self.need_items = need_item super().__init__(selections, additional) def show_menu(self): print(self.additional) + for i,selection in enumerate(self.selections): - if(self.need_items[i] != None and self.need_items[i] not in self.inv): + if(self.need_items[i] != None and all(element not in self.inventory for element in self.need_items[i])): + c = "" + for i,item in enumerate(self.need_items[i]): + if item not in self.inventory: + if i == len(self.need_items)-self.need_items.count(None)-1: # last item, don't add a comma + c+=f"{item} " + else: + c+=f"{item}, " # user does not have the needed item if(self.selected == i): - print(f"{Fore.RED}-> {Fore.CYAN}{selection}{Fore.RESET} (Need '{self.need_items[i]}')") + print(f"{Fore.RED}-> {Fore.CYAN}{selection}{Fore.RESET} (Need {c})") else: print(f" {Fore.CYAN}{selection}{Fore.RESET}") else: @@ -66,3 +76,5 @@ class HasItemDialogue(MenuManager): print(f"{Fore.RED}->{Fore.RESET} {selection}") else: print(f" {selection}") + def make_selection(self) -> int: + keyboard.remove_all_hotkeys() From 7361882831dfebc150d55fc5269efb8c83a4d810 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maty=C3=A1=C5=A1=20Caras?= Date: Wed, 6 Apr 2022 10:03:21 +0200 Subject: [PATCH 3/5] Add showing inventory --- __main__.py | 5 +++-- lib/ascii.py | 1 - lib/game.py | 47 +++++++++++++++++++++++++++++++++++------------ lib/lang/cz.yml | 4 ++++ lib/lang/en.yml | 4 ++++ lib/save.py | 3 +-- 6 files changed, 47 insertions(+), 17 deletions(-) diff --git a/__main__.py b/__main__.py index 43908dd..57a9151 100644 --- a/__main__.py +++ b/__main__.py @@ -19,7 +19,7 @@ def lang(): data = yaml.load(f,Loader=SafeLoader) return data -def main(): # TODO: Maybe a menu for available text games? +def main(): l = lang() init() if(not isdir("./games")): @@ -41,7 +41,8 @@ def main(): # TODO: Maybe a menu for available text games? print(l['no_games']) else: names = [] - for n in games: names.append(n.name) + for n in games: + names.append(n.name) m = MenuManager(names,f" TEXTY \n{l['available']}") games[m.selected].main_menu() diff --git a/lib/ascii.py b/lib/ascii.py index 79c6d6c..d7d1cc7 100644 --- a/lib/ascii.py +++ b/lib/ascii.py @@ -21,6 +21,5 @@ class AsciiAnimation: data = yaml.load(c,Loader=yaml.SafeLoader) if(data["speed"] != None): self.speed = data["speed"] - pass with open(f"{tmpdir}/ascii/{name}/{f}",encoding="utf-8") as f: # add all frames into list self.frames.append(f.read()) \ No newline at end of file diff --git a/lib/game.py b/lib/game.py index 05a3fc9..3f404bd 100644 --- a/lib/game.py +++ b/lib/game.py @@ -1,3 +1,4 @@ +import enum import yaml from yaml.loader import SafeLoader from colorama import Fore, Back @@ -73,12 +74,13 @@ class Game: # the game class keeps information about the loaded game if "add_item" in self.nodes[self.current].keys(): # if there is an add_inventory key in the node, # add item to inventory item = self.nodes[self.current]['add_item'] - self.inventory.append(item) - print(self.inventory) - system("clear||cls") - print(f"{self.lang['acquire'].replace('$item',f'{Fore.CYAN}{item}{Fore.RESET}')}") - sleep(3) - system("clear||cls") + if item not in self.inventory: + self.inventory.append(item) + print(self.inventory) + system("clear||cls") + print(f"{self.lang['acquire'].replace('$item',f'{Fore.CYAN}{item}{Fore.RESET}')}") + sleep(3) + system("clear||cls") animated = re.search(r"(?!{).+(?=})",self.nodes[self.current]["text"]) # find the animated text if(animated != None): self.print_animated(animated.group(0)) @@ -93,27 +95,48 @@ class Game: # the game class keeps information about the loaded game need_item.append(self.nodes[option]["has_item"]) else: need_item.append(None) - except: + except Exception: print(f"{Back.RED}{Fore.WHITE}{self.lang['no_action'].replace('$action',option)}{Fore.RESET}") exit(1) m = "" + actions_desc.extend([self.lang['inventory'],self.lang['quit']]) if(all(element == None for element in need_item) is False): + need_item.extend([None, None]) # we need to check if user has item m = HasItemDialogue(actions_desc,self.parse_colors(self.nodes[self.current]["text"]),self.inventory,need_item) - print(self.inventory) + # TODO: Remove item from inventory after using it? while need_item[m.selected] != None and all(element not in self.inventory for element in need_item[m.selected]): # until user selects an available prompt, re-prompt again m = HasItemDialogue(actions_desc,self.parse_colors(self.nodes[self.current]["text"]),self.inventory,need_item) else: m = MenuManager(actions_desc,self.parse_colors(self.nodes[self.current]["text"])) sel = m.selected - - self.current = self.nodes[self.current]["actions"][sel] - self.save.currentPrompt = self.current # save the current prompt - self.print_text() + if(sel == len(actions_desc)-2): # show inventory + self.show_inventory() + elif (sel == len(actions_desc)-1): # Save & quit + self.save.currentPrompt = self.current # save the current prompt + self.save.inventory = self.inventory + self.save.save() + exit(0) + else: + self.current = self.nodes[self.current]["actions"][sel] + self.print_text() else: print(self.parse_colors(self.nodes[self.current]["text"])) print("") + def show_inventory(self): + if len(self.inventory) == 0: + MenuManager([self.lang["return"]],f" YOUR INVENTORY \n") + else: + s = "" + for i,item in enumerate(self.inventory): + if(i == len(self.inventory)): # last item + s += f"- {item}" + else: + s += f"- {item}\n" + MenuManager([self.lang["return"]],f" YOUR INVENTORY \n{s}") + self.print_text() + def print_animated(self,animid): # prints the first found occurence of an ascii animation animation = AsciiAnimation() animation.load_ascii(animid) diff --git a/lib/lang/cz.yml b/lib/lang/cz.yml index fb6a532..f8feb64 100644 --- a/lib/lang/cz.yml +++ b/lib/lang/cz.yml @@ -9,8 +9,12 @@ quit: 'Vypnout' quitting: 'Vypínám' continue: 'Pokračovat' new_game: 'Nová hra' +inventory: 'Zobrazit inventář' acquire: 'Získal jsi $item' +inside_inv: "VÁŠ INVENTÁŘ" +return: "Vrátit se" + lang: 'Jazyk' back: 'Zpět' lang_en: 'Angličtina' diff --git a/lib/lang/en.yml b/lib/lang/en.yml index c3aa17a..faa1529 100644 --- a/lib/lang/en.yml +++ b/lib/lang/en.yml @@ -9,8 +9,12 @@ quit: 'Quit' quitting: 'Quitting' continue: 'Continue' new_game: 'New game' +inventory: 'Show inventory' acquire: 'You acquired $item' +inside_inv: "YOUR INVENTORY" +return: "Return" + lang: 'Language' back: 'Back' lang_en: 'English' diff --git a/lib/save.py b/lib/save.py index 2347209..389e830 100644 --- a/lib/save.py +++ b/lib/save.py @@ -5,7 +5,6 @@ class SaveManager: # manages save and configuration files def __init__(self): self.id = "" # game ID self.currentPrompt = "" # Current prompt - self.lang = "" # Selected language self.inventory = [] # Items in inventory def load(self): @@ -18,6 +17,6 @@ class SaveManager: # manages save and configuration files return False def save(self): - data = {"id":self.id,"currentPrompt":self.currentPrompt,"inventory":self.inventory,"lang":self.lang} + data = {"id":self.id,"currentPrompt":self.currentPrompt,"inventory":self.inventory} with open(f"./saves/{self.id}.yml",mode="w",encoding="utf-8") as f: yaml.dump(data,f) \ No newline at end of file From 90358c73c7b8b6b7b406f776fec28cd0277c5c67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maty=C3=A1=C5=A1=20Caras?= Date: Wed, 6 Apr 2022 14:12:23 +0200 Subject: [PATCH 4/5] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4e9a61d..8a0cec0 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ I was bored Check out the `example.yml` file, all games are in the `YAML` format. ## How do I use this -Download/clone the repo and run the `__main__.py` file with the path to a game in `YAML` format as the first argument. +Download/clone the repo and run the `__main__.py` file. You need to have a valid game in a `games` folder. ## TODO [Here](https://github.com/hernikplays/texty/projects/1) From 322980c704ba76cd934fc0972afaf80ac4c53788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maty=C3=A1=C5=A1=20Caras?= Date: Tue, 12 Apr 2022 15:16:38 +0200 Subject: [PATCH 5/5] Remove item --- lib/game.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/game.py b/lib/game.py index 3f404bd..04b8378 100644 --- a/lib/game.py +++ b/lib/game.py @@ -107,6 +107,9 @@ class Game: # the game class keeps information about the loaded game # TODO: Remove item from inventory after using it? while need_item[m.selected] != None and all(element not in self.inventory for element in need_item[m.selected]): # until user selects an available prompt, re-prompt again m = HasItemDialogue(actions_desc,self.parse_colors(self.nodes[self.current]["text"]),self.inventory,need_item) + if "has_item" in self.nodes[m.selected].keys(): + for item in need_item[m.selected]: + self.inventory.remove(item) else: m = MenuManager(actions_desc,self.parse_colors(self.nodes[self.current]["text"])) sel = m.selected