Return to repo list

tzed

Simple story-driven open world 2D CRPG.
Return to HMagellan.com

commit 880d306185bff6e96dbc287098387a558db26800
parent 7295f3e9545ab9790e36db202a9a8178b2759e85
Author: Erik Letson <hmagellan@hmagellan.com>
Date:   Fri, 10 Sep 2021 05:40:36 -0500

dungeons work

Diffstat:
Mdata/boards/testloc1/entities.json | 15+++++++++++++++
Mdata/etc/dungeons.json | 2+-
Mdata/etc/sheets.json | 2+-
Mdata/images/dungeon1_fc.png | 0
Mmain.py | 2++
Msrc/board.py | 3+++
Msrc/dungeon.py | 16+++++++++++++---
Msrc/game.py | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msrc/interface.py | 9++++++---
9 files changed, 102 insertions(+), 24 deletions(-)

diff --git a/data/boards/testloc1/entities.json b/data/boards/testloc1/entities.json @@ -15,6 +15,21 @@ } }, { + "type" : "overlay", + "cell" : [0, 1], + "tile" : [0, 1], + "data" : { + "sprite" : [2, 0], + "event" : { + "type" : "enterdungeon", + "dungeon" : "testdun1", + "direction" : 0, + "floor" : 0, + "cell" : [0, 0] + } + } + }, + { "type" : "npc", "cell" : [1, 1], "tile" : [0, 0], diff --git a/data/etc/dungeons.json b/data/etc/dungeons.json @@ -1,5 +1,5 @@ { "dungeons" : [ - "testdungeon1" + "testdun1" ] } diff --git a/data/etc/sheets.json b/data/etc/sheets.json @@ -12,7 +12,7 @@ "ovrly32" : [32, 32, false], "ovrly64" : [64, 64, false], "ui_tray" : [1024, 768, false], - "dungeon1_fc" : [700, 165, false], + "dungeon1_fc" : [682, 165, false], "dungeon1_w" : [220, 512, false], "dungeon1_h" : [242, 182, false] } diff --git a/data/images/dungeon1_fc.png b/data/images/dungeon1_fc.png Binary files differ. diff --git a/main.py b/main.py @@ -24,6 +24,8 @@ from src import game # generated only once owing to a special "npc_id" int in the entities.json "data" field. This is not good at all. There should be a way for the board # to know that it is generating a StaticEntity for the first time, and to add it to holdovers in that case and not generate again in the future if it # is of the correct type(s) (e.g. NPCs). +# 3. There should be one or more custom error classes raised by the various game object methods that currently do something like return 1. There should +# probably also be a whole logging feature built in. Also also a test suite. ########### # main.py # diff --git a/src/board.py b/src/board.py @@ -218,6 +218,9 @@ class Board(object): if event["type"] == "changeboard": self.game.switch_board(event["board"], tuple(event["cell"])) self.game.spawn_player(self.game.party[self.game.player_name], tuple(event["cell"]), tuple(event["tile"])) + elif event["type"] == "enterdungeon": + self.game.switch_mode(STATE_MODES.Dungeon_Mode) + self.game.switch_dungeon(event["dungeon"], event["direction"], event["floor"], tuple(event["cell"])) def execute_npc_turns(self, time): """ diff --git a/src/dungeon.py b/src/dungeon.py @@ -33,11 +33,21 @@ class Dungeon(object): # Other vals self.direction = 0 - self.current_cell = (0, 0) self.current_floor = 0 + self.current_cell = (0, 0) # Graphics self.dungeon_view = pygame.sprite.Group() + + def enter_dungeon(self, direction, floor, cell): + """ + Start off the dungeon in a particular place, + facing a given direction. Also refreshes the + view. + """ + self.direction = direction + self.current_floor = floor + self.current_cell = cell self.construct_dungeon_view() def move_forward(self): @@ -77,7 +87,7 @@ class Dungeon(object): self.dungeon_view.add(DungeonSprite(self.game.sheets[self.sheetname + "_fc"].sprites[tuple(workcell["floor"])], (self.game.viewport_rect.topleft[0], self.game.viewport_rect.topleft[1] + 347))) self.dungeon_view.add(DungeonSprite(self.game.sheets[self.sheetname + "_h"].sprites[tuple(workcell["horizon"])], (self.game.viewport_rect.center[0] - 121, self.game.viewport_rect.center[1] - 91))) - def update(self, surface = None): + def update_dungeon(self, surface = None): """ Update the dungeon logic and visuals. """ @@ -99,7 +109,7 @@ class DungeonSprite(pygame.sprite.Sprite): pygame.sprite.Sprite.__init__(self) # Saved values - self.imgage = image + self.image = image self.rect = self.image.get_rect() self.rect.topleft = pos diff --git a/src/game.py b/src/game.py @@ -88,6 +88,7 @@ class Game(object): # Loading self.load_sheets("sheets.json") self.load_boards("boards.json") + self.load_dungeons("dungeons.json") self.build_ui() # TMP! @@ -132,10 +133,10 @@ class Game(object): dungeonlist = json.load(df) # Create dungeons and add to loaded dungeons - for d in dungeonlist: + for d in dungeonlist["dungeons"]: with open(os.path.join(DUNGEON_PATH, d, "dungeon.json")) as dj: dungeondef = json.load(dj) - nd = dungeon.Dungeon(self, d, dungeondef["display_name"], dungeondef["width"], dungeondef["height"], dungeondef["sheetname"], tuple(dungeondef["entrance"]), dungeondef["layout"]) + nd = dungeon.Dungeon(self, d, dungeondef["display_name"], dungeondef["width"], dungeondef["height"], dungeondef["sheet"], tuple(dungeondef["entrance"]), dungeondef["layout"]) self.loaded_dungeons[d] = nd def build_ui(self): @@ -163,6 +164,20 @@ class Game(object): else: return 1 + def switch_dungeon(self, dungeonname, direction = 0, floor = 0, cell = (0, 0)): + """ + Switch to the given dungeon and go + to the given floor, facing the given + direction, and in the given cell. + """ + if dungeonname in self.loaded_dungeons.keys(): + self.current_dungeon = self.loaded_dungeons[dungeonname] + self.current_dungeon.enter_dungeon(direction, floor, cell) + self.collect_game_data() + self.message_board.post("$PLAYERNAME enters $CURRENTDUNGEONNAME.", self.gamedata) + else: + return 1 + def spawn_player(self, playerchar, cellpos, tilepos): """ Spawn the player in the current board at @@ -275,7 +290,7 @@ class Game(object): self.days -= self.months * 39 # Then, if take_turn is true, take a turn for the other entities. - if take_turn: + if self.state_mode in OVERHEAD_MODES and take_turn: self.current_board.get_playerpos() self.current_board.execute_npc_turns(time_mod) @@ -389,19 +404,40 @@ class Game(object): """ # TODO: This will see regular expansion self.gamedata["$PLAYERNAME"] = self.player_name - self.gamedata["$CURRENTBOARDNAME"] = self.current_board.display_name + self.gamedata["$CURRENTBOARDNAME"] = self.current_board.display_name if self.current_board != None else "!NOWHERE!" + self.gamedata["$CURRENTDUNGEONNAME"] = self.current_dungeon.display_name if self.current_dungeon != None else "!NODUNGEON!" def save_game(self, savename): """ Save the current game state as a JSON file. """ + # First, determine what kind of location data we need to save + if self.state_mode in OVERHEAD_MODES: + at = { + "type" : "location", + "data" : { + "board" : self.current_board.name, + "cell" : self.player.cellpos, + "tile" : self.player.tilepos, + } + } + elif self.state_mode == STATE_MODES.Dungeon_Mode: + at = { + "type" : "dungeon", + "data" : { + "dungeon" : self.current_dungeon.name, + "direction" : self.current_dungeon.direction, + "floor" : self.current_dungeon.current_floor, + "cell" : self.current_dungeon.current_cell, + } + } + + # Then, construct the savestate and write it to a json savestate = { "story" : self.active_story, "player" : self.player_name, "gametime" : self.gametime, - "board" : self.current_board.name, - "cell" : self.player.cellpos, - "tile" : self.player.tilepos, + "at" : at, "party" : self.party, "flags" : self.prog_flags } @@ -411,19 +447,25 @@ class Game(object): """ Load a save from JSON. """ + # Open the json and apply universal values if os.path.exists(os.path.join(SAVE_PATH, savename + ".json")): with open(os.path.join(SAVE_PATH, savename + ".json")) as lj: saveraw = json.load(lj) self.active_scenario = saveraw["scenario"] self.player_name = saveraw["player"] self.party = saveraw["party"] - self.switch_board(saveraw["board"], tuple(saveraw["cell"])) - self.spawn_player(saveraw["party"][saveraw["player"]], tuple(saveraw["cell"]), tuple(saveraw["tile"])) - # Switch to game control - # TODO: Saves will eventually take note of what mode they were saved in - self.switch_mode(STATE_MODES.Overworld_Mode) - self.pass_time(saveraw["gametime"], False) + # Load a board + if saveraw["at"]["type"] == "location": + self.switch_board(saveraw["at"]["data"]["board"], tuple(saveraw["at"]["data"]["cell"])) + self.spawn_player(saveraw["party"][saveraw["player"]], tuple(saveraw["at"]["data"]["cell"]), tuple(saveraw["at"]["data"]["tile"])) + self.switch_mode(STATE_MODES.Overworld_Mode) + + # Load a dungeon + elif saveraw["at"]["type"] == "dungeon": + self.switch_dungeon(saveraw["at"]["data"]["dungeon"], saveraw["at"]["data"]["direction"], saveraw["at"]["data"]["floor"], tuple(saveraw["at"]["data"]["cell"])) + # Pass time up + self.pass_time(saveraw["gametime"], False) else: return 1 @@ -448,9 +490,12 @@ class Game(object): # Next, update and draw objects self.screen.blit(self.viewport, self.viewport_rect) - self.current_board.update_board(self.screen, self.viewport_rect) - if self.player != None: - self.player.update(self.screen, self.viewport_rect) + if self.state_mode in OVERHEAD_MODES: + self.current_board.update_board(self.screen, self.viewport_rect) + if self.player != None: + self.player.update(self.screen, self.viewport_rect) + elif self.state_mode == STATE_MODES.Dungeon_Mode: + self.current_dungeon.update_dungeon(self.screen) self.ui_group.update(self.screen) self.message_board.update_message_board(self.screen) self.update_dynamic_ui(self.screen) diff --git a/src/interface.py b/src/interface.py @@ -80,9 +80,10 @@ class Interface(object): if k in CONTROLS["up"]: if self.game.state_mode in OVERHEAD_MODES: self.game.move_player_on_board((0, -1)) - elif self.game.stat_mode == STATE_MODES.Dungeon_Mode: + elif self.game.state_mode == STATE_MODES.Dungeon_Mode: if self.game.current_dungeon != None: self.game.current_dungeon.move_forward() + self.game.pass_time() for j in CONTROLS["up"]: self.key_bools[j] = False return @@ -95,18 +96,20 @@ class Interface(object): elif k in CONTROLS["left"]: if self.game.state_mode in OVERHEAD_MODES: self.game.move_player_on_board((-1, 0)) - elif self.game.stat_mode == STATE_MODES.Dungeon_Mode: + elif self.game.state_mode == STATE_MODES.Dungeon_Mode: if self.game.current_dungeon != None: self.game.current_dungeon.rotate_direction(-1) + self.game.pass_time() for j in CONTROLS["left"]: self.key_bools[j] = False return elif k in CONTROLS["right"]: if self.game.state_mode in OVERHEAD_MODES: self.game.move_player_on_board((1, 0)) - elif self.game.stat_mode == STATE_MODES.Dungeon_Mode: + elif self.game.state_mode == STATE_MODES.Dungeon_Mode: if self.game.current_dungeon != None: self.game.current_dungeon.rotate_direction() + self.game.pass_time() for j in CONTROLS["right"]: self.key_bools[j] = False return