crimsonland 0.1.0.dev12__py3-none-any.whl → 0.1.0.dev14__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.
@@ -21,7 +21,9 @@ from ..perks import PerkId, perk_display_description, perk_display_name
21
21
  from ..tutorial.timeline import TutorialFrameActions, TutorialState, tick_tutorial_timeline
22
22
  from ..ui.cursor import draw_aim_cursor, draw_menu_cursor
23
23
  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
24
25
  from ..ui.perk_menu import (
26
+ PERK_MENU_TRANSITION_MS,
25
27
  PerkMenuAssets,
26
28
  PerkMenuLayout,
27
29
  UiButtonState,
@@ -29,10 +31,10 @@ from ..ui.perk_menu import (
29
31
  button_update,
30
32
  button_width,
31
33
  draw_menu_item,
32
- draw_menu_panel,
33
34
  draw_ui_text,
34
35
  load_perk_menu_assets,
35
36
  menu_item_hit_rect,
37
+ perk_menu_panel_slide_x,
36
38
  perk_menu_compute_layout,
37
39
  ui_origin,
38
40
  ui_scale,
@@ -282,6 +284,8 @@ class TutorialMode(BaseGameplayMode):
282
284
  screen_h = float(rl.get_screen_height())
283
285
  scale = ui_scale(screen_w, screen_h)
284
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)
285
289
 
286
290
  mouse = self._ui_mouse_pos()
287
291
  click = rl.is_mouse_button_pressed(rl.MouseButton.MOUSE_BUTTON_LEFT)
@@ -297,6 +301,7 @@ class TutorialMode(BaseGameplayMode):
297
301
  choice_count=len(choices),
298
302
  expert_owned=expert_owned,
299
303
  master_owned=master_owned,
304
+ panel_slide_x=slide_x,
300
305
  )
301
306
 
302
307
  fx_toggle = int(self._config.data.get("fx_toggle", 0) or 0) if self._config is not None else 0
@@ -361,9 +366,9 @@ class TutorialMode(BaseGameplayMode):
361
366
  self._perk_menu_handle_input(dt_frame, dt_ui_ms)
362
367
 
363
368
  if self._perk_menu_open:
364
- self._perk_menu_timeline_ms = _clamp(self._perk_menu_timeline_ms + dt_ui_ms, 0.0, 200.0)
369
+ self._perk_menu_timeline_ms = _clamp(self._perk_menu_timeline_ms + dt_ui_ms, 0.0, PERK_MENU_TRANSITION_MS)
365
370
  else:
366
- self._perk_menu_timeline_ms = _clamp(self._perk_menu_timeline_ms - dt_ui_ms, 0.0, 200.0)
371
+ self._perk_menu_timeline_ms = _clamp(self._perk_menu_timeline_ms - dt_ui_ms, 0.0, PERK_MENU_TRANSITION_MS)
367
372
 
368
373
  dt_world = 0.0 if self._paused or perk_menu_active else dt_frame
369
374
 
@@ -604,12 +609,13 @@ class TutorialMode(BaseGameplayMode):
604
609
  choice_count=len(choices),
605
610
  expert_owned=expert_owned,
606
611
  master_owned=master_owned,
612
+ panel_slide_x=slide_x,
607
613
  )
608
614
 
609
615
  panel_tex = assets.menu_panel
610
616
  if panel_tex is not None:
611
617
  fx_detail = bool(int(self._config.data.get("fx_detail_0", 0) or 0)) if self._config is not None else False
612
- draw_menu_panel(panel_tex, dst=computed.panel, shadow=fx_detail)
618
+ draw_classic_menu_panel(panel_tex, dst=computed.panel, shadow=fx_detail)
613
619
 
614
620
  title_tex = assets.title_pick_perk
615
621
  if title_tex is not None:
@@ -0,0 +1,127 @@
1
+ from __future__ import annotations
2
+
3
+ import pyray as rl
4
+
5
+ from .shadow import UI_SHADOW_OFFSET, draw_ui_quad_shadow
6
+
7
+
8
+ # Classic menu panel is rendered from the *inset* inner region of ui_menuPanel:
9
+ # - X inset: 1px on each side (uv 1/512 .. 511/512) => 510px wide
10
+ # - Y inset: 1px on each side (uv 1/256 .. 255/256) => 254px tall
11
+ #
12
+ # When a panel is taller than the base height, the original stretches it using a
13
+ # 3-slice: [top][mid][bottom]. The source slice boundaries are at y=130 and y=150
14
+ # in the texture (see grim UVs in ui_render_trace).
15
+ MENU_PANEL_INSET = 1.0
16
+ MENU_PANEL_SRC_SLICE_Y1 = 130.0
17
+ MENU_PANEL_SRC_SLICE_Y2 = 150.0
18
+
19
+ # Destination slice heights observed in the original at scale=1.0 (1024x768).
20
+ MENU_PANEL_DST_TOP_H = 138.0
21
+ MENU_PANEL_DST_BOTTOM_H = 116.0
22
+
23
+
24
+ def draw_classic_menu_panel(
25
+ texture: rl.Texture2D,
26
+ *,
27
+ dst: rl.Rectangle,
28
+ tint: rl.Color = rl.WHITE,
29
+ shadow: bool = False,
30
+ ) -> None:
31
+ """
32
+ Draw a classic menu panel (ui_menuPanel) with the same slicing behavior as the original.
33
+
34
+ - Uses inset source rect (1px border skipped) to match the vertex/UV inset.
35
+ - Uses 3-slice only when dst is taller than (top + bottom); otherwise draws a single quad.
36
+ """
37
+
38
+ tex_w = float(texture.width)
39
+ tex_h = float(texture.height)
40
+ if tex_w <= 0.0 or tex_h <= 0.0:
41
+ return
42
+
43
+ inset = MENU_PANEL_INSET
44
+ src_x = inset
45
+ src_y = inset
46
+ src_w = max(0.0, tex_w - inset * 2.0)
47
+ src_h = max(0.0, tex_h - inset * 2.0)
48
+
49
+ # Scale slice heights with the panel width (menu panel uses the same scale factor).
50
+ # dst.width is already in our "inset" width space (510 at scale=1.0).
51
+ scale = (float(dst.width) / 510.0) if float(dst.width) != 0.0 else 1.0
52
+ top_h = MENU_PANEL_DST_TOP_H * scale
53
+ bottom_h = MENU_PANEL_DST_BOTTOM_H * scale
54
+ mid_h = float(dst.height) - top_h - bottom_h
55
+
56
+ origin = rl.Vector2(0.0, 0.0)
57
+
58
+ if mid_h <= 0.0:
59
+ src = rl.Rectangle(src_x, src_y, src_w, src_h)
60
+ if shadow:
61
+ draw_ui_quad_shadow(
62
+ texture=texture,
63
+ src=src,
64
+ dst=rl.Rectangle(
65
+ float(dst.x + UI_SHADOW_OFFSET),
66
+ float(dst.y + UI_SHADOW_OFFSET),
67
+ float(dst.width),
68
+ float(dst.height),
69
+ ),
70
+ origin=origin,
71
+ rotation_deg=0.0,
72
+ )
73
+ rl.draw_texture_pro(texture, src, dst, origin, 0.0, tint)
74
+ return
75
+
76
+ # Source slice rects (in texture pixels, with 1px inset).
77
+ src_top = rl.Rectangle(src_x, src_y, src_w, max(0.0, MENU_PANEL_SRC_SLICE_Y1 - inset))
78
+ src_mid = rl.Rectangle(src_x, MENU_PANEL_SRC_SLICE_Y1, src_w, max(0.0, MENU_PANEL_SRC_SLICE_Y2 - MENU_PANEL_SRC_SLICE_Y1))
79
+ src_bot = rl.Rectangle(src_x, MENU_PANEL_SRC_SLICE_Y2, src_w, max(0.0, (tex_h - inset) - MENU_PANEL_SRC_SLICE_Y2))
80
+
81
+ # Destination slices.
82
+ dst_top = rl.Rectangle(float(dst.x), float(dst.y), float(dst.width), float(top_h))
83
+ dst_mid = rl.Rectangle(float(dst.x), float(dst.y) + float(top_h), float(dst.width), float(mid_h))
84
+ dst_bot = rl.Rectangle(float(dst.x), float(dst.y) + float(top_h) + float(mid_h), float(dst.width), float(bottom_h))
85
+
86
+ if shadow:
87
+ draw_ui_quad_shadow(
88
+ texture=texture,
89
+ src=src_top,
90
+ dst=rl.Rectangle(
91
+ float(dst_top.x + UI_SHADOW_OFFSET),
92
+ float(dst_top.y + UI_SHADOW_OFFSET),
93
+ float(dst_top.width),
94
+ float(dst_top.height),
95
+ ),
96
+ origin=origin,
97
+ rotation_deg=0.0,
98
+ )
99
+ draw_ui_quad_shadow(
100
+ texture=texture,
101
+ src=src_mid,
102
+ dst=rl.Rectangle(
103
+ float(dst_mid.x + UI_SHADOW_OFFSET),
104
+ float(dst_mid.y + UI_SHADOW_OFFSET),
105
+ float(dst_mid.width),
106
+ float(dst_mid.height),
107
+ ),
108
+ origin=origin,
109
+ rotation_deg=0.0,
110
+ )
111
+ draw_ui_quad_shadow(
112
+ texture=texture,
113
+ src=src_bot,
114
+ dst=rl.Rectangle(
115
+ float(dst_bot.x + UI_SHADOW_OFFSET),
116
+ float(dst_bot.y + UI_SHADOW_OFFSET),
117
+ float(dst_bot.width),
118
+ float(dst_bot.height),
119
+ ),
120
+ origin=origin,
121
+ rotation_deg=0.0,
122
+ )
123
+
124
+ rl.draw_texture_pro(texture, src_top, dst_top, origin, 0.0, tint)
125
+ rl.draw_texture_pro(texture, src_mid, dst_mid, origin, 0.0, tint)
126
+ rl.draw_texture_pro(texture, src_bot, dst_bot, origin, 0.0, tint)
127
+
crimson/ui/perk_menu.py CHANGED
@@ -9,15 +9,19 @@ import pyray as rl
9
9
  from grim.assets import TextureLoader
10
10
  from grim.fonts.small import SmallFontData, draw_small_text, measure_small_text_width
11
11
 
12
- from .shadow import UI_SHADOW_OFFSET, draw_ui_quad_shadow
12
+ from .menu_panel import draw_classic_menu_panel
13
13
 
14
14
 
15
15
  UI_BASE_WIDTH = 640.0
16
16
  UI_BASE_HEIGHT = 480.0
17
17
 
18
-
19
- MENU_PANEL_SLICE_Y1 = 130.0
20
- MENU_PANEL_SLICE_Y2 = 150.0
18
+ # Perk selection screen panel uses ui_element-style timeline animation:
19
+ # - fully hidden until end_ms
20
+ # - slides in over (end_ms..start_ms)
21
+ # - fully visible at start_ms
22
+ PERK_MENU_ANIM_START_MS = 400.0
23
+ PERK_MENU_ANIM_END_MS = 100.0
24
+ PERK_MENU_TRANSITION_MS = PERK_MENU_ANIM_START_MS
21
25
 
22
26
  # Layout offsets from the classic game (perk selection screen), derived from
23
27
  # `perk_selection_screen_update` (see analysis/ghidra + BN).
@@ -45,11 +49,13 @@ MENU_DESC_RIGHT_X = 480.0
45
49
  @dataclass(slots=True)
46
50
  class PerkMenuLayout:
47
51
  # Coordinates live in the original 640x480 UI space.
48
- # Matches the classic menu panel: pos (-45, 110) + offset (20, -82).
49
- panel_x: float = -25.0
50
- panel_y: float = 28.0
51
- panel_w: float = 512.0
52
- panel_h: float = 379.0
52
+ # Capture (1024x768) shows the perk menu panel uses the 3-slice variant:
53
+ # open bbox (-108,119) -> (402,497)
54
+ # which corresponds to ui_element pos (-45,110) + geom (-63,-81) and size 510x378.
55
+ panel_x: float = -108.0
56
+ panel_y: float = 29.0
57
+ panel_w: float = 510.0
58
+ panel_h: float = 378.0
53
59
 
54
60
 
55
61
  @dataclass(slots=True)
@@ -145,88 +151,47 @@ def perk_menu_compute_layout(
145
151
  cancel_y=float(cancel_y),
146
152
  )
147
153
 
148
-
149
- def draw_menu_panel(
150
- texture: rl.Texture,
154
+ def ui_element_slide_x(
155
+ t_ms: float,
151
156
  *,
152
- dst: rl.Rectangle,
153
- tint: rl.Color = rl.WHITE,
154
- shadow: bool = False,
155
- ) -> None:
156
- scale = float(dst.width) / float(texture.width)
157
- top_h = MENU_PANEL_SLICE_Y1 * scale
158
- bottom_h = (float(texture.height) - MENU_PANEL_SLICE_Y2) * scale
159
- mid_h = float(dst.height) - top_h - bottom_h
160
- if mid_h < 0.0:
161
- src = rl.Rectangle(0.0, 0.0, float(texture.width), float(texture.height))
162
- if shadow:
163
- draw_ui_quad_shadow(
164
- texture=texture,
165
- src=src,
166
- dst=rl.Rectangle(
167
- float(dst.x + UI_SHADOW_OFFSET),
168
- float(dst.y + UI_SHADOW_OFFSET),
169
- float(dst.width),
170
- float(dst.height),
171
- ),
172
- origin=rl.Vector2(0.0, 0.0),
173
- rotation_deg=0.0,
174
- )
175
- rl.draw_texture_pro(texture, src, dst, rl.Vector2(0.0, 0.0), 0.0, tint)
176
- return
157
+ start_ms: float,
158
+ end_ms: float,
159
+ width: float,
160
+ direction_flag: int = 0,
161
+ ) -> float:
162
+ """
163
+ Slide offset helper matching ui_element_update semantics (see MenuView._ui_element_anim).
164
+
165
+ direction_flag=0: slide from left (-width -> 0)
166
+ direction_flag=1: slide from right (+width -> 0)
167
+ """
168
+
169
+ if start_ms <= end_ms or width <= 0.0:
170
+ return 0.0
171
+
172
+ width = abs(float(width))
173
+ t = float(t_ms)
174
+ if t < float(end_ms):
175
+ slide = width
176
+ elif t < float(start_ms):
177
+ elapsed = t - float(end_ms)
178
+ span = float(start_ms) - float(end_ms)
179
+ p = elapsed / span if span > 1e-6 else 1.0
180
+ slide = (1.0 - p) * width
181
+ else:
182
+ slide = 0.0
177
183
 
178
- src_w = float(texture.width)
179
- src_h = float(texture.height)
180
-
181
- src_top = rl.Rectangle(0.0, 0.0, src_w, MENU_PANEL_SLICE_Y1)
182
- src_mid = rl.Rectangle(0.0, MENU_PANEL_SLICE_Y1, src_w, MENU_PANEL_SLICE_Y2 - MENU_PANEL_SLICE_Y1)
183
- src_bot = rl.Rectangle(0.0, MENU_PANEL_SLICE_Y2, src_w, src_h - MENU_PANEL_SLICE_Y2)
184
-
185
- dst_top = rl.Rectangle(float(dst.x), float(dst.y), float(dst.width), top_h)
186
- dst_mid = rl.Rectangle(float(dst.x), float(dst.y) + top_h, float(dst.width), mid_h)
187
- dst_bot = rl.Rectangle(float(dst.x), float(dst.y) + top_h + mid_h, float(dst.width), bottom_h)
188
-
189
- origin = rl.Vector2(0.0, 0.0)
190
- if shadow:
191
- draw_ui_quad_shadow(
192
- texture=texture,
193
- src=src_top,
194
- dst=rl.Rectangle(
195
- float(dst_top.x + UI_SHADOW_OFFSET),
196
- float(dst_top.y + UI_SHADOW_OFFSET),
197
- float(dst_top.width),
198
- float(dst_top.height),
199
- ),
200
- origin=origin,
201
- rotation_deg=0.0,
202
- )
203
- draw_ui_quad_shadow(
204
- texture=texture,
205
- src=src_mid,
206
- dst=rl.Rectangle(
207
- float(dst_mid.x + UI_SHADOW_OFFSET),
208
- float(dst_mid.y + UI_SHADOW_OFFSET),
209
- float(dst_mid.width),
210
- float(dst_mid.height),
211
- ),
212
- origin=origin,
213
- rotation_deg=0.0,
214
- )
215
- draw_ui_quad_shadow(
216
- texture=texture,
217
- src=src_bot,
218
- dst=rl.Rectangle(
219
- float(dst_bot.x + UI_SHADOW_OFFSET),
220
- float(dst_bot.y + UI_SHADOW_OFFSET),
221
- float(dst_bot.width),
222
- float(dst_bot.height),
223
- ),
224
- origin=origin,
225
- rotation_deg=0.0,
226
- )
227
- rl.draw_texture_pro(texture, src_top, dst_top, origin, 0.0, tint)
228
- rl.draw_texture_pro(texture, src_mid, dst_mid, origin, 0.0, tint)
229
- rl.draw_texture_pro(texture, src_bot, dst_bot, origin, 0.0, tint)
184
+ return slide if int(direction_flag) else -slide
185
+
186
+
187
+ def perk_menu_panel_slide_x(t_ms: float, *, width: float) -> float:
188
+ return ui_element_slide_x(
189
+ t_ms,
190
+ start_ms=PERK_MENU_ANIM_START_MS,
191
+ end_ms=PERK_MENU_ANIM_END_MS,
192
+ width=width,
193
+ direction_flag=0,
194
+ )
230
195
 
231
196
 
232
197
  @dataclass(slots=True)
@@ -21,6 +21,7 @@ from ..persistence.highscores import (
21
21
  upsert_highscore_record,
22
22
  )
23
23
  from ..quests.results import QuestFinalTime, QuestResultsBreakdownAnim, tick_quest_results_breakdown_anim
24
+ from .menu_panel import draw_classic_menu_panel
24
25
  from .perk_menu import (
25
26
  PerkMenuAssets,
26
27
  UiButtonState,
@@ -28,7 +29,6 @@ from .perk_menu import (
28
29
  button_update,
29
30
  button_width,
30
31
  cursor_draw,
31
- draw_menu_panel,
32
32
  draw_ui_text,
33
33
  load_perk_menu_assets,
34
34
  )
@@ -55,7 +55,7 @@ def _menu_widescreen_y_shift(layout_w: float) -> float:
55
55
  # `quest_results_screen_update` base layout (Crimsonland classic UI panel).
56
56
  # Values are derived from `ui_menu_assets_init` + `ui_menu_layout_init` and how
57
57
  # the quest results screen composes `ui_menuPanel` geometry:
58
- # panel_left = geom_x0 + pos_x + 180 + slide_x
58
+ # panel_left = geom_x0 + pos_x + slide_x
59
59
  # panel_top = geom_y0 + pos_y
60
60
  #
61
61
  # Where:
@@ -66,10 +66,9 @@ QUEST_RESULTS_PANEL_POS_X = -45.0
66
66
  QUEST_RESULTS_PANEL_POS_Y = 110.0
67
67
  QUEST_RESULTS_PANEL_GEOM_X0 = -63.0
68
68
  QUEST_RESULTS_PANEL_GEOM_Y0 = -81.0
69
- QUEST_RESULTS_PANEL_BASE_X = 180.0
70
69
 
71
- QUEST_RESULTS_PANEL_W = 512.0
72
- QUEST_RESULTS_PANEL_H = 379.0
70
+ QUEST_RESULTS_PANEL_W = 510.0
71
+ QUEST_RESULTS_PANEL_H = 378.0
73
72
 
74
73
  TEXTURE_TOP_BANNER_W = 256.0
75
74
  TEXTURE_TOP_BANNER_H = 64.0
@@ -77,7 +76,11 @@ TEXTURE_TOP_BANNER_H = 64.0
77
76
  INPUT_BOX_W = 166.0
78
77
  INPUT_BOX_H = 18.0
79
78
 
80
- PANEL_SLIDE_DURATION_MS = 250.0
79
+ # Capture (1024x768) shows the quest results panel uses the same ui_element
80
+ # timeline pattern as other screens: fully hidden until 100ms, then slides in
81
+ # over 300ms (end=100, start=400).
82
+ PANEL_SLIDE_START_MS = 400.0
83
+ PANEL_SLIDE_END_MS = 100.0
81
84
 
82
85
  COLOR_TEXT = rl.Color(255, 255, 255, 255)
83
86
  COLOR_TEXT_MUTED = rl.Color(255, 255, 255, int(255 * 0.8))
@@ -101,11 +104,6 @@ def _poll_text_input(max_len: int, *, allow_space: bool = True) -> str:
101
104
  return out
102
105
 
103
106
 
104
- def _ease_out_cubic(t: float) -> float:
105
- t = max(0.0, min(1.0, float(t)))
106
- return 1.0 - (1.0 - t) ** 3
107
-
108
-
109
107
  def _format_ordinal(value_1_based: int) -> str:
110
108
  value = int(value_1_based)
111
109
  if value % 100 in (11, 12, 13):
@@ -289,11 +287,18 @@ class QuestResultsUi:
289
287
  rl.draw_text(text, int(x), int(y), int(20 * scale), color)
290
288
 
291
289
  def _panel_layout(self, *, screen_w: float, scale: float) -> tuple[rl.Rectangle, float, float]:
292
- t = self._intro_ms / PANEL_SLIDE_DURATION_MS if PANEL_SLIDE_DURATION_MS > 1e-6 else 1.0
293
- eased = _ease_out_cubic(t)
294
- panel_slide_x = -QUEST_RESULTS_PANEL_W * (1.0 - eased)
290
+ # Match MenuView._ui_element_anim offset math (linear, with a 100ms hold hidden).
291
+ t_ms = float(self._intro_ms)
292
+ if t_ms < PANEL_SLIDE_END_MS:
293
+ panel_slide_x = -QUEST_RESULTS_PANEL_W
294
+ elif t_ms < PANEL_SLIDE_START_MS:
295
+ span = float(PANEL_SLIDE_START_MS - PANEL_SLIDE_END_MS)
296
+ p = (t_ms - PANEL_SLIDE_END_MS) / span if span > 1e-6 else 1.0
297
+ panel_slide_x = -((1.0 - p) * QUEST_RESULTS_PANEL_W)
298
+ else:
299
+ panel_slide_x = 0.0
295
300
 
296
- left = (QUEST_RESULTS_PANEL_GEOM_X0 + QUEST_RESULTS_PANEL_POS_X + QUEST_RESULTS_PANEL_BASE_X + panel_slide_x) * scale
301
+ left = (QUEST_RESULTS_PANEL_GEOM_X0 + QUEST_RESULTS_PANEL_POS_X + panel_slide_x) * scale
297
302
  layout_w = screen_w / scale if scale else screen_w
298
303
  widescreen_shift_y = _menu_widescreen_y_shift(layout_w)
299
304
  top = (QUEST_RESULTS_PANEL_GEOM_Y0 + QUEST_RESULTS_PANEL_POS_Y + widescreen_shift_y) * scale
@@ -328,8 +333,8 @@ class QuestResultsUi:
328
333
  return action
329
334
  return None
330
335
 
331
- self._intro_ms = min(PANEL_SLIDE_DURATION_MS, self._intro_ms + dt_ms)
332
- if (not self._panel_open_sfx_played) and play_sfx is not None and self._intro_ms >= PANEL_SLIDE_DURATION_MS - 1e-3:
336
+ self._intro_ms = min(PANEL_SLIDE_START_MS, self._intro_ms + dt_ms)
337
+ if (not self._panel_open_sfx_played) and play_sfx is not None and self._intro_ms >= PANEL_SLIDE_START_MS - 1e-3:
333
338
  play_sfx("sfx_ui_panelclick")
334
339
  self._panel_open_sfx_played = True
335
340
  if self._consume_enter:
@@ -507,7 +512,8 @@ class QuestResultsUi:
507
512
  panel, left, top = self._panel_layout(screen_w=screen_w, scale=scale)
508
513
 
509
514
  if self.assets.menu_panel is not None:
510
- draw_menu_panel(self.assets.menu_panel, dst=panel, tint=rl.WHITE)
515
+ fx_detail = bool(int(self.config.data.get("fx_detail_0", 0) or 0))
516
+ draw_classic_menu_panel(self.assets.menu_panel, dst=panel, tint=rl.WHITE, shadow=fx_detail)
511
517
 
512
518
  banner_x = left + 22.0 * scale
513
519
  banner_y = top + 36.0 * scale
@@ -6,6 +6,7 @@ from grim.fonts.small import SmallFontData, load_small_font, measure_small_text_
6
6
  from grim.view import View, ViewContext
7
7
 
8
8
  from ..perks import PERK_BY_ID, PerkId, perk_display_description, perk_display_name
9
+ from ..ui.menu_panel import draw_classic_menu_panel
9
10
  from ..ui.perk_menu import (
10
11
  PerkMenuAssets,
11
12
  PerkMenuLayout,
@@ -14,7 +15,6 @@ from ..ui.perk_menu import (
14
15
  button_update,
15
16
  button_width,
16
17
  cursor_draw,
17
- draw_menu_panel,
18
18
  draw_menu_item,
19
19
  draw_ui_text,
20
20
  load_perk_menu_assets,
@@ -336,7 +336,7 @@ class PerkMenuDebugView:
336
336
  )
337
337
 
338
338
  if self._assets.menu_panel is not None:
339
- draw_menu_panel(self._assets.menu_panel, dst=computed.panel)
339
+ draw_classic_menu_panel(self._assets.menu_panel, dst=computed.panel)
340
340
 
341
341
  if self._assets.title_pick_perk is not None:
342
342
  tex = self._assets.title_pick_perk
crimson/views/perks.py CHANGED
@@ -8,6 +8,7 @@ from grim.view import ViewContext
8
8
  from ..game_modes import GameMode
9
9
  from ..gameplay import GameplayState, PlayerState, perk_selection_current_choices, perk_selection_pick, survival_check_level_up
10
10
  from ..perks import PERK_BY_ID, PerkId, perk_display_description, perk_display_name
11
+ from ..ui.menu_panel import draw_classic_menu_panel
11
12
  from ..ui.perk_menu import (
12
13
  PerkMenuLayout,
13
14
  UiButtonState,
@@ -15,7 +16,6 @@ from ..ui.perk_menu import (
15
16
  button_update,
16
17
  button_width,
17
18
  cursor_draw,
18
- draw_menu_panel,
19
19
  draw_menu_item,
20
20
  draw_ui_text,
21
21
  load_perk_menu_assets,
@@ -300,7 +300,7 @@ class PerkSelectionView:
300
300
 
301
301
  panel_tex = self._ui_assets.menu_panel
302
302
  if panel_tex is not None:
303
- draw_menu_panel(panel_tex, dst=computed.panel)
303
+ draw_classic_menu_panel(panel_tex, dst=computed.panel)
304
304
 
305
305
  title_tex = self._ui_assets.title_pick_perk
306
306
  if title_tex is not None: