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/tutorial_mode.py
CHANGED
|
@@ -10,45 +10,26 @@ from grim.assets import PaqTextureCache
|
|
|
10
10
|
from grim.audio import AudioState
|
|
11
11
|
from grim.console import ConsoleState
|
|
12
12
|
from grim.config import CrimsonConfig
|
|
13
|
+
from grim.math import clamp
|
|
13
14
|
from grim.view import ViewContext
|
|
14
15
|
|
|
15
|
-
from ..bonuses import BonusId
|
|
16
16
|
from ..creatures.runtime import CreatureFlags
|
|
17
17
|
from ..game_modes import GameMode
|
|
18
|
-
from ..gameplay import PlayerInput,
|
|
18
|
+
from ..gameplay import PlayerInput, survival_check_level_up, weapon_assign_player
|
|
19
19
|
from ..input_codes import config_keybinds, input_code_is_down, input_code_is_pressed, player_move_fire_binds
|
|
20
|
-
from ..perks import PerkId, perk_display_description, perk_display_name
|
|
21
20
|
from ..tutorial.timeline import TutorialFrameActions, TutorialState, tick_tutorial_timeline
|
|
22
21
|
from ..ui.cursor import draw_aim_cursor, draw_menu_cursor
|
|
23
22
|
from ..ui.hud import draw_hud_overlay, hud_flags_for_game_mode, hud_ui_scale
|
|
24
|
-
from ..ui.menu_panel import draw_classic_menu_panel
|
|
25
23
|
from ..ui.perk_menu import (
|
|
26
|
-
PERK_MENU_TRANSITION_MS,
|
|
27
24
|
PerkMenuAssets,
|
|
28
|
-
PerkMenuLayout,
|
|
29
25
|
UiButtonState,
|
|
30
26
|
button_draw,
|
|
31
27
|
button_update,
|
|
32
28
|
button_width,
|
|
33
|
-
draw_menu_item,
|
|
34
|
-
draw_ui_text,
|
|
35
29
|
load_perk_menu_assets,
|
|
36
|
-
menu_item_hit_rect,
|
|
37
|
-
perk_menu_panel_slide_x,
|
|
38
|
-
perk_menu_compute_layout,
|
|
39
|
-
ui_origin,
|
|
40
|
-
ui_scale,
|
|
41
|
-
wrap_ui_text,
|
|
42
30
|
)
|
|
43
31
|
from .base_gameplay_mode import BaseGameplayMode
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
def _clamp(value: float, lo: float, hi: float) -> float:
|
|
47
|
-
if value < lo:
|
|
48
|
-
return lo
|
|
49
|
-
if value > hi:
|
|
50
|
-
return hi
|
|
51
|
-
return value
|
|
32
|
+
from .components.perk_menu_controller import PerkMenuContext, PerkMenuController
|
|
52
33
|
|
|
53
34
|
|
|
54
35
|
UI_TEXT_COLOR = rl.Color(220, 220, 220, 255)
|
|
@@ -95,11 +76,7 @@ class TutorialMode(BaseGameplayMode):
|
|
|
95
76
|
self._ui_assets: PerkMenuAssets | None = None
|
|
96
77
|
self._ui_layout = _TutorialUiLayout()
|
|
97
78
|
|
|
98
|
-
self.
|
|
99
|
-
self._perk_cancel_button = UiButtonState("Cancel")
|
|
100
|
-
self._perk_menu_open = False
|
|
101
|
-
self._perk_menu_selected = 0
|
|
102
|
-
self._perk_menu_timeline_ms = 0.0
|
|
79
|
+
self._perk_menu = PerkMenuController()
|
|
103
80
|
|
|
104
81
|
self._skip_button = UiButtonState("Skip tutorial", force_wide=True)
|
|
105
82
|
self._play_button = UiButtonState("Play a game", force_wide=True)
|
|
@@ -111,11 +88,7 @@ class TutorialMode(BaseGameplayMode):
|
|
|
111
88
|
if self._ui_assets.missing:
|
|
112
89
|
self._missing_assets.extend(self._ui_assets.missing)
|
|
113
90
|
|
|
114
|
-
self.
|
|
115
|
-
self._perk_cancel_button = UiButtonState("Cancel")
|
|
116
|
-
self._perk_menu_open = False
|
|
117
|
-
self._perk_menu_selected = 0
|
|
118
|
-
self._perk_menu_timeline_ms = 0.0
|
|
91
|
+
self._perk_menu.reset()
|
|
119
92
|
|
|
120
93
|
self._skip_button = UiButtonState("Skip tutorial", force_wide=True)
|
|
121
94
|
self._play_button = UiButtonState("Play a game", force_wide=True)
|
|
@@ -136,9 +109,28 @@ class TutorialMode(BaseGameplayMode):
|
|
|
136
109
|
self._ui_assets = None
|
|
137
110
|
super().close()
|
|
138
111
|
|
|
112
|
+
def _perk_menu_context(self) -> PerkMenuContext:
|
|
113
|
+
fx_toggle = int(self._config.data.get("fx_toggle", 0) or 0) if self._config is not None else 0
|
|
114
|
+
fx_detail = bool(int(self._config.data.get("fx_detail_0", 0) or 0)) if self._config is not None else False
|
|
115
|
+
return PerkMenuContext(
|
|
116
|
+
state=self._state,
|
|
117
|
+
perk_state=self._state.perk_selection,
|
|
118
|
+
players=[self._player],
|
|
119
|
+
creatures=self._creatures.entries,
|
|
120
|
+
player=self._player,
|
|
121
|
+
game_mode=int(GameMode.TUTORIAL),
|
|
122
|
+
player_count=1,
|
|
123
|
+
fx_toggle=fx_toggle,
|
|
124
|
+
fx_detail=fx_detail,
|
|
125
|
+
font=self._small,
|
|
126
|
+
assets=self._ui_assets,
|
|
127
|
+
mouse=self._ui_mouse_pos(),
|
|
128
|
+
play_sfx=None,
|
|
129
|
+
)
|
|
130
|
+
|
|
139
131
|
def _handle_input(self) -> None:
|
|
140
|
-
if self.
|
|
141
|
-
self.
|
|
132
|
+
if self._perk_menu.open and rl.is_key_pressed(rl.KeyboardKey.KEY_ESCAPE):
|
|
133
|
+
self._perk_menu.close()
|
|
142
134
|
return
|
|
143
135
|
|
|
144
136
|
if rl.is_key_pressed(rl.KeyboardKey.KEY_TAB):
|
|
@@ -214,7 +206,7 @@ class TutorialMode(BaseGameplayMode):
|
|
|
214
206
|
self._play_button.enabled = prompt_alpha > 1e-3
|
|
215
207
|
self._repeat_button.enabled = prompt_alpha > 1e-3
|
|
216
208
|
else:
|
|
217
|
-
skip_alpha =
|
|
209
|
+
skip_alpha = clamp(float(self._tutorial.stage_timer_ms - 1000) * 0.001, 0.0, 1.0)
|
|
218
210
|
self._skip_button.alpha = skip_alpha
|
|
219
211
|
self._skip_button.enabled = skip_alpha > 1e-3
|
|
220
212
|
|
|
@@ -240,113 +232,6 @@ class TutorialMode(BaseGameplayMode):
|
|
|
240
232
|
if button_update(self._skip_button, x=10.0, y=y, width=w, dt_ms=dt_ms, mouse=mouse, click=click):
|
|
241
233
|
self.close_requested = True
|
|
242
234
|
|
|
243
|
-
def _open_perk_menu(self) -> None:
|
|
244
|
-
if self._ui_assets is None:
|
|
245
|
-
return
|
|
246
|
-
choices = perk_selection_current_choices(
|
|
247
|
-
self._state,
|
|
248
|
-
[self._player],
|
|
249
|
-
self._state.perk_selection,
|
|
250
|
-
game_mode=int(GameMode.TUTORIAL),
|
|
251
|
-
player_count=1,
|
|
252
|
-
)
|
|
253
|
-
if not choices:
|
|
254
|
-
self._perk_menu_open = False
|
|
255
|
-
return
|
|
256
|
-
self._perk_menu_open = True
|
|
257
|
-
self._perk_menu_selected = 0
|
|
258
|
-
|
|
259
|
-
def _perk_menu_handle_input(self, dt_frame: float, dt_ms: float) -> None:
|
|
260
|
-
if self._ui_assets is None:
|
|
261
|
-
self._perk_menu_open = False
|
|
262
|
-
return
|
|
263
|
-
|
|
264
|
-
perk_state = self._state.perk_selection
|
|
265
|
-
choices = perk_selection_current_choices(
|
|
266
|
-
self._state,
|
|
267
|
-
[self._player],
|
|
268
|
-
perk_state,
|
|
269
|
-
game_mode=int(GameMode.TUTORIAL),
|
|
270
|
-
player_count=1,
|
|
271
|
-
)
|
|
272
|
-
if not choices:
|
|
273
|
-
self._perk_menu_open = False
|
|
274
|
-
return
|
|
275
|
-
if self._perk_menu_selected >= len(choices):
|
|
276
|
-
self._perk_menu_selected = 0
|
|
277
|
-
|
|
278
|
-
if rl.is_key_pressed(rl.KeyboardKey.KEY_DOWN):
|
|
279
|
-
self._perk_menu_selected = (self._perk_menu_selected + 1) % len(choices)
|
|
280
|
-
if rl.is_key_pressed(rl.KeyboardKey.KEY_UP):
|
|
281
|
-
self._perk_menu_selected = (self._perk_menu_selected - 1) % len(choices)
|
|
282
|
-
|
|
283
|
-
screen_w = float(rl.get_screen_width())
|
|
284
|
-
screen_h = float(rl.get_screen_height())
|
|
285
|
-
scale = ui_scale(screen_w, screen_h)
|
|
286
|
-
origin_x, origin_y = ui_origin(screen_w, screen_h, scale)
|
|
287
|
-
slide_x = perk_menu_panel_slide_x(self._perk_menu_timeline_ms, width=self._perk_ui_layout.panel_w)
|
|
288
|
-
slide_x = perk_menu_panel_slide_x(self._perk_menu_timeline_ms, width=self._perk_ui_layout.panel_w)
|
|
289
|
-
|
|
290
|
-
mouse = self._ui_mouse_pos()
|
|
291
|
-
click = rl.is_mouse_button_pressed(rl.MouseButton.MOUSE_BUTTON_LEFT)
|
|
292
|
-
|
|
293
|
-
master_owned = int(self._player.perk_counts[int(PerkId.PERK_MASTER)]) > 0
|
|
294
|
-
expert_owned = int(self._player.perk_counts[int(PerkId.PERK_EXPERT)]) > 0
|
|
295
|
-
computed = perk_menu_compute_layout(
|
|
296
|
-
self._perk_ui_layout,
|
|
297
|
-
screen_w=screen_w,
|
|
298
|
-
origin_x=origin_x,
|
|
299
|
-
origin_y=origin_y,
|
|
300
|
-
scale=scale,
|
|
301
|
-
choice_count=len(choices),
|
|
302
|
-
expert_owned=expert_owned,
|
|
303
|
-
master_owned=master_owned,
|
|
304
|
-
panel_slide_x=slide_x,
|
|
305
|
-
)
|
|
306
|
-
|
|
307
|
-
fx_toggle = int(self._config.data.get("fx_toggle", 0) or 0) if self._config is not None else 0
|
|
308
|
-
for idx, perk_id in enumerate(choices):
|
|
309
|
-
label = perk_display_name(int(perk_id), fx_toggle=fx_toggle)
|
|
310
|
-
item_x = computed.list_x
|
|
311
|
-
item_y = computed.list_y + float(idx) * computed.list_step_y
|
|
312
|
-
rect = menu_item_hit_rect(self._small, label, x=item_x, y=item_y, scale=scale)
|
|
313
|
-
if rl.check_collision_point_rec(mouse, rect):
|
|
314
|
-
self._perk_menu_selected = idx
|
|
315
|
-
if click:
|
|
316
|
-
perk_selection_pick(
|
|
317
|
-
self._state,
|
|
318
|
-
[self._player],
|
|
319
|
-
perk_state,
|
|
320
|
-
idx,
|
|
321
|
-
game_mode=int(GameMode.TUTORIAL),
|
|
322
|
-
player_count=1,
|
|
323
|
-
dt=dt_frame,
|
|
324
|
-
creatures=self._creatures.entries,
|
|
325
|
-
)
|
|
326
|
-
self._perk_menu_open = False
|
|
327
|
-
return
|
|
328
|
-
break
|
|
329
|
-
|
|
330
|
-
cancel_w = button_width(self._small, self._perk_cancel_button.label, scale=scale, force_wide=self._perk_cancel_button.force_wide)
|
|
331
|
-
cancel_x = computed.cancel_x
|
|
332
|
-
cancel_y = computed.cancel_y
|
|
333
|
-
if button_update(self._perk_cancel_button, x=cancel_x, y=cancel_y, width=cancel_w, dt_ms=dt_ms, mouse=mouse, click=click):
|
|
334
|
-
self._perk_menu_open = False
|
|
335
|
-
return
|
|
336
|
-
|
|
337
|
-
if rl.is_key_pressed(rl.KeyboardKey.KEY_ENTER) or rl.is_key_pressed(rl.KeyboardKey.KEY_SPACE):
|
|
338
|
-
perk_selection_pick(
|
|
339
|
-
self._state,
|
|
340
|
-
[self._player],
|
|
341
|
-
perk_state,
|
|
342
|
-
self._perk_menu_selected,
|
|
343
|
-
game_mode=int(GameMode.TUTORIAL),
|
|
344
|
-
player_count=1,
|
|
345
|
-
dt=dt_frame,
|
|
346
|
-
creatures=self._creatures.entries,
|
|
347
|
-
)
|
|
348
|
-
self._perk_menu_open = False
|
|
349
|
-
|
|
350
235
|
def update(self, dt: float) -> None:
|
|
351
236
|
self._update_audio(dt)
|
|
352
237
|
dt_frame, dt_ui_ms = self._tick_frame(dt, clamp_cursor_pulse=True)
|
|
@@ -357,18 +242,15 @@ class TutorialMode(BaseGameplayMode):
|
|
|
357
242
|
if self.close_requested:
|
|
358
243
|
return
|
|
359
244
|
|
|
245
|
+
perk_ctx = self._perk_menu_context()
|
|
360
246
|
perk_pending = int(self._state.perk_selection.pending_count) > 0 and self._player.health > 0.0
|
|
361
|
-
if int(self._tutorial.stage_index) == 6 and perk_pending and not self.
|
|
362
|
-
self.
|
|
363
|
-
|
|
364
|
-
perk_menu_active = self._perk_menu_open or self._perk_menu_timeline_ms > 1e-3
|
|
365
|
-
if self._perk_menu_open:
|
|
366
|
-
self._perk_menu_handle_input(dt_frame, dt_ui_ms)
|
|
247
|
+
if int(self._tutorial.stage_index) == 6 and perk_pending and not self._perk_menu.open:
|
|
248
|
+
self._perk_menu.open_if_available(perk_ctx)
|
|
367
249
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
250
|
+
perk_menu_active = self._perk_menu.active
|
|
251
|
+
if self._perk_menu.open:
|
|
252
|
+
self._perk_menu.handle_input(perk_ctx, dt_frame=dt_frame, dt_ui_ms=dt_ui_ms)
|
|
253
|
+
self._perk_menu.tick_timeline(dt_ui_ms)
|
|
372
254
|
|
|
373
255
|
dt_world = 0.0 if self._paused or perk_menu_active else dt_frame
|
|
374
256
|
|
|
@@ -418,6 +300,10 @@ class TutorialMode(BaseGameplayMode):
|
|
|
418
300
|
self._player.experience = int(actions.force_player_experience)
|
|
419
301
|
survival_check_level_up(self._player, self._state.perk_selection)
|
|
420
302
|
|
|
303
|
+
detail_preset = 5
|
|
304
|
+
if self._world.config is not None:
|
|
305
|
+
detail_preset = int(self._world.config.data.get("detail_preset", 5) or 5)
|
|
306
|
+
|
|
421
307
|
for call in actions.spawn_bonuses:
|
|
422
308
|
spawned = self._state.bonus_pool.spawn_at(
|
|
423
309
|
float(call.pos[0]),
|
|
@@ -433,7 +319,7 @@ class TutorialMode(BaseGameplayMode):
|
|
|
433
319
|
pos_y=float(spawned.pos_y),
|
|
434
320
|
count=12,
|
|
435
321
|
rand=self._state.rng.rand,
|
|
436
|
-
detail_preset=
|
|
322
|
+
detail_preset=detail_preset,
|
|
437
323
|
)
|
|
438
324
|
|
|
439
325
|
for call in actions.spawn_templates:
|
|
@@ -443,6 +329,8 @@ class TutorialMode(BaseGameplayMode):
|
|
|
443
329
|
float(call.heading),
|
|
444
330
|
self._state.rng,
|
|
445
331
|
rand=self._state.rng.rand,
|
|
332
|
+
state=self._state,
|
|
333
|
+
detail_preset=detail_preset,
|
|
446
334
|
)
|
|
447
335
|
if int(call.template_id) == 0x27 and primary is not None and actions.stage5_bonus_carrier_drop is not None:
|
|
448
336
|
drop_id, drop_amount = actions.stage5_bonus_carrier_drop
|
|
@@ -458,7 +346,7 @@ class TutorialMode(BaseGameplayMode):
|
|
|
458
346
|
self._update_prompt_buttons(dt_ms=dt_ui_ms, mouse=mouse, click=click)
|
|
459
347
|
|
|
460
348
|
def draw(self) -> None:
|
|
461
|
-
perk_menu_active = self.
|
|
349
|
+
perk_menu_active = self._perk_menu.active
|
|
462
350
|
self._world.draw(draw_aim_indicators=not perk_menu_active)
|
|
463
351
|
self._draw_screen_fade()
|
|
464
352
|
|
|
@@ -468,6 +356,7 @@ class TutorialMode(BaseGameplayMode):
|
|
|
468
356
|
self._draw_target_health_bar()
|
|
469
357
|
hud_bottom = draw_hud_overlay(
|
|
470
358
|
self._hud_assets,
|
|
359
|
+
state=self._hud_state,
|
|
471
360
|
player=self._player,
|
|
472
361
|
players=self._world.players,
|
|
473
362
|
bonus_hud=self._state.bonus_hud,
|
|
@@ -496,7 +385,7 @@ class TutorialMode(BaseGameplayMode):
|
|
|
496
385
|
self._draw_ui_text(warn, 24.0, warn_y, UI_ERROR_COLOR, scale=0.8)
|
|
497
386
|
|
|
498
387
|
if perk_menu_active:
|
|
499
|
-
self.
|
|
388
|
+
self._perk_menu.draw(self._perk_menu_context())
|
|
500
389
|
self._draw_menu_cursor()
|
|
501
390
|
else:
|
|
502
391
|
self._draw_aim_cursor()
|
|
@@ -538,14 +427,14 @@ class TutorialMode(BaseGameplayMode):
|
|
|
538
427
|
self._draw_ui_text("paused (TAB)", x, y, UI_HINT_COLOR)
|
|
539
428
|
|
|
540
429
|
def _draw_prompt_panel(self, text: str, *, alpha: float, y: float) -> None:
|
|
541
|
-
alpha =
|
|
430
|
+
alpha = clamp(float(alpha), 0.0, 1.0)
|
|
542
431
|
rect, lines, line_h = self._prompt_panel_rect(text, y=float(y), scale=1.0)
|
|
543
432
|
fill = rl.Color(0, 0, 0, int(255 * alpha * 0.8))
|
|
544
433
|
border = rl.Color(255, 255, 255, int(255 * alpha))
|
|
545
434
|
rl.draw_rectangle(int(rect.x), int(rect.y), int(rect.width), int(rect.height), fill)
|
|
546
435
|
rl.draw_rectangle_lines(int(rect.x), int(rect.y), int(rect.width), int(rect.height), border)
|
|
547
436
|
|
|
548
|
-
text_alpha = int(255 *
|
|
437
|
+
text_alpha = int(255 * clamp(alpha * 0.9, 0.0, 1.0))
|
|
549
438
|
color = rl.Color(255, 255, 255, text_alpha)
|
|
550
439
|
x = float(rect.x + self._ui_layout.panel_pad_x)
|
|
551
440
|
line_y = float(rect.y + self._ui_layout.panel_pad_y)
|
|
@@ -577,93 +466,3 @@ class TutorialMode(BaseGameplayMode):
|
|
|
577
466
|
x=float(self._ui_mouse_x),
|
|
578
467
|
y=float(self._ui_mouse_y),
|
|
579
468
|
)
|
|
580
|
-
|
|
581
|
-
def _draw_perk_menu(self) -> None:
|
|
582
|
-
assets = self._ui_assets
|
|
583
|
-
if assets is None:
|
|
584
|
-
return
|
|
585
|
-
perk_state = self._state.perk_selection
|
|
586
|
-
choices = perk_selection_current_choices(
|
|
587
|
-
self._state,
|
|
588
|
-
[self._player],
|
|
589
|
-
perk_state,
|
|
590
|
-
game_mode=int(GameMode.TUTORIAL),
|
|
591
|
-
player_count=1,
|
|
592
|
-
)
|
|
593
|
-
if not choices:
|
|
594
|
-
return
|
|
595
|
-
|
|
596
|
-
screen_w = float(rl.get_screen_width())
|
|
597
|
-
screen_h = float(rl.get_screen_height())
|
|
598
|
-
scale = ui_scale(screen_w, screen_h)
|
|
599
|
-
origin_x, origin_y = ui_origin(screen_w, screen_h, scale)
|
|
600
|
-
|
|
601
|
-
master_owned = int(self._player.perk_counts[int(PerkId.PERK_MASTER)]) > 0
|
|
602
|
-
expert_owned = int(self._player.perk_counts[int(PerkId.PERK_EXPERT)]) > 0
|
|
603
|
-
computed = perk_menu_compute_layout(
|
|
604
|
-
self._perk_ui_layout,
|
|
605
|
-
screen_w=screen_w,
|
|
606
|
-
origin_x=origin_x,
|
|
607
|
-
origin_y=origin_y,
|
|
608
|
-
scale=scale,
|
|
609
|
-
choice_count=len(choices),
|
|
610
|
-
expert_owned=expert_owned,
|
|
611
|
-
master_owned=master_owned,
|
|
612
|
-
panel_slide_x=slide_x,
|
|
613
|
-
)
|
|
614
|
-
|
|
615
|
-
panel_tex = assets.menu_panel
|
|
616
|
-
if panel_tex is not None:
|
|
617
|
-
fx_detail = bool(int(self._config.data.get("fx_detail_0", 0) or 0)) if self._config is not None else False
|
|
618
|
-
draw_classic_menu_panel(panel_tex, dst=computed.panel, shadow=fx_detail)
|
|
619
|
-
|
|
620
|
-
title_tex = assets.title_pick_perk
|
|
621
|
-
if title_tex is not None:
|
|
622
|
-
src = rl.Rectangle(0.0, 0.0, float(title_tex.width), float(title_tex.height))
|
|
623
|
-
rl.draw_texture_pro(title_tex, src, computed.title, rl.Vector2(0.0, 0.0), 0.0, rl.WHITE)
|
|
624
|
-
|
|
625
|
-
sponsor = None
|
|
626
|
-
if master_owned:
|
|
627
|
-
sponsor = "extra perks sponsored by the Perk Master"
|
|
628
|
-
elif expert_owned:
|
|
629
|
-
sponsor = "extra perk sponsored by the Perk Expert"
|
|
630
|
-
if sponsor:
|
|
631
|
-
draw_ui_text(
|
|
632
|
-
self._small,
|
|
633
|
-
sponsor,
|
|
634
|
-
computed.sponsor_x,
|
|
635
|
-
computed.sponsor_y,
|
|
636
|
-
scale=scale,
|
|
637
|
-
color=UI_SPONSOR_COLOR,
|
|
638
|
-
)
|
|
639
|
-
|
|
640
|
-
mouse = self._ui_mouse_pos()
|
|
641
|
-
fx_toggle = int(self._config.data.get("fx_toggle", 0) or 0) if self._config is not None else 0
|
|
642
|
-
for idx, perk_id in enumerate(choices):
|
|
643
|
-
label = perk_display_name(int(perk_id), fx_toggle=fx_toggle)
|
|
644
|
-
item_x = computed.list_x
|
|
645
|
-
item_y = computed.list_y + float(idx) * computed.list_step_y
|
|
646
|
-
rect = menu_item_hit_rect(self._small, label, x=item_x, y=item_y, scale=scale)
|
|
647
|
-
hovered = rl.check_collision_point_rec(mouse, rect) or (idx == self._perk_menu_selected)
|
|
648
|
-
draw_menu_item(self._small, label, x=item_x, y=item_y, scale=scale, hovered=hovered)
|
|
649
|
-
|
|
650
|
-
selected = choices[self._perk_menu_selected]
|
|
651
|
-
desc = perk_display_description(int(selected), fx_toggle=fx_toggle)
|
|
652
|
-
desc_x = float(computed.desc.x)
|
|
653
|
-
desc_y = float(computed.desc.y)
|
|
654
|
-
desc_w = float(computed.desc.width)
|
|
655
|
-
desc_h = float(computed.desc.height)
|
|
656
|
-
desc_scale = scale * 0.85
|
|
657
|
-
desc_lines = wrap_ui_text(self._small, desc, max_width=desc_w, scale=desc_scale)
|
|
658
|
-
line_h = float(self._small.cell_size * desc_scale) if self._small is not None else float(20 * desc_scale)
|
|
659
|
-
y = desc_y
|
|
660
|
-
for line in desc_lines:
|
|
661
|
-
if y + line_h > desc_y + desc_h:
|
|
662
|
-
break
|
|
663
|
-
draw_ui_text(self._small, line, desc_x, y, scale=desc_scale, color=UI_TEXT_COLOR)
|
|
664
|
-
y += line_h
|
|
665
|
-
|
|
666
|
-
cancel_w = button_width(self._small, self._perk_cancel_button.label, scale=scale, force_wide=self._perk_cancel_button.force_wide)
|
|
667
|
-
cancel_x = computed.cancel_x
|
|
668
|
-
cancel_y = computed.cancel_y
|
|
669
|
-
button_draw(assets, self._small, self._perk_cancel_button, x=cancel_x, y=cancel_y, width=cancel_w, scale=scale)
|
crimson/modes/typo_mode.py
CHANGED
|
@@ -14,9 +14,7 @@ from grim.view import ViewContext
|
|
|
14
14
|
|
|
15
15
|
from ..creatures.spawn import CreatureFlags, CreatureInit, CreatureTypeId
|
|
16
16
|
from ..game_modes import GameMode
|
|
17
|
-
from ..gameplay import most_used_weapon_id_for_player
|
|
18
17
|
from ..typo.player import build_typo_player_input, enforce_typo_player_frame
|
|
19
|
-
from ..persistence.highscores import HighScoreRecord
|
|
20
18
|
from ..typo.names import CreatureNameTable, load_typo_dictionary
|
|
21
19
|
from ..typo.spawns import tick_typo_spawns
|
|
22
20
|
from ..typo.typing import TypingBuffer
|
|
@@ -24,6 +22,7 @@ from ..ui.cursor import draw_aim_cursor, draw_menu_cursor
|
|
|
24
22
|
from ..ui.hud import draw_hud_overlay, hud_flags_for_game_mode
|
|
25
23
|
from ..ui.perk_menu import load_perk_menu_assets
|
|
26
24
|
from .base_gameplay_mode import BaseGameplayMode
|
|
25
|
+
from .components.highscore_record_builder import build_highscore_record_for_game_over
|
|
27
26
|
|
|
28
27
|
WORLD_SIZE = 1024.0
|
|
29
28
|
|
|
@@ -211,48 +210,21 @@ class TypoShooterMode(BaseGameplayMode):
|
|
|
211
210
|
if self._game_over_active:
|
|
212
211
|
return
|
|
213
212
|
|
|
214
|
-
record =
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
213
|
+
record = build_highscore_record_for_game_over(
|
|
214
|
+
state=self._state,
|
|
215
|
+
player=self._player,
|
|
216
|
+
survival_elapsed_ms=int(self._typo.elapsed_ms),
|
|
217
|
+
creature_kill_count=int(self._creatures.kill_count),
|
|
218
|
+
game_mode_id=int(GameMode.TYPO),
|
|
219
|
+
shots_fired=int(self._typing.shots_fired),
|
|
220
|
+
shots_hit=int(self._typing.shots_hit),
|
|
221
|
+
clamp_shots_hit=False,
|
|
220
222
|
)
|
|
221
|
-
record.most_used_weapon_id = int(weapon_id)
|
|
222
|
-
record.shots_fired = int(self._typing.shots_fired)
|
|
223
|
-
record.shots_hit = int(self._typing.shots_hit)
|
|
224
|
-
record.game_mode_id = int(GameMode.TYPO)
|
|
225
223
|
|
|
226
224
|
self._game_over_record = record
|
|
227
225
|
self._game_over_ui.open()
|
|
228
226
|
self._game_over_active = True
|
|
229
227
|
|
|
230
|
-
def _update_game_over_ui(self, dt: float) -> None:
|
|
231
|
-
record = self._game_over_record
|
|
232
|
-
if record is None:
|
|
233
|
-
self._enter_game_over()
|
|
234
|
-
record = self._game_over_record
|
|
235
|
-
if record is None:
|
|
236
|
-
return
|
|
237
|
-
|
|
238
|
-
action = self._game_over_ui.update(
|
|
239
|
-
dt,
|
|
240
|
-
record=record,
|
|
241
|
-
player_name_default=self._player_name_default(),
|
|
242
|
-
play_sfx=self._world.audio_router.play_sfx,
|
|
243
|
-
rand=self._state.rng.rand,
|
|
244
|
-
mouse=self._ui_mouse_pos(),
|
|
245
|
-
)
|
|
246
|
-
if action == "play_again":
|
|
247
|
-
self.open()
|
|
248
|
-
return
|
|
249
|
-
if action == "high_scores":
|
|
250
|
-
self._action = "open_high_scores"
|
|
251
|
-
return
|
|
252
|
-
if action == "main_menu":
|
|
253
|
-
self._action = "back_to_menu"
|
|
254
|
-
self.close_requested = True
|
|
255
|
-
|
|
256
228
|
def update(self, dt: float) -> None:
|
|
257
229
|
self._update_audio(dt)
|
|
258
230
|
|
|
@@ -444,6 +416,7 @@ class TypoShooterMode(BaseGameplayMode):
|
|
|
444
416
|
self._draw_target_health_bar()
|
|
445
417
|
draw_hud_overlay(
|
|
446
418
|
self._hud_assets,
|
|
419
|
+
state=self._hud_state,
|
|
447
420
|
player=self._player,
|
|
448
421
|
players=self._world.players,
|
|
449
422
|
bonus_hud=self._state.bonus_hud,
|