Added functionnal save system and broken load system
This commit is contained in:
		
				
					committed by
					
						
						Yohann D'ANELLO
					
				
			
			
				
	
			
			
			
						parent
						
							d95747159f
						
					
				
				
					commit
					41d1696c9b
				
			
							
								
								
									
										
											BIN
										
									
								
								dungeonbattle/__init__.pyc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dungeonbattle/__init__.pyc
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								dungeonbattle/bootstrap.pyc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dungeonbattle/bootstrap.pyc
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -5,6 +5,9 @@ from ..interfaces import FightingEntity, Map
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Monster(FightingEntity):
 | 
			
		||||
    def __init__(self) -> 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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
@@ -38,11 +40,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.
 | 
			
		||||
@@ -66,7 +63,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)
 | 
			
		||||
@@ -89,3 +86,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()))
 | 
			
		||||
 
 | 
			
		||||
@@ -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])
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user