Merge branch 'main' of https://github.com/hernikplays/texty
This commit is contained in:
commit
b347fd7585
9 changed files with 124 additions and 28 deletions
|
@ -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)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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."
|
||||||
|
|
||||||
|
|
|
@ -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())
|
66
lib/game.py
66
lib/game.py
|
@ -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 = MenuManager(actions_desc,self.parse_colors(self.nodes[self.current]["text"]))
|
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"]))
|
||||||
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.print_text()
|
self.save.save()
|
||||||
|
exit(0)
|
||||||
|
else:
|
||||||
|
self.current = self.nodes[self.current]["actions"][sel]
|
||||||
|
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)
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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'
|
||||||
|
|
37
lib/menu.py
37
lib/menu.py
|
@ -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()
|
||||||
|
|
|
@ -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)
|
Reference in a new issue