diff --git a/classes/Character/CharacterCreater.py b/classes/Character/CharacterCreater.py new file mode 100644 index 0000000..99688ff --- /dev/null +++ b/classes/Character/CharacterCreater.py @@ -0,0 +1,107 @@ +from simple_term_menu import TerminalMenu +from tabulate import tabulate +import logging +import sys, re + +LOGGING = logging.getLogger(__name__) +class CharacterCreater: + @classmethod + def make_dict_list_into_table(cls, dict_list:dict, change_by_key=None, ignore_keys:list[str]=[]): + dict_keys = list(dict_list.keys()) + keys = list(dict_list[dict_keys[0]].keys()) + table = [dict_keys] + + for key in keys: + row = [] + if not key in ignore_keys: + row.append(key) + for element in dict_list.values(): + if change_by_key != None: + element[key] = change_by_key(key, element) + + row.append(element[key]) + table.append(row) + + return tabulate(table, headers='firstrow', tablefmt='grid') + + @classmethod + def change_character_key(cls, key, element): + if key == "fixed_type": + if not element[key]: + return None + + return element[key] + + @classmethod + def select_a_species(cls, player_config:dict, block_by_fixed_type:bool=False): + print(CharacterCreater.make_dict_list_into_table(player_config["species"], change_by_key=lambda key, element: CharacterCreater.change_character_key(key, element))) + if not block_by_fixed_type: + select_species = list(player_config["species"].keys()) + else: + select_species = list(player_config["species"].keys())[:-1] + + m = TerminalMenu(select_species, title='Select a Species') + selection = m.show() + + characte_species = player_config["species"][select_species[selection]] + characte_species["name"] = select_species[selection] + + if not characte_species["fixed_type"] and not block_by_fixed_type: + types = [ x["name"] for x in player_config["types"] ] + m = TerminalMenu(types, title='Select a Type') + selection = m.show() + + characte_type = (types[selection]) + else: + characte_type = characte_species["fixed_type"] + + if characte_species["combineble"]: + combineble_species = True + else: + combineble_species = False + + return { + "species": characte_species, + "type": characte_type, + "combineble": combineble_species + } + + @classmethod + def create_character(cls, player_config:dict, message:str): + print(message) + while True: + try: + characte_name = input("Enter Character Name: ") + if re.match("[a-zA-Z]", characte_name): + break + except KeyboardInterrupt as e: + LOGGING.debug(e) + sys.exit(1) + + characte_species = CharacterCreater.select_a_species(player_config) + + if not characte_species["combineble"]: + combineble_species = False + else: + # TODO: Remove all combineble Classes + del player_config["species"][characte_species["species"]["name"]] + player_config["species"]["Current Selected"] = characte_species["species"] + combineble_species = CharacterCreater.select_a_species(player_config, block_by_fixed_type=True)["species"] + + return CharacterCreater.cleanup({ + "name": characte_name, + "species": characte_species, + "type": characte_species["type"], + "combineble_species": combineble_species + }) + + @classmethod + def cleanup(cls, player_config:dict): + if player_config["species"]["species"]: + player_config["species"] = player_config["species"]["species"] + + if player_config["combineble_species"]: + del player_config["combineble_species"]["combineble"] + del player_config["combineble_species"]["fixed_type"] + + return player_config diff --git a/classes/Player.py b/classes/Character/Player.py similarity index 58% rename from classes/Player.py rename to classes/Character/Player.py index 9b9d257..8394e50 100644 --- a/classes/Player.py +++ b/classes/Character/Player.py @@ -2,10 +2,11 @@ import logging LOGGING = logging.getLogger(__name__) class Player: - def __init__(self, name:str, type:dict, species:dict): + def __init__(self, name:str, type:dict, species:dict, combineble_species:dict): self.name = name self.type = type self.species = species + self.combineble_species = combineble_species self.inventory = [] self.inventory_size = species["inventory_size"] @@ -22,4 +23,4 @@ class Player: pass def __str__(self): - return f"{self.__class__.__name__} | Name :{self.name}\nType :{self.type}\nSpecies :{self.species}\nInventory: {self.inventory}" + return f"{self.__class__.__name__} | Name: {self.name} - {self.type}\nSpecies: {self.species}\nInventory: {self.inventory}\nCombineble Species: {self.combineble_species}" diff --git a/classes/GameBoard.py b/classes/GameBoard.py index 0ec52bb..f376ab2 100644 --- a/classes/GameBoard.py +++ b/classes/GameBoard.py @@ -1,10 +1,11 @@ +from classes.Character.CharacterCreater import CharacterCreater from classes.SavedState import SavedState -import my_helpers.myPickle as my_pickle +from classes.Map import Map from simple_term_menu import TerminalMenu from tabulate import tabulate import logging -import sys, os, re +import os LOGGING = logging.getLogger(__name__) class GameBoard: @@ -13,106 +14,23 @@ class GameBoard: self.save_state_file = save_state_file self.map_file = map_file - def make_dict_list_into_table(self, dict_list:dict, change_by_key=None, ignore_keys:list[str]=[]): - dict_keys = list(dict_list.keys()) - keys = list(dict_list[dict_keys[0]].keys()) - table = [dict_keys] - - for key in keys: - row = [] - if not key in ignore_keys: - row.append(key) - for element in dict_list.values(): - if change_by_key != None: - element[key] = change_by_key(key, element) - - row.append(element[key]) - table.append(row) - - return tabulate(table, headers='firstrow', tablefmt='grid') - - def change_character_key(self, key, element): - if key == "fixed_type": - if not element[key]: - return None - - return element[key] - def print_story(self, story:str): print(story) - def create_character(self, player_config:dict, message:str): - self.print_story(message) - while True: - try: - characte_name = input("Enter Character Name: ") - if re.match("[a-zA-Z]", characte_name): - break - except KeyboardInterrupt as e: - LOGGING.debug(e) - sys.exit(1) - - print(self.make_dict_list_into_table(player_config["species"], change_by_key=lambda key, element: self.change_character_key(key, element))) - select_species = list(player_config["species"].keys()) - m = TerminalMenu(select_species, title='Select a Species') - selection = m.show() - - characte_species = player_config["species"][select_species[selection]] - characte_species["name"] = select_species[selection] - - if not characte_species["fixed_type"]: - types = [ x["name"] for x in player_config["types"] ] - m = TerminalMenu(types, title='Select a Type') - selection = m.show() - - characte_type = (types[selection]) - else: - characte_type = characte_species["fixed_type"] - - return { - "name": characte_name, - "species": characte_species, - "type": characte_type - } - - def find_save_state(self): + def find_game_state(self): if os.path.exists(self.save_state_file['path']): - saved_state:SavedState = self.load_from_file(self.save_state_file) + self.saved_state = SavedState.load_from_file(self.save_state_file) else: - saved_state = SavedState() - player = self.create_character(self.config["player"], self.config["create_character_message"]) - saved_state.add_player(player) - self.save_to_file(saved_state, self.save_state_file) + self.saved_state = SavedState() + self.saved_state.add_player(CharacterCreater.create_character(self.config["player"], self.config["create_character_message"])) + self.saved_state.save_to_file(self.save_state_file) print() - self.map = self.load_from_file(self.map_file) - self.saved_state = saved_state - return saved_state + self.map = Map.load_from_file(self.map_file) + return self.saved_state - def load_from_file(self, file_options): - LOGGING.debug(f"Loading from file: {file_options}") - if os.path.exists(file_options["path"]): - with open(file_options["path"], "rb") as f: - data = my_pickle.load(f, file_options['compression'], None) - - LOGGING.debug(f"Loaded {data}") - return data - else: - raise FileNotFoundError(f"Could not load map file: {file_options['path']}") - - def save_to_file(self, obj, file_options): - LOGGING.debug(f"Saving Object {obj} To file: {file_options}") - os.makedirs(os.path.dirname(file_options["path"]), exist_ok=True) - with open(file_options["path"], "wb") as f: - my_pickle.dump(obj, f, file_options['compression'], None) - - def by_the_place(self): - is_by_a_place = self.saved_state.get_place() - LOGGING.debug(is_by_a_place) - if is_by_a_place: - return self.map[self.saved_state.get_chapter()]["Places"][is_by_a_place] - - return self.map[self.saved_state.get_chapter()]["World"][self.saved_state.get_story_moves()] + def save_game_state(self): + self.saved_state.save_to_file(self.save_state_file) def replace_keyword_into_place_story(self, place:dict): story:str = place['story'] @@ -121,6 +39,9 @@ class GameBoard: return story + def by_the_place(self): + return self.map.by_the_place(self.saved_state.get_place(), self.saved_state.get_chapter(), self.saved_state.get_story_moves()) + def user_input(self): while True: try: diff --git a/classes/Map.py b/classes/Map.py index 73c8dec..4c71b96 100644 --- a/classes/Map.py +++ b/classes/Map.py @@ -1,6 +1,9 @@ -from json import load as json_load -import os +import my_helpers.myPickle as my_pickle +from json import load as json_load +import logging, os + +LOGGING = logging.getLogger(__name__) class Map: def __init__(self, path): self.path = path @@ -20,3 +23,30 @@ class Map: def __getitem__(self, key): return self.story[key] + + @classmethod + def load_from_file(cls, file_options): + LOGGING.debug(f"Loading from file: {file_options}") + if os.path.exists(file_options["path"]): + with open(file_options["path"], "rb") as f: + data = my_pickle.load(f, file_options['compression'], None) + + new_class = cls(file_options["path"]) + new_class.__dict__.update(data.__dict__) + LOGGING.debug(f"Loaded {data}", {"loaded_data": new_class}) + return new_class + else: + raise FileNotFoundError(f"Could not load map file: {file_options['path']}") + + def save_to_file(self, file_options): + LOGGING.debug(f"Saving Object {self} To file: {file_options}") + os.makedirs(os.path.dirname(file_options["path"]), exist_ok=True) + with open(file_options["path"], "wb") as f: + my_pickle.dump(self, f, file_options['compression'], None) + + def by_the_place(self, is_by_a_place, chapter, moves): + LOGGING.debug(is_by_a_place) + if is_by_a_place: + return self[chapter]["Places"][is_by_a_place] + + return self[chapter]["World"][moves] diff --git a/classes/SavedState.py b/classes/SavedState.py index 0f9eefa..2e76add 100644 --- a/classes/SavedState.py +++ b/classes/SavedState.py @@ -1,9 +1,10 @@ -import logging - -from classes.Player import Player +import my_helpers.myPickle as my_pickle +from classes.Character.Player import Player from classes.MapObject.Home import Home +import logging, os + LOGGING = logging.getLogger(__name__) class SavedState: def __init__(self, story_position:str="The Beginning"): @@ -16,7 +17,7 @@ class SavedState: } def add_player(self, player:dict): - self.player = Player(player["name"], player["type"], player["species"]) + self.player = Player(player["name"], player["type"], player["species"], player["combineble_species"]) def get_home(self): return self.home @@ -34,4 +35,27 @@ class SavedState: return self.story["place"] def __str__(self): - return f"{self.__class__.__name__} | Home: {self.home}\nStory: {self.story}" \ No newline at end of file + return f"{self.__class__.__name__} | Home: {self.home}\nStory: {self.story}\n\n{self.player}" + + def __repr__(self): + return str(vars(self)) + + @classmethod + def load_from_file(cls, file_options): + LOGGING.debug(f"Loading from file: {file_options}") + if os.path.exists(file_options["path"]): + with open(file_options["path"], "rb") as f: + data = my_pickle.load(f, file_options['compression'], None) + + new_class = cls() + new_class.__dict__.update(data) + LOGGING.debug(f"Loaded {data}", {"loaded_data": new_class}) + return new_class + else: + raise FileNotFoundError(f"Could not load map file: {file_options['path']}") + + def save_to_file(self, file_options): + LOGGING.debug(f"Saving Object {self.__dict__} To file: {file_options}") + os.makedirs(os.path.dirname(file_options["path"]), exist_ok=True) + with open(file_options["path"], "wb") as f: + my_pickle.dump(self.__dict__, f, file_options['compression'], None) diff --git a/config.json b/config.json index 5620afb..9e98332 100644 --- a/config.json +++ b/config.json @@ -11,7 +11,7 @@ }, "logging": { - "enabled": false, + "enabled": true, "file": { "path": "./GameData/log", "name": "debug.log" @@ -26,7 +26,8 @@ "speed": 7, "defense": 3, "inventory_size": 3, - "fixed_type": false + "fixed_type": false, + "combineble": false }, "Dragon": { "hp": 100, @@ -34,7 +35,8 @@ "speed": 15, "defense": 10, "inventory_size": 5, - "fixed_type": "Magician" + "fixed_type": "Magician", + "combineble": false }, "Gnoll": { "hp": 100, @@ -42,7 +44,8 @@ "speed": 5, "defense": 6, "inventory_size": 10, - "fixed_type": "Warrior" + "fixed_type": "Warrior", + "combineble": false }, "Elf": { "hp": 100, @@ -50,7 +53,8 @@ "defense": 3, "speed": 8, "inventory_size": 3, - "fixed_type": false + "fixed_type": false, + "combineble": false }, "Wolf": { "hp": 100, @@ -58,7 +62,8 @@ "speed": 6, "defense": 6, "inventory_size": 4, - "fixed_type": false + "fixed_type": false, + "combineble": false }, "Fox": { "hp": 100, @@ -66,7 +71,17 @@ "speed": 7, "defense": 6, "inventory_size": 4, - "fixed_type": false + "fixed_type": false, + "combineble": false + }, + "Inflatable": { + "hp": 100, + "strength": 2, + "speed": 10, + "defense": 1, + "inventory_size": 0, + "fixed_type": "Magician", + "combineble": true } }, "types": [ diff --git a/run.py b/run.py index ea07484..5fbad7b 100644 --- a/run.py +++ b/run.py @@ -24,7 +24,8 @@ if __name__ == '__main__': } game_board = GameBoard(CONFIG, SAVE_STATE_FILE, MAP_FILE) - game_board.find_save_state() + game_board.find_game_state() game_board.user_input() - game_board.save_to_file(game_board.saved_state, game_board.save_state_file) + print(game_board.saved_state) + game_board.save_game_state()