2021-11-02 17:40:54 +01:00
import yaml
from yaml . loader import SafeLoader
2022-03-24 18:20:39 +01:00
from colorama import Fore , Back
2022-01-25 17:16:07 +01:00
import re
2022-05-04 10:16:30 +02:00
from lib . item import Item
2022-03-24 18:20:39 +01:00
2022-04-05 11:59:11 +02:00
from lib . menu import HasItemDialogue , MenuManager
2022-02-04 19:35:38 +01:00
from . save import SaveManager
2022-01-26 09:23:30 +01:00
from . ascii import AsciiAnimation
2022-05-02 11:32:40 +02:00
from . fight import *
2022-01-25 17:16:07 +01:00
from time import sleep
2022-03-24 18:20:39 +01:00
from os import system
2021-11-02 17:40:54 +01:00
2022-05-04 14:26:32 +02:00
class Game : # Hlavní třída, uchovává údaje o hře
2022-05-04 10:16:30 +02:00
def __init__ ( self , data : dict , lang ) :
2022-05-04 14:26:32 +02:00
self . name = data [ " meta " ] [ " name " ] # Název hry
self . author = data [ " meta " ] [ " creator " ] # Název tvůrce
self . current = " start " # Aktuální node
self . nodes = { } # Seznam všech
self . inventory = [ ] # Hráčův inventář
self . id = data [ " meta " ] [ " id " ] # "Unikátní" ID hry
self . lang = lang # Řetězce pro vybraný jazyk
self . save = SaveManager ( self . id , self . lang ) # Systém ukládání
self . equipped = { " weapon " : None , " armor " : None } # Předměty vybavené hráčem
self . enemies = { } # Seznam všech nepřátel
2022-04-19 12:36:05 +02:00
if " equippable " in data [ " meta " ] . keys ( ) :
2022-05-04 14:26:32 +02:00
self . equippable = [ ] # Předměty, které si hráč může vybavit
2022-04-19 12:36:05 +02:00
for item in data [ " meta " ] [ " equippable " ] :
name = list ( item . keys ( ) ) [ 0 ]
if " def " in item [ name ] . keys ( ) and " atk " in item [ name ] . keys ( ) :
2022-05-04 14:26:32 +02:00
self . equippable . append ( Item ( item [ name ] [ " name " ] , item [ name ] [ " atk " ] , item [ name ] [ " def " ] ) )
2022-04-19 12:36:05 +02:00
elif " def " in item [ name ] . keys ( ) :
2022-05-04 14:26:32 +02:00
self . equippable . append ( Item ( name = item [ name ] [ " name " ] , defense = item [ name ] [ " def " ] ) )
2022-04-19 12:36:05 +02:00
elif " atk " in item [ name ] . keys ( ) :
2022-05-04 14:26:32 +02:00
self . equippable . append ( Item ( item [ name ] [ " name " ] , item [ name ] [ " atk " ] ) )
if ( " starter " in item [ name ] . keys ( ) ) : # Pokud je starter, přidáme hráčí na začátku do inventáře
2022-04-19 12:36:05 +02:00
if item [ name ] [ " starter " ] :
2022-05-16 15:56:11 +02:00
i = next ( ( x for x in self . equippable if x . name == item [ name ] [ " name " ] ) ) # V případě, že nenalezne předmět, vrací None
2022-04-19 12:36:05 +02:00
self . inventory . append ( i )
self . equipped [ i . type ] = i
2022-05-17 17:03:25 +02:00
self . save . equipped [ i . type ]
2022-05-02 11:32:40 +02:00
if " enemies " in data [ " meta " ] . keys ( ) :
2022-05-04 14:26:32 +02:00
# Načte nepřátele
2022-05-02 11:32:40 +02:00
for en in data [ " meta " ] [ " enemies " ] :
name = list ( en . keys ( ) ) [ 0 ]
self . enemies [ name ] = { " name " : en [ " name " ] , " hp " : en [ " hp " ] , " attacks " : en [ " attacks " ] , " def " : en [ " def " ] }
2022-05-04 14:26:32 +02:00
for k in data [ " game " ] : # načte všechny nody
2021-11-26 22:13:30 +01:00
self . nodes . update ( { k : data [ " game " ] [ k ] } )
2021-11-02 17:40:54 +01:00
2022-05-04 14:26:32 +02:00
def main_menu ( self ) : # Zobrazí hlavní menu
2022-02-04 19:35:38 +01:00
l = self . save . load ( )
if not l :
2022-05-04 14:26:32 +02:00
# V případě nové hry
2022-03-24 18:20:39 +01:00
m = MenuManager ( [ self . lang [ ' start ' ] , self . lang [ ' options ' ] , self . lang [ ' quit ' ] ] , f " { self . name } \n { self . lang [ ' game_by ' ] . replace ( ' $author ' , self . author ) } " )
selection = m . selected
2022-02-23 19:28:50 +01:00
system ( " cls||clear " )
2022-05-04 14:26:32 +02:00
if ( selection == 0 ) : # Začít
2022-02-23 19:28:50 +01:00
self . print_text ( )
2022-05-04 14:26:32 +02:00
elif ( selection == 1 ) : # Nastavení
2022-02-23 19:28:50 +01:00
self . settings_menu ( )
2022-05-04 14:26:32 +02:00
elif ( selection == 2 ) : # Vypnout
2022-03-23 14:22:12 +01:00
print ( self . lang [ ' quitting ' ] )
2022-02-23 19:28:50 +01:00
exit ( )
2022-05-04 14:26:32 +02:00
else : # V případě uložené hry zobrazí "Pokračovat"
2022-04-17 20:03:52 +02:00
m = MenuManager ( [ self . lang [ ' continue ' ] , self . lang [ ' new_game ' ] , self . lang [ ' options ' ] , self . lang [ ' quit ' ] ] , f " { self . name } \n { self . lang [ ' game_by ' ] . replace ( ' $author ' , self . author ) } " )
2022-03-24 18:20:39 +01:00
selection = m . selected
2022-02-04 19:35:38 +01:00
system ( " cls||clear " )
2022-03-24 18:20:39 +01:00
if ( selection == 0 ) :
2022-02-04 19:35:38 +01:00
self . current = self . save . currentPrompt
self . inventory = self . save . inventory
2022-05-17 17:03:25 +02:00
self . equipped = self . save . equipped
2022-02-04 19:35:38 +01:00
self . print_text ( )
2022-03-24 18:20:39 +01:00
elif ( selection == 1 ) :
2022-02-04 19:35:38 +01:00
self . print_text ( )
2022-03-24 18:20:39 +01:00
elif ( selection == 2 ) :
2022-02-23 19:28:50 +01:00
self . settings_menu ( )
2022-03-24 18:20:39 +01:00
elif ( selection == 3 ) :
print ( self . lang [ ' quitting ' ] )
2022-02-04 19:35:38 +01:00
exit ( )
2022-05-04 14:26:32 +02:00
def settings_menu ( self ) : # Zobrazí nastavení
2022-03-24 18:20:39 +01:00
m = MenuManager ( [ self . lang [ ' lang ' ] , self . lang [ ' back ' ] ] , self . lang [ ' options ' ] )
selection = m . selected
if ( selection == 0 ) :
m = MenuManager ( [ " English " , " Česky " , self . lang [ ' back ' ] ] , self . lang [ ' lang ' ] )
selection = m . selected
2022-02-04 19:35:38 +01:00
system ( " cls||clear " )
2022-03-24 18:20:39 +01:00
if ( selection == 0 ) :
2022-02-04 19:35:38 +01:00
with open ( " ./saves/lang " , " w " ) as f :
f . write ( " en " )
2022-03-24 18:20:39 +01:00
elif ( selection == 1 ) :
2022-02-04 19:35:38 +01:00
with open ( " ./saves/lang " , " w " ) as f :
f . write ( " cz " )
self . settings_menu ( )
2022-02-23 19:28:50 +01:00
else :
self . main_menu ( )
2021-11-02 17:40:54 +01:00
2022-05-04 14:26:32 +02:00
def print_text ( self ) : # Zobrazí hráči aktuální node
2022-02-23 19:28:50 +01:00
system ( " cls||clear " )
2022-05-04 14:26:32 +02:00
if " add_item " in self . nodes [ self . current ] . keys ( ) : # V případě, že máme přidat hráči věc do inventáře
2022-04-06 09:42:47 +02:00
item = self . nodes [ self . current ] [ ' add_item ' ]
2022-05-04 14:26:32 +02:00
for i in self . equippable :
if i . name == item : # Pokud lze vybavit, změnit na instanci třídy Item
item = i
2022-04-06 10:03:21 +02:00
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 " )
2022-05-04 14:26:32 +02:00
animated = re . search ( r " (?! { ).+(?=}) " , self . nodes [ self . current ] [ " text " ] ) # Hledá kód pro vložení animovaného textu
2022-01-25 17:16:07 +01:00
if ( animated != None ) :
self . print_animated ( animated . group ( 0 ) )
2022-05-04 14:26:32 +02:00
self . nodes [ self . current ] [ " text " ] = self . nodes [ self . current ] [ " text " ] . replace ( " { " + animated . group ( 0 ) + " } " , " " ) # Odstraní kód z textu
2021-11-26 22:13:30 +01:00
if ( " actions " in self . nodes [ self . current ] . keys ( ) ) :
2022-05-04 14:26:32 +02:00
actions_desc = [ ] # uchovává text nodu, abychom jej nemuseli hledat v MenuManager
need_item = [ ] # pomáhá implementovat kontrolu potřebného předmětu
2022-03-24 18:20:39 +01:00
for option in self . nodes [ self . current ] [ " actions " ] :
try :
actions_desc . append ( self . nodes [ option ] [ " description " ] )
2022-04-05 11:59:11 +02:00
if " has_item " in self . nodes [ option ] . keys ( ) :
need_item . append ( self . nodes [ option ] [ " has_item " ] )
else :
need_item . append ( None )
2022-04-06 10:03:21 +02:00
except Exception :
2022-03-24 18:20:39 +01:00
print ( f " { Back . RED } { Fore . WHITE } { self . lang [ ' no_action ' ] . replace ( ' $action ' , option ) } { Fore . RESET } " )
exit ( 1 )
2022-04-05 11:59:11 +02:00
m = " "
2022-04-06 10:03:21 +02:00
actions_desc . extend ( [ self . lang [ ' inventory ' ] , self . lang [ ' quit ' ] ] )
2022-05-04 14:26:32 +02:00
if ( all ( element == None for element in need_item ) is False ) : # Pokud platí, musíme zkontrolovat, jestli hráč má předmět
2022-04-06 10:03:21 +02:00
need_item . extend ( [ None , None ] )
2022-04-06 09:42:47 +02:00
m = HasItemDialogue ( actions_desc , self . parse_colors ( self . nodes [ self . current ] [ " text " ] ) , self . inventory , need_item )
2022-05-04 14:26:32 +02:00
while need_item [ m . selected ] != None and all ( element not in self . inventory for element in need_item [ m . selected ] ) : # Opakovat, dokud uživatel nevybere platný výběr
2022-04-06 09:42:47 +02:00
m = HasItemDialogue ( actions_desc , self . parse_colors ( self . nodes [ self . current ] [ " text " ] ) , self . inventory , need_item )
2022-04-17 19:02:11 +02:00
if m . selected < = len ( actions_desc ) - 3 and " has_item " in self . nodes [ self . nodes [ self . current ] [ " actions " ] [ m . selected ] ] . keys ( ) :
2022-04-12 15:16:38 +02:00
for item in need_item [ m . selected ] :
self . inventory . remove ( item )
2022-05-02 11:32:40 +02:00
elif " fight " in self . nodes [ self . current ] . keys ( ) :
2022-05-04 14:26:32 +02:00
# Spustí boj
enemy = self . enemies [ self . nodes [ self . current ] [ " fight " ] ] # Získá info o nepříteli
2022-05-04 10:16:30 +02:00
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 ( )
2022-05-04 14:26:32 +02:00
m . rebind ( ) # Znovu nastavuje klávesy, kvůli MenuManageru uvnitř show_inventory, který je maže
2022-05-02 11:32:40 +02:00
input ( )
2022-05-04 10:16:30 +02:00
system ( " cls||clear " )
keyboard . remove_all_hotkeys ( )
2022-05-17 17:03:25 +02:00
self . equipped = m . equipped
self . save . equipped = m . equipped
2022-05-04 10:16:30 +02:00
if m . hp < 1 :
2022-05-04 14:26:32 +02:00
# Nepřítel byl poražen
2022-05-04 10:16:30 +02:00
print ( self . lang [ " defeated " ] . replace ( " $enemy " , enemy [ " name " ] ) )
2022-05-04 14:26:32 +02:00
sleep ( 3 )
self . current = self . nodes [ self . current ] [ " actions " ] [ 0 ] # Přesune na první akci
2022-05-04 10:16:30 +02:00
self . print_text ( )
else :
2022-05-17 17:03:25 +02:00
# Hráč byl poražen
2022-05-04 10:16:30 +02:00
print ( self . lang [ " defeat " ] . replace ( " $enemy " , enemy [ " name " ] ) )
2022-05-04 14:26:32 +02:00
sleep ( 3 )
2022-05-04 10:16:30 +02:00
self . print_text ( )
2022-05-16 15:59:06 +02:00
return
2022-04-05 11:59:11 +02:00
else :
2022-04-06 09:42:47 +02:00
m = MenuManager ( actions_desc , self . parse_colors ( self . nodes [ self . current ] [ " text " ] ) )
2022-03-24 18:20:39 +01:00
sel = m . selected
2022-05-04 14:26:32 +02:00
if ( sel == len ( actions_desc ) - 2 ) : # Zobrazit inventář
2022-04-06 10:03:21 +02:00
self . show_inventory ( )
2022-05-04 14:26:32 +02:00
elif ( sel == len ( actions_desc ) - 1 ) : # Uložit a ukončit
self . save . currentPrompt = self . current
2022-04-06 10:03:21 +02:00
self . save . inventory = self . inventory
self . save . save ( )
exit ( 0 )
else :
self . current = self . nodes [ self . current ] [ " actions " ] [ sel ]
self . print_text ( )
2022-03-24 18:20:39 +01:00
else :
print ( self . parse_colors ( self . nodes [ self . current ] [ " text " ] ) )
print ( " " )
2022-01-25 17:16:07 +01:00
2022-05-04 14:26:32 +02:00
def show_inventory ( self ) : # Zobrazí hráčův inventář
2022-04-06 10:03:21 +02:00
if len ( self . inventory ) == 0 :
2022-04-19 12:36:05 +02:00
MenuManager ( [ self . lang [ " return " ] ] , f " { self . lang [ ' inside_inv ' ] } \n " )
2022-04-06 10:03:21 +02:00
else :
s = " "
2022-05-16 15:56:11 +02:00
op = [ ]
items = [ ]
2022-04-06 10:03:21 +02:00
for i , item in enumerate ( self . inventory ) :
2022-05-04 14:26:32 +02:00
if type ( item ) is Item : # Pokud je předmět třídy Item, zobrazit zda-li je vybaven nebo ne
if self . equipped [ " weapon " ] == item or self . equipped [ " armor " ] == item :
op . append ( f " - { item . name } | { self . lang [ ' equipped ' ] } " )
2022-05-04 10:16:30 +02:00
else :
2022-05-04 14:26:32 +02:00
op . append ( f " - { item . name } " )
2022-05-16 15:56:11 +02:00
items . append ( item )
2022-04-06 10:03:21 +02:00
else :
2022-05-04 14:26:32 +02:00
if ( i == len ( self . inventory ) ) : # poslední, nepřidávat newline
2022-05-04 10:16:30 +02:00
s + = f " - { item } "
else :
s + = f " - { item } \n "
2022-05-16 15:56:11 +02:00
items . append ( None )
op . append ( self . lang [ " return " ] )
2022-05-04 14:26:32 +02:00
m = MenuManager ( op , f " { self . lang [ ' inside_inv ' ] } \n { s } " )
if ( m . selected != len ( op ) - 1 ) :
# Vybavit
2022-05-16 15:56:11 +02:00
i = items [ m . selected ]
2022-05-04 14:26:32 +02:00
self . equipped [ i . type ] = i
2022-05-17 17:03:25 +02:00
self . save . equipped [ i . type ] = i
2022-04-06 10:03:21 +02:00
self . print_text ( )
2022-05-04 14:26:32 +02:00
def print_animated ( self , animid ) : # Zobrazí animaci
2022-01-26 09:23:30 +01:00
animation = AsciiAnimation ( )
animation . load_ascii ( animid )
2022-04-17 20:03:52 +02:00
animation . play ( )
2022-01-25 17:30:09 +01:00
print ( )
2022-01-25 17:16:07 +01:00
2022-05-04 14:26:32 +02:00
def parse_colors ( self , text : str ) - > str : # Převádí kód na barvy v terminálu
2021-12-02 11:20:39 +01:00
newText = text . replace ( " &b " , Fore . CYAN ) . replace ( " &c " , Fore . RED ) . replace ( " &e " , Fore . YELLOW ) . replace ( " &a " , Fore . GREEN ) . replace ( " &9 " , Fore . BLUE ) . replace ( " &r " , Fore . RESET ) . replace ( " &f " , Fore . WHITE ) . replace ( " &5 " , Fore . MAGENTA ) . replace ( " \n " , Fore . RESET + " \n " ) # replace color codes and newlines with colorama
2022-05-04 14:26:32 +02:00
newText + = Fore . RESET # resetovat na konci
2021-11-26 22:13:30 +01:00
return newText
2021-11-03 10:23:37 +01:00
2022-05-04 14:26:32 +02:00
def load ( file_path , lang ) : # Načte hru z YAML souboru
2022-05-16 15:56:11 +02:00
with open ( file_path ) as f :
data = yaml . load ( f , Loader = SafeLoader )
g = Game ( data , lang )
return g