Draw a path from the hero to the current mouse point
Add a highlight grid to Map, with locations set to True if that point should be drawn with a "highlight" treatment. Add the highlight graphic_dtype to all Tiles.
This commit is contained in:
parent
f05dfdef55
commit
6c9d01771f
4 changed files with 80 additions and 29 deletions
|
@ -68,7 +68,9 @@ class Engine:
|
|||
self.map = Map(map_size, map_generator)
|
||||
|
||||
self.event_handler: 'EventHandler' = MainGameEventHandler(self)
|
||||
self.current_mouse_point: Optional[Point] = None
|
||||
|
||||
self.__current_mouse_point: Optional[Point] = None
|
||||
self.__mouse_path_points: Optional[List[Point]] = None
|
||||
|
||||
self.entities: MutableSet[Entity] = set()
|
||||
|
||||
|
@ -103,6 +105,8 @@ class Engine:
|
|||
|
||||
def print_to_console(self, console):
|
||||
'''Print the whole game to the given console.'''
|
||||
self.map.highlight_points(self.__mouse_path_points or [])
|
||||
|
||||
self.map.print_to_console(console)
|
||||
|
||||
console.print(x=1, y=45, string='HP:')
|
||||
|
@ -124,7 +128,7 @@ class Engine:
|
|||
|
||||
ent.print_to_console(console)
|
||||
|
||||
if ent.position == self.current_mouse_point:
|
||||
if ent.position == self.__current_mouse_point:
|
||||
entities_at_mouse_position.append(ent)
|
||||
|
||||
if len(entities_at_mouse_position) > 0:
|
||||
|
@ -141,12 +145,15 @@ class Engine:
|
|||
self.event_handler.handle_events(context)
|
||||
self.finish_turn()
|
||||
|
||||
def process_input_action(self, action: Action) -> ActionResult:
|
||||
def process_input_action(self, action: Action):
|
||||
'''Process an Action from player input'''
|
||||
|
||||
log.ACTIONS_TREE.info('Processing Hero Actions')
|
||||
log.ACTIONS_TREE.info('|-> %s', action.actor)
|
||||
|
||||
# Clear the mouse path highlight before handling actions.
|
||||
self.__mouse_path_points = None
|
||||
|
||||
result = self._perform_action_until_done(action)
|
||||
|
||||
# Player's action failed, don't proceed with turn.
|
||||
|
@ -225,7 +232,7 @@ class Engine:
|
|||
|
||||
return result
|
||||
|
||||
def update_field_of_view(self) -> None:
|
||||
def update_field_of_view(self):
|
||||
'''Compute visible area of the map based on the player's position and point of view.'''
|
||||
# FIXME: Move this to the Map class
|
||||
self.map.visible[:] = tcod.map.compute_fov(
|
||||
|
@ -233,9 +240,37 @@ class Engine:
|
|||
tuple(self.hero.position),
|
||||
radius=8)
|
||||
|
||||
# Visible tiles should be added to the explored list
|
||||
# Add visible tiles to the explored grid
|
||||
self.map.explored |= self.map.visible
|
||||
|
||||
def update_mouse_point(self, mouse_point: Optional[Point]):
|
||||
if mouse_point == self.__current_mouse_point:
|
||||
return
|
||||
|
||||
should_render_mouse_path = (
|
||||
mouse_point
|
||||
and self.map.tile_is_in_bounds(mouse_point)
|
||||
and self.map.tile_is_walkable(mouse_point))
|
||||
|
||||
if not should_render_mouse_path:
|
||||
self.__current_mouse_point = None
|
||||
self.__mouse_path_points = None
|
||||
return
|
||||
|
||||
self.__current_mouse_point = mouse_point
|
||||
|
||||
path_from_hero_to_mouse_point = tcod.los.bresenham(tuple(self.hero.position), tuple(self.__current_mouse_point))
|
||||
mouse_path_points = [Point(x, y) for x, y in path_from_hero_to_mouse_point.tolist()]
|
||||
|
||||
all_mouse_path_points_are_walkable = all(
|
||||
self.map.tile_is_walkable(pt) and self.map.point_is_explored(pt) for pt in mouse_path_points)
|
||||
if not all_mouse_path_points_are_walkable:
|
||||
self.__current_mouse_point = None
|
||||
self.__mouse_path_points = None
|
||||
return
|
||||
|
||||
self.__mouse_path_points = mouse_path_points
|
||||
|
||||
def begin_turn(self) -> None:
|
||||
'''Begin the current turn'''
|
||||
if self.did_begin_turn:
|
||||
|
|
|
@ -28,7 +28,7 @@ class EventHandler(tcod.event.EventDispatch[Action]):
|
|||
context.convert_event(event)
|
||||
self.handle_event(event)
|
||||
|
||||
def handle_event(self, event: tcod.event.Event) -> None:
|
||||
def handle_event(self, event: tcod.event.Event):
|
||||
'''
|
||||
Handle an event by transforming it into an Action and processing it until it is completed. If the Action
|
||||
succeeds, also process actions from other Entities.
|
||||
|
@ -95,7 +95,7 @@ class MainGameEventHandler(EventHandler):
|
|||
mouse_point = Point(event.tile.x, event.tile.y)
|
||||
if not self.engine.map.tile_is_in_bounds(mouse_point):
|
||||
mouse_point = None
|
||||
self.engine.current_mouse_point = mouse_point
|
||||
self.engine.update_mouse_point(mouse_point)
|
||||
|
||||
|
||||
class GameOverEventHandler(EventHandler):
|
||||
|
|
|
@ -6,6 +6,7 @@ parts of a map.
|
|||
'''
|
||||
|
||||
import random
|
||||
from typing import Iterable
|
||||
|
||||
import numpy as np
|
||||
import numpy.typing as npt
|
||||
|
@ -20,17 +21,17 @@ class Map:
|
|||
def __init__(self, size: Size, generator: MapGenerator):
|
||||
self.size = size
|
||||
|
||||
self.generator = generator
|
||||
self.tiles = np.full(tuple(size), fill_value=Empty, order='F')
|
||||
generator.generate(self.tiles)
|
||||
|
||||
self.up_stairs = generator.up_stairs
|
||||
self.down_stairs = generator.down_stairs
|
||||
|
||||
self.highlighted = np.full(tuple(self.size), fill_value=False, order='F')
|
||||
# Map tiles that are currently visible to the player
|
||||
self.visible = np.full(tuple(self.size), fill_value=True, order='F')
|
||||
self.visible = np.full(tuple(self.size), fill_value=False, order='F')
|
||||
# Map tiles that the player has explored
|
||||
self.explored = np.full(tuple(self.size), fill_value=True, order='F')
|
||||
self.explored = np.full(tuple(self.size), fill_value=False, order='F')
|
||||
|
||||
self.__walkable_points = None
|
||||
|
||||
|
@ -47,7 +48,14 @@ class Map:
|
|||
|
||||
def tile_is_walkable(self, point: Point) -> bool:
|
||||
'''Return True if the tile at the given point is walkable'''
|
||||
return self.tiles[point.x, point.y]['walkable']
|
||||
return self.tile_is_in_bounds(point) and self.tiles[point.x, point.y]['walkable']
|
||||
|
||||
def highlight_points(self, points: Iterable[Point]):
|
||||
'''Update the highlight graph with the list of points to highlight.'''
|
||||
self.highlighted.fill(False)
|
||||
|
||||
for pt in points if points:
|
||||
self.highlighted[pt.x, pt.y] = True
|
||||
|
||||
def print_to_console(self, console: tcod.Console) -> None:
|
||||
'''Render the map to the console.'''
|
||||
|
@ -56,6 +64,6 @@ class Map:
|
|||
# If a tile is in the visible array, draw it with the "light" color. If it's not, but it's in the explored
|
||||
# array, draw it with the "dark" color. Otherwise, draw it as Empty.
|
||||
console.tiles_rgb[0:size.width, 0:size.height] = np.select(
|
||||
condlist=[self.visible, self.explored],
|
||||
choicelist=[self.tiles['light'], self.tiles['dark']],
|
||||
condlist=[self.highlighted, self.visible, self.explored],
|
||||
choicelist=[self.tiles['highlighted'], self.tiles['light'], self.tiles['dark']],
|
||||
default=Shroud)
|
||||
|
|
|
@ -6,9 +6,9 @@ graphic_datatype = np.dtype([
|
|||
# Character, a Unicode codepoint represented as an int32
|
||||
('ch', np.int32),
|
||||
# Foreground color, three bytes
|
||||
('fg', '3B'),
|
||||
('fg', '4B'),
|
||||
# Background color, three bytes
|
||||
('bg', '3B'),
|
||||
('bg', '4B'),
|
||||
])
|
||||
|
||||
tile_datatype = np.dtype([
|
||||
|
@ -20,37 +20,45 @@ tile_datatype = np.dtype([
|
|||
('dark', graphic_datatype),
|
||||
# A graphic struct (as above) defining the look of this tile when it's visible
|
||||
('light', graphic_datatype),
|
||||
# A graphic struct (as above) defining the look of this tile when it's highlighted
|
||||
('highlighted', graphic_datatype),
|
||||
])
|
||||
|
||||
|
||||
def tile(*,
|
||||
walkable: int,
|
||||
transparent: int,
|
||||
dark: Tuple[int, Tuple[int, int, int], Tuple[int, int, int]],
|
||||
light: Tuple[int, Tuple[int, int, int], Tuple[int, int, int]]) -> np.ndarray:
|
||||
return np.array((walkable, transparent, dark, light), dtype=tile_datatype)
|
||||
dark: Tuple[int, Tuple[int, int, int, int], Tuple[int, int, int, int]],
|
||||
light: Tuple[int, Tuple[int, int, int, int], Tuple[int, int, int, int]],
|
||||
highlighted: Tuple[int, Tuple[int, int, int, int], Tuple[int, int, int, int]]) -> np.ndarray:
|
||||
return np.array((walkable, transparent, dark, light, highlighted), dtype=tile_datatype)
|
||||
|
||||
|
||||
# An overlay color for tiles that are not visible and have not been explored
|
||||
Shroud = np.array((ord(' '), (255, 255, 255), (0, 0, 0)), dtype=graphic_datatype)
|
||||
Shroud = np.array((ord(' '), (255, 255, 255, 255), (0, 0, 0, 0)), dtype=graphic_datatype)
|
||||
|
||||
Empty = tile(
|
||||
walkable=False, transparent=False,
|
||||
dark=(ord(' '), (255, 255, 255), (0, 0, 0)),
|
||||
light=(ord(' '), (255, 255, 255), (0, 0, 0)))
|
||||
dark=(ord('#'), (20, 20, 20, 255), (0, 0, 0, 0)),
|
||||
light=(ord('#'), (20, 20, 20, 255), (0, 0, 0, 0)),
|
||||
highlighted=(ord('#'), (20, 20, 20, 255), (30, 30, 30, 255)))
|
||||
Floor = tile(
|
||||
walkable=True, transparent=True,
|
||||
dark=(ord('·'), (80, 80, 100), (50, 50, 50)),
|
||||
light=(ord('·'), (100, 100, 120), (80, 80, 100)))
|
||||
dark=(ord('·'), (80, 80, 100, 255), (50, 50, 50, 255)),
|
||||
light=(ord('·'), (100, 100, 120, 255), (80, 80, 100, 255)),
|
||||
highlighted=(ord('·'), (100, 100, 120, 255), (80, 80, 150, 255)))
|
||||
StairsUp = tile(
|
||||
walkable=True, transparent=True,
|
||||
dark=(ord('<'), (80, 80, 100), (50, 50, 50)),
|
||||
light=(ord('<'), (100, 100, 120), (80, 80, 100)))
|
||||
dark=(ord('<'), (80, 80, 100, 255), (50, 50, 50, 255)),
|
||||
light=(ord('<'), (100, 100, 120, 255), (80, 80, 100, 255)),
|
||||
highlighted=(ord('<'), (100, 100, 120, 255), (80, 80, 150, 255)))
|
||||
StairsDown = tile(
|
||||
walkable=True, transparent=True,
|
||||
dark=(ord('>'), (80, 80, 100), (50, 50, 50)),
|
||||
light=(ord('>'), (100, 100, 120), (80, 80, 100)))
|
||||
dark=(ord('>'), (80, 80, 100, 255), (50, 50, 50, 255)),
|
||||
light=(ord('>'), (100, 100, 120, 255), (80, 80, 100, 255)),
|
||||
highlighted=(ord('>'), (100, 100, 120, 255), (80, 80, 150, 255)))
|
||||
Wall = tile(
|
||||
walkable=False, transparent=False,
|
||||
dark=(ord(' '), (255, 255, 255), (0, 0, 150)),
|
||||
light=(ord(' '), (255, 255, 255), (50, 50, 200)))
|
||||
dark=(ord('#'), (80, 80, 80, 255), (0, 0, 0, 255)),
|
||||
light=(ord('#'), (100, 100, 100, 255), (20, 20, 20, 255)),
|
||||
highlighted=(ord('#'), (100, 100, 100, 255), (20, 20, 20, 255)))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue