Reformat with black
This commit is contained in:
parent
142950e474
commit
8ceb5f0e5d
@ -61,10 +61,7 @@ class PickupAction(Action):
|
|||||||
|
|
||||||
class ItemAction(Action):
|
class ItemAction(Action):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self, entity: Actor, item: Item, target_xy: Optional[Tuple[int, int]] = None
|
||||||
entity: Actor,
|
|
||||||
item: Item,
|
|
||||||
target_xy: Optional[Tuple[int, int]] = None
|
|
||||||
):
|
):
|
||||||
super().__init__(entity)
|
super().__init__(entity)
|
||||||
self.item = item
|
self.item = item
|
||||||
@ -101,8 +98,7 @@ class TakeStairsAction(Action):
|
|||||||
if (self.entity.x, self.entity.y) == self.engine.game_map.downstairs_location:
|
if (self.entity.x, self.entity.y) == self.engine.game_map.downstairs_location:
|
||||||
self.engine.game_world.generate_floor()
|
self.engine.game_world.generate_floor()
|
||||||
self.engine.message_log.add_message(
|
self.engine.message_log.add_message(
|
||||||
"You descent the staircase.",
|
"You descent the staircase.", color.descend
|
||||||
color.descend
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise exceptions.Impossible("There are no stairs here.")
|
raise exceptions.Impossible("There are no stairs here.")
|
||||||
|
@ -13,7 +13,6 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
|
|
||||||
class BaseAI(Action):
|
class BaseAI(Action):
|
||||||
|
|
||||||
def get_path_to(self, dest_x: int, dest_y: int) -> List[Tuple[int, int]]:
|
def get_path_to(self, dest_x: int, dest_y: int) -> List[Tuple[int, int]]:
|
||||||
"""Compute and return a path to the target position.
|
"""Compute and return a path to the target position.
|
||||||
|
|
||||||
@ -52,10 +51,7 @@ class ConfusedEnemy(BaseAI):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self, entity: Actor, previous_ai: Optional[BaseAI], turns_remaining: int
|
||||||
entity: Actor,
|
|
||||||
previous_ai: Optional[BaseAI],
|
|
||||||
turns_remaining: int
|
|
||||||
):
|
):
|
||||||
super().__init__(entity)
|
super().__init__(entity)
|
||||||
|
|
||||||
@ -65,7 +61,9 @@ class ConfusedEnemy(BaseAI):
|
|||||||
def perform(self) -> None:
|
def perform(self) -> None:
|
||||||
# Rever the AI back to the original state if the effect has run its course.
|
# Rever the AI back to the original state if the effect has run its course.
|
||||||
if self.turns_remaining <= 0:
|
if self.turns_remaining <= 0:
|
||||||
self.engine.message_log.add_message(f"The {self.entity.name} is no longer confused.")
|
self.engine.message_log.add_message(
|
||||||
|
f"The {self.entity.name} is no longer confused."
|
||||||
|
)
|
||||||
self.entity.ai = self.previous_ai
|
self.entity.ai = self.previous_ai
|
||||||
else:
|
else:
|
||||||
# Pick a random direction
|
# Pick a random direction
|
||||||
|
@ -11,7 +11,7 @@ from exceptions import Impossible
|
|||||||
from input_handlers import (
|
from input_handlers import (
|
||||||
ActionOrHandler,
|
ActionOrHandler,
|
||||||
AreaRangedAttackHandler,
|
AreaRangedAttackHandler,
|
||||||
SingleRangedAttackHandler
|
SingleRangedAttackHandler,
|
||||||
)
|
)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -46,8 +46,7 @@ class ConfusionConsumable(Consumable):
|
|||||||
|
|
||||||
def get_action(self, consumer: Actor) -> SingleRangedAttackHandler:
|
def get_action(self, consumer: Actor) -> SingleRangedAttackHandler:
|
||||||
self.engine.message_log.add_message(
|
self.engine.message_log.add_message(
|
||||||
"Select a target location.",
|
"Select a target location.", color.needs_target
|
||||||
color.needs_target
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return SingleRangedAttackHandler(
|
return SingleRangedAttackHandler(
|
||||||
@ -90,7 +89,7 @@ class HealingConsumable(Consumable):
|
|||||||
if amount_recovered > 0:
|
if amount_recovered > 0:
|
||||||
self.engine.message_log.add_message(
|
self.engine.message_log.add_message(
|
||||||
f"You consume the {self.parent.name}, and recover {amount_recovered} HP!",
|
f"You consume the {self.parent.name}, and recover {amount_recovered} HP!",
|
||||||
color.health_recovered
|
color.health_recovered,
|
||||||
)
|
)
|
||||||
self.consume()
|
self.consume()
|
||||||
else:
|
else:
|
||||||
@ -104,8 +103,7 @@ class FireballDamageConsumable(Consumable):
|
|||||||
|
|
||||||
def get_action(self, consumer: Actor) -> AreaRangedAttackHandler:
|
def get_action(self, consumer: Actor) -> AreaRangedAttackHandler:
|
||||||
self.engine.message_log.add_message(
|
self.engine.message_log.add_message(
|
||||||
"Select a target location.",
|
"Select a target location.", color.needs_target
|
||||||
color.needs_target
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return AreaRangedAttackHandler(
|
return AreaRangedAttackHandler(
|
||||||
|
@ -13,10 +13,10 @@ class Equippable(BaseComponent):
|
|||||||
parent: Item
|
parent: Item
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
equipment_type: EquipmentType,
|
equipment_type: EquipmentType,
|
||||||
power_bonus: int = 0,
|
power_bonus: int = 0,
|
||||||
defense_bonus: int = 0,
|
defense_bonus: int = 0,
|
||||||
):
|
):
|
||||||
self.equipment_type = equipment_type
|
self.equipment_type = equipment_type
|
||||||
|
|
||||||
|
@ -12,12 +12,12 @@ class Level(BaseComponent):
|
|||||||
parent: Actor
|
parent: Actor
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
current_level: int = 1,
|
current_level: int = 1,
|
||||||
current_xp: int = 0,
|
current_xp: int = 0,
|
||||||
level_up_base: int = 0,
|
level_up_base: int = 0,
|
||||||
level_up_factor: int = 150,
|
level_up_factor: int = 150,
|
||||||
xp_given: int = 0
|
xp_given: int = 0,
|
||||||
):
|
):
|
||||||
self.current_level = current_level
|
self.current_level = current_level
|
||||||
self.current_xp = current_xp
|
self.current_xp = current_xp
|
||||||
|
@ -57,12 +57,12 @@ class Engine:
|
|||||||
)
|
)
|
||||||
|
|
||||||
render_functions.render_dungeon_level(
|
render_functions.render_dungeon_level(
|
||||||
console,
|
console, dungeon_level=self.game_world.current_floor, location=(0, 47)
|
||||||
dungeon_level=self.game_world.current_floor,
|
|
||||||
location=(0, 47)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
render_functions.render_names_at_mouse_location(console, x=21, y=44, engine=self)
|
render_functions.render_names_at_mouse_location(
|
||||||
|
console, x=21, y=44, engine=self
|
||||||
|
)
|
||||||
|
|
||||||
def save_as(self, filename: str) -> None:
|
def save_as(self, filename: str) -> None:
|
||||||
"""Save this Engine instance as a compressed file."""
|
"""Save this Engine instance as a compressed file."""
|
||||||
|
58
entity.py
58
entity.py
@ -26,15 +26,15 @@ class Entity:
|
|||||||
parent: Union[GameMap, Inventory]
|
parent: Union[GameMap, Inventory]
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
parent: Optional[GameMap] = None,
|
parent: Optional[GameMap] = None,
|
||||||
x: int = 0,
|
x: int = 0,
|
||||||
y: int = 0,
|
y: int = 0,
|
||||||
char: str = "?",
|
char: str = "?",
|
||||||
color: Tuple[int, int, int] = (255, 255, 255),
|
color: Tuple[int, int, int] = (255, 255, 255),
|
||||||
name: str = "<Unnamed>",
|
name: str = "<Unnamed>",
|
||||||
blocks_movement: bool = False,
|
blocks_movement: bool = False,
|
||||||
render_order: RenderOrder = RenderOrder.CORPSE,
|
render_order: RenderOrder = RenderOrder.CORPSE,
|
||||||
):
|
):
|
||||||
self.x = x
|
self.x = x
|
||||||
self.y = y
|
self.y = y
|
||||||
@ -87,17 +87,17 @@ class Entity:
|
|||||||
|
|
||||||
class Actor(Entity):
|
class Actor(Entity):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
x: int = 0,
|
x: int = 0,
|
||||||
y: int = 0,
|
y: int = 0,
|
||||||
char: str = "?",
|
char: str = "?",
|
||||||
color: Tuple[int, int, int] = (255, 255, 255),
|
color: Tuple[int, int, int] = (255, 255, 255),
|
||||||
name: str = "<Unamed>",
|
name: str = "<Unamed>",
|
||||||
ai_cls: Type[BaseAI],
|
ai_cls: Type[BaseAI],
|
||||||
fighter: Fighter,
|
fighter: Fighter,
|
||||||
inventory: Inventory,
|
inventory: Inventory,
|
||||||
level: Level
|
level: Level,
|
||||||
):
|
):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
x=x,
|
x=x,
|
||||||
@ -128,15 +128,15 @@ class Actor(Entity):
|
|||||||
|
|
||||||
class Item(Entity):
|
class Item(Entity):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
x: int = 0,
|
x: int = 0,
|
||||||
y: int = 0,
|
y: int = 0,
|
||||||
char: str = "?",
|
char: str = "?",
|
||||||
color: Tuple[int, int, int] = (255, 255, 255),
|
color: Tuple[int, int, int] = (255, 255, 255),
|
||||||
name: str = "<Unamed>",
|
name: str = "<Unamed>",
|
||||||
consumable: Optional[Consumable] = None,
|
consumable: Optional[Consumable] = None,
|
||||||
equippable: Optional[Equippable] = None,
|
equippable: Optional[Equippable] = None,
|
||||||
):
|
):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
x=x,
|
x=x,
|
||||||
|
49
game_map.py
49
game_map.py
@ -15,11 +15,7 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
class GameMap:
|
class GameMap:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self, engine: Engine, width: int, height: int, entities: Iterable[Entity] = ()
|
||||||
engine: Engine,
|
|
||||||
width: int,
|
|
||||||
height: int,
|
|
||||||
entities: Iterable[Entity] = ()
|
|
||||||
):
|
):
|
||||||
self.engine = engine
|
self.engine = engine
|
||||||
self.width, self.height = width, height
|
self.width, self.height = width, height
|
||||||
@ -27,14 +23,10 @@ class GameMap:
|
|||||||
self.tiles = np.full((width, height), fill_value=tile_types.wall, order="F")
|
self.tiles = np.full((width, height), fill_value=tile_types.wall, order="F")
|
||||||
|
|
||||||
self.visible = np.full(
|
self.visible = np.full(
|
||||||
(width, height),
|
(width, height), fill_value=False, order="F"
|
||||||
fill_value=False,
|
|
||||||
order="F"
|
|
||||||
) # Tiles the player can currently see
|
) # Tiles the player can currently see
|
||||||
self.explored = np.full(
|
self.explored = np.full(
|
||||||
(width, height),
|
(width, height), fill_value=False, order="F"
|
||||||
fill_value=False,
|
|
||||||
order="F"
|
|
||||||
) # Tiles the player has seen before
|
) # Tiles the player has seen before
|
||||||
|
|
||||||
self.downstairs_location = (0, 0)
|
self.downstairs_location = (0, 0)
|
||||||
@ -57,15 +49,13 @@ class GameMap:
|
|||||||
yield from (entity for entity in self.entities if isinstance(entity, Item))
|
yield from (entity for entity in self.entities if isinstance(entity, Item))
|
||||||
|
|
||||||
def get_blocking_entity_at_location(
|
def get_blocking_entity_at_location(
|
||||||
self,
|
self, location_x: int, location_y: int
|
||||||
location_x: int,
|
|
||||||
location_y: int
|
|
||||||
) -> Optional[Entity]:
|
) -> Optional[Entity]:
|
||||||
for entity in self.entities:
|
for entity in self.entities:
|
||||||
if (
|
if (
|
||||||
entity.blocks_movement
|
entity.blocks_movement
|
||||||
and entity.x == location_x
|
and entity.x == location_x
|
||||||
and entity.y == location_y
|
and entity.y == location_y
|
||||||
):
|
):
|
||||||
return entity
|
return entity
|
||||||
|
|
||||||
@ -92,7 +82,7 @@ class GameMap:
|
|||||||
:param console:
|
:param console:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
console.tiles_rgb[0: self.width, 0: self.height] = np.select(
|
console.tiles_rgb[0 : self.width, 0 : self.height] = np.select(
|
||||||
condlist=[self.visible, self.explored],
|
condlist=[self.visible, self.explored],
|
||||||
choicelist=[self.tiles["light"], self.tiles["dark"]],
|
choicelist=[self.tiles["light"], self.tiles["dark"]],
|
||||||
default=tile_types.SHROUD,
|
default=tile_types.SHROUD,
|
||||||
@ -106,10 +96,7 @@ class GameMap:
|
|||||||
# Only print entities that are in the FOV
|
# Only print entities that are in the FOV
|
||||||
if self.visible[entity.x, entity.y]:
|
if self.visible[entity.x, entity.y]:
|
||||||
console.print(
|
console.print(
|
||||||
x=entity.x,
|
x=entity.x, y=entity.y, string=entity.char, fg=entity.color
|
||||||
y=entity.y,
|
|
||||||
string=entity.char,
|
|
||||||
fg=entity.color
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -119,15 +106,15 @@ class GameWorld:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
engine: Engine,
|
engine: Engine,
|
||||||
map_width: int,
|
map_width: int,
|
||||||
map_height: int,
|
map_height: int,
|
||||||
max_rooms: int,
|
max_rooms: int,
|
||||||
room_min_size: int,
|
room_min_size: int,
|
||||||
room_max_size: int,
|
room_max_size: int,
|
||||||
current_floor: int = 0
|
current_floor: int = 0,
|
||||||
):
|
):
|
||||||
self.engine = engine
|
self.engine = engine
|
||||||
|
|
||||||
|
@ -7,12 +7,7 @@ from typing import overload, Callable, Optional, Tuple, TYPE_CHECKING, Union
|
|||||||
import tcod.event
|
import tcod.event
|
||||||
|
|
||||||
import actions
|
import actions
|
||||||
from actions import (
|
from actions import Action, BumpAction, PickupAction, WaitAction
|
||||||
Action,
|
|
||||||
BumpAction,
|
|
||||||
PickupAction,
|
|
||||||
WaitAction
|
|
||||||
)
|
|
||||||
import color
|
import color
|
||||||
import exceptions
|
import exceptions
|
||||||
|
|
||||||
@ -30,7 +25,6 @@ MOVE_KEYS = {
|
|||||||
tcod.event.K_END: (-1, 1),
|
tcod.event.K_END: (-1, 1),
|
||||||
tcod.event.K_PAGEUP: (1, -1),
|
tcod.event.K_PAGEUP: (1, -1),
|
||||||
tcod.event.K_PAGEDOWN: (1, 1),
|
tcod.event.K_PAGEDOWN: (1, 1),
|
||||||
|
|
||||||
# Numpad keys
|
# Numpad keys
|
||||||
tcod.event.K_KP_1: (-1, 1),
|
tcod.event.K_KP_1: (-1, 1),
|
||||||
tcod.event.K_KP_2: (0, 1),
|
tcod.event.K_KP_2: (0, 1),
|
||||||
@ -40,7 +34,6 @@ MOVE_KEYS = {
|
|||||||
tcod.event.K_KP_7: (-1, -1),
|
tcod.event.K_KP_7: (-1, -1),
|
||||||
tcod.event.K_KP_8: (0, -1),
|
tcod.event.K_KP_8: (0, -1),
|
||||||
tcod.event.K_KP_9: (1, -1),
|
tcod.event.K_KP_9: (1, -1),
|
||||||
|
|
||||||
# Vi keys
|
# Vi keys
|
||||||
tcod.event.K_h: (-1, 0),
|
tcod.event.K_h: (-1, 0),
|
||||||
tcod.event.K_j: (0, 1),
|
tcod.event.K_j: (0, 1),
|
||||||
@ -183,7 +176,9 @@ class AskUserEventHandler(EventHandler):
|
|||||||
|
|
||||||
return self.on_exit()
|
return self.on_exit()
|
||||||
|
|
||||||
def ev_mousebuttondown(self, event: tcod.event.MouseButtonDown) -> Optional[ActionOrHandler]:
|
def ev_mousebuttondown(
|
||||||
|
self, event: tcod.event.MouseButtonDown
|
||||||
|
) -> Optional[ActionOrHandler]:
|
||||||
"""By default any mouse click exits this input handler."""
|
"""By default any mouse click exits this input handler."""
|
||||||
return self.on_exit()
|
return self.on_exit()
|
||||||
|
|
||||||
@ -221,20 +216,12 @@ class CharacterScreenEventHandler(AskUserEventHandler):
|
|||||||
bg=(0, 0, 0),
|
bg=(0, 0, 0),
|
||||||
)
|
)
|
||||||
|
|
||||||
console.print(
|
console.print(x + 1, y + 1, f"Level: {self.engine.player.level.current_level}")
|
||||||
x + 1,
|
console.print(x + 1, y + 2, f"XP: {self.engine.player.level.current_xp}")
|
||||||
y + 1,
|
|
||||||
f"Level: {self.engine.player.level.current_level}"
|
|
||||||
)
|
|
||||||
console.print(
|
|
||||||
x + 1,
|
|
||||||
y + 2,
|
|
||||||
f"XP: {self.engine.player.level.current_xp}"
|
|
||||||
)
|
|
||||||
console.print(
|
console.print(
|
||||||
x + 1,
|
x + 1,
|
||||||
y + 3,
|
y + 3,
|
||||||
f"XP for next Level: {self.engine.player.level.experience_to_next_level}"
|
f"XP for next Level: {self.engine.player.level.experience_to_next_level}",
|
||||||
)
|
)
|
||||||
console.print(
|
console.print(
|
||||||
x=x + 1, y=y + 4, string=f"Attack: {self.engine.player.fighter.power}"
|
x=x + 1, y=y + 4, string=f"Attack: {self.engine.player.fighter.power}"
|
||||||
@ -263,7 +250,7 @@ class LevelUpEventHandler(AskUserEventHandler):
|
|||||||
title=self.TITLE,
|
title=self.TITLE,
|
||||||
clear=True,
|
clear=True,
|
||||||
fg=(255, 255, 255),
|
fg=(255, 255, 255),
|
||||||
bg=(0, 0, 0)
|
bg=(0, 0, 0),
|
||||||
)
|
)
|
||||||
|
|
||||||
console.print(x + 1, 1, "Congratulations! You level up!")
|
console.print(x + 1, 1, "Congratulations! You level up!")
|
||||||
@ -272,17 +259,17 @@ class LevelUpEventHandler(AskUserEventHandler):
|
|||||||
console.print(
|
console.print(
|
||||||
x=x + 1,
|
x=x + 1,
|
||||||
y=4,
|
y=4,
|
||||||
string=f"a) Constitution (+20 HP, from {self.engine.player.fighter.max_hp})"
|
string=f"a) Constitution (+20 HP, from {self.engine.player.fighter.max_hp})",
|
||||||
)
|
)
|
||||||
console.print(
|
console.print(
|
||||||
x=x + 1,
|
x=x + 1,
|
||||||
y=5,
|
y=5,
|
||||||
string=f"b) Strength (+1 attack, from {self.engine.player.fighter.power})"
|
string=f"b) Strength (+1 attack, from {self.engine.player.fighter.power})",
|
||||||
)
|
)
|
||||||
console.print(
|
console.print(
|
||||||
x=x + 1,
|
x=x + 1,
|
||||||
y=6,
|
y=6,
|
||||||
string=f"c) Agility (+1 defense, from {self.engine.player.fighter.defense})"
|
string=f"c) Agility (+1 defense, from {self.engine.player.fighter.defense})",
|
||||||
)
|
)
|
||||||
|
|
||||||
def ev_keydown(self, event: tcod.event.KeyDown) -> Optional[ActionOrHandler]:
|
def ev_keydown(self, event: tcod.event.KeyDown) -> Optional[ActionOrHandler]:
|
||||||
@ -304,7 +291,9 @@ class LevelUpEventHandler(AskUserEventHandler):
|
|||||||
|
|
||||||
return super().ev_keydown(event)
|
return super().ev_keydown(event)
|
||||||
|
|
||||||
def ev_mousebuttondown(self, event: tcod.event.MouseButtonDown) -> Optional[ActionOrHandler]:
|
def ev_mousebuttondown(
|
||||||
|
self, event: tcod.event.MouseButtonDown
|
||||||
|
) -> Optional[ActionOrHandler]:
|
||||||
"""
|
"""
|
||||||
Don't allow the player to click to exit the menu, like normal
|
Don't allow the player to click to exit the menu, like normal
|
||||||
"""
|
"""
|
||||||
@ -443,7 +432,9 @@ class SelectIndexHandler(AskUserEventHandler):
|
|||||||
|
|
||||||
return super().ev_keydown(event)
|
return super().ev_keydown(event)
|
||||||
|
|
||||||
def ev_mousebuttondown(self, event: tcod.event.MouseButtonDown) -> Optional[ActionOrHandler]:
|
def ev_mousebuttondown(
|
||||||
|
self, event: tcod.event.MouseButtonDown
|
||||||
|
) -> Optional[ActionOrHandler]:
|
||||||
"""Left click confirms a selection."""
|
"""Left click confirms a selection."""
|
||||||
if self.engine.game_map.in_bounds(*event.tile):
|
if self.engine.game_map.in_bounds(*event.tile):
|
||||||
if event.button == 1:
|
if event.button == 1:
|
||||||
@ -468,9 +459,9 @@ class SingleRangedAttackHandler(SelectIndexHandler):
|
|||||||
"""Handles targeting a single enemy. Only the enemy selected will be affected."""
|
"""Handles targeting a single enemy. Only the enemy selected will be affected."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
engine: Engine,
|
engine: Engine,
|
||||||
callback: Callable[[Tuple[int, int]], Optional[ActionOrHandler]]
|
callback: Callable[[Tuple[int, int]], Optional[ActionOrHandler]],
|
||||||
):
|
):
|
||||||
super().__init__(engine)
|
super().__init__(engine)
|
||||||
|
|
||||||
@ -487,10 +478,10 @@ class AreaRangedAttackHandler(SelectIndexHandler):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
engine: Engine,
|
engine: Engine,
|
||||||
radius: int,
|
radius: int,
|
||||||
callback: Callable[[Tuple[int, int]], Optional[ActionOrHandler]]
|
callback: Callable[[Tuple[int, int]], Optional[ActionOrHandler]],
|
||||||
):
|
):
|
||||||
super().__init__(engine)
|
super().__init__(engine)
|
||||||
|
|
||||||
@ -507,8 +498,8 @@ class AreaRangedAttackHandler(SelectIndexHandler):
|
|||||||
console.draw_frame(
|
console.draw_frame(
|
||||||
x=x - self.radius - 1,
|
x=x - self.radius - 1,
|
||||||
y=y - self.radius - 1,
|
y=y - self.radius - 1,
|
||||||
width=self.radius ** 2,
|
width=self.radius**2,
|
||||||
height=self.radius ** 2,
|
height=self.radius**2,
|
||||||
fg=color.red,
|
fg=color.red,
|
||||||
clear=False,
|
clear=False,
|
||||||
)
|
)
|
||||||
@ -527,7 +518,7 @@ class MainGameEventHandler(EventHandler):
|
|||||||
player = self.engine.player
|
player = self.engine.player
|
||||||
|
|
||||||
if key == tcod.event.K_PERIOD and modifier & (
|
if key == tcod.event.K_PERIOD and modifier & (
|
||||||
tcod.event.KMOD_LSHIFT | tcod.event.KMOD_RSHIFT
|
tcod.event.KMOD_LSHIFT | tcod.event.KMOD_RSHIFT
|
||||||
):
|
):
|
||||||
return actions.TakeStairsAction(player)
|
return actions.TakeStairsAction(player)
|
||||||
|
|
||||||
@ -598,12 +589,7 @@ class HistoryViewer(EventHandler):
|
|||||||
# Draw a frame with a custom banner title.
|
# Draw a frame with a custom banner title.
|
||||||
log_console.draw_frame(0, 0, log_console.width, log_console.height)
|
log_console.draw_frame(0, 0, log_console.width, log_console.height)
|
||||||
log_console.print_box(
|
log_console.print_box(
|
||||||
0,
|
0, 0, log_console.width, 1, "┤Message history├", alignment=tcod.CENTER
|
||||||
0,
|
|
||||||
log_console.width,
|
|
||||||
1,
|
|
||||||
"┤Message history├",
|
|
||||||
alignment=tcod.CENTER
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Render the message log using the cursor parameter.
|
# Render the message log using the cursor parameter.
|
||||||
|
15
main.py
15
main.py
@ -21,20 +21,17 @@ def main() -> None:
|
|||||||
screen_height = 50
|
screen_height = 50
|
||||||
|
|
||||||
tileset = tcod.tileset.load_tilesheet(
|
tileset = tcod.tileset.load_tilesheet(
|
||||||
"dejavu10x10_gs_tc.png",
|
"dejavu10x10_gs_tc.png", 32, 8, tcod.tileset.CHARMAP_TCOD
|
||||||
32,
|
|
||||||
8,
|
|
||||||
tcod.tileset.CHARMAP_TCOD
|
|
||||||
)
|
)
|
||||||
|
|
||||||
handler: input_handlers.BaseEventHandler = setup_game.MainMenu()
|
handler: input_handlers.BaseEventHandler = setup_game.MainMenu()
|
||||||
|
|
||||||
with tcod.context.new_terminal(
|
with tcod.context.new_terminal(
|
||||||
screen_width,
|
screen_width,
|
||||||
screen_height,
|
screen_height,
|
||||||
tileset=tileset,
|
tileset=tileset,
|
||||||
title="Yet Another Roguelike Tutorial",
|
title="Yet Another Roguelike Tutorial",
|
||||||
vsync=True,
|
vsync=True,
|
||||||
) as context:
|
) as context:
|
||||||
root_console = tcod.Console(screen_width, screen_height, order="F")
|
root_console = tcod.Console(screen_width, screen_height, order="F")
|
||||||
try:
|
try:
|
||||||
|
@ -26,11 +26,7 @@ class MessageLog:
|
|||||||
self.messages: List[Message] = []
|
self.messages: List[Message] = []
|
||||||
|
|
||||||
def add_message(
|
def add_message(
|
||||||
self,
|
self, text: str, fg: Tuple[int, int, int] = color.white, *, stack: bool = True
|
||||||
text: str,
|
|
||||||
fg: Tuple[int, int, int] = color.white,
|
|
||||||
*,
|
|
||||||
stack: bool = True
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Add a message to this log.
|
"""Add a message to this log.
|
||||||
`text` is the message text, `fg` is the text color.
|
`text` is the message text, `fg` is the text color.
|
||||||
@ -43,12 +39,12 @@ class MessageLog:
|
|||||||
self.messages.append(Message(text, fg))
|
self.messages.append(Message(text, fg))
|
||||||
|
|
||||||
def render(
|
def render(
|
||||||
self,
|
self,
|
||||||
console: tcod.Console,
|
console: tcod.Console,
|
||||||
x: int,
|
x: int,
|
||||||
y: int,
|
y: int,
|
||||||
width: int,
|
width: int,
|
||||||
height: int,
|
height: int,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Render this log over the given area.
|
"""Render this log over the given area.
|
||||||
`x`, `y`, `width`, `height` is the rectangular region to render onto
|
`x`, `y`, `width`, `height` is the rectangular region to render onto
|
||||||
@ -60,21 +56,17 @@ class MessageLog:
|
|||||||
def wrap(string: str, width: int) -> Iterable[str]:
|
def wrap(string: str, width: int) -> Iterable[str]:
|
||||||
"""Return a wrapped text message."""
|
"""Return a wrapped text message."""
|
||||||
for line in string.splitlines(): # Handle newlines in messages.
|
for line in string.splitlines(): # Handle newlines in messages.
|
||||||
yield from textwrap.wrap(
|
yield from textwrap.wrap(line, width, expand_tabs=True)
|
||||||
line,
|
|
||||||
width,
|
|
||||||
expand_tabs=True
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def render_messages(
|
def render_messages(
|
||||||
cls,
|
cls,
|
||||||
console: tcod.Console,
|
console: tcod.Console,
|
||||||
x: int,
|
x: int,
|
||||||
y: int,
|
y: int,
|
||||||
width: int,
|
width: int,
|
||||||
height: int,
|
height: int,
|
||||||
messages: Reversible[Message],
|
messages: Reversible[Message],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Render the messages provided.
|
"""Render the messages provided.
|
||||||
The `messages` are rendered starting at the last message and working
|
The `messages` are rendered starting at the last message and working
|
||||||
|
55
procgen.py
55
procgen.py
@ -40,24 +40,23 @@ enemy_chances: Dict[int, List[Tuple[Entity, int]]] = {
|
|||||||
|
|
||||||
|
|
||||||
def get_max_value_for_floor(
|
def get_max_value_for_floor(
|
||||||
max_value_by_floor: List[Tuple[int, int]],
|
max_value_by_floor: List[Tuple[int, int]], floor: int
|
||||||
floor: int
|
|
||||||
) -> int:
|
) -> int:
|
||||||
current_value = 0
|
current_value = 0
|
||||||
|
|
||||||
for floor_minimum, value in max_value_by_floor:
|
for floor_minimum, value in max_value_by_floor:
|
||||||
if floor_minimum > floor:
|
if floor_minimum > floor:
|
||||||
break;
|
break
|
||||||
else:
|
else:
|
||||||
current_value = value;
|
current_value = value
|
||||||
|
|
||||||
return current_value
|
return current_value
|
||||||
|
|
||||||
|
|
||||||
def get_entities_at_random(
|
def get_entities_at_random(
|
||||||
weighted_chances_by_floor: Dict[int, List[Tuple[Entity, int]]],
|
weighted_chances_by_floor: Dict[int, List[Tuple[Entity, int]]],
|
||||||
number_of_entities: int,
|
number_of_entities: int,
|
||||||
floor: int,
|
floor: int,
|
||||||
) -> List[Entity]:
|
) -> List[Entity]:
|
||||||
entity_weighted_chances = {}
|
entity_weighted_chances = {}
|
||||||
|
|
||||||
@ -75,9 +74,7 @@ def get_entities_at_random(
|
|||||||
entity_weighted_chance_values = list(entity_weighted_chances.values())
|
entity_weighted_chance_values = list(entity_weighted_chances.values())
|
||||||
|
|
||||||
chosen_entities = random.choices(
|
chosen_entities = random.choices(
|
||||||
entities,
|
entities, weights=entity_weighted_chance_values, k=number_of_entities
|
||||||
weights=entity_weighted_chance_values,
|
|
||||||
k=number_of_entities
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return chosen_entities
|
return chosen_entities
|
||||||
@ -105,17 +102,17 @@ class RectangularRoom:
|
|||||||
def intersects(self, other: RectangularRoom) -> bool:
|
def intersects(self, other: RectangularRoom) -> bool:
|
||||||
"""Return True if this room overlaps with another RectangularRoom."""
|
"""Return True if this room overlaps with another RectangularRoom."""
|
||||||
return (
|
return (
|
||||||
self.x1 <= other.x2
|
self.x1 <= other.x2
|
||||||
and self.x2 >= other.x1
|
and self.x2 >= other.x1
|
||||||
and self.y1 <= other.y2
|
and self.y1 <= other.y2
|
||||||
and self.y2 >= other.y1
|
and self.y2 >= other.y1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def place_entities(
|
def place_entities(
|
||||||
room: RectangularRoom,
|
room: RectangularRoom,
|
||||||
dungeon: GameMap,
|
dungeon: GameMap,
|
||||||
floor_number: int,
|
floor_number: int,
|
||||||
) -> None:
|
) -> None:
|
||||||
number_of_monsters = random.randint(
|
number_of_monsters = random.randint(
|
||||||
0, get_max_value_for_floor(max_monsters_by_floor, floor_number)
|
0, get_max_value_for_floor(max_monsters_by_floor, floor_number)
|
||||||
@ -125,14 +122,10 @@ def place_entities(
|
|||||||
)
|
)
|
||||||
|
|
||||||
monsters: List[Entity] = get_entities_at_random(
|
monsters: List[Entity] = get_entities_at_random(
|
||||||
enemy_chances,
|
enemy_chances, number_of_monsters, floor_number
|
||||||
number_of_monsters,
|
|
||||||
floor_number
|
|
||||||
)
|
)
|
||||||
items: List[Entity] = get_entities_at_random(
|
items: List[Entity] = get_entities_at_random(
|
||||||
item_chances,
|
item_chances, number_of_items, floor_number
|
||||||
number_of_items,
|
|
||||||
floor_number
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for entity in monsters + items:
|
for entity in monsters + items:
|
||||||
@ -143,7 +136,9 @@ def place_entities(
|
|||||||
entity.spawn(dungeon, x, y)
|
entity.spawn(dungeon, x, y)
|
||||||
|
|
||||||
|
|
||||||
def tunnel_between(start: Tuple[int, int], end: Tuple[int, int]) -> Iterator[Tuple[int, int]]:
|
def tunnel_between(
|
||||||
|
start: Tuple[int, int], end: Tuple[int, int]
|
||||||
|
) -> Iterator[Tuple[int, int]]:
|
||||||
"""Return an L-shaped tunnel between these two points."""
|
"""Return an L-shaped tunnel between these two points."""
|
||||||
x1, y1 = start
|
x1, y1 = start
|
||||||
x2, y2 = end
|
x2, y2 = end
|
||||||
@ -163,12 +158,12 @@ def tunnel_between(start: Tuple[int, int], end: Tuple[int, int]) -> Iterator[Tup
|
|||||||
|
|
||||||
|
|
||||||
def generate_dungeon(
|
def generate_dungeon(
|
||||||
max_rooms: int,
|
max_rooms: int,
|
||||||
room_min_size: int,
|
room_min_size: int,
|
||||||
room_max_size: int,
|
room_max_size: int,
|
||||||
map_width: int,
|
map_width: int,
|
||||||
map_height: int,
|
map_height: int,
|
||||||
engine: Engine,
|
engine: Engine,
|
||||||
) -> GameMap:
|
) -> GameMap:
|
||||||
"""Generate a new dungeon map."""
|
"""Generate a new dungeon map."""
|
||||||
player = engine.player
|
player = engine.player
|
||||||
|
@ -22,10 +22,10 @@ def get_names_at_location(x: int, y: int, game_map: GameMap) -> str:
|
|||||||
|
|
||||||
|
|
||||||
def render_bar(
|
def render_bar(
|
||||||
console: Console,
|
console: Console,
|
||||||
current_value: int,
|
current_value: int,
|
||||||
maximum_value: int,
|
maximum_value: int,
|
||||||
total_width: int,
|
total_width: int,
|
||||||
) -> None:
|
) -> None:
|
||||||
bar_width = int(float(current_value) / maximum_value * total_width)
|
bar_width = int(float(current_value) / maximum_value * total_width)
|
||||||
|
|
||||||
@ -33,12 +33,7 @@ def render_bar(
|
|||||||
|
|
||||||
if bar_width > 0:
|
if bar_width > 0:
|
||||||
console.draw_rect(
|
console.draw_rect(
|
||||||
x=0,
|
x=0, y=45, width=bar_width, height=1, ch=1, bg=color.bar_filled
|
||||||
y=45,
|
|
||||||
width=bar_width,
|
|
||||||
height=1,
|
|
||||||
ch=1,
|
|
||||||
bg=color.bar_filled
|
|
||||||
)
|
)
|
||||||
|
|
||||||
console.print(
|
console.print(
|
||||||
@ -50,9 +45,7 @@ def render_bar(
|
|||||||
|
|
||||||
|
|
||||||
def render_dungeon_level(
|
def render_dungeon_level(
|
||||||
console: Console,
|
console: Console, dungeon_level: int, location: Tuple[int, int]
|
||||||
dungeon_level: int,
|
|
||||||
location: Tuple[int, int]
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Render the level the player is currently on, at the given location.
|
Render the level the player is currently on, at the given location.
|
||||||
@ -63,10 +56,7 @@ def render_dungeon_level(
|
|||||||
|
|
||||||
|
|
||||||
def render_names_at_mouse_location(
|
def render_names_at_mouse_location(
|
||||||
console: Console,
|
console: Console, x: int, y: int, engine: Engine
|
||||||
x: int,
|
|
||||||
y: int,
|
|
||||||
engine: Engine
|
|
||||||
) -> None:
|
) -> None:
|
||||||
mouse_x, mouse_y = engine.mouse_location
|
mouse_x, mouse_y = engine.mouse_location
|
||||||
|
|
||||||
|
@ -44,8 +44,7 @@ def new_game() -> Engine:
|
|||||||
engine.update_fov()
|
engine.update_fov()
|
||||||
|
|
||||||
engine.message_log.add_message(
|
engine.message_log.add_message(
|
||||||
"Hello and welcome, adventurer, to yet another dungeon!",
|
"Hello and welcome, adventurer, to yet another dungeon!", color.welcome_text
|
||||||
color.welcome_text
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return engine
|
return engine
|
||||||
@ -83,11 +82,9 @@ class MainMenu(input_handlers.BaseEventHandler):
|
|||||||
)
|
)
|
||||||
|
|
||||||
menu_width = 24
|
menu_width = 24
|
||||||
for i, text in enumerate([
|
for i, text in enumerate(
|
||||||
"[N] Play a new game",
|
["[N] Play a new game", "[C] Continue last game", "[Q] Quit"]
|
||||||
"[C] Continue last game",
|
):
|
||||||
"[Q] Quit"
|
|
||||||
]):
|
|
||||||
console.print(
|
console.print(
|
||||||
console.width // 2,
|
console.width // 2,
|
||||||
console.height // 2 - 2 + i,
|
console.height // 2 - 2 + i,
|
||||||
@ -98,7 +95,9 @@ class MainMenu(input_handlers.BaseEventHandler):
|
|||||||
bg_blend=tcod.BKGND_ALPHA(64),
|
bg_blend=tcod.BKGND_ALPHA(64),
|
||||||
)
|
)
|
||||||
|
|
||||||
def ev_keydown(self, event: tcod.event.KeyDown) -> Optional[input_handlers.BaseEventHandler]:
|
def ev_keydown(
|
||||||
|
self, event: tcod.event.KeyDown
|
||||||
|
) -> Optional[input_handlers.BaseEventHandler]:
|
||||||
if event.sym in (tcod.event.K_q, tcod.event.K_ESCAPE):
|
if event.sym in (tcod.event.K_q, tcod.event.K_ESCAPE):
|
||||||
raise SystemExit()
|
raise SystemExit()
|
||||||
elif event.sym == tcod.event.K_c:
|
elif event.sym == tcod.event.K_c:
|
||||||
|
@ -7,7 +7,10 @@ graphic_dt = np.dtype(
|
|||||||
[
|
[
|
||||||
("ch", np.int32), # Unicode codepoint.
|
("ch", np.int32), # Unicode codepoint.
|
||||||
("fg", "3B"), # 3 unsigned bytes, for RGB colors.
|
("fg", "3B"), # 3 unsigned bytes, for RGB colors.
|
||||||
("bg", "3B",)
|
(
|
||||||
|
"bg",
|
||||||
|
"3B",
|
||||||
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -23,11 +26,11 @@ tile_dt = np.dtype(
|
|||||||
|
|
||||||
|
|
||||||
def new_tile(
|
def new_tile(
|
||||||
*, # Enforce the use of keywords, so that parameter order doesn't matter
|
*, # Enforce the use of keywords, so that parameter order doesn't matter
|
||||||
walkable: int,
|
walkable: int,
|
||||||
transparent: int,
|
transparent: int,
|
||||||
dark: Tuple[int, Tuple[int, int, int], Tuple[int, int, int]],
|
dark: Tuple[int, Tuple[int, int, int], Tuple[int, int, int]],
|
||||||
light: Tuple[int, Tuple[int, int, int], Tuple[int, int, int]]
|
light: Tuple[int, Tuple[int, int, int], Tuple[int, int, int]]
|
||||||
) -> np.ndarray:
|
) -> np.ndarray:
|
||||||
"""Helper function for defining individual tile types"""
|
"""Helper function for defining individual tile types"""
|
||||||
return np.array((walkable, transparent, dark, light), dtype=tile_dt)
|
return np.array((walkable, transparent, dark, light), dtype=tile_dt)
|
||||||
|
Loading…
Reference in New Issue
Block a user