-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathengine.py
More file actions
154 lines (128 loc) · 6.21 KB
/
Copy pathengine.py
File metadata and controls
154 lines (128 loc) · 6.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
"""ゲームエンジン。状態・ターン処理・描写を統合する中核。"""
from __future__ import annotations
import colors
from exceptions import GameOver, Impossible
from fov import compute_fov
import entity_factory
import render_functions
from input_handlers import (
CharacterScreenHandler, EventHandler, InventoryActivateHandler,
InventoryDropHandler, MainGameEventHandler, QuitConfirmationHandler,
)
from map_gen import generate_dungeon
from message_log import MessageLog
class Engine:
"""全ゲーム状態とターン処理の中央管理。"""
def __init__(self, player):
self.player = player
self.game_map = None
self.message_log = MessageLog()
self.event_handler: EventHandler = MainGameEventHandler()
self.fov_radius = 8
# 画面レイアウト
self.screen_width = 80
self.screen_height = 24
self.map_height = 17 # メッセージ領域 = screen_height - map_height - 1(HUD)
# ダンジョン生成パラメータ
self.max_rooms = 30
self.room_min_size = 6
self.room_max_size = 10
# ────────────────────────── 視界 ──────────────────────────
def update_fov(self) -> None:
compute_fov(self.game_map, self.player.x, self.player.y, self.fov_radius)
# ────────────────────────── ターン処理 ──────────────────────────
def handle_enemy_turns(self) -> None:
"""プレイヤー以外の全アクターを1ターン行動させる。"""
for entity in list(self.game_map.entities):
if entity.is_alive and entity is not self.player:
try:
entity.ai.perform(self)
except Impossible:
pass
def handle_player_input(self, key: int) -> None:
"""プレイヤーのキー入力を処理し、成功すれば敵ターンへ進む。"""
result = self.event_handler.handle_key(key, self)
if result is None:
return # 無効キー: ターン消費なし
# 状態遷移(メニュー等)
if isinstance(result, EventHandler):
self.event_handler = result
return
# 行動の実行
action = result
self.event_handler = MainGameEventHandler()
try:
action.perform(self)
except Impossible as exc:
self.message_log.add_text(str(exc), colors.UI_WARN)
return
# 行動成功 → 敵のターン → 視界更新(GameOver は呼び出し元へ伝播)
self.handle_enemy_turns()
self.update_fov()
# ────────────────────────── 階層移動 ──────────────────────────
def descend(self) -> None:
"""階段を下りて次の階層へ。"""
new_level = self.game_map.dungeon_level + 1
self._enter_floor(new_level)
self.message_log.add_text(f"第{new_level}階層に降りた。", colors.UI_WARN)
def _enter_floor(self, level: int) -> None:
new_map = generate_dungeon(
max_rooms=self.max_rooms,
room_min_size=self.room_min_size,
room_max_size=self.room_max_size,
map_width=self.screen_width,
map_height=self.map_height,
dungeon_level=level,
)
self.game_map = new_map
self.player.place(*new_map.first_room_center, gamemap=new_map)
entity_factory.place_entities(new_map, level)
self.update_fov()
# ────────────────────────── 死亡処理 ──────────────────────────
def check_and_handle_death(self, entity) -> None:
"""エンティティのHPを確認し、0以下で死亡処理。"""
fighter = getattr(entity, "fighter", None)
if fighter and fighter.hp <= 0 and not getattr(entity, "_dead", False):
self._kill_entity(entity)
def _kill_entity(self, entity) -> None:
was_player = entity is self.player
xp = entity.level.xp_given if getattr(entity, "level", None) else 0
original_name = entity.name
# 死亡処理(フラグで再入を防ぐ)
entity._dead = True
# 死体に変える
entity.char = "%"
entity.color = colors.UI_DIM
entity.blocks_movement = False
entity.render_order = 0
entity.name = f"{original_name}の死体"
entity.ai = None
if was_player:
raise GameOver(victory=False)
self.message_log.add_text(f"{original_name}を倒した!", colors.UI_GOOD)
# プレイヤーに経験値
if self.player.level and xp > 0:
self.player.level.add_xp(xp)
while self.player.level.requires_level_up:
self.player.level.level_up()
self.message_log.add_text(
f"レベル{self.player.level.current_level}になった! "
f"身体能力が向上した。",
colors.UI_TITLE)
# ────────────────────────── 描写 ──────────────────────────
def render(self, stdscr) -> None:
stdscr.erase()
if isinstance(self.event_handler, (InventoryActivateHandler, InventoryDropHandler)):
render_functions.render_inventory_menu(stdscr, self, self.event_handler.title)
stdscr.refresh()
return
if isinstance(self.event_handler, CharacterScreenHandler):
render_functions.render_character_screen(stdscr, self)
stdscr.refresh()
return
render_functions.render_map(stdscr, self)
render_functions.render_hud(stdscr, self)
render_functions.render_messages(stdscr, self)
if isinstance(self.event_handler, QuitConfirmationHandler):
render_functions.render_quit_confirmation(stdscr, self)
stdscr.refresh()