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/quest_mode.py
CHANGED
|
@@ -10,14 +10,14 @@ from grim.audio import AudioState
|
|
|
10
10
|
from grim.console import ConsoleState
|
|
11
11
|
from grim.config import CrimsonConfig
|
|
12
12
|
from grim.fonts.grim_mono import GrimMonoFont, load_grim_mono_font
|
|
13
|
+
from grim.math import clamp
|
|
13
14
|
from grim.view import ViewContext
|
|
14
15
|
|
|
15
16
|
from ..debug import debug_enabled
|
|
16
17
|
from ..game_modes import GameMode
|
|
17
|
-
from ..gameplay import most_used_weapon_id_for_player,
|
|
18
|
+
from ..gameplay import most_used_weapon_id_for_player, weapon_assign_player
|
|
18
19
|
from ..input_codes import config_keybinds, input_code_is_down, input_code_is_pressed, player_move_fire_binds
|
|
19
20
|
from ..persistence.save_status import GameStatus
|
|
20
|
-
from ..perks import PerkId, perk_display_description, perk_display_name
|
|
21
21
|
from ..quests import quest_by_level
|
|
22
22
|
from ..quests.runtime import build_quest_spawn_table, tick_quest_completion_transition
|
|
23
23
|
from ..quests.timeline import quest_spawn_table_empty, tick_quest_mode_spawns
|
|
@@ -25,28 +25,11 @@ from ..quests.types import QuestContext, QuestDefinition, SpawnEntry
|
|
|
25
25
|
from ..terrain_assets import terrain_texture_by_id
|
|
26
26
|
from ..ui.cursor import draw_aim_cursor, draw_menu_cursor
|
|
27
27
|
from ..ui.hud import draw_hud_overlay, hud_flags_for_game_mode
|
|
28
|
-
from ..ui.
|
|
29
|
-
from ..ui.perk_menu import (
|
|
30
|
-
PERK_MENU_TRANSITION_MS,
|
|
31
|
-
PerkMenuAssets,
|
|
32
|
-
PerkMenuLayout,
|
|
33
|
-
UiButtonState,
|
|
34
|
-
button_draw,
|
|
35
|
-
button_update,
|
|
36
|
-
button_width,
|
|
37
|
-
draw_menu_item,
|
|
38
|
-
draw_ui_text,
|
|
39
|
-
load_perk_menu_assets,
|
|
40
|
-
menu_item_hit_rect,
|
|
41
|
-
perk_menu_panel_slide_x,
|
|
42
|
-
perk_menu_compute_layout,
|
|
43
|
-
ui_origin,
|
|
44
|
-
ui_scale,
|
|
45
|
-
wrap_ui_text,
|
|
46
|
-
)
|
|
28
|
+
from ..ui.perk_menu import PerkMenuAssets, draw_ui_text, load_perk_menu_assets
|
|
47
29
|
from ..views.quest_title_overlay import draw_quest_title_overlay
|
|
48
30
|
from ..weapons import WEAPON_BY_ID
|
|
49
|
-
from .base_gameplay_mode import BaseGameplayMode
|
|
31
|
+
from .base_gameplay_mode import BaseGameplayMode
|
|
32
|
+
from .components.perk_menu_controller import PerkMenuContext, PerkMenuController
|
|
50
33
|
|
|
51
34
|
WORLD_SIZE = 1024.0
|
|
52
35
|
QUEST_TITLE_FADE_IN_MS = 500.0
|
|
@@ -177,11 +160,7 @@ class QuestMode(BaseGameplayMode):
|
|
|
177
160
|
self._perk_prompt_timer_ms = 0.0
|
|
178
161
|
self._perk_prompt_hover = False
|
|
179
162
|
self._perk_prompt_pulse = 0.0
|
|
180
|
-
self.
|
|
181
|
-
self._perk_menu_selected = 0
|
|
182
|
-
self._perk_menu_timeline_ms = 0.0
|
|
183
|
-
self._perk_ui_layout = PerkMenuLayout()
|
|
184
|
-
self._perk_cancel_button = UiButtonState("Cancel")
|
|
163
|
+
self._perk_menu = PerkMenuController(on_close=self._reset_perk_prompt)
|
|
185
164
|
|
|
186
165
|
def open(self) -> None:
|
|
187
166
|
super().open()
|
|
@@ -198,11 +177,7 @@ class QuestMode(BaseGameplayMode):
|
|
|
198
177
|
self._perk_prompt_timer_ms = 0.0
|
|
199
178
|
self._perk_prompt_hover = False
|
|
200
179
|
self._perk_prompt_pulse = 0.0
|
|
201
|
-
self.
|
|
202
|
-
self._perk_menu_selected = 0
|
|
203
|
-
self._perk_menu_timeline_ms = 0.0
|
|
204
|
-
self._perk_ui_layout = PerkMenuLayout()
|
|
205
|
-
self._perk_cancel_button = UiButtonState("Cancel")
|
|
180
|
+
self._perk_menu.reset()
|
|
206
181
|
|
|
207
182
|
def close(self) -> None:
|
|
208
183
|
if self._grim_mono is not None:
|
|
@@ -211,6 +186,33 @@ class QuestMode(BaseGameplayMode):
|
|
|
211
186
|
self._perk_menu_assets = None
|
|
212
187
|
super().close()
|
|
213
188
|
|
|
189
|
+
def _reset_perk_prompt(self) -> None:
|
|
190
|
+
if int(self._state.perk_selection.pending_count) > 0:
|
|
191
|
+
# Reset the prompt swing so each pending perk replays the intro.
|
|
192
|
+
self._perk_prompt_timer_ms = 0.0
|
|
193
|
+
self._perk_prompt_hover = False
|
|
194
|
+
self._perk_prompt_pulse = 0.0
|
|
195
|
+
|
|
196
|
+
def _perk_menu_context(self) -> PerkMenuContext:
|
|
197
|
+
fx_toggle = int(self._config.data.get("fx_toggle", 0) or 0) if self._config is not None else 0
|
|
198
|
+
fx_detail = bool(int(self._config.data.get("fx_detail_0", 0) or 0)) if self._config is not None else False
|
|
199
|
+
players = self._world.players
|
|
200
|
+
return PerkMenuContext(
|
|
201
|
+
state=self._state,
|
|
202
|
+
perk_state=self._state.perk_selection,
|
|
203
|
+
players=players,
|
|
204
|
+
creatures=self._creatures.entries,
|
|
205
|
+
player=self._player,
|
|
206
|
+
game_mode=int(GameMode.QUESTS),
|
|
207
|
+
player_count=len(players),
|
|
208
|
+
fx_toggle=fx_toggle,
|
|
209
|
+
fx_detail=fx_detail,
|
|
210
|
+
font=self._small,
|
|
211
|
+
assets=self._perk_menu_assets,
|
|
212
|
+
mouse=self._ui_mouse_pos(),
|
|
213
|
+
play_sfx=self._world.audio_router.play_sfx,
|
|
214
|
+
)
|
|
215
|
+
|
|
214
216
|
def select_level(self, level: str | None) -> None:
|
|
215
217
|
self._selected_level = level
|
|
216
218
|
|
|
@@ -301,15 +303,15 @@ class QuestMode(BaseGameplayMode):
|
|
|
301
303
|
status.increment_quest_play_count(idx)
|
|
302
304
|
|
|
303
305
|
def _handle_input(self) -> None:
|
|
304
|
-
if self.
|
|
306
|
+
if self._perk_menu.open and rl.is_key_pressed(rl.KeyboardKey.KEY_ESCAPE):
|
|
305
307
|
self._world.audio_router.play_sfx("sfx_ui_buttonclick")
|
|
306
|
-
self.
|
|
308
|
+
self._perk_menu.close()
|
|
307
309
|
return
|
|
308
310
|
|
|
309
311
|
if rl.is_key_pressed(rl.KeyboardKey.KEY_TAB):
|
|
310
312
|
self._paused = not self._paused
|
|
311
313
|
|
|
312
|
-
if debug_enabled() and (not self.
|
|
314
|
+
if debug_enabled() and (not self._perk_menu.open):
|
|
313
315
|
if rl.is_key_pressed(rl.KeyboardKey.KEY_F2):
|
|
314
316
|
self._state.debug_god_mode = not bool(self._state.debug_god_mode)
|
|
315
317
|
self._world.audio_router.play_sfx("sfx_ui_buttonclick")
|
|
@@ -414,139 +416,6 @@ class QuestMode(BaseGameplayMode):
|
|
|
414
416
|
y = margin
|
|
415
417
|
return rl.Rectangle(x, y, text_w, text_h)
|
|
416
418
|
|
|
417
|
-
def _open_perk_menu(self) -> None:
|
|
418
|
-
if self._perk_menu_open:
|
|
419
|
-
return
|
|
420
|
-
players = self._world.players
|
|
421
|
-
choices = perk_selection_current_choices(
|
|
422
|
-
self._state,
|
|
423
|
-
players,
|
|
424
|
-
self._state.perk_selection,
|
|
425
|
-
game_mode=int(GameMode.QUESTS),
|
|
426
|
-
player_count=len(players),
|
|
427
|
-
)
|
|
428
|
-
if not choices:
|
|
429
|
-
self._perk_menu_open = False
|
|
430
|
-
return
|
|
431
|
-
self._world.audio_router.play_sfx("sfx_ui_panelclick")
|
|
432
|
-
self._perk_menu_open = True
|
|
433
|
-
self._perk_menu_selected = 0
|
|
434
|
-
|
|
435
|
-
def _close_perk_menu(self) -> None:
|
|
436
|
-
self._perk_menu_open = False
|
|
437
|
-
if int(self._state.perk_selection.pending_count) > 0:
|
|
438
|
-
# Reset the prompt swing so each pending perk replays the intro.
|
|
439
|
-
self._perk_prompt_timer_ms = 0.0
|
|
440
|
-
self._perk_prompt_hover = False
|
|
441
|
-
self._perk_prompt_pulse = 0.0
|
|
442
|
-
|
|
443
|
-
def _perk_menu_handle_input(self, dt_frame: float, dt_ms: float) -> None:
|
|
444
|
-
if self._perk_menu_assets is None:
|
|
445
|
-
self._close_perk_menu()
|
|
446
|
-
return
|
|
447
|
-
|
|
448
|
-
perk_state = self._state.perk_selection
|
|
449
|
-
players = self._world.players
|
|
450
|
-
choices = perk_selection_current_choices(
|
|
451
|
-
self._state,
|
|
452
|
-
players,
|
|
453
|
-
perk_state,
|
|
454
|
-
game_mode=int(GameMode.QUESTS),
|
|
455
|
-
player_count=len(players),
|
|
456
|
-
)
|
|
457
|
-
if not choices:
|
|
458
|
-
self._close_perk_menu()
|
|
459
|
-
return
|
|
460
|
-
if self._perk_menu_selected >= len(choices):
|
|
461
|
-
self._perk_menu_selected = 0
|
|
462
|
-
|
|
463
|
-
if rl.is_key_pressed(rl.KeyboardKey.KEY_DOWN):
|
|
464
|
-
self._perk_menu_selected = (self._perk_menu_selected + 1) % len(choices)
|
|
465
|
-
if rl.is_key_pressed(rl.KeyboardKey.KEY_UP):
|
|
466
|
-
self._perk_menu_selected = (self._perk_menu_selected - 1) % len(choices)
|
|
467
|
-
|
|
468
|
-
screen_w = float(rl.get_screen_width())
|
|
469
|
-
screen_h = float(rl.get_screen_height())
|
|
470
|
-
scale = ui_scale(screen_w, screen_h)
|
|
471
|
-
origin_x, origin_y = ui_origin(screen_w, screen_h, scale)
|
|
472
|
-
slide_x = perk_menu_panel_slide_x(self._perk_menu_timeline_ms, width=self._perk_ui_layout.panel_w)
|
|
473
|
-
|
|
474
|
-
mouse = self._ui_mouse_pos()
|
|
475
|
-
click = rl.is_mouse_button_pressed(rl.MouseButton.MOUSE_BUTTON_LEFT)
|
|
476
|
-
|
|
477
|
-
master_owned = int(self._player.perk_counts[int(PerkId.PERK_MASTER)]) > 0
|
|
478
|
-
expert_owned = int(self._player.perk_counts[int(PerkId.PERK_EXPERT)]) > 0
|
|
479
|
-
computed = perk_menu_compute_layout(
|
|
480
|
-
self._perk_ui_layout,
|
|
481
|
-
screen_w=screen_w,
|
|
482
|
-
origin_x=origin_x,
|
|
483
|
-
origin_y=origin_y,
|
|
484
|
-
scale=scale,
|
|
485
|
-
choice_count=len(choices),
|
|
486
|
-
expert_owned=expert_owned,
|
|
487
|
-
master_owned=master_owned,
|
|
488
|
-
panel_slide_x=slide_x,
|
|
489
|
-
)
|
|
490
|
-
|
|
491
|
-
fx_toggle = int(self._config.data.get("fx_toggle", 0) or 0) if self._config is not None else 0
|
|
492
|
-
for idx, perk_id in enumerate(choices):
|
|
493
|
-
label = perk_display_name(int(perk_id), fx_toggle=fx_toggle)
|
|
494
|
-
item_x = computed.list_x
|
|
495
|
-
item_y = computed.list_y + float(idx) * computed.list_step_y
|
|
496
|
-
rect = menu_item_hit_rect(self._small, label, x=item_x, y=item_y, scale=scale)
|
|
497
|
-
if rl.check_collision_point_rec(mouse, rect):
|
|
498
|
-
self._perk_menu_selected = idx
|
|
499
|
-
if click:
|
|
500
|
-
self._world.audio_router.play_sfx("sfx_ui_buttonclick")
|
|
501
|
-
picked = perk_selection_pick(
|
|
502
|
-
self._state,
|
|
503
|
-
players,
|
|
504
|
-
perk_state,
|
|
505
|
-
idx,
|
|
506
|
-
game_mode=int(GameMode.QUESTS),
|
|
507
|
-
player_count=len(players),
|
|
508
|
-
dt=dt_frame,
|
|
509
|
-
creatures=self._creatures.entries,
|
|
510
|
-
)
|
|
511
|
-
if picked is not None:
|
|
512
|
-
self._world.audio_router.play_sfx("sfx_ui_bonus")
|
|
513
|
-
self._close_perk_menu()
|
|
514
|
-
return
|
|
515
|
-
break
|
|
516
|
-
|
|
517
|
-
cancel_w = button_width(self._small, self._perk_cancel_button.label, scale=scale, force_wide=self._perk_cancel_button.force_wide)
|
|
518
|
-
cancel_x = computed.cancel_x
|
|
519
|
-
button_y = computed.cancel_y
|
|
520
|
-
|
|
521
|
-
if button_update(
|
|
522
|
-
self._perk_cancel_button,
|
|
523
|
-
x=cancel_x,
|
|
524
|
-
y=button_y,
|
|
525
|
-
width=cancel_w,
|
|
526
|
-
dt_ms=dt_ms,
|
|
527
|
-
mouse=mouse,
|
|
528
|
-
click=click,
|
|
529
|
-
):
|
|
530
|
-
self._world.audio_router.play_sfx("sfx_ui_buttonclick")
|
|
531
|
-
self._close_perk_menu()
|
|
532
|
-
return
|
|
533
|
-
|
|
534
|
-
if rl.is_key_pressed(rl.KeyboardKey.KEY_ENTER) or rl.is_key_pressed(rl.KeyboardKey.KEY_SPACE):
|
|
535
|
-
self._world.audio_router.play_sfx("sfx_ui_buttonclick")
|
|
536
|
-
picked = perk_selection_pick(
|
|
537
|
-
self._state,
|
|
538
|
-
players,
|
|
539
|
-
perk_state,
|
|
540
|
-
self._perk_menu_selected,
|
|
541
|
-
game_mode=int(GameMode.QUESTS),
|
|
542
|
-
player_count=len(players),
|
|
543
|
-
dt=dt_frame,
|
|
544
|
-
creatures=self._creatures.entries,
|
|
545
|
-
)
|
|
546
|
-
if picked is not None:
|
|
547
|
-
self._world.audio_router.play_sfx("sfx_ui_bonus")
|
|
548
|
-
self._close_perk_menu()
|
|
549
|
-
|
|
550
419
|
def _close_failed_run(self) -> None:
|
|
551
420
|
if self._outcome is None:
|
|
552
421
|
fired = 0
|
|
@@ -584,7 +453,7 @@ class QuestMode(BaseGameplayMode):
|
|
|
584
453
|
self.close_requested = True
|
|
585
454
|
|
|
586
455
|
def _draw_perk_prompt(self) -> None:
|
|
587
|
-
if self.
|
|
456
|
+
if self._perk_menu.active:
|
|
588
457
|
return
|
|
589
458
|
if not any(player.health > 0.0 for player in self._world.players):
|
|
590
459
|
return
|
|
@@ -640,94 +509,6 @@ class QuestMode(BaseGameplayMode):
|
|
|
640
509
|
rl.draw_texture_pro(tex, src, dst, origin, rot_deg, pulse_tint)
|
|
641
510
|
rl.end_blend_mode()
|
|
642
511
|
|
|
643
|
-
def _draw_perk_menu(self) -> None:
|
|
644
|
-
menu_t = _clamp(self._perk_menu_timeline_ms / PERK_MENU_TRANSITION_MS, 0.0, 1.0)
|
|
645
|
-
if menu_t <= 1e-3:
|
|
646
|
-
return
|
|
647
|
-
if self._perk_menu_assets is None:
|
|
648
|
-
return
|
|
649
|
-
|
|
650
|
-
perk_state = self._state.perk_selection
|
|
651
|
-
players = self._world.players
|
|
652
|
-
choices = perk_selection_current_choices(
|
|
653
|
-
self._state,
|
|
654
|
-
players,
|
|
655
|
-
perk_state,
|
|
656
|
-
game_mode=int(GameMode.QUESTS),
|
|
657
|
-
player_count=len(players),
|
|
658
|
-
)
|
|
659
|
-
if not choices:
|
|
660
|
-
return
|
|
661
|
-
|
|
662
|
-
screen_w = float(rl.get_screen_width())
|
|
663
|
-
screen_h = float(rl.get_screen_height())
|
|
664
|
-
scale = ui_scale(screen_w, screen_h)
|
|
665
|
-
origin_x, origin_y = ui_origin(screen_w, screen_h, scale)
|
|
666
|
-
slide_x = perk_menu_panel_slide_x(self._perk_menu_timeline_ms, width=self._perk_ui_layout.panel_w)
|
|
667
|
-
|
|
668
|
-
master_owned = int(self._player.perk_counts[int(PerkId.PERK_MASTER)]) > 0
|
|
669
|
-
expert_owned = int(self._player.perk_counts[int(PerkId.PERK_EXPERT)]) > 0
|
|
670
|
-
computed = perk_menu_compute_layout(
|
|
671
|
-
self._perk_ui_layout,
|
|
672
|
-
screen_w=screen_w,
|
|
673
|
-
origin_x=origin_x,
|
|
674
|
-
origin_y=origin_y,
|
|
675
|
-
scale=scale,
|
|
676
|
-
choice_count=len(choices),
|
|
677
|
-
expert_owned=expert_owned,
|
|
678
|
-
master_owned=master_owned,
|
|
679
|
-
panel_slide_x=slide_x,
|
|
680
|
-
)
|
|
681
|
-
|
|
682
|
-
panel_tex = self._perk_menu_assets.menu_panel
|
|
683
|
-
if panel_tex is not None:
|
|
684
|
-
fx_detail = bool(int(self._config.data.get("fx_detail_0", 0) or 0)) if self._config is not None else False
|
|
685
|
-
draw_classic_menu_panel(panel_tex, dst=computed.panel, shadow=fx_detail)
|
|
686
|
-
|
|
687
|
-
title_tex = self._perk_menu_assets.title_pick_perk
|
|
688
|
-
if title_tex is not None:
|
|
689
|
-
src = rl.Rectangle(0.0, 0.0, float(title_tex.width), float(title_tex.height))
|
|
690
|
-
rl.draw_texture_pro(title_tex, src, computed.title, rl.Vector2(0.0, 0.0), 0.0, rl.WHITE)
|
|
691
|
-
|
|
692
|
-
sponsor = None
|
|
693
|
-
if master_owned:
|
|
694
|
-
sponsor = "extra perks sponsored by the Perk Master"
|
|
695
|
-
elif expert_owned:
|
|
696
|
-
sponsor = "extra perk sponsored by the Perk Expert"
|
|
697
|
-
if sponsor:
|
|
698
|
-
draw_ui_text(self._small, sponsor, computed.sponsor_x, computed.sponsor_y, scale=scale, color=UI_SPONSOR_COLOR)
|
|
699
|
-
|
|
700
|
-
mouse = self._ui_mouse_pos()
|
|
701
|
-
fx_toggle = int(self._config.data.get("fx_toggle", 0) or 0) if self._config is not None else 0
|
|
702
|
-
for idx, perk_id in enumerate(choices):
|
|
703
|
-
label = perk_display_name(int(perk_id), fx_toggle=fx_toggle)
|
|
704
|
-
item_x = computed.list_x
|
|
705
|
-
item_y = computed.list_y + float(idx) * computed.list_step_y
|
|
706
|
-
rect = menu_item_hit_rect(self._small, label, x=item_x, y=item_y, scale=scale)
|
|
707
|
-
hovered = rl.check_collision_point_rec(mouse, rect) or (idx == self._perk_menu_selected)
|
|
708
|
-
draw_menu_item(self._small, label, x=item_x, y=item_y, scale=scale, hovered=hovered)
|
|
709
|
-
|
|
710
|
-
selected = choices[self._perk_menu_selected]
|
|
711
|
-
desc = perk_display_description(int(selected), fx_toggle=fx_toggle)
|
|
712
|
-
desc_x = float(computed.desc.x)
|
|
713
|
-
desc_y = float(computed.desc.y)
|
|
714
|
-
desc_w = float(computed.desc.width)
|
|
715
|
-
desc_h = float(computed.desc.height)
|
|
716
|
-
desc_scale = scale * 0.85
|
|
717
|
-
desc_lines = wrap_ui_text(self._small, desc, max_width=desc_w, scale=desc_scale)
|
|
718
|
-
line_h = float(self._small.cell_size * desc_scale) if self._small is not None else float(20 * desc_scale)
|
|
719
|
-
y = desc_y
|
|
720
|
-
for line in desc_lines:
|
|
721
|
-
if y + line_h > desc_y + desc_h:
|
|
722
|
-
break
|
|
723
|
-
draw_ui_text(self._small, line, desc_x, y, scale=desc_scale, color=UI_TEXT_COLOR)
|
|
724
|
-
y += line_h
|
|
725
|
-
|
|
726
|
-
cancel_w = button_width(self._small, self._perk_cancel_button.label, scale=scale, force_wide=self._perk_cancel_button.force_wide)
|
|
727
|
-
cancel_x = computed.cancel_x
|
|
728
|
-
button_y = computed.cancel_y
|
|
729
|
-
button_draw(self._perk_menu_assets, self._small, self._perk_cancel_button, x=cancel_x, y=button_y, width=cancel_w, scale=scale)
|
|
730
|
-
|
|
731
512
|
def update(self, dt: float) -> None:
|
|
732
513
|
self._update_audio(dt)
|
|
733
514
|
|
|
@@ -743,10 +524,11 @@ class QuestMode(BaseGameplayMode):
|
|
|
743
524
|
perk_pending = int(self._state.perk_selection.pending_count) > 0 and any_alive
|
|
744
525
|
|
|
745
526
|
self._perk_prompt_hover = False
|
|
746
|
-
|
|
747
|
-
|
|
527
|
+
perk_ctx = self._perk_menu_context()
|
|
528
|
+
if self._perk_menu.open:
|
|
529
|
+
self._perk_menu.handle_input(perk_ctx, dt_frame=dt_frame, dt_ui_ms=dt_ui_ms)
|
|
748
530
|
|
|
749
|
-
perk_menu_active = self.
|
|
531
|
+
perk_menu_active = self._perk_menu.active
|
|
750
532
|
|
|
751
533
|
if (not perk_menu_active) and perk_pending and (not self._paused):
|
|
752
534
|
label = self._perk_prompt_label()
|
|
@@ -765,29 +547,26 @@ class QuestMode(BaseGameplayMode):
|
|
|
765
547
|
|
|
766
548
|
if input_code_is_pressed(pick_key) and (not input_code_is_down(fire_key)):
|
|
767
549
|
self._perk_prompt_pulse = 1000.0
|
|
768
|
-
self.
|
|
550
|
+
self._perk_menu.open_if_available(perk_ctx)
|
|
769
551
|
elif self._perk_prompt_hover and input_code_is_pressed(fire_key):
|
|
770
552
|
self._perk_prompt_pulse = 1000.0
|
|
771
|
-
self.
|
|
553
|
+
self._perk_menu.open_if_available(perk_ctx)
|
|
772
554
|
|
|
773
|
-
perk_menu_active = self.
|
|
555
|
+
perk_menu_active = self._perk_menu.active
|
|
774
556
|
|
|
775
557
|
if not self._paused:
|
|
776
558
|
pulse_delta = dt_ui_ms * (6.0 if self._perk_prompt_hover else -2.0)
|
|
777
|
-
self._perk_prompt_pulse =
|
|
559
|
+
self._perk_prompt_pulse = clamp(self._perk_prompt_pulse + pulse_delta, 0.0, 1000.0)
|
|
778
560
|
|
|
779
561
|
prompt_active = perk_pending and (not perk_menu_active) and (not self._paused)
|
|
780
562
|
if prompt_active:
|
|
781
|
-
self._perk_prompt_timer_ms =
|
|
563
|
+
self._perk_prompt_timer_ms = clamp(self._perk_prompt_timer_ms + dt_ui_ms, 0.0, PERK_PROMPT_MAX_TIMER_MS)
|
|
782
564
|
else:
|
|
783
|
-
self._perk_prompt_timer_ms =
|
|
565
|
+
self._perk_prompt_timer_ms = clamp(self._perk_prompt_timer_ms - dt_ui_ms, 0.0, PERK_PROMPT_MAX_TIMER_MS)
|
|
784
566
|
|
|
785
|
-
|
|
786
|
-
self._perk_menu_timeline_ms = _clamp(self._perk_menu_timeline_ms + dt_ui_ms, 0.0, PERK_MENU_TRANSITION_MS)
|
|
787
|
-
else:
|
|
788
|
-
self._perk_menu_timeline_ms = _clamp(self._perk_menu_timeline_ms - dt_ui_ms, 0.0, PERK_MENU_TRANSITION_MS)
|
|
567
|
+
self._perk_menu.tick_timeline(dt_ui_ms)
|
|
789
568
|
|
|
790
|
-
dt_world = 0.0 if self._paused or (not any_alive) or
|
|
569
|
+
dt_world = 0.0 if self._paused or (not any_alive) or self._perk_menu.active else dt_frame
|
|
791
570
|
if dt_world <= 0.0:
|
|
792
571
|
if not any(player.health > 0.0 for player in self._world.players):
|
|
793
572
|
self._close_failed_run()
|
|
@@ -823,6 +602,9 @@ class QuestMode(BaseGameplayMode):
|
|
|
823
602
|
self._quest.spawn_timeline_ms = float(timeline_ms)
|
|
824
603
|
self._quest.no_creatures_timer_ms = float(no_creatures_timer_ms)
|
|
825
604
|
|
|
605
|
+
detail_preset = 5
|
|
606
|
+
if self._world.config is not None:
|
|
607
|
+
detail_preset = int(self._world.config.data.get("detail_preset", 5) or 5)
|
|
826
608
|
for call in spawns:
|
|
827
609
|
self._creatures.spawn_template(
|
|
828
610
|
int(call.template_id),
|
|
@@ -830,6 +612,8 @@ class QuestMode(BaseGameplayMode):
|
|
|
830
612
|
float(call.heading),
|
|
831
613
|
self._state.rng,
|
|
832
614
|
rand=self._state.rng.rand,
|
|
615
|
+
state=self._state,
|
|
616
|
+
detail_preset=detail_preset,
|
|
833
617
|
)
|
|
834
618
|
|
|
835
619
|
completion_ms, completed = tick_quest_completion_transition(
|
|
@@ -876,7 +660,7 @@ class QuestMode(BaseGameplayMode):
|
|
|
876
660
|
self.close_requested = True
|
|
877
661
|
|
|
878
662
|
def draw(self) -> None:
|
|
879
|
-
perk_menu_active = self.
|
|
663
|
+
perk_menu_active = self._perk_menu.active
|
|
880
664
|
self._world.draw(draw_aim_indicators=not perk_menu_active)
|
|
881
665
|
self._draw_screen_fade()
|
|
882
666
|
|
|
@@ -889,6 +673,7 @@ class QuestMode(BaseGameplayMode):
|
|
|
889
673
|
self._draw_target_health_bar()
|
|
890
674
|
hud_bottom = draw_hud_overlay(
|
|
891
675
|
self._hud_assets,
|
|
676
|
+
state=self._hud_state,
|
|
892
677
|
player=self._player,
|
|
893
678
|
players=self._world.players,
|
|
894
679
|
bonus_hud=self._state.bonus_hud,
|
|
@@ -922,7 +707,7 @@ class QuestMode(BaseGameplayMode):
|
|
|
922
707
|
self._draw_ui_text(warn, 24.0, warn_y, rl.Color(240, 80, 80, 255), scale=0.8)
|
|
923
708
|
|
|
924
709
|
self._draw_perk_prompt()
|
|
925
|
-
self.
|
|
710
|
+
self._perk_menu.draw(self._perk_menu_context())
|
|
926
711
|
|
|
927
712
|
if perk_menu_active:
|
|
928
713
|
self._draw_game_cursor()
|
crimson/modes/rush_mode.py
CHANGED
|
@@ -13,13 +13,13 @@ from grim.view import ViewContext
|
|
|
13
13
|
|
|
14
14
|
from ..creatures.spawn import tick_rush_mode_spawns
|
|
15
15
|
from ..game_modes import GameMode
|
|
16
|
-
from ..gameplay import PlayerInput,
|
|
16
|
+
from ..gameplay import PlayerInput, weapon_assign_player
|
|
17
17
|
from ..input_codes import config_keybinds, input_code_is_down, input_code_is_pressed, player_move_fire_binds
|
|
18
|
-
from ..persistence.highscores import HighScoreRecord
|
|
19
18
|
from ..ui.cursor import draw_aim_cursor, draw_menu_cursor
|
|
20
19
|
from ..ui.hud import draw_hud_overlay, hud_flags_for_game_mode
|
|
21
20
|
from ..ui.perk_menu import load_perk_menu_assets
|
|
22
21
|
from .base_gameplay_mode import BaseGameplayMode
|
|
22
|
+
from .components.highscore_record_builder import build_highscore_record_for_game_over
|
|
23
23
|
|
|
24
24
|
WORLD_SIZE = 1024.0
|
|
25
25
|
RUSH_WEAPON_ID = 2
|
|
@@ -146,25 +146,14 @@ class RushMode(BaseGameplayMode):
|
|
|
146
146
|
if self._game_over_active:
|
|
147
147
|
return
|
|
148
148
|
|
|
149
|
-
|
|
150
|
-
record
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
try:
|
|
158
|
-
fired = int(self._state.shots_fired[int(self._player.index)])
|
|
159
|
-
hit = int(self._state.shots_hit[int(self._player.index)])
|
|
160
|
-
except Exception:
|
|
161
|
-
fired = 0
|
|
162
|
-
hit = 0
|
|
163
|
-
fired = max(0, int(fired))
|
|
164
|
-
hit = max(0, min(int(hit), fired))
|
|
165
|
-
record.shots_fired = fired
|
|
166
|
-
record.shots_hit = hit
|
|
167
|
-
record.game_mode_id = int(self._config.data.get("game_mode", int(GameMode.RUSH))) if self._config is not None else int(GameMode.RUSH)
|
|
149
|
+
game_mode_id = int(self._config.data.get("game_mode", int(GameMode.RUSH))) if self._config is not None else int(GameMode.RUSH)
|
|
150
|
+
record = build_highscore_record_for_game_over(
|
|
151
|
+
state=self._state,
|
|
152
|
+
player=self._player,
|
|
153
|
+
survival_elapsed_ms=int(self._rush.elapsed_ms),
|
|
154
|
+
creature_kill_count=int(self._creatures.kill_count),
|
|
155
|
+
game_mode_id=game_mode_id,
|
|
156
|
+
)
|
|
168
157
|
|
|
169
158
|
self._game_over_record = record
|
|
170
159
|
self._game_over_ui.open()
|
|
@@ -179,28 +168,7 @@ class RushMode(BaseGameplayMode):
|
|
|
179
168
|
return
|
|
180
169
|
|
|
181
170
|
if self._game_over_active:
|
|
182
|
-
|
|
183
|
-
if record is None:
|
|
184
|
-
self._enter_game_over()
|
|
185
|
-
record = self._game_over_record
|
|
186
|
-
if record is not None:
|
|
187
|
-
action = self._game_over_ui.update(
|
|
188
|
-
dt,
|
|
189
|
-
record=record,
|
|
190
|
-
player_name_default=self._player_name_default(),
|
|
191
|
-
play_sfx=self._world.audio_router.play_sfx,
|
|
192
|
-
rand=self._state.rng.rand,
|
|
193
|
-
mouse=self._ui_mouse_pos(),
|
|
194
|
-
)
|
|
195
|
-
if action == "play_again":
|
|
196
|
-
self.open()
|
|
197
|
-
return
|
|
198
|
-
if action == "high_scores":
|
|
199
|
-
self._action = "open_high_scores"
|
|
200
|
-
return
|
|
201
|
-
if action == "main_menu":
|
|
202
|
-
self._action = "back_to_menu"
|
|
203
|
-
self.close_requested = True
|
|
171
|
+
self._update_game_over_ui(dt)
|
|
204
172
|
return
|
|
205
173
|
|
|
206
174
|
any_alive = any(player.health > 0.0 for player in self._world.players)
|
|
@@ -265,6 +233,7 @@ class RushMode(BaseGameplayMode):
|
|
|
265
233
|
self._draw_target_health_bar()
|
|
266
234
|
hud_bottom = draw_hud_overlay(
|
|
267
235
|
self._hud_assets,
|
|
236
|
+
state=self._hud_state,
|
|
268
237
|
player=self._player,
|
|
269
238
|
players=self._world.players,
|
|
270
239
|
bonus_hud=self._state.bonus_hud,
|