crimsonland 0.1.0.dev15__py3-none-any.whl → 0.1.0.dev16__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.
- crimson/cli.py +61 -0
- crimson/creatures/damage.py +111 -36
- crimson/creatures/runtime.py +246 -156
- crimson/creatures/spawn.py +7 -3
- crimson/demo.py +38 -45
- crimson/effects.py +7 -13
- crimson/frontend/high_scores_layout.py +81 -0
- crimson/frontend/panels/base.py +4 -1
- crimson/frontend/panels/controls.py +0 -15
- crimson/frontend/panels/databases.py +291 -3
- crimson/frontend/panels/mods.py +0 -15
- crimson/frontend/panels/play_game.py +0 -16
- crimson/game.py +441 -1
- crimson/gameplay.py +905 -569
- crimson/modes/base_gameplay_mode.py +33 -12
- crimson/modes/components/__init__.py +2 -0
- crimson/modes/components/highscore_record_builder.py +58 -0
- crimson/modes/components/perk_menu_controller.py +325 -0
- crimson/modes/quest_mode.py +58 -273
- crimson/modes/rush_mode.py +12 -43
- crimson/modes/survival_mode.py +71 -328
- crimson/modes/tutorial_mode.py +46 -247
- crimson/modes/typo_mode.py +11 -38
- crimson/oracle.py +396 -0
- crimson/perks.py +5 -2
- crimson/player_damage.py +94 -37
- crimson/projectiles.py +539 -320
- crimson/render/projectile_draw_registry.py +637 -0
- crimson/render/projectile_render_registry.py +110 -0
- crimson/render/secondary_projectile_draw_registry.py +206 -0
- crimson/render/world_renderer.py +58 -707
- crimson/sim/world_state.py +118 -61
- crimson/typo/spawns.py +5 -12
- crimson/ui/demo_trial_overlay.py +3 -11
- crimson/ui/formatting.py +24 -0
- crimson/ui/game_over.py +12 -58
- crimson/ui/hud.py +72 -39
- crimson/ui/layout.py +20 -0
- crimson/ui/perk_menu.py +9 -34
- crimson/ui/quest_results.py +12 -64
- crimson/ui/text_input.py +20 -0
- crimson/views/_ui_helpers.py +27 -0
- crimson/views/aim_debug.py +15 -32
- crimson/views/animations.py +18 -28
- crimson/views/arsenal_debug.py +22 -32
- crimson/views/bonuses.py +23 -36
- crimson/views/camera_debug.py +16 -29
- crimson/views/camera_shake.py +9 -33
- crimson/views/corpse_stamp_debug.py +13 -21
- crimson/views/decals_debug.py +36 -23
- crimson/views/fonts.py +8 -25
- crimson/views/ground.py +4 -21
- crimson/views/lighting_debug.py +42 -45
- crimson/views/particles.py +33 -42
- crimson/views/perk_menu_debug.py +3 -10
- crimson/views/player.py +50 -44
- crimson/views/player_sprite_debug.py +24 -31
- crimson/views/projectile_fx.py +57 -52
- crimson/views/projectile_render_debug.py +24 -33
- crimson/views/projectiles.py +24 -37
- crimson/views/spawn_plan.py +13 -29
- crimson/views/sprites.py +14 -29
- crimson/views/terrain.py +6 -23
- crimson/views/ui.py +7 -24
- crimson/views/wicons.py +28 -33
- {crimsonland-0.1.0.dev15.dist-info → crimsonland-0.1.0.dev16.dist-info}/METADATA +1 -1
- {crimsonland-0.1.0.dev15.dist-info → crimsonland-0.1.0.dev16.dist-info}/RECORD +72 -64
- {crimsonland-0.1.0.dev15.dist-info → crimsonland-0.1.0.dev16.dist-info}/WHEEL +2 -2
- grim/config.py +29 -1
- grim/console.py +7 -10
- grim/math.py +12 -0
- crimson/.DS_Store +0 -0
- crimson/creatures/.DS_Store +0 -0
- grim/.DS_Store +0 -0
- {crimsonland-0.1.0.dev15.dist-info → crimsonland-0.1.0.dev16.dist-info}/entry_points.txt +0 -0
crimson/modes/survival_mode.py
CHANGED
|
@@ -9,6 +9,7 @@ from grim.assets import PaqTextureCache
|
|
|
9
9
|
from grim.audio import AudioState
|
|
10
10
|
from grim.console import ConsoleState
|
|
11
11
|
from grim.config import CrimsonConfig
|
|
12
|
+
from grim.math import clamp
|
|
12
13
|
from grim.view import ViewContext
|
|
13
14
|
|
|
14
15
|
from ..creatures.spawn import advance_survival_spawn_stage, tick_survival_wave_spawns
|
|
@@ -16,37 +17,18 @@ from ..debug import debug_enabled
|
|
|
16
17
|
from ..game_modes import GameMode
|
|
17
18
|
from ..gameplay import (
|
|
18
19
|
PlayerInput,
|
|
19
|
-
most_used_weapon_id_for_player,
|
|
20
|
-
perk_selection_current_choices,
|
|
21
|
-
perk_selection_pick,
|
|
22
20
|
survival_check_level_up,
|
|
23
21
|
weapon_assign_player,
|
|
24
22
|
)
|
|
25
|
-
from ..
|
|
26
|
-
from ..perks import PerkId, perk_display_description, perk_display_name
|
|
23
|
+
from ..perks import PerkId
|
|
27
24
|
from ..ui.cursor import draw_aim_cursor, draw_menu_cursor
|
|
28
25
|
from ..ui.hud import draw_hud_overlay, hud_flags_for_game_mode
|
|
29
|
-
from ..ui.menu_panel import draw_classic_menu_panel
|
|
30
26
|
from ..input_codes import config_keybinds, input_code_is_down, input_code_is_pressed, player_move_fire_binds
|
|
31
|
-
from ..ui.perk_menu import
|
|
32
|
-
PERK_MENU_TRANSITION_MS,
|
|
33
|
-
PerkMenuLayout,
|
|
34
|
-
UiButtonState,
|
|
35
|
-
button_draw,
|
|
36
|
-
button_update,
|
|
37
|
-
button_width,
|
|
38
|
-
draw_menu_item,
|
|
39
|
-
draw_ui_text,
|
|
40
|
-
load_perk_menu_assets,
|
|
41
|
-
menu_item_hit_rect,
|
|
42
|
-
perk_menu_panel_slide_x,
|
|
43
|
-
perk_menu_compute_layout,
|
|
44
|
-
ui_origin,
|
|
45
|
-
ui_scale,
|
|
46
|
-
wrap_ui_text,
|
|
47
|
-
)
|
|
27
|
+
from ..ui.perk_menu import PERK_MENU_TRANSITION_MS, draw_ui_text, load_perk_menu_assets
|
|
48
28
|
from ..weapons import WEAPON_BY_ID
|
|
49
|
-
from .base_gameplay_mode import BaseGameplayMode
|
|
29
|
+
from .base_gameplay_mode import BaseGameplayMode
|
|
30
|
+
from .components.highscore_record_builder import build_highscore_record_for_game_over
|
|
31
|
+
from .components.perk_menu_controller import PerkMenuContext, PerkMenuController
|
|
50
32
|
|
|
51
33
|
WORLD_SIZE = 1024.0
|
|
52
34
|
|
|
@@ -118,15 +100,38 @@ class SurvivalMode(BaseGameplayMode):
|
|
|
118
100
|
self._perk_prompt_timer_ms = 0.0
|
|
119
101
|
self._perk_prompt_hover = False
|
|
120
102
|
self._perk_prompt_pulse = 0.0
|
|
121
|
-
self.
|
|
122
|
-
self._perk_menu_selected = 0
|
|
123
|
-
self._perk_menu_timeline_ms = 0.0
|
|
103
|
+
self._perk_menu = PerkMenuController(on_close=self._reset_perk_prompt)
|
|
124
104
|
self._hud_fade_ms = PERK_MENU_TRANSITION_MS
|
|
125
105
|
self._perk_menu_assets = None
|
|
126
|
-
self._perk_ui_layout = PerkMenuLayout()
|
|
127
|
-
self._perk_cancel_button = UiButtonState("Cancel")
|
|
128
106
|
self._cursor_time = 0.0
|
|
129
107
|
|
|
108
|
+
def _reset_perk_prompt(self) -> None:
|
|
109
|
+
if int(self._state.perk_selection.pending_count) > 0:
|
|
110
|
+
# Reset the prompt swing so each pending perk replays the intro.
|
|
111
|
+
self._perk_prompt_timer_ms = 0.0
|
|
112
|
+
self._perk_prompt_hover = False
|
|
113
|
+
self._perk_prompt_pulse = 0.0
|
|
114
|
+
|
|
115
|
+
def _perk_menu_context(self) -> PerkMenuContext:
|
|
116
|
+
fx_toggle = int(self._config.data.get("fx_toggle", 0) or 0) if self._config is not None else 0
|
|
117
|
+
fx_detail = bool(int(self._config.data.get("fx_detail_0", 0) or 0)) if self._config is not None else False
|
|
118
|
+
players = self._world.players
|
|
119
|
+
return PerkMenuContext(
|
|
120
|
+
state=self._state,
|
|
121
|
+
perk_state=self._state.perk_selection,
|
|
122
|
+
players=players,
|
|
123
|
+
creatures=self._creatures.entries,
|
|
124
|
+
player=self._player,
|
|
125
|
+
game_mode=int(GameMode.SURVIVAL),
|
|
126
|
+
player_count=len(players),
|
|
127
|
+
fx_toggle=fx_toggle,
|
|
128
|
+
fx_detail=fx_detail,
|
|
129
|
+
font=self._small,
|
|
130
|
+
assets=self._perk_menu_assets,
|
|
131
|
+
mouse=self._ui_mouse_pos(),
|
|
132
|
+
play_sfx=self._world.audio_router.play_sfx,
|
|
133
|
+
)
|
|
134
|
+
|
|
130
135
|
def _wrap_ui_text(self, text: str, *, max_width: float, scale: float = UI_TEXT_SCALE) -> list[str]:
|
|
131
136
|
lines: list[str] = []
|
|
132
137
|
for raw in text.splitlines() or [""]:
|
|
@@ -158,8 +163,7 @@ class SurvivalMode(BaseGameplayMode):
|
|
|
158
163
|
self._perk_menu_assets = load_perk_menu_assets(self._assets_root)
|
|
159
164
|
if self._perk_menu_assets.missing:
|
|
160
165
|
self._missing_assets.extend(self._perk_menu_assets.missing)
|
|
161
|
-
self.
|
|
162
|
-
self._perk_cancel_button = UiButtonState("Cancel")
|
|
166
|
+
self._perk_menu.reset()
|
|
163
167
|
self._cursor_time = 0.0
|
|
164
168
|
self._cursor_pulse_time = 0.0
|
|
165
169
|
self._survival = _SurvivalState()
|
|
@@ -167,9 +171,6 @@ class SurvivalMode(BaseGameplayMode):
|
|
|
167
171
|
self._perk_prompt_timer_ms = 0.0
|
|
168
172
|
self._perk_prompt_hover = False
|
|
169
173
|
self._perk_prompt_pulse = 0.0
|
|
170
|
-
self._perk_menu_open = False
|
|
171
|
-
self._perk_menu_selected = 0
|
|
172
|
-
self._perk_menu_timeline_ms = 0.0
|
|
173
174
|
self._hud_fade_ms = PERK_MENU_TRANSITION_MS
|
|
174
175
|
|
|
175
176
|
def close(self) -> None:
|
|
@@ -183,15 +184,15 @@ class SurvivalMode(BaseGameplayMode):
|
|
|
183
184
|
self._action = "back_to_menu"
|
|
184
185
|
self.close_requested = True
|
|
185
186
|
return
|
|
186
|
-
if self.
|
|
187
|
+
if self._perk_menu.open and rl.is_key_pressed(rl.KeyboardKey.KEY_ESCAPE):
|
|
187
188
|
self._world.audio_router.play_sfx("sfx_ui_buttonclick")
|
|
188
|
-
self.
|
|
189
|
+
self._perk_menu.close()
|
|
189
190
|
return
|
|
190
191
|
|
|
191
192
|
if rl.is_key_pressed(rl.KeyboardKey.KEY_TAB):
|
|
192
193
|
self._paused = not self._paused
|
|
193
194
|
|
|
194
|
-
if debug_enabled() and (not self.
|
|
195
|
+
if debug_enabled() and (not self._perk_menu.open):
|
|
195
196
|
if rl.is_key_pressed(rl.KeyboardKey.KEY_F2):
|
|
196
197
|
self._state.debug_god_mode = not bool(self._state.debug_god_mode)
|
|
197
198
|
self._world.audio_router.play_sfx("sfx_ui_buttonclick")
|
|
@@ -274,31 +275,18 @@ class SurvivalMode(BaseGameplayMode):
|
|
|
274
275
|
def _enter_game_over(self) -> None:
|
|
275
276
|
if self._game_over_active:
|
|
276
277
|
return
|
|
277
|
-
|
|
278
|
-
record
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
hit = 0
|
|
286
|
-
try:
|
|
287
|
-
fired = int(self._state.shots_fired[int(self._player.index)])
|
|
288
|
-
hit = int(self._state.shots_hit[int(self._player.index)])
|
|
289
|
-
except Exception:
|
|
290
|
-
fired = 0
|
|
291
|
-
hit = 0
|
|
292
|
-
fired = max(0, int(fired))
|
|
293
|
-
hit = max(0, min(int(hit), fired))
|
|
294
|
-
record.shots_fired = fired
|
|
295
|
-
record.shots_hit = hit
|
|
296
|
-
|
|
297
|
-
record.game_mode_id = int(self._config.data.get("game_mode", 1)) if self._config is not None else 1
|
|
278
|
+
game_mode_id = int(self._config.data.get("game_mode", 1)) if self._config is not None else 1
|
|
279
|
+
record = build_highscore_record_for_game_over(
|
|
280
|
+
state=self._state,
|
|
281
|
+
player=self._player,
|
|
282
|
+
survival_elapsed_ms=int(self._survival.elapsed_ms),
|
|
283
|
+
creature_kill_count=int(self._creatures.kill_count),
|
|
284
|
+
game_mode_id=game_mode_id,
|
|
285
|
+
)
|
|
298
286
|
self._game_over_record = record
|
|
299
287
|
self._game_over_ui.open()
|
|
300
288
|
self._game_over_active = True
|
|
301
|
-
self.
|
|
289
|
+
self._perk_menu.close()
|
|
302
290
|
|
|
303
291
|
def _perk_prompt_label(self) -> str:
|
|
304
292
|
if self._config is not None and not bool(int(self._config.data.get("ui_info_texts", 1) or 0)):
|
|
@@ -338,138 +326,6 @@ class SurvivalMode(BaseGameplayMode):
|
|
|
338
326
|
y = margin
|
|
339
327
|
return rl.Rectangle(x, y, text_w, text_h)
|
|
340
328
|
|
|
341
|
-
def _open_perk_menu(self) -> None:
|
|
342
|
-
if self._perk_menu_open:
|
|
343
|
-
return
|
|
344
|
-
players = self._world.players
|
|
345
|
-
choices = perk_selection_current_choices(
|
|
346
|
-
self._state,
|
|
347
|
-
players,
|
|
348
|
-
self._state.perk_selection,
|
|
349
|
-
game_mode=int(GameMode.SURVIVAL),
|
|
350
|
-
player_count=len(players),
|
|
351
|
-
)
|
|
352
|
-
if not choices:
|
|
353
|
-
self._perk_menu_open = False
|
|
354
|
-
return
|
|
355
|
-
self._world.audio_router.play_sfx("sfx_ui_panelclick")
|
|
356
|
-
self._perk_menu_open = True
|
|
357
|
-
self._perk_menu_selected = 0
|
|
358
|
-
|
|
359
|
-
def _close_perk_menu(self) -> None:
|
|
360
|
-
self._perk_menu_open = False
|
|
361
|
-
if int(self._state.perk_selection.pending_count) > 0:
|
|
362
|
-
# Reset the prompt swing so each pending perk replays the intro.
|
|
363
|
-
self._perk_prompt_timer_ms = 0.0
|
|
364
|
-
self._perk_prompt_hover = False
|
|
365
|
-
self._perk_prompt_pulse = 0.0
|
|
366
|
-
|
|
367
|
-
def _perk_menu_handle_input(self, dt_frame: float, dt_ms: float) -> None:
|
|
368
|
-
if self._perk_menu_assets is None:
|
|
369
|
-
self._close_perk_menu()
|
|
370
|
-
return
|
|
371
|
-
perk_state = self._state.perk_selection
|
|
372
|
-
players = self._world.players
|
|
373
|
-
choices = perk_selection_current_choices(
|
|
374
|
-
self._state,
|
|
375
|
-
players,
|
|
376
|
-
perk_state,
|
|
377
|
-
game_mode=int(GameMode.SURVIVAL),
|
|
378
|
-
player_count=len(players),
|
|
379
|
-
)
|
|
380
|
-
if not choices:
|
|
381
|
-
self._close_perk_menu()
|
|
382
|
-
return
|
|
383
|
-
if self._perk_menu_selected >= len(choices):
|
|
384
|
-
self._perk_menu_selected = 0
|
|
385
|
-
|
|
386
|
-
if rl.is_key_pressed(rl.KeyboardKey.KEY_DOWN):
|
|
387
|
-
self._perk_menu_selected = (self._perk_menu_selected + 1) % len(choices)
|
|
388
|
-
if rl.is_key_pressed(rl.KeyboardKey.KEY_UP):
|
|
389
|
-
self._perk_menu_selected = (self._perk_menu_selected - 1) % len(choices)
|
|
390
|
-
|
|
391
|
-
screen_w = float(rl.get_screen_width())
|
|
392
|
-
screen_h = float(rl.get_screen_height())
|
|
393
|
-
scale = ui_scale(screen_w, screen_h)
|
|
394
|
-
origin_x, origin_y = ui_origin(screen_w, screen_h, scale)
|
|
395
|
-
slide_x = perk_menu_panel_slide_x(self._perk_menu_timeline_ms, width=self._perk_ui_layout.panel_w)
|
|
396
|
-
|
|
397
|
-
mouse = self._ui_mouse_pos()
|
|
398
|
-
click = rl.is_mouse_button_pressed(rl.MouseButton.MOUSE_BUTTON_LEFT)
|
|
399
|
-
|
|
400
|
-
master_owned = int(self._player.perk_counts[int(PerkId.PERK_MASTER)]) > 0
|
|
401
|
-
expert_owned = int(self._player.perk_counts[int(PerkId.PERK_EXPERT)]) > 0
|
|
402
|
-
computed = perk_menu_compute_layout(
|
|
403
|
-
self._perk_ui_layout,
|
|
404
|
-
screen_w=screen_w,
|
|
405
|
-
origin_x=origin_x,
|
|
406
|
-
origin_y=origin_y,
|
|
407
|
-
scale=scale,
|
|
408
|
-
choice_count=len(choices),
|
|
409
|
-
expert_owned=expert_owned,
|
|
410
|
-
master_owned=master_owned,
|
|
411
|
-
panel_slide_x=slide_x,
|
|
412
|
-
)
|
|
413
|
-
|
|
414
|
-
fx_toggle = int(self._config.data.get("fx_toggle", 0) or 0) if self._config is not None else 0
|
|
415
|
-
for idx, perk_id in enumerate(choices):
|
|
416
|
-
label = perk_display_name(int(perk_id), fx_toggle=fx_toggle)
|
|
417
|
-
item_x = computed.list_x
|
|
418
|
-
item_y = computed.list_y + float(idx) * computed.list_step_y
|
|
419
|
-
rect = menu_item_hit_rect(self._small, label, x=item_x, y=item_y, scale=scale)
|
|
420
|
-
if rl.check_collision_point_rec(mouse, rect):
|
|
421
|
-
self._perk_menu_selected = idx
|
|
422
|
-
if click:
|
|
423
|
-
self._world.audio_router.play_sfx("sfx_ui_buttonclick")
|
|
424
|
-
picked = perk_selection_pick(
|
|
425
|
-
self._state,
|
|
426
|
-
players,
|
|
427
|
-
perk_state,
|
|
428
|
-
idx,
|
|
429
|
-
game_mode=int(GameMode.SURVIVAL),
|
|
430
|
-
player_count=len(players),
|
|
431
|
-
dt=dt_frame,
|
|
432
|
-
creatures=self._creatures.entries,
|
|
433
|
-
)
|
|
434
|
-
if picked is not None:
|
|
435
|
-
self._world.audio_router.play_sfx("sfx_ui_bonus")
|
|
436
|
-
self._close_perk_menu()
|
|
437
|
-
return
|
|
438
|
-
break
|
|
439
|
-
|
|
440
|
-
cancel_w = button_width(self._small, self._perk_cancel_button.label, scale=scale, force_wide=self._perk_cancel_button.force_wide)
|
|
441
|
-
cancel_x = computed.cancel_x
|
|
442
|
-
button_y = computed.cancel_y
|
|
443
|
-
|
|
444
|
-
if button_update(
|
|
445
|
-
self._perk_cancel_button,
|
|
446
|
-
x=cancel_x,
|
|
447
|
-
y=button_y,
|
|
448
|
-
width=cancel_w,
|
|
449
|
-
dt_ms=dt_ms,
|
|
450
|
-
mouse=mouse,
|
|
451
|
-
click=click,
|
|
452
|
-
):
|
|
453
|
-
self._world.audio_router.play_sfx("sfx_ui_buttonclick")
|
|
454
|
-
self._close_perk_menu()
|
|
455
|
-
return
|
|
456
|
-
|
|
457
|
-
if rl.is_key_pressed(rl.KeyboardKey.KEY_ENTER) or rl.is_key_pressed(rl.KeyboardKey.KEY_SPACE):
|
|
458
|
-
self._world.audio_router.play_sfx("sfx_ui_buttonclick")
|
|
459
|
-
picked = perk_selection_pick(
|
|
460
|
-
self._state,
|
|
461
|
-
players,
|
|
462
|
-
perk_state,
|
|
463
|
-
self._perk_menu_selected,
|
|
464
|
-
game_mode=int(GameMode.SURVIVAL),
|
|
465
|
-
player_count=len(players),
|
|
466
|
-
dt=dt_frame,
|
|
467
|
-
creatures=self._creatures.entries,
|
|
468
|
-
)
|
|
469
|
-
if picked is not None:
|
|
470
|
-
self._world.audio_router.play_sfx("sfx_ui_bonus")
|
|
471
|
-
self._close_perk_menu()
|
|
472
|
-
|
|
473
329
|
def update(self, dt: float) -> None:
|
|
474
330
|
self._update_audio(dt)
|
|
475
331
|
|
|
@@ -480,40 +336,19 @@ class SurvivalMode(BaseGameplayMode):
|
|
|
480
336
|
return
|
|
481
337
|
|
|
482
338
|
if self._game_over_active:
|
|
483
|
-
|
|
484
|
-
if record is None:
|
|
485
|
-
self._enter_game_over()
|
|
486
|
-
record = self._game_over_record
|
|
487
|
-
if record is not None:
|
|
488
|
-
action = self._game_over_ui.update(
|
|
489
|
-
dt,
|
|
490
|
-
record=record,
|
|
491
|
-
player_name_default=self._player_name_default(),
|
|
492
|
-
play_sfx=self._world.audio_router.play_sfx,
|
|
493
|
-
rand=self._state.rng.rand,
|
|
494
|
-
mouse=self._ui_mouse_pos(),
|
|
495
|
-
)
|
|
496
|
-
if action == "play_again":
|
|
497
|
-
self.open()
|
|
498
|
-
return
|
|
499
|
-
if action == "high_scores":
|
|
500
|
-
self._action = "open_high_scores"
|
|
501
|
-
return
|
|
502
|
-
if action == "main_menu":
|
|
503
|
-
self._action = "back_to_menu"
|
|
504
|
-
self.close_requested = True
|
|
505
|
-
return
|
|
339
|
+
self._update_game_over_ui(dt)
|
|
506
340
|
return
|
|
507
341
|
|
|
508
342
|
any_alive = any(player.health > 0.0 for player in self._world.players)
|
|
509
343
|
perk_pending = int(self._state.perk_selection.pending_count) > 0 and any_alive
|
|
510
344
|
|
|
511
345
|
self._perk_prompt_hover = False
|
|
512
|
-
|
|
513
|
-
|
|
346
|
+
perk_ctx = self._perk_menu_context()
|
|
347
|
+
if self._perk_menu.open:
|
|
348
|
+
self._perk_menu.handle_input(perk_ctx, dt_frame=dt_frame, dt_ui_ms=dt_ui_ms)
|
|
514
349
|
dt = 0.0
|
|
515
350
|
|
|
516
|
-
perk_menu_active = self.
|
|
351
|
+
perk_menu_active = self._perk_menu.active
|
|
517
352
|
|
|
518
353
|
if (not perk_menu_active) and perk_pending and (not self._paused):
|
|
519
354
|
label = self._perk_prompt_label()
|
|
@@ -533,32 +368,29 @@ class SurvivalMode(BaseGameplayMode):
|
|
|
533
368
|
|
|
534
369
|
if input_code_is_pressed(pick_key) and (not input_code_is_down(fire_key)):
|
|
535
370
|
self._perk_prompt_pulse = 1000.0
|
|
536
|
-
self.
|
|
371
|
+
self._perk_menu.open_if_available(perk_ctx)
|
|
537
372
|
elif self._perk_prompt_hover and input_code_is_pressed(fire_key):
|
|
538
373
|
self._perk_prompt_pulse = 1000.0
|
|
539
|
-
self.
|
|
374
|
+
self._perk_menu.open_if_available(perk_ctx)
|
|
540
375
|
|
|
541
376
|
if not self._paused and not self._game_over_active:
|
|
542
377
|
pulse_delta = dt_ui_ms * (6.0 if self._perk_prompt_hover else -2.0)
|
|
543
|
-
self._perk_prompt_pulse =
|
|
378
|
+
self._perk_prompt_pulse = clamp(self._perk_prompt_pulse + pulse_delta, 0.0, 1000.0)
|
|
544
379
|
|
|
545
380
|
if self._paused or (not any_alive) or perk_menu_active:
|
|
546
381
|
dt = 0.0
|
|
547
382
|
|
|
548
383
|
prompt_active = perk_pending and (not perk_menu_active) and (not self._paused)
|
|
549
384
|
if prompt_active:
|
|
550
|
-
self._perk_prompt_timer_ms =
|
|
385
|
+
self._perk_prompt_timer_ms = clamp(self._perk_prompt_timer_ms + dt_ui_ms, 0.0, PERK_PROMPT_MAX_TIMER_MS)
|
|
551
386
|
else:
|
|
552
|
-
self._perk_prompt_timer_ms =
|
|
387
|
+
self._perk_prompt_timer_ms = clamp(self._perk_prompt_timer_ms - dt_ui_ms, 0.0, PERK_PROMPT_MAX_TIMER_MS)
|
|
553
388
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
else:
|
|
557
|
-
self._perk_menu_timeline_ms = _clamp(self._perk_menu_timeline_ms - dt_ui_ms, 0.0, PERK_MENU_TRANSITION_MS)
|
|
558
|
-
if self._perk_menu_timeline_ms > 1e-3 or self._perk_menu_open:
|
|
389
|
+
self._perk_menu.tick_timeline(dt_ui_ms)
|
|
390
|
+
if self._perk_menu.active:
|
|
559
391
|
self._hud_fade_ms = 0.0
|
|
560
392
|
else:
|
|
561
|
-
self._hud_fade_ms =
|
|
393
|
+
self._hud_fade_ms = clamp(self._hud_fade_ms + dt_ui_ms, 0.0, PERK_MENU_TRANSITION_MS)
|
|
562
394
|
|
|
563
395
|
self._survival.elapsed_ms += dt * 1000.0
|
|
564
396
|
|
|
@@ -579,6 +411,9 @@ class SurvivalMode(BaseGameplayMode):
|
|
|
579
411
|
# Scripted milestone spawns based on level.
|
|
580
412
|
stage, milestone_calls = advance_survival_spawn_stage(self._survival.stage, player_level=self._player.level)
|
|
581
413
|
self._survival.stage = stage
|
|
414
|
+
detail_preset = 5
|
|
415
|
+
if self._world.config is not None:
|
|
416
|
+
detail_preset = int(self._world.config.data.get("detail_preset", 5) or 5)
|
|
582
417
|
for call in milestone_calls:
|
|
583
418
|
self._creatures.spawn_template(
|
|
584
419
|
int(call.template_id),
|
|
@@ -586,6 +421,8 @@ class SurvivalMode(BaseGameplayMode):
|
|
|
586
421
|
float(call.heading),
|
|
587
422
|
self._state.rng,
|
|
588
423
|
rand=self._state.rng.rand,
|
|
424
|
+
state=self._state,
|
|
425
|
+
detail_preset=detail_preset,
|
|
589
426
|
)
|
|
590
427
|
|
|
591
428
|
# Regular wave spawns based on elapsed time.
|
|
@@ -608,7 +445,7 @@ class SurvivalMode(BaseGameplayMode):
|
|
|
608
445
|
def _draw_perk_prompt(self) -> None:
|
|
609
446
|
if self._game_over_active:
|
|
610
447
|
return
|
|
611
|
-
if self.
|
|
448
|
+
if self._perk_menu.active:
|
|
612
449
|
return
|
|
613
450
|
if not any(player.health > 0.0 for player in self._world.players):
|
|
614
451
|
return
|
|
@@ -664,102 +501,6 @@ class SurvivalMode(BaseGameplayMode):
|
|
|
664
501
|
rl.draw_texture_pro(tex, src, dst, origin, rot_deg, pulse_tint)
|
|
665
502
|
rl.end_blend_mode()
|
|
666
503
|
|
|
667
|
-
def _draw_perk_menu(self) -> None:
|
|
668
|
-
if self._game_over_active:
|
|
669
|
-
return
|
|
670
|
-
menu_t = _clamp(self._perk_menu_timeline_ms / PERK_MENU_TRANSITION_MS, 0.0, 1.0)
|
|
671
|
-
if menu_t <= 1e-3:
|
|
672
|
-
return
|
|
673
|
-
if self._perk_menu_assets is None:
|
|
674
|
-
return
|
|
675
|
-
|
|
676
|
-
perk_state = self._state.perk_selection
|
|
677
|
-
players = self._world.players
|
|
678
|
-
choices = perk_selection_current_choices(
|
|
679
|
-
self._state,
|
|
680
|
-
players,
|
|
681
|
-
perk_state,
|
|
682
|
-
game_mode=int(GameMode.SURVIVAL),
|
|
683
|
-
player_count=len(players),
|
|
684
|
-
)
|
|
685
|
-
if not choices:
|
|
686
|
-
return
|
|
687
|
-
screen_w = float(rl.get_screen_width())
|
|
688
|
-
screen_h = float(rl.get_screen_height())
|
|
689
|
-
scale = ui_scale(screen_w, screen_h)
|
|
690
|
-
origin_x, origin_y = ui_origin(screen_w, screen_h, scale)
|
|
691
|
-
slide_x = perk_menu_panel_slide_x(self._perk_menu_timeline_ms, width=self._perk_ui_layout.panel_w)
|
|
692
|
-
|
|
693
|
-
master_owned = int(self._player.perk_counts[int(PerkId.PERK_MASTER)]) > 0
|
|
694
|
-
expert_owned = int(self._player.perk_counts[int(PerkId.PERK_EXPERT)]) > 0
|
|
695
|
-
computed = perk_menu_compute_layout(
|
|
696
|
-
self._perk_ui_layout,
|
|
697
|
-
screen_w=screen_w,
|
|
698
|
-
origin_x=origin_x,
|
|
699
|
-
origin_y=origin_y,
|
|
700
|
-
scale=scale,
|
|
701
|
-
choice_count=len(choices),
|
|
702
|
-
expert_owned=expert_owned,
|
|
703
|
-
master_owned=master_owned,
|
|
704
|
-
panel_slide_x=slide_x,
|
|
705
|
-
)
|
|
706
|
-
|
|
707
|
-
panel_tex = self._perk_menu_assets.menu_panel
|
|
708
|
-
if panel_tex is not None:
|
|
709
|
-
fx_detail = bool(int(self._config.data.get("fx_detail_0", 0) or 0)) if self._config is not None else False
|
|
710
|
-
draw_classic_menu_panel(panel_tex, dst=computed.panel, shadow=fx_detail)
|
|
711
|
-
|
|
712
|
-
title_tex = self._perk_menu_assets.title_pick_perk
|
|
713
|
-
if title_tex is not None:
|
|
714
|
-
src = rl.Rectangle(0.0, 0.0, float(title_tex.width), float(title_tex.height))
|
|
715
|
-
rl.draw_texture_pro(title_tex, src, computed.title, rl.Vector2(0.0, 0.0), 0.0, rl.WHITE)
|
|
716
|
-
|
|
717
|
-
sponsor = None
|
|
718
|
-
if master_owned:
|
|
719
|
-
sponsor = "extra perks sponsored by the Perk Master"
|
|
720
|
-
elif expert_owned:
|
|
721
|
-
sponsor = "extra perk sponsored by the Perk Expert"
|
|
722
|
-
if sponsor:
|
|
723
|
-
draw_ui_text(
|
|
724
|
-
self._small,
|
|
725
|
-
sponsor,
|
|
726
|
-
computed.sponsor_x,
|
|
727
|
-
computed.sponsor_y,
|
|
728
|
-
scale=scale,
|
|
729
|
-
color=UI_SPONSOR_COLOR,
|
|
730
|
-
)
|
|
731
|
-
|
|
732
|
-
mouse = self._ui_mouse_pos()
|
|
733
|
-
fx_toggle = int(self._config.data.get("fx_toggle", 0) or 0) if self._config is not None else 0
|
|
734
|
-
for idx, perk_id in enumerate(choices):
|
|
735
|
-
label = perk_display_name(int(perk_id), fx_toggle=fx_toggle)
|
|
736
|
-
item_x = computed.list_x
|
|
737
|
-
item_y = computed.list_y + float(idx) * computed.list_step_y
|
|
738
|
-
rect = menu_item_hit_rect(self._small, label, x=item_x, y=item_y, scale=scale)
|
|
739
|
-
hovered = rl.check_collision_point_rec(mouse, rect) or (idx == self._perk_menu_selected)
|
|
740
|
-
draw_menu_item(self._small, label, x=item_x, y=item_y, scale=scale, hovered=hovered)
|
|
741
|
-
|
|
742
|
-
selected = choices[self._perk_menu_selected]
|
|
743
|
-
desc = perk_display_description(int(selected), fx_toggle=fx_toggle)
|
|
744
|
-
desc_x = float(computed.desc.x)
|
|
745
|
-
desc_y = float(computed.desc.y)
|
|
746
|
-
desc_w = float(computed.desc.width)
|
|
747
|
-
desc_h = float(computed.desc.height)
|
|
748
|
-
desc_scale = scale * 0.85
|
|
749
|
-
desc_lines = wrap_ui_text(self._small, desc, max_width=desc_w, scale=desc_scale)
|
|
750
|
-
line_h = float(self._small.cell_size * desc_scale) if self._small is not None else float(20 * desc_scale)
|
|
751
|
-
y = desc_y
|
|
752
|
-
for line in desc_lines:
|
|
753
|
-
if y + line_h > desc_y + desc_h:
|
|
754
|
-
break
|
|
755
|
-
draw_ui_text(self._small, line, desc_x, y, scale=desc_scale, color=UI_TEXT_COLOR)
|
|
756
|
-
y += line_h
|
|
757
|
-
|
|
758
|
-
cancel_w = button_width(self._small, self._perk_cancel_button.label, scale=scale, force_wide=self._perk_cancel_button.force_wide)
|
|
759
|
-
cancel_x = computed.cancel_x
|
|
760
|
-
button_y = computed.cancel_y
|
|
761
|
-
button_draw(self._perk_menu_assets, self._small, self._perk_cancel_button, x=cancel_x, y=button_y, width=cancel_w, scale=scale)
|
|
762
|
-
|
|
763
504
|
def _draw_game_cursor(self) -> None:
|
|
764
505
|
mouse_x = float(self._ui_mouse_x)
|
|
765
506
|
mouse_y = float(self._ui_mouse_y)
|
|
@@ -779,17 +520,18 @@ class SurvivalMode(BaseGameplayMode):
|
|
|
779
520
|
draw_aim_cursor(self._world.particles_texture, aim_tex, x=mouse_x, y=mouse_y)
|
|
780
521
|
|
|
781
522
|
def draw(self) -> None:
|
|
782
|
-
perk_menu_active = self.
|
|
523
|
+
perk_menu_active = self._perk_menu.active
|
|
783
524
|
self._world.draw(draw_aim_indicators=(not self._game_over_active) and (not perk_menu_active))
|
|
784
525
|
self._draw_screen_fade()
|
|
785
526
|
|
|
786
527
|
hud_bottom = 0.0
|
|
787
528
|
if (not self._game_over_active) and (not perk_menu_active) and self._hud_assets is not None:
|
|
788
|
-
hud_alpha =
|
|
529
|
+
hud_alpha = clamp(self._hud_fade_ms / PERK_MENU_TRANSITION_MS, 0.0, 1.0)
|
|
789
530
|
hud_flags = hud_flags_for_game_mode(self._config_game_mode_id())
|
|
790
531
|
self._draw_target_health_bar(alpha=hud_alpha)
|
|
791
532
|
hud_bottom = draw_hud_overlay(
|
|
792
533
|
self._hud_assets,
|
|
534
|
+
state=self._hud_state,
|
|
793
535
|
player=self._player,
|
|
794
536
|
players=self._world.players,
|
|
795
537
|
bonus_hud=self._state.bonus_hud,
|
|
@@ -829,7 +571,8 @@ class SurvivalMode(BaseGameplayMode):
|
|
|
829
571
|
self._draw_ui_text(warn, 24.0, warn_y, UI_ERROR_COLOR, scale=0.8)
|
|
830
572
|
|
|
831
573
|
self._draw_perk_prompt()
|
|
832
|
-
self.
|
|
574
|
+
if not self._game_over_active:
|
|
575
|
+
self._perk_menu.draw(self._perk_menu_context())
|
|
833
576
|
if (not self._game_over_active) and perk_menu_active:
|
|
834
577
|
self._draw_game_cursor()
|
|
835
578
|
if (not self._game_over_active) and (not perk_menu_active):
|