This commit is contained in:
Matyáš Caras 2022-04-17 18:47:02 +02:00
commit b347fd7585
9 changed files with 124 additions and 28 deletions

View file

@ -9,7 +9,7 @@ I was bored
Check out the `example.yml` file, all games are in the `YAML` format. Check out the `example.yml` file, all games are in the `YAML` format.
## How do I use this ## 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 ## TODO
[Here](https://github.com/hernikplays/texty/projects/1) [Here](https://github.com/hernikplays/texty/projects/1)

View file

@ -19,7 +19,7 @@ def lang():
data = yaml.load(f,Loader=SafeLoader) data = yaml.load(f,Loader=SafeLoader)
return data return data
def main(): # TODO: Maybe a menu for available text games? def main():
l = lang() l = lang()
init() init()
if(not isdir("./games")): if(not isdir("./games")):
@ -41,7 +41,8 @@ def main(): # TODO: Maybe a menu for available text games?
print(l['no_games']) print(l['no_games'])
else: else:
names = [] 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']}") m = MenuManager(names,f" TEXTY \n{l['available']}")
games[m.selected].main_menu() games[m.selected].main_menu()

View file

@ -21,24 +21,28 @@ game: # here goes all the game logic
beer: beer:
description: "Order beer" description: "Order beer"
text: "You order some &ebeer" text: "You order some &ebeer"
add_inventory: "Beer" # add something to inventory add_item: "Beer" # add something to inventory
actions:
- do_something
nothing: nothing:
description: "Do nothing" description: "Do nothing"
text: "You sit and wait..." text: "You sit and wait..."
actions: actions:
- last - drink
last: - leave
description: 'Continue' do_something:
text: 'You look around the tavern' description: "Continue"
text: "You start to feel bored."
actions: actions:
- drink - drink
- sitmore - leave
drink: drink:
needs_item: has_item: ["Beer"] # item names are case-sensitive
- 'Beer'
description: "Drink beer" description: "Drink beer"
text: 'You take a sip of your beer' text: "You take a sip of your cold &eBeer"
sitmore: actions:
description: 'Sit some more' - leave
text: 'You sit some more...' leave:
description: "Leave"
text: "You decide to leave."

View file

@ -21,6 +21,5 @@ class AsciiAnimation:
data = yaml.load(c,Loader=yaml.SafeLoader) data = yaml.load(c,Loader=yaml.SafeLoader)
if(data["speed"] != None): if(data["speed"] != None):
self.speed = data["speed"] self.speed = data["speed"]
pass
with open(f"{tmpdir}/ascii/{name}/{f}",encoding="utf-8") as f: # add all frames into list with open(f"{tmpdir}/ascii/{name}/{f}",encoding="utf-8") as f: # add all frames into list
self.frames.append(f.read()) self.frames.append(f.read())

View file

@ -1,9 +1,10 @@
import enum
import yaml import yaml
from yaml.loader import SafeLoader from yaml.loader import SafeLoader
from colorama import Fore, Back from colorama import Fore, Back
import re import re
from lib.menu import MenuManager from lib.menu import HasItemDialogue, MenuManager
from .save import SaveManager from .save import SaveManager
from .ascii import AsciiAnimation from .ascii import AsciiAnimation
from time import sleep from time import sleep
@ -70,30 +71,75 @@ class Game: # the game class keeps information about the loaded game
def print_text(self): # Prints out the current prompt def print_text(self): # Prints out the current prompt
system("cls||clear") 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']
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 animated = re.search(r"(?!{).+(?=})",self.nodes[self.current]["text"]) # find the animated text
if(animated != None): if(animated != None):
self.print_animated(animated.group(0)) 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 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()): if("actions" in self.nodes[self.current].keys()):
actions_desc = [] 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"]: for option in self.nodes[self.current]["actions"]:
try: try:
actions_desc.append(self.nodes[option]["description"]) actions_desc.append(self.nodes[option]["description"])
except: if "has_item" in self.nodes[option].keys():
need_item.append(self.nodes[option]["has_item"])
else:
need_item.append(None)
except Exception:
print(f"{Back.RED}{Fore.WHITE}{self.lang['no_action'].replace('$action',option)}{Fore.RESET}") print(f"{Back.RED}{Fore.WHITE}{self.lang['no_action'].replace('$action',option)}{Fore.RESET}")
exit(1) 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)
# 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"])) m = MenuManager(actions_desc,self.parse_colors(self.nodes[self.current]["text"]))
sel = m.selected sel = m.selected
if "add_item" in self.nodes[self.current]: # if there is an add_inventory key in the node, if(sel == len(actions_desc)-2): # show inventory
# add item to inventory self.show_inventory()
self.inventory.append(self.nodes[self.current]["add_inventory"]) elif (sel == len(actions_desc)-1): # Save & quit
self.current = self.nodes[self.current]["actions"][sel]
self.save.currentPrompt = self.current # save the current prompt 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() self.print_text()
else: else:
print(self.parse_colors(self.nodes[self.current]["text"])) print(self.parse_colors(self.nodes[self.current]["text"]))
print("") 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 def print_animated(self,animid): # prints the first found occurence of an ascii animation
animation = AsciiAnimation() animation = AsciiAnimation()
animation.load_ascii(animid) animation.load_ascii(animid)

View file

@ -9,6 +9,11 @@ quit: 'Vypnout'
quitting: 'Vypínám' quitting: 'Vypínám'
continue: 'Pokračovat' continue: 'Pokračovat'
new_game: 'Nová hra' new_game: 'Nová hra'
inventory: 'Zobrazit inventář'
acquire: 'Získal jsi $item'
inside_inv: "VÁŠ INVENTÁŘ"
return: "Vrátit se"
lang: 'Jazyk' lang: 'Jazyk'
back: 'Zpět' back: 'Zpět'

View file

@ -9,6 +9,11 @@ quit: 'Quit'
quitting: 'Quitting' quitting: 'Quitting'
continue: 'Continue' continue: 'Continue'
new_game: 'New game' new_game: 'New game'
inventory: 'Show inventory'
acquire: 'You acquired $item'
inside_inv: "YOUR INVENTORY"
return: "Return"
lang: 'Language' lang: 'Language'
back: 'Back' back: 'Back'

View file

@ -35,9 +35,46 @@ class MenuManager:
self.show_menu() self.show_menu()
def show_menu(self): def show_menu(self):
system("cls||clear")
print(self.additional) print(self.additional)
for selection in self.selections: for selection in self.selections:
if(self.selected == self.selections.index(selection)): if(self.selected == self.selections.index(selection)):
print(f"{Fore.RED}->{Fore.RESET} {selection}") print(f"{Fore.RED}->{Fore.RESET} {selection}")
else: else:
print(f" {selection}") 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):
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 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 {c})")
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}")
def make_selection(self) -> int:
keyboard.remove_all_hotkeys()

View file

@ -5,7 +5,6 @@ class SaveManager: # manages save and configuration files
def __init__(self): def __init__(self):
self.id = "" # game ID self.id = "" # game ID
self.currentPrompt = "" # Current prompt self.currentPrompt = "" # Current prompt
self.lang = "" # Selected language
self.inventory = [] # Items in inventory self.inventory = [] # Items in inventory
def load(self): def load(self):
@ -18,6 +17,6 @@ class SaveManager: # manages save and configuration files
return False return False
def save(self): 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: with open(f"./saves/{self.id}.yml",mode="w",encoding="utf-8") as f:
yaml.dump(data,f) yaml.dump(data,f)