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.
- crimson/assets_fetch.py +23 -8
- crimson/frontend/high_scores_layout.py +26 -0
- crimson/frontend/menu.py +22 -20
- crimson/frontend/panels/base.py +14 -26
- crimson/frontend/panels/controls.py +151 -62
- crimson/frontend/panels/credits.py +221 -0
- crimson/frontend/panels/databases.py +307 -0
- crimson/frontend/panels/options.py +4 -3
- crimson/frontend/panels/play_game.py +4 -4
- crimson/frontend/panels/stats.py +255 -296
- crimson/game.py +219 -81
- crimson/modes/quest_mode.py +10 -9
- crimson/modes/survival_mode.py +10 -9
- crimson/modes/tutorial_mode.py +10 -4
- crimson/ui/menu_panel.py +127 -0
- crimson/ui/perk_menu.py +54 -89
- crimson/ui/quest_results.py +24 -18
- crimson/views/perk_menu_debug.py +2 -2
- crimson/views/perks.py +2 -2
- crimsonland-0.1.0.dev14.dist-info/METADATA +197 -0
- {crimsonland-0.1.0.dev12.dist-info → crimsonland-0.1.0.dev14.dist-info}/RECORD +23 -19
- crimsonland-0.1.0.dev12.dist-info/METADATA +0 -9
- {crimsonland-0.1.0.dev12.dist-info → crimsonland-0.1.0.dev14.dist-info}/WHEEL +0 -0
- {crimsonland-0.1.0.dev12.dist-info → crimsonland-0.1.0.dev14.dist-info}/entry_points.txt +0 -0
crimson/modes/tutorial_mode.py
CHANGED
|
@@ -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,
|
|
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,
|
|
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
|
-
|
|
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:
|
crimson/ui/menu_panel.py
ADDED
|
@@ -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 .
|
|
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
|
-
|
|
20
|
-
|
|
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
|
-
#
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
150
|
-
texture: rl.Texture,
|
|
154
|
+
def ui_element_slide_x(
|
|
155
|
+
t_ms: float,
|
|
151
156
|
*,
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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)
|
crimson/ui/quest_results.py
CHANGED
|
@@ -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 +
|
|
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 =
|
|
72
|
-
QUEST_RESULTS_PANEL_H =
|
|
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
|
-
|
|
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
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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 +
|
|
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(
|
|
332
|
-
if (not self._panel_open_sfx_played) and play_sfx is not None and self._intro_ms >=
|
|
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
|
-
|
|
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
|
crimson/views/perk_menu_debug.py
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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:
|