crimsonland 0.1.0.dev10__py3-none-any.whl → 0.1.0.dev12__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.
@@ -9,6 +9,7 @@ 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,
@@ -54,6 +55,7 @@ class PlayGameMenuView(PanelMenuView):
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
- # Mode buttons (disabled while the player dropdown is open).
137
- if self._player_list_open:
138
- return
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(mode, base_x, y, scale)
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
- rl.clear_background(rl.BLACK)
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
@@ -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 _button_tex_for_label(self, label: str, scale: float) -> rl.Texture2D | None:
329
- md = self._button_md
330
- sm = self._button_sm
331
- if md is None:
332
- return sm
333
- if sm is None:
334
- return md
335
-
336
- # `ui_button_update` picks between button sizes based on rendered label width.
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
- label_w = measure_small_text_width(font, label, 1.0 * scale)
339
- return sm if label_w < 40.0 * scale else md
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
- # Panel title label from ui_itemTexts (same as OptionsMenuView).
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
- MENU_LABEL_WIDTH,
465
- MENU_LABEL_ROW_HEIGHT,
484
+ title_w,
485
+ title_h,
466
486
  )
467
487
  dst = rl.Rectangle(
468
- panel_left + 212.0 * scale,
469
- panel_top + 32.0 * scale,
470
- MENU_LABEL_WIDTH * scale,
471
- MENU_LABEL_ROW_HEIGHT * scale,
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(panel_left + 212.0 * scale), int(panel_top + 32.0 * scale), int(24 * scale), rl.WHITE)
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.BLACK)
522
- rl.draw_rectangle_lines(int(x), int(y), int(w), int(widget_h), rl.WHITE)
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 = 191 if self._player_list_open else 242 # 0x3f400000 / 0x3f733333
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 = 179 # 0x3f333333
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
- tex = self._button_tex_for_label(mode.label, scale)
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
- rect = self._mode_button_rect(mode.label, x, y, scale)
564
-
565
- mouse = rl.get_mouse_position()
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
@@ -49,9 +49,7 @@ class StatisticsMenuView(PanelMenuView):
49
49
  play_music(self._state.audio, "shortie_monk")
50
50
 
51
51
  def draw(self) -> None:
52
- rl.clear_background(rl.BLACK)
53
- if self._ground is not None:
54
- self._ground.draw(0.0, 0.0)
52
+ self._draw_background()
55
53
  _draw_screen_fade(self._state)
56
54
  assets = self._assets
57
55
  entry = self._entry