crimsonland 0.1.0.dev11__py3-none-any.whl → 0.1.0.dev13__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/assets_fetch.py +23 -8
- crimson/creatures/runtime.py +15 -0
- crimson/demo.py +47 -38
- crimson/effects.py +46 -1
- crimson/frontend/boot.py +2 -1
- crimson/frontend/high_scores_layout.py +26 -0
- crimson/frontend/menu.py +24 -43
- crimson/frontend/panels/base.py +27 -29
- crimson/frontend/panels/controls.py +152 -65
- crimson/frontend/panels/credits.py +221 -0
- crimson/frontend/panels/databases.py +307 -0
- crimson/frontend/panels/mods.py +1 -3
- crimson/frontend/panels/options.py +36 -42
- crimson/frontend/panels/play_game.py +82 -74
- crimson/frontend/panels/stats.py +255 -298
- crimson/frontend/pause_menu.py +425 -0
- crimson/game.py +512 -505
- crimson/gameplay.py +35 -6
- crimson/modes/base_gameplay_mode.py +3 -0
- crimson/modes/quest_mode.py +54 -44
- crimson/modes/rush_mode.py +4 -1
- crimson/modes/survival_mode.py +15 -10
- crimson/modes/tutorial_mode.py +15 -5
- crimson/modes/typo_mode.py +4 -1
- crimson/persistence/highscores.py +6 -2
- crimson/render/world_renderer.py +1 -1
- crimson/sim/world_state.py +8 -1
- crimson/typo/spawns.py +3 -4
- crimson/ui/demo_trial_overlay.py +3 -3
- crimson/ui/game_over.py +18 -2
- crimson/ui/menu_panel.py +127 -0
- crimson/ui/perk_menu.py +101 -44
- crimson/ui/quest_results.py +669 -0
- crimson/ui/shadow.py +39 -0
- crimson/views/particles.py +1 -1
- crimson/views/perk_menu_debug.py +2 -2
- crimson/views/perks.py +2 -2
- crimson/weapons.py +110 -110
- {crimsonland-0.1.0.dev11.dist-info → crimsonland-0.1.0.dev13.dist-info}/METADATA +1 -1
- {crimsonland-0.1.0.dev11.dist-info → crimsonland-0.1.0.dev13.dist-info}/RECORD +43 -36
- grim/app.py +3 -0
- {crimsonland-0.1.0.dev11.dist-info → crimsonland-0.1.0.dev13.dist-info}/WHEEL +0 -0
- {crimsonland-0.1.0.dev11.dist-info → crimsonland-0.1.0.dev13.dist-info}/entry_points.txt +0 -0
|
@@ -9,13 +9,12 @@ from grim.audio import update_audio
|
|
|
9
9
|
from grim.fonts.small import SmallFontData, draw_small_text, load_small_font, measure_small_text_width
|
|
10
10
|
|
|
11
11
|
from ...debug import debug_enabled
|
|
12
|
+
from ...ui.perk_menu import UiButtonState, UiButtonTextureSet, button_draw, button_update, button_width
|
|
12
13
|
|
|
13
14
|
from ..menu import (
|
|
14
15
|
MENU_LABEL_ROW_HEIGHT,
|
|
15
16
|
MENU_LABEL_ROW_PLAY_GAME,
|
|
16
17
|
MENU_LABEL_WIDTH,
|
|
17
|
-
MENU_PANEL_OFFSET_X,
|
|
18
|
-
MENU_PANEL_OFFSET_Y,
|
|
19
18
|
MENU_PANEL_WIDTH,
|
|
20
19
|
MenuView,
|
|
21
20
|
_draw_menu_cursor,
|
|
@@ -49,11 +48,14 @@ class PlayGameMenuView(PanelMenuView):
|
|
|
49
48
|
super().__init__(
|
|
50
49
|
state,
|
|
51
50
|
title="Play Game",
|
|
51
|
+
panel_offset_x=-63.0,
|
|
52
|
+
panel_height=278.0,
|
|
52
53
|
back_pos_y=462.0,
|
|
53
54
|
)
|
|
54
55
|
self._small_font: SmallFontData | None = None
|
|
55
56
|
self._button_sm: rl.Texture2D | None = None
|
|
56
57
|
self._button_md: rl.Texture2D | None = None
|
|
58
|
+
self._button_textures: UiButtonTextureSet | None = None
|
|
57
59
|
self._drop_on: rl.Texture2D | None = None
|
|
58
60
|
self._drop_off: rl.Texture2D | None = None
|
|
59
61
|
|
|
@@ -62,17 +64,20 @@ class PlayGameMenuView(PanelMenuView):
|
|
|
62
64
|
|
|
63
65
|
# Hover fade timers for tooltips (0..1000ms-ish; original uses ~0.0009 alpha scale).
|
|
64
66
|
self._tooltip_ms: dict[str, int] = {}
|
|
67
|
+
self._mode_buttons: dict[str, UiButtonState] = {}
|
|
65
68
|
|
|
66
69
|
def open(self) -> None:
|
|
67
70
|
super().open()
|
|
68
71
|
cache = self._ensure_cache()
|
|
69
72
|
self._button_sm = cache.get_or_load("ui_buttonSm", "ui/ui_button_64x32.jaz").texture
|
|
70
73
|
self._button_md = cache.get_or_load("ui_buttonMd", "ui/ui_button_128x32.jaz").texture
|
|
74
|
+
self._button_textures = UiButtonTextureSet(button_sm=self._button_sm, button_md=self._button_md)
|
|
71
75
|
self._drop_on = cache.get_or_load("ui_dropOn", "ui/ui_dropDownOn.jaz").texture
|
|
72
76
|
self._drop_off = cache.get_or_load("ui_dropOff", "ui/ui_dropDownOff.jaz").texture
|
|
73
77
|
self._player_list_open = False
|
|
74
78
|
self._dirty = False
|
|
75
79
|
self._tooltip_ms.clear()
|
|
80
|
+
self._mode_buttons.clear()
|
|
76
81
|
|
|
77
82
|
def update(self, dt: float) -> None:
|
|
78
83
|
if self._state.audio is not None:
|
|
@@ -133,14 +138,24 @@ class PlayGameMenuView(PanelMenuView):
|
|
|
133
138
|
if consumed_click:
|
|
134
139
|
return
|
|
135
140
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
141
|
+
mouse = rl.get_mouse_position()
|
|
142
|
+
click = rl.is_mouse_button_pressed(rl.MOUSE_BUTTON_LEFT)
|
|
143
|
+
button_enabled = not self._player_list_open
|
|
144
|
+
|
|
139
145
|
y = base_y
|
|
140
146
|
entries, y_step, y_start, y_end = self._mode_entries()
|
|
141
147
|
y += y_start * scale
|
|
142
148
|
for mode in entries:
|
|
143
|
-
clicked, hovered = self._update_mode_button(
|
|
149
|
+
clicked, hovered = self._update_mode_button(
|
|
150
|
+
mode,
|
|
151
|
+
base_x,
|
|
152
|
+
y,
|
|
153
|
+
scale,
|
|
154
|
+
dt_ms=dt_ms,
|
|
155
|
+
mouse=mouse,
|
|
156
|
+
click=click,
|
|
157
|
+
enabled=button_enabled,
|
|
158
|
+
)
|
|
144
159
|
self._update_tooltip_timer(mode.key, hovered, dt_ms)
|
|
145
160
|
if clicked:
|
|
146
161
|
self._activate_mode(mode)
|
|
@@ -155,9 +170,7 @@ class PlayGameMenuView(PanelMenuView):
|
|
|
155
170
|
self._tooltip_ms[key] = max(0, self._tooltip_ms[key] - dt_ms * 2)
|
|
156
171
|
|
|
157
172
|
def draw(self) -> None:
|
|
158
|
-
|
|
159
|
-
if self._ground is not None:
|
|
160
|
-
self._ground.draw(0.0, 0.0)
|
|
173
|
+
self._draw_background()
|
|
161
174
|
_draw_screen_fade(self._state)
|
|
162
175
|
assets = self._assets
|
|
163
176
|
entry = self._entry
|
|
@@ -198,8 +211,8 @@ class PlayGameMenuView(PanelMenuView):
|
|
|
198
211
|
)
|
|
199
212
|
panel_x = self._panel_pos_x + slide_x
|
|
200
213
|
panel_y = self._panel_pos_y + self._widescreen_y_shift
|
|
201
|
-
origin_x = -(
|
|
202
|
-
origin_y = -(
|
|
214
|
+
origin_x = -(self._panel_offset_x * panel_scale)
|
|
215
|
+
origin_y = -(self._panel_offset_y * panel_scale)
|
|
203
216
|
panel_left = panel_x - origin_x
|
|
204
217
|
panel_top = panel_y - origin_y
|
|
205
218
|
|
|
@@ -325,31 +338,33 @@ class PlayGameMenuView(PanelMenuView):
|
|
|
325
338
|
y_end = y_start + y_step * float(len(entries))
|
|
326
339
|
return entries, y_step, y_start, y_end
|
|
327
340
|
|
|
328
|
-
def
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
341
|
+
def _mode_button_state(self, mode: _PlayGameModeEntry) -> UiButtonState:
|
|
342
|
+
state = self._mode_buttons.get(mode.key)
|
|
343
|
+
if state is None:
|
|
344
|
+
state = UiButtonState(mode.label)
|
|
345
|
+
self._mode_buttons[mode.key] = state
|
|
346
|
+
else:
|
|
347
|
+
state.label = mode.label
|
|
348
|
+
return state
|
|
349
|
+
|
|
350
|
+
def _update_mode_button(
|
|
351
|
+
self,
|
|
352
|
+
mode: _PlayGameModeEntry,
|
|
353
|
+
x: float,
|
|
354
|
+
y: float,
|
|
355
|
+
scale: float,
|
|
356
|
+
*,
|
|
357
|
+
dt_ms: int,
|
|
358
|
+
mouse: rl.Vector2,
|
|
359
|
+
click: bool,
|
|
360
|
+
enabled: bool,
|
|
361
|
+
) -> tuple[bool, bool]:
|
|
362
|
+
state = self._mode_button_state(mode)
|
|
363
|
+
state.enabled = bool(enabled)
|
|
337
364
|
font = self._ensure_small_font()
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
def _mode_button_rect(self, label: str, x: float, y: float, scale: float) -> rl.Rectangle:
|
|
342
|
-
tex = self._button_tex_for_label(label, scale)
|
|
343
|
-
if tex is None:
|
|
344
|
-
return rl.Rectangle(x, y, 145.0 * scale, 32.0 * scale)
|
|
345
|
-
return rl.Rectangle(x, y, float(tex.width) * scale, float(tex.height) * scale)
|
|
346
|
-
|
|
347
|
-
def _update_mode_button(self, mode: _PlayGameModeEntry, x: float, y: float, scale: float) -> tuple[bool, bool]:
|
|
348
|
-
rect = self._mode_button_rect(mode.label, x, y, scale)
|
|
349
|
-
mouse = rl.get_mouse_position()
|
|
350
|
-
hovered = rect.x <= mouse.x <= rect.x + rect.width and rect.y <= mouse.y <= rect.y + rect.height
|
|
351
|
-
clicked = hovered and rl.is_mouse_button_pressed(rl.MOUSE_BUTTON_LEFT)
|
|
352
|
-
return clicked, hovered
|
|
365
|
+
width = button_width(font, state.label, scale=scale, force_wide=state.force_wide)
|
|
366
|
+
clicked = button_update(state, x=x, y=y, width=width, dt_ms=float(dt_ms), mouse=mouse, click=bool(click))
|
|
367
|
+
return clicked, state.hovered
|
|
353
368
|
|
|
354
369
|
def _activate_mode(self, mode: _PlayGameModeEntry) -> None:
|
|
355
370
|
if mode.game_mode is not None:
|
|
@@ -456,19 +471,24 @@ class PlayGameMenuView(PanelMenuView):
|
|
|
456
471
|
text_scale = 1.0 * scale
|
|
457
472
|
text_color = rl.Color(255, 255, 255, int(255 * 0.8))
|
|
458
473
|
|
|
459
|
-
#
|
|
474
|
+
# `sub_44ed80`: title label at (xy - 64, var_1c - 8), size 128x32.
|
|
475
|
+
title_w = 128.0
|
|
476
|
+
title_h = MENU_LABEL_ROW_HEIGHT
|
|
477
|
+
title_x = base_x - 64.0 * scale
|
|
478
|
+
title_y = base_y - 8.0 * scale
|
|
479
|
+
|
|
460
480
|
if labels_tex is not None:
|
|
461
481
|
src = rl.Rectangle(
|
|
462
482
|
0.0,
|
|
463
483
|
float(MENU_LABEL_ROW_PLAY_GAME) * MENU_LABEL_ROW_HEIGHT,
|
|
464
|
-
|
|
465
|
-
|
|
484
|
+
title_w,
|
|
485
|
+
title_h,
|
|
466
486
|
)
|
|
467
487
|
dst = rl.Rectangle(
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
488
|
+
title_x,
|
|
489
|
+
title_y,
|
|
490
|
+
title_w * scale,
|
|
491
|
+
title_h * scale,
|
|
472
492
|
)
|
|
473
493
|
MenuView._draw_ui_quad(
|
|
474
494
|
texture=labels_tex,
|
|
@@ -479,9 +499,7 @@ class PlayGameMenuView(PanelMenuView):
|
|
|
479
499
|
tint=rl.WHITE,
|
|
480
500
|
)
|
|
481
501
|
else:
|
|
482
|
-
rl.draw_text(self._title, int(
|
|
483
|
-
|
|
484
|
-
self._draw_player_count(drop_x, drop_y, scale)
|
|
502
|
+
rl.draw_text(self._title, int(title_x), int(title_y), int(24 * scale), rl.WHITE)
|
|
485
503
|
|
|
486
504
|
entries, y_step, y_start, y_end = self._mode_entries()
|
|
487
505
|
y = base_y + y_start * scale
|
|
@@ -496,6 +514,8 @@ class PlayGameMenuView(PanelMenuView):
|
|
|
496
514
|
self._draw_mode_count(mode.key, base_x + 158.0 * scale, y + 8.0 * scale, text_scale, text_color)
|
|
497
515
|
y += y_step * scale
|
|
498
516
|
|
|
517
|
+
# `sub_44ed80`: the list widget is drawn before tooltips, so tooltips can overlay it.
|
|
518
|
+
self._draw_player_count(drop_x, drop_y, scale)
|
|
499
519
|
self._draw_tooltips(entries, base_x, base_y, y_end, scale)
|
|
500
520
|
|
|
501
521
|
def _draw_player_count(self, x: float, y: float, scale: float) -> None:
|
|
@@ -518,13 +538,18 @@ class PlayGameMenuView(PanelMenuView):
|
|
|
518
538
|
|
|
519
539
|
# `ui_list_widget_update` draws a single bordered black rect for the widget.
|
|
520
540
|
widget_h = full_h if self._player_list_open else header_h
|
|
521
|
-
rl.draw_rectangle(int(x), int(y), int(w), int(widget_h), rl.
|
|
522
|
-
|
|
541
|
+
rl.draw_rectangle(int(x), int(y), int(w), int(widget_h), rl.WHITE)
|
|
542
|
+
inner_w = max(0, int(w) - 2)
|
|
543
|
+
inner_h = max(0, int(widget_h) - 2)
|
|
544
|
+
rl.draw_rectangle(int(x) + 1, int(y) + 1, inner_w, inner_h, rl.BLACK)
|
|
523
545
|
|
|
524
546
|
# Arrow icon (the ui_drop* assets are 16x16 icons, not the background).
|
|
525
547
|
mouse = rl.get_mouse_position()
|
|
526
548
|
hovered_header = x <= mouse.x <= x + w and y <= mouse.y <= y + header_h
|
|
527
549
|
arrow_tex = drop_on if (self._player_list_open or hovered_header) else drop_off
|
|
550
|
+
if self._player_list_open or hovered_header:
|
|
551
|
+
line_h = max(1, int(1.0 * scale))
|
|
552
|
+
rl.draw_rectangle(int(x), int(y + 15.0 * scale), int(w), line_h, rl.Color(255, 255, 255, 128))
|
|
528
553
|
if arrow_tex is not None:
|
|
529
554
|
rl.draw_texture_pro(
|
|
530
555
|
arrow_tex,
|
|
@@ -541,7 +566,7 @@ class PlayGameMenuView(PanelMenuView):
|
|
|
541
566
|
if player_count > len(self._PLAYER_COUNT_LABELS):
|
|
542
567
|
player_count = len(self._PLAYER_COUNT_LABELS)
|
|
543
568
|
label = self._PLAYER_COUNT_LABELS[player_count - 1]
|
|
544
|
-
header_alpha =
|
|
569
|
+
header_alpha = 242 if hovered_header else 191 # 0x3f733333 / 0x3f400000
|
|
545
570
|
draw_small_text(font, label, text_x, text_y, text_scale, rl.Color(255, 255, 255, header_alpha))
|
|
546
571
|
|
|
547
572
|
if not self._player_list_open:
|
|
@@ -550,7 +575,7 @@ class PlayGameMenuView(PanelMenuView):
|
|
|
550
575
|
for idx, item in enumerate(self._PLAYER_COUNT_LABELS):
|
|
551
576
|
item_y = rows_y0 + row_h * float(idx)
|
|
552
577
|
hovered = x <= mouse.x <= x + w and item_y <= mouse.y <= item_y + row_h
|
|
553
|
-
alpha =
|
|
578
|
+
alpha = 153 # 0x3f19999a
|
|
554
579
|
if hovered:
|
|
555
580
|
alpha = 242 # 0x3f733333
|
|
556
581
|
if idx == (player_count - 1):
|
|
@@ -558,32 +583,15 @@ class PlayGameMenuView(PanelMenuView):
|
|
|
558
583
|
draw_small_text(font, item, text_x, item_y, text_scale, rl.Color(255, 255, 255, alpha))
|
|
559
584
|
|
|
560
585
|
def _draw_mode_button(self, mode: _PlayGameModeEntry, x: float, y: float, scale: float) -> None:
|
|
561
|
-
|
|
586
|
+
textures = self._button_textures
|
|
587
|
+
if textures is None:
|
|
588
|
+
return
|
|
589
|
+
if textures.button_sm is None and textures.button_md is None:
|
|
590
|
+
return
|
|
562
591
|
font = self._ensure_small_font()
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
hovered = rect.x <= mouse.x <= rect.x + rect.width and rect.y <= mouse.y <= rect.y + rect.height
|
|
567
|
-
alpha = 255
|
|
568
|
-
|
|
569
|
-
if tex is not None:
|
|
570
|
-
rl.draw_texture_pro(
|
|
571
|
-
tex,
|
|
572
|
-
rl.Rectangle(0.0, 0.0, float(tex.width), float(tex.height)),
|
|
573
|
-
rect,
|
|
574
|
-
rl.Vector2(0.0, 0.0),
|
|
575
|
-
0.0,
|
|
576
|
-
rl.Color(255, 255, 255, alpha),
|
|
577
|
-
)
|
|
578
|
-
else:
|
|
579
|
-
rl.draw_rectangle_lines(int(rect.x), int(rect.y), int(rect.width), int(rect.height), rl.Color(255, 255, 255, alpha))
|
|
580
|
-
|
|
581
|
-
label_w = measure_small_text_width(font, mode.label, 1.0 * scale)
|
|
582
|
-
# `ui_button_update` uses x centered (+1) and y = y + 10 (not fully centered).
|
|
583
|
-
text_x = rect.x + (rect.width - label_w) * 0.5 + 1.0 * scale
|
|
584
|
-
text_y = rect.y + 10.0 * scale
|
|
585
|
-
text_alpha = 255 if hovered else 179 # 0x3f800000 / 0x3f333333
|
|
586
|
-
draw_small_text(font, mode.label, text_x, text_y, 1.0 * scale, rl.Color(255, 255, 255, text_alpha))
|
|
592
|
+
state = self._mode_button_state(mode)
|
|
593
|
+
width = button_width(font, state.label, scale=scale, force_wide=state.force_wide)
|
|
594
|
+
button_draw(textures, font, state, x=x, y=y, width=width, scale=scale)
|
|
587
595
|
|
|
588
596
|
def _draw_mode_count(self, key: str, x: float, y: float, scale: float, color: rl.Color) -> None:
|
|
589
597
|
status = self._state.status
|