commit cceaaaa865a8e243c1d12c46e4121c4e063f9cc9
parent bed90a4b9717102f5a9d383502e06ddf788ffa24
Author: Erik Letson <hmagellan@hmagellan.com>
Date: Fri, 13 Nov 2020 21:42:57 -0600
Initial, non-working version of turn display
Diffstat:
13 files changed, 155 insertions(+), 26 deletions(-)
diff --git a/data/board/testmap1/testmap1.json b/data/board/testmap1/testmap1.json
@@ -4,6 +4,7 @@
"type" : "Piece",
"sheet" : "jisella_1",
"sprite" : [0, 0],
+ "pictures" : "jisella_pictures_1",
"visible" : true,
"animation" : "stand_L",
"animated" : true,
@@ -61,6 +62,7 @@
"type" : "Piece",
"sheet" : "jisella_2",
"sprite" : [0, 0],
+ "pictures" : "jisella_pictures_2",
"visible" : true,
"animation" : "stand_R",
"animated" : true,
@@ -118,6 +120,7 @@
"type" : "Piece",
"sheet" : "jisella_4",
"sprite" : [0, 0],
+ "pictures" : "jisella_pictures_4",
"visible" : true,
"animation" : "stand_R",
"animated" : true,
@@ -175,6 +178,7 @@
"type" : "Piece",
"sheet" : "jisella_3",
"sprite" : [0, 0],
+ "pictures" : "jisella_pictures_3",
"visible" : true,
"animation" : "stand_R",
"animated" : true,
diff --git a/data/img/pictures/jisella_1/icons_small.png b/data/img/pictures/jisella_1/icons_small.png
Binary files differ.
diff --git a/data/img/pictures/jisella_2/icons_small.png b/data/img/pictures/jisella_2/icons_small.png
Binary files differ.
diff --git a/data/img/pictures/jisella_3/icons_small.png b/data/img/pictures/jisella_3/icons_small.png
Binary files differ.
diff --git a/data/img/pictures/jisella_4/icons_small.png b/data/img/pictures/jisella_4/icons_small.png
Binary files differ.
diff --git a/data/img/turn_icon_holder_1.png b/data/img/turn_icon_holder_1.png
Binary files differ.
diff --git a/data/json/sheets.json b/data/json/sheets.json
@@ -54,6 +54,26 @@
"dimensions" : [64, 64],
"total_sprites" : 72
},
+ "jisella_pictures_1_icons_small" : {
+ "filename" : "pictures/jisella_1/icons_small.png",
+ "dimensions" : [24, 24],
+ "total_sprites" : 2
+ },
+ "jisella_pictures_2_icons_small" : {
+ "filename" : "pictures/jisella_2/icons_small.png",
+ "dimensions" : [24, 24],
+ "total_sprites" : 2
+ },
+ "jisella_pictures_3_icons_small" : {
+ "filename" : "pictures/jisella_3/icons_small.png",
+ "dimensions" : [24, 24],
+ "total_sprites" : 2
+ },
+ "jisella_pictures_4_icons_small" : {
+ "filename" : "pictures/jisella_4/icons_small.png",
+ "dimensions" : [24, 24],
+ "total_sprites" : 2
+ },
"cursor1" : {
"filename" : "cursor1.png",
"dimensions" : [64, 64],
@@ -63,5 +83,15 @@
"filename" : "board_overlays_1.png",
"dimensions" : [64, 64],
"total_sprites" : 4
- }
+ },
+ "turn_order_tray_1" : {
+ "filename" : "turn_order_tray_1.png",
+ "dimensions" : [135, 128],
+ "total_sprites" : 1
+ },
+ "turn_icon_holder_1" : {
+ "filename" : "turn_icon_holder_1.png",
+ "dimensions" : [128, 28],
+ "total_sprites" : 1
+ }
}
diff --git a/main.py b/main.py
@@ -2,15 +2,22 @@ import pygame
from src import game
## GLOBAL TODO:
-# 2. The JSON loading methods are all over the place. Need to decide about whether or not things like units should be defined in individual JSONs and
-# referenced by a big meta JSON or if there should just be many individual JSONs for that. One problem with it is that when saving is implemented
-# there will have to be a way to distinguish between the basic versions of a unit and the ones that are leveled up. Maybe JSONs are not the correct
-# choice altogether. Perhaps there should be one huge save.json file for all changes. If that is so, then there could be several JSONs in the dir
-# located at data/json that are loaded first, then the save.json file is parsed by a save-load subsystem and any changes are applied, at which point
-# the game would be in a loaded state. This seems the ideal solution, and it can be put off a bit.
-# 3. Implement the "draw()" functionality of DirtySprite for all VGOs, which will be done in anything that manages a LayeredDirty group, e.g. in the
-# EntityManager object.
-# 6. Implement the pre-rendered cutscene playing methodology using Pyglet as described here: http://www.sbirch.net/tidbits/pygame_video.html
+# 2. The JSON loading methods are all over the place. Need to decide about whether or not things like units should be defined in individual JSONs and
+# referenced by a big meta JSON or if there should just be many individual JSONs for that. One problem with it is that when saving is implemented
+# there will have to be a way to distinguish between the basic versions of a unit and the ones that are leveled up. Maybe JSONs are not the correct
+# choice altogether. Perhaps there should be one huge save.json file for all changes. If that is so, then there could be several JSONs in the dir
+# located at data/json that are loaded first, then the save.json file is parsed by a save-load subsystem and any changes are applied, at which point
+# the game would be in a loaded state. This seems the ideal solution, and it can be put off a bit.
+# 3. Implement the "draw()" functionality of DirtySprite for all VGOs, which will be done in anything that manages a LayeredDirty group, e.g. in the
+# EntityManager object.
+# 6. Implement the pre-rendered cutscene playing methodology using Pyglet as described here: http://www.sbirch.net/tidbits/pygame_video.html
+# 7. ALL character-related art could go in the 'data/img/pictures' directory, and it could have common names (all icons called icon.png, all
+# in-battle spritesheets called battle_sprites.png, etc.) The sheet/piece/other manager(s) could be made to search these dirs instead of
+# looking for single specific files. This would greatly simplify animation. Animations could simply be made to match one of these common file
+# names, and thus only a fraction of the animations would have to be loaded, and it would simplify fetch calls too (desirable since fetch calls
+# for sheets and animations are looking like they will be very common). The 'pictures' directory should maybe be renamed to 'chars' or something.
+# Scene character art could also be stored in this dir, but scene def JSONs will still just point to specific files (already should support
+# subdir pathing at this point since it is loaded with os.join).
# Initialization of pygame and submodules
pygame.mixer.pre_init(44100, -16, 4, 1024)
diff --git a/src/camera.py b/src/camera.py
@@ -64,6 +64,19 @@ class GameCamera(subsystem.GameSubsystem):
changey = rel_offset[1] * speed_multiple
self.camera_surface_offset = (self.camera_surface_offset[0] + changex, self.camera_surface_offset[1] + changey)
+ def lock_to_position(self, position):
+ """
+ Lock the camera to a position, relative
+ to the screen. The given position should
+ be coordinates on the camera surface, and
+ this method will compute that to produce
+ an offset such that the camera surface
+ appears centered to that position in
+ relation to the game screen.
+ """
+ # TODO: Work here
+ self.camera_surface_offset = position
+
def update_camera(self, surface = None):
"""
Update and draw the camera contents.
diff --git a/src/constants.py b/src/constants.py
@@ -27,6 +27,7 @@ COLORKEY = (255, 0, 255)
PIECE_MOVE_SPEED = 2
PIECE_MOVE_DELAY = PIECE_MOVE_SPEED * 4
SCROLL_SPEED = 4
+UI_FONT = "ArchivoNarrow-Regular.otf"
# File paths
DATA_PATH = os.path.join(os.getcwd(), "data")
diff --git a/src/game.py b/src/game.py
@@ -136,18 +136,18 @@ class Game(object):
self.interface.update_interface()
# State_Mode-specific actions (can be further subdivided by Control_Mode)
+ # Camera draw occurs in all these modes
if self.state_mode == STATE_MODES.Main_Menu_Mode:
self.menu_manager.update(self.camera.camera_surface)
+ self.camera.update_camera(self.screen)
elif self.state_mode == STATE_MODES.Battle_Mode:
self.board_manager.update(self.camera.camera_surface)
self.piece_manager.update(self.camera.camera_surface)
- self.turn_manager.update(self.camera.camera_surface)
+ self.camera.update_camera(self.screen)
+ self.turn_manager.update(self.screen) # Draw to the screen since it manages UI elements
elif self.state_mode == STATE_MODES.Still_Scene_Mode:
self.scene_manager.update(self.camera.camera_surface)
-
- # Draw the camera to the screen
- #self.screen.blit(self.camera.camera_surface, self.camera.camera_surface_offset)
- self.camera.update_camera(self.screen)
+ self.camera.update_camera(self.screen)
# State_Mode agnostic, Control_Mode specific actions
if self.control_mode == CTRL_MODES.No_Control:
diff --git a/src/piece.py b/src/piece.py
@@ -57,12 +57,13 @@ class PieceManager(manager.Manager):
n_anim = self.bus.fetch("sheet_manager", "animations")[definition[p]["sheet"]][definition[p]["animation"]]
n_animated = definition[p]["animated"]
n_name = definition[p]["name"]
+ n_pictures = definition[p]["pictures"]
n_passable = definition[p]["passable"]
n_nstats = definition[p]["normal_stats"]
n_astats = definition[p]["active_stats"]
n_team = definition[p]["team"]
n_equip = definition[p]["equipment"]
- np = Piece(n_sheet, n_sprite, n_anim, n_animated, self, n_name, n_passable, n_nstats, n_astats, n_team, n_equip)
+ np = Piece(n_sheet, n_sprite, n_anim, n_animated, self, n_name, n_pictures, n_passable, n_nstats, n_astats, n_team, n_equip)
np.assign_tile(tuple(definition[p]["tile"]), self.bus.fetch("board_manager", "board_tile_layer")[tuple(definition[p]["tile"])])
np.snap_to_tile()
self.add_piece(np)
@@ -190,7 +191,8 @@ class Piece(entity.Entity):
"""
def __init__(self, sheet, sprite = (0, 0), animation = None, animated = False,
- manager = None, name = None, passable = False, normal_stats = None, active_stats = None, team = None, equipment = None):
+ manager = None, name = None, pictures = None, passable = False, normal_stats = None, active_stats = None,
+ team = None, equipment = None):
# Parent initialization
super().__init__(sheet, sprite, animation, animated)
@@ -201,6 +203,12 @@ class Piece(entity.Entity):
# Others
self.manager = manager
self.name = name
+ self.pictures = {
+ "icons_small" : None,
+ "icons_large" : None,
+ "portrait" : None
+ }
+ self.load_pictures(pictures)
self.passable = passable
self.normal_stats = normal_stats
self.active_stats = active_stats
@@ -217,6 +225,13 @@ class Piece(entity.Entity):
self.taking_turn = False
self.haste_mod = 3 # 3 - normal, 1 - minimum (slow 2), 5 - maximum (haste 2)
+ def load_pictures(self, pictures):
+ """
+ Load universal pictures from a given pictures
+ directory.
+ """
+ self.pictures["icons_small"] = pictures + "_icons_small"
+
def set_facing(self, direction):
"""
Set the direction this piece should face. 'direction' should
diff --git a/src/turn.py b/src/turn.py
@@ -43,6 +43,10 @@ class TurnManager(manager.Manager):
Load up the turns for the first time.
"""
self.in_play_pieces = pieces
+ self.turn_tray = TurnTray(self.bus.fetch("sheet_manager", "sheets")["turn_order_tray_1"])
+ # TODO: Probably shouldn't be hardcoded
+ self.turn_tray.set_position((898, 28))
+ self.turn_icons = []
self.shift_turns()
def shift_turns(self):
@@ -82,6 +86,9 @@ class TurnManager(manager.Manager):
self.current_active_piece.taking_turn = True
self.current_active_piece.readiness -= 100
+ # Predict the next turn order
+ self.project_turn_order()
+
def project_turn_order(self):
"""
Make a projection of the upcoming turn order.
@@ -89,27 +96,59 @@ class TurnManager(manager.Manager):
turn_depth value (accounting for that many
projected turns).
"""
+ # Initial setup
pt = self.current_tick
- self.turn_projection = []
+ self.turn_projection = [self.current_active_piece]
+ self.turn_icons = []
next_turn_candidates = []
- rds = { self.in_play_pieces[i] : self.in_play_pieces[i].readiness for i in self.in_play_pieces }
+ rds = { i : i.readiness for i in self.in_play_pieces }
+
+ # If anybody has readiness >= 100 already, go ahead and
+ # account for them
+ for fc in rds:
+ if rds[fc] >= 100:
+ self.turn_projection.append(fc)
+ rds[fc] -= 100
+
+ # If we did the above, reverse-sort the turn projection
+ if len(self.turn_projection) > 1:
+ self.turn_projection.sort(reverse = True, key = lambda g: (g.readiness, g.active_stats["SPD"]))
+
+ # Until we have the desired amount of projected turns, keep trying
+ # to add new ones
while len(self.turn_projection) < self.turn_depth:
pt += 1
for p in rds:
rds[p] += p.active_stats["INIT"] + min(1, (p.active_stats["SPD"] // 3))
- if rds[p] >= 100:
- next_turn_candidates.append[p]
+ if rds[p] >= 100 and len(self.turn_projection) < self.turn_depth:
+ next_turn_candidates.append(p)
rds[p] -= 100
next_turn_candidates.sort(reverse = True, key = lambda can: (can.readiness, can.active_stats["SPD"]))
for ntc in next_turn_candidates:
self.turn_projection.append(ntc)
+ # Fill up the turn icons
+ j = 0
+ for pj in self.turn_projection:
+ self.construct_turn_icon(pj, j)
+ j += 1
+
+ def construct_turn_icon(self, piece, index):
+ """
+ Create a turn icon for the given piece and append
+ it to the turn_icons list.
+ """
+ ni = TurnIcon(self.bus.fetch("sheet_manager", "sheets")["turn_icon_holder_1"], (0, 0), None, False, self, piece, index)
+ self.turn_icons.append(ni)
+
def update_managed(self, surface):
"""
Update the entities this manager controls.
"""
if surface != None:
- pass
+ self.turn_tray.update(surface)
+ for i in self.turn_icons:
+ i.update(surface)
#############################
# Section 2 - Turn Entities #
@@ -120,7 +159,8 @@ class TurnTray(entity.Entity):
The TurnTray is the on-screen object where icons
and names representing the next Pieces to take
their turns are drawn to. It is a seperate class
- mostly because it must write specific text.
+ mostly because it must write specific text and
+ it can grow to show more turns.
"""
def __init__(self, sheet, sprite = (0, 0), animation = None, animated = False):
@@ -128,16 +168,35 @@ class TurnTray(entity.Entity):
# Parent initialization
super().__init__(sheet, sprite, animation, animated)
-class TurnButton(entity.Entity):
+class TurnIcon(entity.Entity):
"""
Class representing the buttons with icons and names
that appear in order inside the TurnTray object.
Clicking one will lock the cursor on that Piece.
"""
- def __init__(self, sheet, sprite = (0, 0), animation = None, animated = False):
+ def __init__(self, sheet, sprite = (0, 0), animation = None, animated = False,
+ manager = None, piece = None, index = -1):
# Parent initialization
super().__init__(sheet, sprite, animation, animated)
-
+ # Initialize important settings based on piece
+ self.manager = manager
+ self.piece = piece
+ self.piece_name = piece.name
+ self.piece_picture = entity.Entity(self.manager.bus.fetch("sheet_manager", "sheets")[piece.pictures["icons_small"]])
+ # TODO: Font size should be dynamically determined from screen size
+ self.font = pygame.font.Font(os.path.join(FONT_PATH, UI_FONT), 12)
+ self.index = index
+ # TODO: Set this in settings??? Should at least dynamically derive y multiple from screen size
+ self.set_position((900, 32 + (32 * index)))
+ self.piece_picture.set_position(self.rect.topleft)
+
+ def update(self, surface = None):
+ """
+ Overwrite of parent update() since this entity
+ draws sub-sprites.
+ """
+ super().update(surface)
+ self.piece_picture.update(surface)