zombie-escape 1.8.0__py3-none-any.whl → 1.10.0__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/colors.py +41 -8
- zombie_escape/entities.py +295 -332
- zombie_escape/entities_constants.py +6 -0
- zombie_escape/gameplay/__init__.py +2 -2
- zombie_escape/gameplay/constants.py +1 -1
- zombie_escape/gameplay/footprints.py +2 -2
- zombie_escape/gameplay/interactions.py +4 -10
- zombie_escape/gameplay/layout.py +38 -4
- zombie_escape/gameplay/movement.py +5 -7
- zombie_escape/gameplay/spawn.py +245 -12
- zombie_escape/gameplay/state.py +17 -16
- zombie_escape/gameplay/survivors.py +5 -4
- zombie_escape/gameplay/utils.py +19 -1
- zombie_escape/locales/ui.en.json +14 -2
- zombie_escape/locales/ui.ja.json +14 -2
- zombie_escape/models.py +52 -7
- zombie_escape/render.py +704 -267
- zombie_escape/render_constants.py +12 -0
- zombie_escape/screens/__init__.py +1 -0
- zombie_escape/screens/game_over.py +4 -4
- zombie_escape/screens/gameplay.py +10 -24
- zombie_escape/stage_constants.py +90 -2
- zombie_escape/world_grid.py +134 -0
- zombie_escape/zombie_escape.py +65 -61
- {zombie_escape-1.8.0.dist-info → zombie_escape-1.10.0.dist-info}/METADATA +8 -1
- zombie_escape-1.10.0.dist-info/RECORD +47 -0
- zombie_escape-1.8.0.dist-info/RECORD +0 -46
- {zombie_escape-1.8.0.dist-info → zombie_escape-1.10.0.dist-info}/WHEEL +0 -0
- {zombie_escape-1.8.0.dist-info → zombie_escape-1.10.0.dist-info}/entry_points.txt +0 -0
- {zombie_escape-1.8.0.dist-info → zombie_escape-1.10.0.dist-info}/licenses/LICENSE.txt +0 -0
|
@@ -17,10 +17,11 @@ from ..entities_constants import (
|
|
|
17
17
|
ZOMBIE_RADIUS,
|
|
18
18
|
)
|
|
19
19
|
from .constants import SURVIVOR_MESSAGE_DURATION_MS, SURVIVOR_SPEED_PENALTY_PER_PASSENGER
|
|
20
|
-
from ..localization import
|
|
20
|
+
from ..localization import translate_dict, translate_list
|
|
21
21
|
from ..models import GameData, ProgressState
|
|
22
22
|
from ..rng import get_rng
|
|
23
|
-
from ..entities import Survivor, Zombie, spritecollideany_walls
|
|
23
|
+
from ..entities import Survivor, Zombie, spritecollideany_walls
|
|
24
|
+
from ..world_grid import WallIndex
|
|
24
25
|
from .spawn import _create_zombie
|
|
25
26
|
from .utils import find_nearby_offscreen_spawn_position, rect_visible_on_screen
|
|
26
27
|
|
|
@@ -286,8 +287,8 @@ def handle_survivor_zombie_collisions(
|
|
|
286
287
|
config,
|
|
287
288
|
start_pos=survivor.rect.center,
|
|
288
289
|
stage=game_data.stage,
|
|
289
|
-
tracker=
|
|
290
|
-
wall_follower=
|
|
290
|
+
tracker=collided_zombie.tracker,
|
|
291
|
+
wall_follower=collided_zombie.wall_follower,
|
|
291
292
|
)
|
|
292
293
|
zombie_group.add(new_zombie)
|
|
293
294
|
game_data.groups.all_sprites.add(new_zombie, layer=1)
|
zombie_escape/gameplay/utils.py
CHANGED
|
@@ -108,7 +108,9 @@ def find_nearby_offscreen_spawn_position(
|
|
|
108
108
|
jitter_x = RNG.uniform(-cell.width * 0.35, cell.width * 0.35)
|
|
109
109
|
jitter_y = RNG.uniform(-cell.height * 0.35, cell.height * 0.35)
|
|
110
110
|
candidate = (int(cell.centerx + jitter_x), int(cell.centery + jitter_y))
|
|
111
|
-
if player is not None and (
|
|
111
|
+
if player is not None and (
|
|
112
|
+
min_distance_sq is not None or max_distance_sq is not None
|
|
113
|
+
):
|
|
112
114
|
dx = candidate[0] - player.x
|
|
113
115
|
dy = candidate[1] - player.y
|
|
114
116
|
dist_sq = dx * dx + dy * dy
|
|
@@ -119,6 +121,22 @@ def find_nearby_offscreen_spawn_position(
|
|
|
119
121
|
if view_rect is not None and view_rect.collidepoint(candidate):
|
|
120
122
|
continue
|
|
121
123
|
return candidate
|
|
124
|
+
if player is not None and (min_distance_sq is not None or max_distance_sq is not None):
|
|
125
|
+
for _ in range(20):
|
|
126
|
+
cell = RNG.choice(walkable_cells)
|
|
127
|
+
center = (cell.centerx, cell.centery)
|
|
128
|
+
if view_rect is not None and view_rect.collidepoint(center):
|
|
129
|
+
continue
|
|
130
|
+
dx = center[0] - player.x
|
|
131
|
+
dy = center[1] - player.y
|
|
132
|
+
dist_sq = dx * dx + dy * dy
|
|
133
|
+
if min_distance_sq is not None and dist_sq < min_distance_sq:
|
|
134
|
+
continue
|
|
135
|
+
if max_distance_sq is not None and dist_sq > max_distance_sq:
|
|
136
|
+
continue
|
|
137
|
+
fallback_x = RNG.uniform(-cell.width * 0.2, cell.width * 0.2)
|
|
138
|
+
fallback_y = RNG.uniform(-cell.height * 0.2, cell.height * 0.2)
|
|
139
|
+
return (int(cell.centerx + fallback_x), int(cell.centery + fallback_y))
|
|
122
140
|
fallback_cell = RNG.choice(walkable_cells)
|
|
123
141
|
fallback_x = RNG.uniform(-fallback_cell.width * 0.35, fallback_cell.width * 0.35)
|
|
124
142
|
fallback_y = RNG.uniform(-fallback_cell.height * 0.35, fallback_cell.height * 0.35)
|
zombie_escape/locales/ui.en.json
CHANGED
|
@@ -107,6 +107,18 @@
|
|
|
107
107
|
"No, no, no!",
|
|
108
108
|
"Please!"
|
|
109
109
|
]
|
|
110
|
+
},
|
|
111
|
+
"stage11": {
|
|
112
|
+
"name": "#11 Don't Look Back!",
|
|
113
|
+
"description": "Left or right. Trust your instinct."
|
|
114
|
+
},
|
|
115
|
+
"stage12": {
|
|
116
|
+
"name": "#12 OVERHEAD HAZARD",
|
|
117
|
+
"description": "An open factory floor. Zombies may fall from above."
|
|
118
|
+
},
|
|
119
|
+
"stage13": {
|
|
120
|
+
"name": "#13 Rescue Buddy 3",
|
|
121
|
+
"description": "Rescue your buddy. Zombies may fall from above."
|
|
110
122
|
}
|
|
111
123
|
},
|
|
112
124
|
"status": {
|
|
@@ -122,7 +134,7 @@
|
|
|
122
134
|
"need_fuel": "Need fuel to drive!",
|
|
123
135
|
"paused": "PAUSED",
|
|
124
136
|
"pause_hint": "P/Start: Resume · ESC/Select: Return to Title",
|
|
125
|
-
"
|
|
137
|
+
"endurance_timer_label": "Until dawn %{time}",
|
|
126
138
|
"time_accel": ">> 4x",
|
|
127
139
|
"time_accel_hint": "Hold Shift/R1: 4x"
|
|
128
140
|
},
|
|
@@ -181,7 +193,7 @@
|
|
|
181
193
|
"prompt": "ESC/SPACE/Select/South: Title · R: Retry",
|
|
182
194
|
"scream": "AAAAHHH!!",
|
|
183
195
|
"survivors_summary": "Evacuated: %{count}",
|
|
184
|
-
"
|
|
196
|
+
"endurance_duration": "Time survived %{time}"
|
|
185
197
|
}
|
|
186
198
|
}
|
|
187
199
|
}
|
zombie_escape/locales/ui.ja.json
CHANGED
|
@@ -107,6 +107,18 @@
|
|
|
107
107
|
"やだ、やだ!",
|
|
108
108
|
"誰かー!"
|
|
109
109
|
]
|
|
110
|
+
},
|
|
111
|
+
"stage11": {
|
|
112
|
+
"name": "#11 振り返るな!",
|
|
113
|
+
"description": "右か左か。直感を信じて。"
|
|
114
|
+
},
|
|
115
|
+
"stage12": {
|
|
116
|
+
"name": "#12 頭上注意",
|
|
117
|
+
"description": "吹き抜けの工場。落ちてくるゾンビあり。"
|
|
118
|
+
},
|
|
119
|
+
"stage13": {
|
|
120
|
+
"name": "#13 相棒を救え 3",
|
|
121
|
+
"description": "はぐれた相棒を救え。ゾンビの落下あり。"
|
|
110
122
|
}
|
|
111
123
|
},
|
|
112
124
|
"status": {
|
|
@@ -122,7 +134,7 @@
|
|
|
122
134
|
"need_fuel": "燃料が必要です!",
|
|
123
135
|
"paused": "一時停止",
|
|
124
136
|
"pause_hint": "P/Start: ゲーム再開 ESC/Select: タイトルに戻る",
|
|
125
|
-
"
|
|
137
|
+
"endurance_timer_label": "夜明けまであと %{time}",
|
|
126
138
|
"time_accel": ">> 4x",
|
|
127
139
|
"time_accel_hint": "Shift/R1押下: 4x"
|
|
128
140
|
},
|
|
@@ -181,7 +193,7 @@
|
|
|
181
193
|
"prompt": "ESC/Space/Select/South: タイトルへ R: 再挑戦",
|
|
182
194
|
"scream": "ぎゃあーーー!!",
|
|
183
195
|
"survivors_summary": "救出人数: %{count}",
|
|
184
|
-
"
|
|
196
|
+
"endurance_duration": "逃げ延びた時間 %{time}"
|
|
185
197
|
}
|
|
186
198
|
}
|
|
187
199
|
}
|
zombie_escape/models.py
CHANGED
|
@@ -9,7 +9,11 @@ import pygame
|
|
|
9
9
|
from pygame import sprite, surface
|
|
10
10
|
|
|
11
11
|
from .entities_constants import ZOMBIE_AGING_DURATION_FRAMES
|
|
12
|
-
from .gameplay_constants import
|
|
12
|
+
from .gameplay_constants import (
|
|
13
|
+
DEFAULT_FLASHLIGHT_SPAWN_COUNT,
|
|
14
|
+
SURVIVOR_SPAWN_RATE,
|
|
15
|
+
ZOMBIE_SPAWN_DELAY_MS,
|
|
16
|
+
)
|
|
13
17
|
from .level_constants import DEFAULT_GRID_COLS, DEFAULT_GRID_ROWS
|
|
14
18
|
from .localization import translate as tr
|
|
15
19
|
|
|
@@ -27,9 +31,42 @@ class LevelLayout:
|
|
|
27
31
|
walkable_cells: list[pygame.Rect]
|
|
28
32
|
outer_wall_cells: set[tuple[int, int]]
|
|
29
33
|
wall_cells: set[tuple[int, int]]
|
|
34
|
+
fall_spawn_cells: set[tuple[int, int]]
|
|
30
35
|
bevel_corners: dict[tuple[int, int], tuple[bool, bool, bool, bool]]
|
|
31
36
|
|
|
32
37
|
|
|
38
|
+
@dataclass
|
|
39
|
+
class FallingZombie:
|
|
40
|
+
"""Represents a zombie falling toward a target position."""
|
|
41
|
+
|
|
42
|
+
start_pos: tuple[int, int]
|
|
43
|
+
target_pos: tuple[int, int]
|
|
44
|
+
started_at_ms: int
|
|
45
|
+
pre_fx_ms: int
|
|
46
|
+
fall_duration_ms: int
|
|
47
|
+
dust_duration_ms: int
|
|
48
|
+
tracker: bool
|
|
49
|
+
wall_follower: bool
|
|
50
|
+
dust_started: bool = False
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass
|
|
54
|
+
class DustRing:
|
|
55
|
+
"""Short-lived dust ring spawned on impact."""
|
|
56
|
+
|
|
57
|
+
pos: tuple[int, int]
|
|
58
|
+
started_at_ms: int
|
|
59
|
+
duration_ms: int
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@dataclass(frozen=True)
|
|
63
|
+
class Footprint:
|
|
64
|
+
"""Tracked player footprint."""
|
|
65
|
+
|
|
66
|
+
pos: tuple[float, float]
|
|
67
|
+
time: int
|
|
68
|
+
|
|
69
|
+
|
|
33
70
|
@dataclass
|
|
34
71
|
class ProgressState:
|
|
35
72
|
"""Game progress/state flags."""
|
|
@@ -40,8 +77,8 @@ class ProgressState:
|
|
|
40
77
|
game_over_at: int | None
|
|
41
78
|
scaled_overview: surface.Surface | None
|
|
42
79
|
overview_created: bool
|
|
43
|
-
footprints: list
|
|
44
|
-
last_footprint_pos: tuple | None
|
|
80
|
+
footprints: list[Footprint]
|
|
81
|
+
last_footprint_pos: tuple[float, float] | None
|
|
45
82
|
elapsed_play_ms: int
|
|
46
83
|
has_fuel: bool
|
|
47
84
|
flashlight_count: int
|
|
@@ -56,14 +93,17 @@ class ProgressState:
|
|
|
56
93
|
survivor_messages: list
|
|
57
94
|
survivor_capacity: int
|
|
58
95
|
seed: int | None
|
|
59
|
-
|
|
60
|
-
|
|
96
|
+
endurance_elapsed_ms: int
|
|
97
|
+
endurance_goal_ms: int
|
|
61
98
|
dawn_ready: bool
|
|
62
99
|
dawn_prompt_at: int | None
|
|
63
100
|
time_accel_active: bool
|
|
64
101
|
last_zombie_spawn_time: int
|
|
65
102
|
dawn_carbonized: bool
|
|
66
103
|
debug_mode: bool
|
|
104
|
+
falling_zombies: list[FallingZombie]
|
|
105
|
+
falling_spawn_carry: int
|
|
106
|
+
dust_rings: list[DustRing]
|
|
67
107
|
|
|
68
108
|
|
|
69
109
|
@dataclass
|
|
@@ -109,14 +149,17 @@ class Stage:
|
|
|
109
149
|
requires_fuel: bool = False
|
|
110
150
|
buddy_required_count: int = 0
|
|
111
151
|
rescue_stage: bool = False
|
|
112
|
-
|
|
113
|
-
|
|
152
|
+
endurance_stage: bool = False
|
|
153
|
+
endurance_goal_ms: int = 0
|
|
114
154
|
fuel_spawn_count: int = 1
|
|
155
|
+
initial_flashlight_count: int = DEFAULT_FLASHLIGHT_SPAWN_COUNT
|
|
115
156
|
survivor_spawn_rate: float = SURVIVOR_SPAWN_RATE
|
|
116
157
|
spawn_interval_ms: int = ZOMBIE_SPAWN_DELAY_MS
|
|
117
158
|
initial_interior_spawn_rate: float = 0.015
|
|
118
159
|
exterior_spawn_weight: float = 1.0
|
|
119
160
|
interior_spawn_weight: float = 0.0
|
|
161
|
+
interior_fall_spawn_weight: float = 0.0
|
|
162
|
+
fall_spawn_zones: list[tuple[int, int, int, int]] = field(default_factory=list)
|
|
120
163
|
zombie_tracker_ratio: float = 0.0
|
|
121
164
|
zombie_wall_follower_ratio: float = 0.0
|
|
122
165
|
zombie_normal_ratio: float = 1.0
|
|
@@ -135,6 +178,8 @@ class Stage:
|
|
|
135
178
|
|
|
136
179
|
__all__ = [
|
|
137
180
|
"LevelLayout",
|
|
181
|
+
"FallingZombie",
|
|
182
|
+
"DustRing",
|
|
138
183
|
"ProgressState",
|
|
139
184
|
"Groups",
|
|
140
185
|
"GameData",
|