From f67eae3803f0936f58996e1da94a4b1206eae2f0 Mon Sep 17 00:00:00 2001 From: eichhornchen Date: Mon, 16 Nov 2020 01:01:18 +0100 Subject: [PATCH] Added functionnal save system and broken load system --- dungeonbattle/__init__.pyc | Bin 0 -> 176 bytes dungeonbattle/bootstrap.pyc | Bin 0 -> 1075 bytes dungeonbattle/entities/monsters.py | 11 ++++ dungeonbattle/game.py | 58 ++++++++++++++++++--- dungeonbattle/interfaces.py | 79 ++++++++++++++++++++++++++++- dungeonbattle/menus.py | 19 +------ resources/example_map_3.txt | 45 ++++++++++++++++ save.json | 1 + test.py | 17 +++++++ 9 files changed, 204 insertions(+), 26 deletions(-) create mode 100644 dungeonbattle/__init__.pyc create mode 100644 dungeonbattle/bootstrap.pyc create mode 100644 resources/example_map_3.txt create mode 100644 save.json create mode 100644 test.py diff --git a/dungeonbattle/__init__.pyc b/dungeonbattle/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c5124407892592c0feed40fde1506c5cf0dcda29 GIT binary patch literal 176 zcmZSn%**w~e`$O&0~9az*Q}arS^?eQX3ySiyQcL24U7;-fl+wKP)cic%q{NbvoKzSW%8QTB f%*!l^kJl@xEa3o}Zj+mzQks)$2XaFR5HkP(Lkld_ literal 0 HcmV?d00001 diff --git a/dungeonbattle/bootstrap.pyc b/dungeonbattle/bootstrap.pyc new file mode 100644 index 0000000000000000000000000000000000000000..80c152bc030ab5343a9311a65911f7db09afefab GIT binary patch literal 1075 zcmcgqO^?$s5FI;d%9iq>l@Jnlq+Dpk9U%mZmdmb0inNf6l})TBRbp51RA{C4w1_Kb z{se!H9{@9U%7^y8X+4=Y@yB~_9R0jE`~LNZs$hH~dcUIKPASy%7tjIp0tx|wv4l=S zA3+fX96=XDKY?OGIEH!(^#r~ETmyV65~vecrgvzs_7^>=pbTRQr)94Lx=-k&b(^ld zIx9`N(nF}fnYdD{QU72lVCtk|SOK!`7ty z#yJOaO7+1%Z!jN%taV(PQVKq}g0if!z0P!7HH{ri)o7EQ*lODo6PKMm&o+ZyYgEg( zW0uuhv(nZ)yDSkqeSjmnJoII;x$-iJo0rLw9rFV@7e`_yj>TN0F=0PVDMK`s!WmVR z>TSIx{mLtHSYlg|h{o1AZ}C^bZOF*kTHhaTU?R`M@$4ubQyBdS1}uC_sS5b?#<#Hn ni$f2`E`=NL None: + super().__init__() + def act(self, m: Map) -> None: """ By default, a monster will move randomly where it is possible @@ -35,24 +38,32 @@ class Monster(FightingEntity): class Beaver(Monster): + def __init__(self) -> None: + super().__init__() name = "beaver" maxhealth = 30 strength = 2 class Hedgehog(Monster): + def __init__(self) -> None: + super().__init__() name = "hedgehog" maxhealth = 10 strength = 3 class Rabbit(Monster): + def __init__(self) -> None: + super().__init__() name = "rabbit" maxhealth = 15 strength = 1 class TeddyBear(Monster): + def __init__(self) -> None: + super().__init__() name = "teddy_bear" maxhealth = 50 strength = 0 diff --git a/dungeonbattle/game.py b/dungeonbattle/game.py index 39e7b48..e050e50 100644 --- a/dungeonbattle/game.py +++ b/dungeonbattle/game.py @@ -1,5 +1,7 @@ from random import randint -from typing import Any, Optional +from typing import Any, Optional,Generator +import json +import os from .entities.player import Player from .enums import GameMode, KeyValues, DisplayActions @@ -37,11 +39,6 @@ class Game: self.player.move(self.map.start_y, self.map.start_x) self.map.spawn_random_entities(randint(3, 10)) - @staticmethod - def load_game(filename: str) -> None: - # TODO loading map from a file - raise NotImplementedError() - def run(self, screen: Any) -> None: """ Main infinite loop. @@ -65,7 +62,7 @@ class Game: if self.state == GameMode.PLAY: self.handle_key_pressed_play(key) elif self.state == GameMode.MAINMENU: - self.main_menu.handle_key_pressed(key, self) + self.handle_key_pressed_main_menu(key) elif self.state == GameMode.SETTINGS: self.settings_menu.handle_key_pressed(key, raw_key, self) self.display_actions(DisplayActions.REFRESH) @@ -88,3 +85,50 @@ class Game: self.map.tick() elif key == KeyValues.SPACE: self.state = GameMode.MAINMENU + + def handle_key_pressed_main_menu(self, key: KeyValues) -> None: + """ + In the main menu, we can navigate through options. + """ + if key == KeyValues.DOWN: + self.main_menu.go_down() + if key == KeyValues.UP: + self.main_menu.go_up() + if key == KeyValues.ENTER: + option = self.main_menu.validate() + if option == menus.MainMenuValues.START: + self.state = GameMode.PLAY + elif option == menus.MainMenuValues.SAVE: + self.save_game() + elif option == menus.MainMenuValues.LOAD: + self.load_game() + elif option == menus.MainMenuValues.SETTINGS: + self.state = GameMode.SETTINGS + elif option == menus.MainMenuValues.EXIT: + sys.exit(0) + + def game_to_str(self) -> str: + d = dict() + d["Map"] = game.map + d["Player"] = game.player + + def save_state(self) -> dict(): + return self.map.save_state() + + def load_state(self, d: dict) -> None: + self.map.load_state(d) + + def load_game(self) -> None: + """ + Loads the game from a file + """ + if os.path.isfile("save.json"): + with open("save.json", "r") as f: + self.load_state(json.loads(f.read())) + + def save_game(self) -> None: + """ + Save the game to a file + """ + with open("save.json", "w") as f: + f.write(json.dumps(self.save_state())) diff --git a/dungeonbattle/interfaces.py b/dungeonbattle/interfaces.py index b057400..7a8ae8b 100644 --- a/dungeonbattle/interfaces.py +++ b/dungeonbattle/interfaces.py @@ -78,6 +78,17 @@ class Map: return Map(width, height, tiles, start_y, start_x) + @staticmethod + def load_dungeon_from_string(content: str) -> "Map": + """ + Transforms a string into the list of corresponding tiles + """ + lines = content.split("\n") + lines = [line for line in lines[1:] if line] + tiles = [[Tile.from_ascii_char(c) + for x, c in enumerate(line)] for y, line in enumerate(lines)] + return tiles + def draw_string(self, pack: TexturePack) -> str: """ Draw the current map as a string object that can be rendered @@ -108,14 +119,39 @@ class Map: for entity in self.entities: entity.act(self) + def save_state(self) -> dict: + d = dict() + d["width"] = self.width + d["height"] = self.height + d["start_y"] = self.start_y + d["start_x"] = self.start_x + d["currentx"] = self.currentx + d["currenty"] = self.currenty + for enti in self.entities: + d.update(enti.save_state()) + d["map"] = self.draw_string(TexturePack.ASCII_PACK) + return d + + def load_state(self, d: dict) -> None: + self.width = d["width"] + self.height = d["height"] + self.start_y = d["start_y"] + self.start_x = d["start_x"] + self.currentx = d["currentx"] + self.currenty = d["currenty"] + self.map = self.load_dungeon_from_string(d["map"]) + #add entities class Tile(Enum): EMPTY = auto() WALL = auto() FLOOR = auto() - @classmethod - def from_ascii_char(cls, ch: str) -> "Tile": + @staticmethod + def from_ascii_char(ch: str) -> "Tile": + """ + Maps an ascii character to its equivalent in the texture pack + """ for tile in Tile: if tile.char(TexturePack.ASCII_PACK) == ch: return tile @@ -206,6 +242,22 @@ class Entity: Rabbit, TeddyBear return [Beaver, Bomb, Heart, Hedgehog, Rabbit, TeddyBear] + def save_state(self) -> dict: + """ + Saves the coordinates of the entity + """ + d = dict() + d["x"] = self.x + d["y"] = self.y + return d + + def recover_state(self, d : dict) -> None: + """ + Loads the coordinates of the entity from a dictionnary + """ + self.x = d["x"] + self.y = d["y"] + class FightingEntity(Entity): maxhealth: int @@ -222,6 +274,15 @@ class FightingEntity(Entity): super().__init__() self.health = self.maxhealth self.dead = False + self.health = 0 + self.strength = 0 + self.dead = False + self.intelligence = 0 + self.charisma = 0 + self.dexterity = 0 + self.constitution = 0 + self.level = 1 + def hit(self, opponent: "FightingEntity") -> None: opponent.take_damage(self, self.strength) @@ -234,3 +295,17 @@ class FightingEntity(Entity): def die(self) -> None: self.dead = True self.map.remove_entity(self) + + def keys(self) -> list: + return ["maxhealth", "health", "level", "dead", "strength", "intelligence", "charisma", "dexterity", "constitution"] + + def save_state(self) -> dict: + d = super().save_state() + for name in self.keys(): + d[name] = self.__getattribute__(name) + return d + + def recover_state(self, d : dict) -> None: + super().recover_state(d) + for name in d.keys(): + self.__setattribute__(name, d[name]) diff --git a/dungeonbattle/menus.py b/dungeonbattle/menus.py index 1990b27..e543731 100644 --- a/dungeonbattle/menus.py +++ b/dungeonbattle/menus.py @@ -25,6 +25,8 @@ class Menu: class MainMenuValues(Enum): START = 'Jouer' + SAVE = 'Sauvegarder' + LOAD = 'Charger' SETTINGS = 'Paramètres' EXIT = 'Quitter' @@ -35,23 +37,6 @@ class MainMenuValues(Enum): class MainMenu(Menu): values = [e for e in MainMenuValues] - def handle_key_pressed(self, key: KeyValues, game: Any) -> None: - """ - In the main menu, we can navigate through options. - """ - if key == KeyValues.DOWN: - self.go_down() - if key == KeyValues.UP: - self.go_up() - if key == KeyValues.ENTER: - option = self.validate() - if option == MainMenuValues.START: - game.state = GameMode.PLAY - elif option == MainMenuValues.SETTINGS: - game.state = GameMode.SETTINGS - elif option == MainMenuValues.EXIT: - sys.exit(0) - class SettingsMenu(Menu): waiting_for_key: bool = False diff --git a/resources/example_map_3.txt b/resources/example_map_3.txt new file mode 100644 index 0000000..5a3ae82 --- /dev/null +++ b/resources/example_map_3.txt @@ -0,0 +1,45 @@ +1 1 +############################################################################################################## +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +#............................................................................................................# +############################################################################################################## diff --git a/save.json b/save.json new file mode 100644 index 0000000..0cdcad5 --- /dev/null +++ b/save.json @@ -0,0 +1 @@ +{"width": 80, "height": 40, "start_y": 1, "start_x": 17, "currentx": 29, "currenty": 25, "x": 74, "y": 22, "maxhealth": 50, "health": 0, "level": 1, "dead": false, "strength": 0, "intelligence": 0, "charisma": 0, "dexterity": 0, "constitution": 0, "map": " ########### ######### \n #.........# #.......# \n #.........# ############.......# \n #.........###############..........#.......############## \n #.........#........................#....................# \n #.........#.............#..........#.......#............# \n ########.########.............#..................#............# \n #.........# #.............####.#######.......#............# \n #.........# #.............##.........###################### \n #.........# #####.##########.........# ########### \n #.........# #......# #.........# #.........# \n ########.##########......# #.........# #.........# \n #...........##......# #.........# #.........# \n #...........##......# #.........# #.........# \n #...........##......# #.........# ################.###### \n #...........##......# #.........# #.................############\n #...........##......# ########.########.......#.........#..........#\n #...........##......# #...............#.......#.........#..........#\n #...........######### #...............#.......#.........#..........#\n #...........# #...............#.......#....................#\n #####.####### #.......................#.........#..........#\n #.........# #...............###################..........#\n #.........############ #...............# #..........#\n #.........#..........# #...............# ############\n #....................#####.###########.############# \n ########.#########...................# #.............# \n #........# #..........#........# #.............######### \n #........# ######.##########........# #.............#.......# \n #........# #..........# #........# #.....................# \n #........# #..........# #........# #.............#.......# \n #........# #..........# #........# #.............#.......# \n #........# #..........# #........# #.............#.......# \n #........# #..........#########.##### #.............#.......# \n #........# #..........#.........# ##########.############.####### \n #........# #..........#.........# #..............# #..........# \n ########## #..........#.........# #..............# #..........# \n ############.........# #..............# #..........# \n #.........# #..............# #..........# \n ########### #..............# #..........# \n ################ ############ "} \ No newline at end of file diff --git a/test.py b/test.py new file mode 100644 index 0000000..2129a8d --- /dev/null +++ b/test.py @@ -0,0 +1,17 @@ +import json + +class hi: + PLOP = "hello" + PPPP = "ghjk" + + def __init__(self): + self.bl = "zrfcv" + + def prin(self) : + return json.dumps(self.__dict__) + +def f() : + d = hi() + print(d.prin()) + +f()