zombie-escape 1.14.4__py3-none-any.whl → 1.15.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- zombie_escape/__about__.py +1 -1
- zombie_escape/config.py +1 -0
- zombie_escape/entities.py +126 -199
- zombie_escape/entities_constants.py +11 -1
- zombie_escape/export_images.py +4 -4
- zombie_escape/font_utils.py +47 -0
- zombie_escape/gameplay/__init__.py +2 -1
- zombie_escape/gameplay/constants.py +4 -0
- zombie_escape/gameplay/interactions.py +83 -16
- zombie_escape/gameplay/layout.py +9 -15
- zombie_escape/gameplay/movement.py +45 -29
- zombie_escape/gameplay/spawn.py +15 -29
- zombie_escape/gameplay/state.py +62 -7
- zombie_escape/gameplay/survivors.py +61 -10
- zombie_escape/gameplay/utils.py +33 -0
- zombie_escape/level_blueprints.py +35 -31
- zombie_escape/level_constants.py +2 -2
- zombie_escape/locales/ui.en.json +19 -8
- zombie_escape/locales/ui.ja.json +19 -8
- zombie_escape/localization.py +7 -1
- zombie_escape/models.py +21 -6
- zombie_escape/render/__init__.py +2 -2
- zombie_escape/render/core.py +113 -81
- zombie_escape/render/hud.py +112 -40
- zombie_escape/render/overview.py +93 -2
- zombie_escape/render/shadows.py +2 -2
- zombie_escape/render_constants.py +12 -0
- zombie_escape/screens/__init__.py +6 -189
- zombie_escape/screens/game_over.py +8 -21
- zombie_escape/screens/gameplay.py +71 -26
- zombie_escape/screens/settings.py +114 -43
- zombie_escape/screens/title.py +128 -47
- zombie_escape/stage_constants.py +37 -8
- zombie_escape/windowing.py +508 -0
- zombie_escape/world_grid.py +7 -5
- zombie_escape/zombie_escape.py +26 -13
- {zombie_escape-1.14.4.dist-info → zombie_escape-1.15.2.dist-info}/METADATA +24 -24
- zombie_escape-1.15.2.dist-info/RECORD +54 -0
- zombie_escape-1.14.4.dist-info/RECORD +0 -53
- {zombie_escape-1.14.4.dist-info → zombie_escape-1.15.2.dist-info}/WHEEL +0 -0
- {zombie_escape-1.14.4.dist-info → zombie_escape-1.15.2.dist-info}/entry_points.txt +0 -0
- {zombie_escape-1.14.4.dist-info → zombie_escape-1.15.2.dist-info}/licenses/LICENSE.txt +0 -0
zombie_escape/locales/ui.ja.json
CHANGED
|
@@ -9,14 +9,15 @@
|
|
|
9
9
|
"fonts": {
|
|
10
10
|
"primary": {
|
|
11
11
|
"resource": "assets/fonts/misaki_gothic.ttf",
|
|
12
|
-
"scale": 0.7
|
|
12
|
+
"scale": 0.7,
|
|
13
|
+
"line_height_scale": 1.4
|
|
13
14
|
}
|
|
14
15
|
},
|
|
15
16
|
"menu": {
|
|
16
17
|
"settings": "設定",
|
|
17
18
|
"quit": "終了",
|
|
18
19
|
"locked_suffix": "[Locked]",
|
|
19
|
-
"window_hint": "[
|
|
20
|
+
"window_hint": "[キーで1段階縮小(400x300)、]キーで1段階拡大。\nF: フルスクリーン切替。",
|
|
20
21
|
"seed_label": "シード: %{value}",
|
|
21
22
|
"seed_hint": "数字キーで入力、BSでクリア",
|
|
22
23
|
"seed_empty": "(自動)",
|
|
@@ -24,7 +25,7 @@
|
|
|
24
25
|
"stage_select": "ステージ",
|
|
25
26
|
"resources": "リソース"
|
|
26
27
|
},
|
|
27
|
-
"readme": "README
|
|
28
|
+
"readme": "README/ライセンス",
|
|
28
29
|
"readme_stage6": "ステージ6以降の説明を開く",
|
|
29
30
|
"hints": {
|
|
30
31
|
"navigate": "上下: 項目選択",
|
|
@@ -34,7 +35,7 @@
|
|
|
34
35
|
"option_help": {
|
|
35
36
|
"settings": "設定画面を開いて言語や補助オプションを変更します。",
|
|
36
37
|
"quit": "ゲームを終了します。",
|
|
37
|
-
"readme": "GitHub の README
|
|
38
|
+
"readme": "GitHub の README ページをブラウザで開きます。ライセンス情報もここから確認できます",
|
|
38
39
|
"readme_stage6": "ステージ6以降の説明ページをブラウザで開きます。"
|
|
39
40
|
}
|
|
40
41
|
},
|
|
@@ -67,7 +68,8 @@
|
|
|
67
68
|
},
|
|
68
69
|
"stage5": {
|
|
69
70
|
"name": "#5 持久戦",
|
|
70
|
-
"description": "燃料なし。20分耐え、夜明けになったら徒歩で脱出せよ。"
|
|
71
|
+
"description": "燃料なし。20分耐え、夜明けになったら徒歩で脱出せよ。",
|
|
72
|
+
"intro": "(屋内に燃料はなさそうだ...\n夜明けまで耐えるしかないか。)"
|
|
71
73
|
},
|
|
72
74
|
"stage6": {
|
|
73
75
|
"name": "#6 追ってくる影",
|
|
@@ -94,6 +96,7 @@
|
|
|
94
96
|
"stage10": {
|
|
95
97
|
"name": "#10 感染爆発",
|
|
96
98
|
"description": "建物に避難した生存者の中にゾンビが紛れ込んでいた。",
|
|
99
|
+
"intro": "(広いフロアに避難者が密集している\n...嫌な予感がする。)",
|
|
97
100
|
"survivor_conversion_messages": [
|
|
98
101
|
"痛いぃ!",
|
|
99
102
|
"無理!無理!",
|
|
@@ -128,7 +131,8 @@
|
|
|
128
131
|
},
|
|
129
132
|
"stage15": {
|
|
130
133
|
"name": "#15 分断ライン",
|
|
131
|
-
"description": "建物中央を分断する危険地帯。横断には注意。"
|
|
134
|
+
"description": "建物中央を分断する危険地帯。横断には注意。",
|
|
135
|
+
"intro": "天井付近にメンテナンスハッチが\nぼんやりと見えている。"
|
|
132
136
|
},
|
|
133
137
|
"stage16": {
|
|
134
138
|
"name": "#16 奈落",
|
|
@@ -145,6 +149,11 @@
|
|
|
145
149
|
"stage19": {
|
|
146
150
|
"name": "#19 回廊",
|
|
147
151
|
"description": "細い通路が連なるフロア。"
|
|
152
|
+
},
|
|
153
|
+
"stage20": {
|
|
154
|
+
"name": "#20 救出要請",
|
|
155
|
+
"description": "合流して車で脱出せよ。",
|
|
156
|
+
"intro": "「... \nみんな中にいるはずだ。\n合流してくれ。」"
|
|
148
157
|
}
|
|
149
158
|
},
|
|
150
159
|
"status": {
|
|
@@ -173,9 +182,9 @@
|
|
|
173
182
|
"find_fuel": "燃料を探す",
|
|
174
183
|
"find_car": "車を探す",
|
|
175
184
|
"escape": "建物から脱出する",
|
|
185
|
+
"merge_buddy_single": "相棒と合流する",
|
|
186
|
+
"merge_buddy_multi": "同僚と合流する(合流済: %{count}/%{limit}人)",
|
|
176
187
|
"pickup_buddy": "相棒を救出する",
|
|
177
|
-
"find_buddy": "相棒を探す",
|
|
178
|
-
"escape_with_buddy": "相棒を車に乗せて脱出する",
|
|
179
188
|
"board_buddy": "相棒を車に乗せる",
|
|
180
189
|
"buddy_onboard": "相棒乗車中: %{count}",
|
|
181
190
|
"escape_with_survivors": "生存者を車に乗せて脱出する",
|
|
@@ -188,6 +197,7 @@
|
|
|
188
197
|
"menu": "メニュー",
|
|
189
198
|
"localization": "言語設定",
|
|
190
199
|
"player_support": "サポート",
|
|
200
|
+
"visual": "視覚",
|
|
191
201
|
"tougher_enemies": "強敵"
|
|
192
202
|
},
|
|
193
203
|
"rows": {
|
|
@@ -195,6 +205,7 @@
|
|
|
195
205
|
"language": "テキスト言語",
|
|
196
206
|
"footprints": "足跡",
|
|
197
207
|
"car_hint": "車のヒント",
|
|
208
|
+
"shadows": "影の表示",
|
|
198
209
|
"fast_zombies": "高速ゾンビ",
|
|
199
210
|
"steel_beams": "鉄筋"
|
|
200
211
|
},
|
zombie_escape/localization.py
CHANGED
|
@@ -27,6 +27,7 @@ class LanguageOption:
|
|
|
27
27
|
class FontSettings:
|
|
28
28
|
resource: str | None
|
|
29
29
|
scale: float = 1.0
|
|
30
|
+
line_height_scale: float = 1.0
|
|
30
31
|
|
|
31
32
|
def scaled_size(self, base_size: int) -> int:
|
|
32
33
|
return max(1, round(base_size * self.scale))
|
|
@@ -122,11 +123,16 @@ def get_font_settings(*, name: str = "primary") -> FontSettings:
|
|
|
122
123
|
data = fonts.get(name, {}) if isinstance(fonts, dict) else {}
|
|
123
124
|
resource = data.get("resource") or DEFAULT_FONT_RESOURCE
|
|
124
125
|
scale_raw = data.get("scale", DEFAULT_FONT_SCALE)
|
|
126
|
+
line_height_raw = data.get("line_height_scale", 1.0)
|
|
125
127
|
try:
|
|
126
128
|
scale = float(scale_raw)
|
|
127
129
|
except (TypeError, ValueError):
|
|
128
130
|
scale = DEFAULT_FONT_SCALE
|
|
129
|
-
|
|
131
|
+
try:
|
|
132
|
+
line_height_scale = float(line_height_raw)
|
|
133
|
+
except (TypeError, ValueError):
|
|
134
|
+
line_height_scale = 1.0
|
|
135
|
+
return FontSettings(resource=resource, scale=scale, line_height_scale=line_height_scale)
|
|
130
136
|
|
|
131
137
|
|
|
132
138
|
def _qualify_key(key: str) -> str:
|
zombie_escape/models.py
CHANGED
|
@@ -20,6 +20,7 @@ from .localization import translate as tr
|
|
|
20
20
|
|
|
21
21
|
if TYPE_CHECKING: # pragma: no cover - typing-only imports
|
|
22
22
|
from .entities import Camera, Car, Flashlight, FuelCan, Player, Shoes
|
|
23
|
+
from .level_blueprints import Blueprint
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
@dataclass
|
|
@@ -27,6 +28,8 @@ class LevelLayout:
|
|
|
27
28
|
"""Container for level layout rectangles and cell sets."""
|
|
28
29
|
|
|
29
30
|
field_rect: pygame.Rect
|
|
31
|
+
grid_cols: int
|
|
32
|
+
grid_rows: int
|
|
30
33
|
outside_cells: set[tuple[int, int]]
|
|
31
34
|
walkable_cells: list[tuple[int, int]]
|
|
32
35
|
outer_wall_cells: set[tuple[int, int]]
|
|
@@ -77,7 +80,8 @@ class ProgressState:
|
|
|
77
80
|
|
|
78
81
|
game_over: bool
|
|
79
82
|
game_won: bool
|
|
80
|
-
|
|
83
|
+
timed_message: "TimedMessage | None"
|
|
84
|
+
fade_in_started_at_ms: int | None
|
|
81
85
|
game_over_at: int | None
|
|
82
86
|
scaled_overview: surface.Surface | None
|
|
83
87
|
overview_created: bool
|
|
@@ -91,9 +95,9 @@ class ProgressState:
|
|
|
91
95
|
ambient_palette_key: str
|
|
92
96
|
hint_expires_at: int
|
|
93
97
|
hint_target_type: str | None
|
|
94
|
-
fuel_message_until: int
|
|
95
98
|
buddy_rescued: int
|
|
96
99
|
buddy_onboard: int
|
|
100
|
+
buddy_merged_count: int
|
|
97
101
|
survivors_onboard: int
|
|
98
102
|
survivors_rescued: int
|
|
99
103
|
survivor_messages: list
|
|
@@ -115,6 +119,17 @@ class ProgressState:
|
|
|
115
119
|
player_wall_target_ttl: int
|
|
116
120
|
|
|
117
121
|
|
|
122
|
+
@dataclass(frozen=True)
|
|
123
|
+
class TimedMessage:
|
|
124
|
+
"""Timed HUD message with styling and behavior."""
|
|
125
|
+
|
|
126
|
+
text: str
|
|
127
|
+
expires_at_ms: int
|
|
128
|
+
clear_on_input: bool
|
|
129
|
+
color: tuple[int, int, int] | None
|
|
130
|
+
align: str
|
|
131
|
+
|
|
132
|
+
|
|
118
133
|
@dataclass
|
|
119
134
|
class Groups:
|
|
120
135
|
"""Sprite groups container."""
|
|
@@ -136,8 +151,7 @@ class GameData:
|
|
|
136
151
|
fog: dict
|
|
137
152
|
stage: Stage
|
|
138
153
|
cell_size: int
|
|
139
|
-
|
|
140
|
-
level_height: int
|
|
154
|
+
blueprint: Blueprint | None = None
|
|
141
155
|
fuel: FuelCan | None = None
|
|
142
156
|
flashlights: list[Flashlight] | None = None
|
|
143
157
|
shoes: list[Shoes] | None = None
|
|
@@ -154,9 +168,10 @@ class Stage:
|
|
|
154
168
|
name_key: str
|
|
155
169
|
description_key: str
|
|
156
170
|
available: bool = True
|
|
171
|
+
intro_key: str | None = None
|
|
157
172
|
|
|
158
173
|
# Map layout
|
|
159
|
-
|
|
174
|
+
cell_size: int = 50
|
|
160
175
|
grid_cols: int = DEFAULT_GRID_COLS
|
|
161
176
|
grid_rows: int = DEFAULT_GRID_ROWS
|
|
162
177
|
wall_algorithm: str = "default"
|
|
@@ -180,7 +195,7 @@ class Stage:
|
|
|
180
195
|
waiting_car_target_count: int = 1
|
|
181
196
|
|
|
182
197
|
# Zombie spawning/aging
|
|
183
|
-
# - initial_interior_spawn_rate: fraction of interior floor
|
|
198
|
+
# - initial_interior_spawn_rate: fraction of interior floor cells to seed.
|
|
184
199
|
# - spawn weights: pick area by weight (normalized).
|
|
185
200
|
# - zombie ratios: pick variant by weight (normalized).
|
|
186
201
|
spawn_interval_ms: int = ZOMBIE_SPAWN_DELAY_MS
|
zombie_escape/render/__init__.py
CHANGED
zombie_escape/render/core.py
CHANGED
|
@@ -11,7 +11,6 @@ from pygame import sprite, surface
|
|
|
11
11
|
from ..colors import (
|
|
12
12
|
FOOTPRINT_COLOR,
|
|
13
13
|
LIGHT_GRAY,
|
|
14
|
-
ORANGE,
|
|
15
14
|
WHITE,
|
|
16
15
|
YELLOW,
|
|
17
16
|
get_environment_palette,
|
|
@@ -21,7 +20,7 @@ from ..entities import (
|
|
|
21
20
|
Player,
|
|
22
21
|
)
|
|
23
22
|
from ..entities_constants import INTERNAL_WALL_BEVEL_DEPTH, ZOMBIE_RADIUS
|
|
24
|
-
from ..font_utils import load_font
|
|
23
|
+
from ..font_utils import load_font, render_text_scaled
|
|
25
24
|
from ..gameplay_constants import DEFAULT_FLASHLIGHT_SPAWN_COUNT
|
|
26
25
|
from ..localization import get_font_settings
|
|
27
26
|
from ..localization import translate as tr
|
|
@@ -32,6 +31,7 @@ from ..render_constants import (
|
|
|
32
31
|
FALLING_DUST_COLOR,
|
|
33
32
|
FALLING_WHIRLWIND_COLOR,
|
|
34
33
|
FALLING_ZOMBIE_COLOR,
|
|
34
|
+
GAMEPLAY_FONT_SIZE,
|
|
35
35
|
PITFALL_ABYSS_COLOR,
|
|
36
36
|
PITFALL_EDGE_DEPTH_OFFSET,
|
|
37
37
|
PITFALL_EDGE_METAL_COLOR,
|
|
@@ -39,11 +39,13 @@ from ..render_constants import (
|
|
|
39
39
|
PITFALL_EDGE_STRIPE_SPACING,
|
|
40
40
|
PLAYER_SHADOW_ALPHA_MULT,
|
|
41
41
|
PLAYER_SHADOW_RADIUS_MULT,
|
|
42
|
+
FADE_IN_DURATION_MS,
|
|
42
43
|
)
|
|
43
44
|
from .hud import (
|
|
44
45
|
_build_objective_lines,
|
|
45
46
|
_draw_endurance_timer,
|
|
46
47
|
_draw_hint_indicator,
|
|
48
|
+
_draw_timed_message,
|
|
47
49
|
_draw_inventory_icons,
|
|
48
50
|
_draw_objective,
|
|
49
51
|
_draw_status_bar,
|
|
@@ -65,11 +67,19 @@ def show_message(
|
|
|
65
67
|
size: int,
|
|
66
68
|
color: tuple[int, int, int],
|
|
67
69
|
position: tuple[int, int],
|
|
70
|
+
*,
|
|
71
|
+
scale_factor: int = 1,
|
|
68
72
|
) -> None:
|
|
69
73
|
try:
|
|
70
74
|
font_settings = get_font_settings()
|
|
71
|
-
|
|
72
|
-
text_surface =
|
|
75
|
+
scaled_size = font_settings.scaled_size(size)
|
|
76
|
+
text_surface = render_text_scaled(
|
|
77
|
+
font_settings.resource,
|
|
78
|
+
scaled_size,
|
|
79
|
+
text,
|
|
80
|
+
color,
|
|
81
|
+
scale_factor=scale_factor,
|
|
82
|
+
)
|
|
73
83
|
text_rect = text_surface.get_rect(center=position)
|
|
74
84
|
|
|
75
85
|
# Add a semi-transparent background rectangle for better visibility
|
|
@@ -84,6 +94,23 @@ def show_message(
|
|
|
84
94
|
print(f"Error rendering font or surface: {e}")
|
|
85
95
|
|
|
86
96
|
|
|
97
|
+
def _draw_fade_in_overlay(screen: surface.Surface, state: GameData | Any) -> None:
|
|
98
|
+
started_at = getattr(state, "fade_in_started_at_ms", None)
|
|
99
|
+
if started_at is None:
|
|
100
|
+
return
|
|
101
|
+
elapsed = max(0, int(state.elapsed_play_ms) - int(started_at))
|
|
102
|
+
if elapsed <= 0:
|
|
103
|
+
alpha = 255
|
|
104
|
+
else:
|
|
105
|
+
alpha = int(255 * max(0.0, 1.0 - (elapsed / FADE_IN_DURATION_MS)))
|
|
106
|
+
if alpha <= 0:
|
|
107
|
+
return
|
|
108
|
+
overlay = pygame.Surface(screen.get_size())
|
|
109
|
+
overlay.fill((0, 0, 0))
|
|
110
|
+
overlay.set_alpha(alpha)
|
|
111
|
+
screen.blit(overlay, (0, 0))
|
|
112
|
+
|
|
113
|
+
|
|
87
114
|
def wrap_long_segment(segment: str, font: pygame.font.Font, max_width: int) -> list[str]:
|
|
88
115
|
lines: list[str] = []
|
|
89
116
|
current = ""
|
|
@@ -137,16 +164,30 @@ def blit_wrapped_text(
|
|
|
137
164
|
color: tuple[int, int, int],
|
|
138
165
|
topleft: tuple[int, int],
|
|
139
166
|
max_width: int,
|
|
167
|
+
*,
|
|
168
|
+
resource: str | None = None,
|
|
169
|
+
size: int | None = None,
|
|
170
|
+
scale_factor: int = 1,
|
|
171
|
+
line_height_scale: float = 1.0,
|
|
140
172
|
) -> None:
|
|
141
173
|
"""Render text with simple wrapping constrained to max_width."""
|
|
142
174
|
|
|
143
175
|
x, y = topleft
|
|
144
|
-
line_height = font.get_linesize()
|
|
176
|
+
line_height = int(round(font.get_linesize() * line_height_scale))
|
|
145
177
|
for line in wrap_text(text, font, max_width):
|
|
146
178
|
if not line:
|
|
147
179
|
y += line_height
|
|
148
180
|
continue
|
|
149
|
-
|
|
181
|
+
if resource is not None and size is not None:
|
|
182
|
+
rendered = render_text_scaled(
|
|
183
|
+
resource,
|
|
184
|
+
size,
|
|
185
|
+
line,
|
|
186
|
+
color,
|
|
187
|
+
scale_factor=scale_factor,
|
|
188
|
+
)
|
|
189
|
+
else:
|
|
190
|
+
rendered = font.render(line, False, color)
|
|
150
191
|
target.blit(rendered, (x, y))
|
|
151
192
|
y += line_height
|
|
152
193
|
|
|
@@ -224,14 +265,14 @@ def draw_pause_overlay(screen: pygame.Surface) -> None:
|
|
|
224
265
|
show_message(
|
|
225
266
|
screen,
|
|
226
267
|
tr("hud.paused"),
|
|
227
|
-
|
|
268
|
+
GAMEPLAY_FONT_SIZE,
|
|
228
269
|
WHITE,
|
|
229
270
|
(screen_width // 2, 28),
|
|
230
271
|
)
|
|
231
272
|
show_message(
|
|
232
273
|
screen,
|
|
233
274
|
tr("hud.pause_hint"),
|
|
234
|
-
|
|
275
|
+
GAMEPLAY_FONT_SIZE,
|
|
235
276
|
LIGHT_GRAY,
|
|
236
277
|
(screen_width // 2, screen_height // 2 + 70),
|
|
237
278
|
)
|
|
@@ -291,7 +332,7 @@ def _get_hatch_pattern(
|
|
|
291
332
|
*,
|
|
292
333
|
color: tuple[int, int, int, int] | None = None,
|
|
293
334
|
) -> surface.Surface:
|
|
294
|
-
"""Return cached dot hatch
|
|
335
|
+
"""Return cached dot hatch cell surface (Bayer-ordered, optionally chunky)."""
|
|
295
336
|
cache = fog_data.setdefault("hatch_patterns", {})
|
|
296
337
|
key = (thickness, color)
|
|
297
338
|
if key in cache:
|
|
@@ -491,10 +532,11 @@ def _draw_falling_fx(
|
|
|
491
532
|
falling_zombies: list[FallingZombie],
|
|
492
533
|
flashlight_count: int,
|
|
493
534
|
dust_rings: list[DustRing],
|
|
535
|
+
now_ms: int,
|
|
494
536
|
) -> None:
|
|
495
537
|
if not falling_zombies and not dust_rings:
|
|
496
538
|
return
|
|
497
|
-
now =
|
|
539
|
+
now = now_ms
|
|
498
540
|
for fall in falling_zombies:
|
|
499
541
|
pre_fx_ms = max(0, fall.pre_fx_ms)
|
|
500
542
|
fall_duration_ms = max(1, fall.fall_duration_ms)
|
|
@@ -719,6 +761,7 @@ def _draw_entities(
|
|
|
719
761
|
player: Player,
|
|
720
762
|
*,
|
|
721
763
|
has_fuel: bool,
|
|
764
|
+
show_fuel_indicator: bool,
|
|
722
765
|
) -> pygame.Rect:
|
|
723
766
|
screen_rect_inflated = screen.get_rect().inflate(100, 100)
|
|
724
767
|
player_screen_rect: pygame.Rect | None = None
|
|
@@ -728,12 +771,13 @@ def _draw_entities(
|
|
|
728
771
|
screen.blit(entity.image, sprite_screen_rect)
|
|
729
772
|
if entity is player:
|
|
730
773
|
player_screen_rect = sprite_screen_rect
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
774
|
+
if show_fuel_indicator:
|
|
775
|
+
_draw_fuel_indicator(
|
|
776
|
+
screen,
|
|
777
|
+
player_screen_rect,
|
|
778
|
+
has_fuel=has_fuel,
|
|
779
|
+
in_car=player.in_car,
|
|
780
|
+
)
|
|
737
781
|
return player_screen_rect or camera.apply_rect(player.rect)
|
|
738
782
|
|
|
739
783
|
|
|
@@ -797,25 +841,6 @@ def _draw_fog_of_war(
|
|
|
797
841
|
)
|
|
798
842
|
|
|
799
843
|
|
|
800
|
-
def _draw_need_fuel_message(
|
|
801
|
-
screen: surface.Surface,
|
|
802
|
-
assets: RenderAssets,
|
|
803
|
-
*,
|
|
804
|
-
has_fuel: bool,
|
|
805
|
-
fuel_message_until: int,
|
|
806
|
-
elapsed_play_ms: int,
|
|
807
|
-
) -> None:
|
|
808
|
-
if has_fuel or fuel_message_until <= elapsed_play_ms:
|
|
809
|
-
return
|
|
810
|
-
show_message(
|
|
811
|
-
screen,
|
|
812
|
-
tr("hud.need_fuel"),
|
|
813
|
-
18,
|
|
814
|
-
ORANGE,
|
|
815
|
-
(assets.screen_width // 2, assets.screen_height // 2),
|
|
816
|
-
)
|
|
817
|
-
|
|
818
|
-
|
|
819
844
|
def draw(
|
|
820
845
|
assets: RenderAssets,
|
|
821
846
|
screen: surface.Surface,
|
|
@@ -857,54 +882,58 @@ def draw(
|
|
|
857
882
|
game_data.layout.fall_spawn_cells,
|
|
858
883
|
game_data.layout.pitfall_cells,
|
|
859
884
|
)
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
shadow_layer,
|
|
864
|
-
|
|
865
|
-
wall_cells=game_data.layout.wall_cells,
|
|
866
|
-
wall_group=game_data.groups.wall_group,
|
|
867
|
-
outer_wall_cells=game_data.layout.outer_wall_cells,
|
|
868
|
-
cell_size=game_data.cell_size,
|
|
869
|
-
light_source_pos=(None if (stage and stage.endurance_stage and state.dawn_ready) else fov_target.rect.center)
|
|
870
|
-
if fov_target
|
|
871
|
-
else None,
|
|
872
|
-
)
|
|
873
|
-
drew_shadow |= _draw_entity_shadows(
|
|
874
|
-
shadow_layer,
|
|
875
|
-
camera,
|
|
876
|
-
all_sprites,
|
|
877
|
-
light_source_pos=fov_target.rect.center if fov_target else None,
|
|
878
|
-
exclude_car=active_car if player.in_car else None,
|
|
879
|
-
outside_cells=outside_cells,
|
|
880
|
-
cell_size=game_data.cell_size,
|
|
881
|
-
)
|
|
882
|
-
player_shadow_alpha = max(1, int(ENTITY_SHADOW_ALPHA * PLAYER_SHADOW_ALPHA_MULT))
|
|
883
|
-
player_shadow_radius = int(ZOMBIE_RADIUS * PLAYER_SHADOW_RADIUS_MULT)
|
|
884
|
-
if player.in_car:
|
|
885
|
-
drew_shadow |= _draw_single_entity_shadow(
|
|
885
|
+
shadows_enabled = config.get("visual", {}).get("shadows", {}).get("enabled", True)
|
|
886
|
+
if shadows_enabled:
|
|
887
|
+
shadow_layer = _get_shadow_layer(screen.get_size())
|
|
888
|
+
shadow_layer.fill((0, 0, 0, 0))
|
|
889
|
+
drew_shadow = _draw_wall_shadows(
|
|
886
890
|
shadow_layer,
|
|
887
891
|
camera,
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
892
|
+
wall_cells=game_data.layout.wall_cells,
|
|
893
|
+
wall_group=game_data.groups.wall_group,
|
|
894
|
+
outer_wall_cells=game_data.layout.outer_wall_cells,
|
|
891
895
|
cell_size=game_data.cell_size,
|
|
892
|
-
|
|
893
|
-
|
|
896
|
+
light_source_pos=(
|
|
897
|
+
None if (stage and stage.endurance_stage and state.dawn_ready) else fov_target.rect.center
|
|
898
|
+
)
|
|
899
|
+
if fov_target
|
|
900
|
+
else None,
|
|
894
901
|
)
|
|
895
|
-
|
|
896
|
-
drew_shadow |= _draw_single_entity_shadow(
|
|
902
|
+
drew_shadow |= _draw_entity_shadows(
|
|
897
903
|
shadow_layer,
|
|
898
904
|
camera,
|
|
899
|
-
|
|
905
|
+
all_sprites,
|
|
900
906
|
light_source_pos=fov_target.rect.center if fov_target else None,
|
|
907
|
+
exclude_car=active_car if player.in_car else None,
|
|
901
908
|
outside_cells=outside_cells,
|
|
902
909
|
cell_size=game_data.cell_size,
|
|
903
|
-
shadow_radius=player_shadow_radius,
|
|
904
|
-
alpha=player_shadow_alpha,
|
|
905
910
|
)
|
|
906
|
-
|
|
907
|
-
|
|
911
|
+
player_shadow_alpha = max(1, int(ENTITY_SHADOW_ALPHA * PLAYER_SHADOW_ALPHA_MULT))
|
|
912
|
+
player_shadow_radius = int(ZOMBIE_RADIUS * PLAYER_SHADOW_RADIUS_MULT)
|
|
913
|
+
if player.in_car:
|
|
914
|
+
drew_shadow |= _draw_single_entity_shadow(
|
|
915
|
+
shadow_layer,
|
|
916
|
+
camera,
|
|
917
|
+
entity=active_car,
|
|
918
|
+
light_source_pos=fov_target.rect.center if fov_target else None,
|
|
919
|
+
outside_cells=outside_cells,
|
|
920
|
+
cell_size=game_data.cell_size,
|
|
921
|
+
shadow_radius=player_shadow_radius,
|
|
922
|
+
alpha=player_shadow_alpha,
|
|
923
|
+
)
|
|
924
|
+
else:
|
|
925
|
+
drew_shadow |= _draw_single_entity_shadow(
|
|
926
|
+
shadow_layer,
|
|
927
|
+
camera,
|
|
928
|
+
entity=player,
|
|
929
|
+
light_source_pos=fov_target.rect.center if fov_target else None,
|
|
930
|
+
outside_cells=outside_cells,
|
|
931
|
+
cell_size=game_data.cell_size,
|
|
932
|
+
shadow_radius=player_shadow_radius,
|
|
933
|
+
alpha=player_shadow_alpha,
|
|
934
|
+
)
|
|
935
|
+
if drew_shadow:
|
|
936
|
+
screen.blit(shadow_layer, (0, 0))
|
|
908
937
|
_draw_footprints(
|
|
909
938
|
screen,
|
|
910
939
|
camera,
|
|
@@ -918,6 +947,7 @@ def draw(
|
|
|
918
947
|
all_sprites,
|
|
919
948
|
player,
|
|
920
949
|
has_fuel=has_fuel,
|
|
950
|
+
show_fuel_indicator=not (stage and stage.endurance_stage),
|
|
921
951
|
)
|
|
922
952
|
|
|
923
953
|
_draw_falling_fx(
|
|
@@ -926,6 +956,7 @@ def draw(
|
|
|
926
956
|
state.falling_zombies,
|
|
927
957
|
state.flashlight_count,
|
|
928
958
|
state.dust_rings,
|
|
959
|
+
state.elapsed_play_ms,
|
|
929
960
|
)
|
|
930
961
|
|
|
931
962
|
_draw_hint_indicator(
|
|
@@ -948,13 +979,6 @@ def draw(
|
|
|
948
979
|
flashlight_count=flashlight_count,
|
|
949
980
|
dawn_ready=state.dawn_ready,
|
|
950
981
|
)
|
|
951
|
-
_draw_need_fuel_message(
|
|
952
|
-
screen,
|
|
953
|
-
assets,
|
|
954
|
-
has_fuel=has_fuel,
|
|
955
|
-
fuel_message_until=state.fuel_message_until,
|
|
956
|
-
elapsed_play_ms=state.elapsed_play_ms,
|
|
957
|
-
)
|
|
958
982
|
|
|
959
983
|
objective_lines = _build_objective_lines(
|
|
960
984
|
stage=stage,
|
|
@@ -962,7 +986,7 @@ def draw(
|
|
|
962
986
|
player=player,
|
|
963
987
|
active_car=active_car,
|
|
964
988
|
has_fuel=has_fuel,
|
|
965
|
-
|
|
989
|
+
buddy_merged_count=state.buddy_merged_count,
|
|
966
990
|
buddy_required=stage.buddy_required_count if stage else 0,
|
|
967
991
|
survivors_onboard=state.survivors_onboard,
|
|
968
992
|
)
|
|
@@ -990,3 +1014,11 @@ def draw(
|
|
|
990
1014
|
show_fps=state.show_fps,
|
|
991
1015
|
fps=fps,
|
|
992
1016
|
)
|
|
1017
|
+
|
|
1018
|
+
_draw_fade_in_overlay(screen, state)
|
|
1019
|
+
_draw_timed_message(
|
|
1020
|
+
screen,
|
|
1021
|
+
assets,
|
|
1022
|
+
message=state.timed_message,
|
|
1023
|
+
elapsed_play_ms=state.elapsed_play_ms,
|
|
1024
|
+
)
|