crimsonland 0.1.0.dev12__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 CHANGED
@@ -2,7 +2,9 @@ from __future__ import annotations
2
2
 
3
3
  from dataclasses import dataclass
4
4
  from pathlib import Path
5
+ import os
5
6
  import shutil
7
+ import tempfile
6
8
  import urllib.request
7
9
 
8
10
  from grim.console import ConsoleState
@@ -19,17 +21,30 @@ class DownloadResult:
19
21
 
20
22
 
21
23
  def _download_file(url: str, dest: Path) -> None:
22
- tmp = dest.with_suffix(dest.suffix + ".tmp")
23
- if tmp.exists():
24
- tmp.unlink()
24
+ tmp_path: Path | None = None
25
25
  try:
26
26
  req = urllib.request.Request(url, headers={"User-Agent": "crimsonland-decompile"})
27
- with urllib.request.urlopen(req, timeout=30) as resp, tmp.open("wb") as handle:
28
- shutil.copyfileobj(resp, handle)
29
- tmp.replace(dest)
27
+ with urllib.request.urlopen(req, timeout=30) as resp:
28
+ with tempfile.NamedTemporaryFile(
29
+ mode="wb",
30
+ delete=False,
31
+ dir=dest.parent,
32
+ prefix=dest.name + ".",
33
+ suffix=".tmp",
34
+ ) as handle:
35
+ tmp_path = Path(handle.name)
36
+ shutil.copyfileobj(resp, handle)
37
+ handle.flush()
38
+ os.fsync(handle.fileno())
39
+ if tmp_path is None:
40
+ raise RuntimeError("assets: temporary file not created")
41
+ tmp_path.replace(dest)
30
42
  finally:
31
- if tmp.exists():
32
- tmp.unlink()
43
+ if tmp_path is not None:
44
+ try:
45
+ tmp_path.unlink()
46
+ except FileNotFoundError:
47
+ pass
33
48
 
34
49
 
35
50
  def download_missing_paqs(
@@ -0,0 +1,26 @@
1
+ """
2
+ Layout constants for the classic high scores screen (state_id=14).
3
+
4
+ Measured from analysis/frida/ui_render_trace_oracle_1024x768.json.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ # Panel positions are expressed in "panel pos" (pre-offset) space, matching other menu panels:
10
+ # panel_top_left = (panel_pos_x + MENU_PANEL_OFFSET_X, panel_pos_y + y_shift + MENU_PANEL_OFFSET_Y)
11
+
12
+ HS_LEFT_PANEL_POS_X = -119.0
13
+ HS_LEFT_PANEL_POS_Y = 185.0
14
+ HS_LEFT_PANEL_HEIGHT = 378.0
15
+
16
+ HS_RIGHT_PANEL_POS_X = 609.0
17
+ HS_RIGHT_PANEL_POS_Y = 200.0
18
+ HS_RIGHT_PANEL_HEIGHT = 254.0
19
+
20
+ # Buttons inside the left panel (relative to the left panel top-left).
21
+ HS_BUTTON_X = 234.0 # x0=136 at 1024x768
22
+ HS_BUTTON_Y0 = 268.0 # y0=462
23
+ HS_BUTTON_STEP_Y = 33.0
24
+
25
+ HS_BACK_BUTTON_X = 400.0 # x0=302
26
+ HS_BACK_BUTTON_Y = 301.0 # y0=495
crimson/frontend/menu.py CHANGED
@@ -19,8 +19,8 @@ if TYPE_CHECKING:
19
19
  from ..game import GameState
20
20
 
21
21
 
22
- MENU_LABEL_WIDTH = 124.0
23
- MENU_LABEL_HEIGHT = 30.0
22
+ MENU_LABEL_WIDTH = 122.0
23
+ MENU_LABEL_HEIGHT = 28.0
24
24
  MENU_LABEL_ROW_HEIGHT = 32.0
25
25
  MENU_LABEL_ROW_PLAY_GAME = 1
26
26
  MENU_LABEL_ROW_OPTIONS = 2
@@ -31,18 +31,17 @@ MENU_LABEL_ROW_QUIT = 6
31
31
  MENU_LABEL_ROW_BACK = 7
32
32
  MENU_LABEL_BASE_X = -60.0
33
33
  MENU_LABEL_BASE_Y = 210.0
34
- MENU_LABEL_OFFSET_X = 270.0
35
- MENU_LABEL_OFFSET_Y = -38.0
34
+ MENU_LABEL_OFFSET_X = 271.0
35
+ MENU_LABEL_OFFSET_Y = -37.0
36
36
  MENU_LABEL_STEP = 60.0
37
- MENU_ITEM_OFFSET_X = -72.0
38
- MENU_ITEM_OFFSET_Y = -60.0
39
- MENU_PANEL_WIDTH = 512.0
40
- MENU_PANEL_HEIGHT = 256.0
41
- # ui_menu_assets_init:
42
- # - ui_menuPanel starts with offset_x=+20 (ui_element_set_rect)
43
- # - the menu-panel layout copy applies data_48fdb4 -= 116, so offset_x becomes -96
44
- MENU_PANEL_OFFSET_X = -96.0
45
- MENU_PANEL_OFFSET_Y = -82.0
37
+ MENU_ITEM_OFFSET_X = -71.0
38
+ MENU_ITEM_OFFSET_Y = -59.0
39
+ MENU_PANEL_WIDTH = 510.0
40
+ MENU_PANEL_HEIGHT = 254.0
41
+ # Measured from ui_render_trace at 1024x768 (stable timeline):
42
+ # panel top-left is (pos_x + 21, pos_y - 81) and size is 510x254, plus a shadow pass at +7,+7.
43
+ MENU_PANEL_OFFSET_X = 21.0
44
+ MENU_PANEL_OFFSET_Y = -81.0
46
45
  MENU_PANEL_BASE_X = -45.0
47
46
  MENU_PANEL_BASE_Y = 210.0
48
47
  MENU_SCALE_SMALL_THRESHOLD = 640
@@ -52,10 +51,10 @@ MENU_SCALE_SMALL = 0.8
52
51
  MENU_SCALE_LARGE = 1.2
53
52
  MENU_SCALE_SHIFT = 10.0
54
53
 
55
- MENU_SIGN_WIDTH = 573.44
56
- MENU_SIGN_HEIGHT = 143.36
57
- MENU_SIGN_OFFSET_X = -577.44
58
- MENU_SIGN_OFFSET_Y = -62.0
54
+ MENU_SIGN_WIDTH = 571.44
55
+ MENU_SIGN_HEIGHT = 141.36
56
+ MENU_SIGN_OFFSET_X = -576.44
57
+ MENU_SIGN_OFFSET_Y = -61.0
59
58
  MENU_SIGN_POS_Y = 70.0
60
59
  MENU_SIGN_POS_Y_SMALL = 60.0
61
60
  MENU_SIGN_POS_X_PAD = 4.0
@@ -584,21 +583,24 @@ class MenuView:
584
583
  start_ms: int,
585
584
  end_ms: int,
586
585
  width: float,
586
+ direction_flag: int = 0,
587
587
  ) -> tuple[float, float]:
588
588
  # Matches ui_element_update: angle lerps pi/2 -> 0 over [end_ms, start_ms].
589
- # Direction flag (element+0x314) appears to be 0 for main menu elements.
589
+ # direction_flag=0 slides from left (-width -> 0)
590
+ # direction_flag=1 slides from right (+width -> 0)
590
591
  if start_ms <= end_ms or width <= 0.0:
591
592
  return 0.0, 0.0
593
+ dir_sign = 1.0 if int(direction_flag) else -1.0
592
594
  t = self._timeline_ms
593
595
  if t < end_ms:
594
596
  angle = 1.5707964
595
- offset_x = -abs(width)
597
+ offset_x = dir_sign * abs(width)
596
598
  elif t < start_ms:
597
599
  elapsed = t - end_ms
598
600
  span = float(start_ms - end_ms)
599
601
  p = float(elapsed) / span
600
602
  angle = 1.5707964 * (1.0 - p)
601
- offset_x = -((1.0 - p) * abs(width))
603
+ offset_x = dir_sign * ((1.0 - p) * abs(width))
602
604
  else:
603
605
  angle = 0.0
604
606
  offset_x = 0.0
@@ -8,6 +8,7 @@ from grim.assets import PaqTextureCache
8
8
  from grim.audio import play_sfx, update_audio
9
9
  from grim.terrain_render import GroundRenderer
10
10
 
11
+ from ...ui.menu_panel import draw_classic_menu_panel
11
12
  from ..assets import MenuAssets, _ensure_texture_cache, load_menu_assets
12
13
  from ..menu import (
13
14
  MENU_ITEM_OFFSET_X,
@@ -70,6 +71,9 @@ class PanelMenuView:
70
71
  body: str | None = None,
71
72
  panel_pos_x: float = PANEL_POS_X,
72
73
  panel_pos_y: float = PANEL_POS_Y,
74
+ panel_offset_x: float = MENU_PANEL_OFFSET_X,
75
+ panel_offset_y: float = MENU_PANEL_OFFSET_Y,
76
+ panel_height: float = MENU_PANEL_HEIGHT,
73
77
  back_pos_x: float = PANEL_BACK_POS_X,
74
78
  back_pos_y: float = PANEL_BACK_POS_Y,
75
79
  back_action: str = "back_to_menu",
@@ -79,6 +83,9 @@ class PanelMenuView:
79
83
  self._body_lines = (body or "").splitlines()
80
84
  self._panel_pos_x = panel_pos_x
81
85
  self._panel_pos_y = panel_pos_y
86
+ self._panel_offset_x = panel_offset_x
87
+ self._panel_offset_y = panel_offset_y
88
+ self._panel_height = panel_height
82
89
  self._back_pos_x = back_pos_x
83
90
  self._back_pos_y = back_pos_y
84
91
  self._back_action = back_action
@@ -223,40 +230,21 @@ class PanelMenuView:
223
230
  if assets is None or assets.panel is None:
224
231
  return
225
232
  panel = assets.panel
226
- panel_w = MENU_PANEL_WIDTH
227
- panel_h = MENU_PANEL_HEIGHT
228
233
  _angle_rad, slide_x = MenuView._ui_element_anim(
229
234
  self,
230
235
  index=1,
231
236
  start_ms=PANEL_TIMELINE_START_MS,
232
237
  end_ms=PANEL_TIMELINE_END_MS,
233
- width=panel_w * self._menu_item_scale(0)[0],
238
+ width=MENU_PANEL_WIDTH * self._menu_item_scale(0)[0],
234
239
  )
235
240
  item_scale, _local_y_shift = self._menu_item_scale(0)
236
- dst = rl.Rectangle(
237
- self._panel_pos_x + slide_x,
238
- self._panel_pos_y + self._widescreen_y_shift,
239
- panel_w * item_scale,
240
- panel_h * item_scale,
241
- )
242
- origin = rl.Vector2(-(MENU_PANEL_OFFSET_X * item_scale), -(MENU_PANEL_OFFSET_Y * item_scale))
241
+ panel_w = MENU_PANEL_WIDTH * item_scale
242
+ panel_h = float(self._panel_height) * item_scale
243
+ top_left_x = self._panel_pos_x + slide_x + self._panel_offset_x * item_scale
244
+ top_left_y = self._panel_pos_y + self._widescreen_y_shift + self._panel_offset_y * item_scale
245
+ dst = rl.Rectangle(float(top_left_x), float(top_left_y), float(panel_w), float(panel_h))
243
246
  fx_detail = bool(self._state.config.data.get("fx_detail_0", 0))
244
- if fx_detail:
245
- MenuView._draw_ui_quad_shadow(
246
- texture=panel,
247
- src=rl.Rectangle(0.0, 0.0, float(panel.width), float(panel.height)),
248
- dst=rl.Rectangle(dst.x + UI_SHADOW_OFFSET, dst.y + UI_SHADOW_OFFSET, dst.width, dst.height),
249
- origin=origin,
250
- rotation_deg=0.0,
251
- )
252
- MenuView._draw_ui_quad(
253
- texture=panel,
254
- src=rl.Rectangle(0.0, 0.0, float(panel.width), float(panel.height)),
255
- dst=dst,
256
- origin=origin,
257
- rotation_deg=0.0,
258
- tint=rl.WHITE,
259
- )
247
+ draw_classic_menu_panel(panel, dst=dst, tint=rl.WHITE, shadow=fx_detail)
260
248
 
261
249
  def _draw_entry(self, entry: MenuEntry) -> None:
262
250
  assets = self._assets
@@ -9,11 +9,13 @@ from grim.fonts.small import SmallFontData, draw_small_text, load_small_font
9
9
  from ..menu import (
10
10
  MENU_PANEL_OFFSET_X,
11
11
  MENU_PANEL_OFFSET_Y,
12
+ MENU_PANEL_HEIGHT,
12
13
  MENU_PANEL_WIDTH,
13
14
  MenuView,
14
15
  _draw_menu_cursor,
15
16
  )
16
17
  from ..transitions import _draw_screen_fade
18
+ from ...ui.menu_panel import draw_classic_menu_panel
17
19
  from .base import PANEL_TIMELINE_END_MS, PANEL_TIMELINE_START_MS, PanelMenuView
18
20
  from ...input_codes import config_keybinds, input_code_name, player_move_fire_binds
19
21
 
@@ -21,15 +23,43 @@ if TYPE_CHECKING:
21
23
  from ...game import GameState
22
24
 
23
25
 
26
+ # Measured from ui_render_trace_oracle_1024x768.json (state_3:Configure for:, timeline=300).
27
+ CONTROLS_LEFT_PANEL_POS_X = -165.0
28
+ CONTROLS_LEFT_PANEL_POS_Y = 200.0
29
+ CONTROLS_RIGHT_PANEL_POS_X = 590.0
30
+ CONTROLS_RIGHT_PANEL_POS_Y = 110.0
31
+ CONTROLS_RIGHT_PANEL_HEIGHT = 378.0
32
+ CONTROLS_BACK_POS_X = -155.0
33
+ CONTROLS_BACK_POS_Y = 420.0
34
+
35
+
24
36
  class ControlsMenuView(PanelMenuView):
25
37
  def __init__(self, state: GameState) -> None:
26
- super().__init__(state, title="Controls", back_action="open_options")
38
+ super().__init__(
39
+ state,
40
+ title="Controls",
41
+ back_action="open_options",
42
+ panel_pos_x=CONTROLS_LEFT_PANEL_POS_X,
43
+ panel_pos_y=CONTROLS_LEFT_PANEL_POS_Y,
44
+ back_pos_x=CONTROLS_BACK_POS_X,
45
+ back_pos_y=CONTROLS_BACK_POS_Y,
46
+ )
27
47
  self._small_font: SmallFontData | None = None
28
- self._lines: list[str] = []
48
+ self._text_controls: rl.Texture2D | None = None
49
+ self._drop_off: rl.Texture2D | None = None
50
+ self._check_on: rl.Texture2D | None = None
51
+ self._check_off: rl.Texture2D | None = None
52
+
53
+ self._config_player = 1
29
54
 
30
55
  def open(self) -> None:
31
56
  super().open()
32
- self._lines = self._build_lines()
57
+ cache = self._ensure_cache()
58
+ # UI elements used by the classic controls screen.
59
+ self._text_controls = cache.get_or_load("ui_textControls", "ui/ui_textControls.jaz").texture
60
+ self._drop_off = cache.get_or_load("ui_dropOff", "ui/ui_dropDownOff.jaz").texture
61
+ self._check_on = cache.get_or_load("ui_checkOn", "ui/ui_checkOn.jaz").texture
62
+ self._check_off = cache.get_or_load("ui_checkOff", "ui/ui_checkOff.jaz").texture
33
63
 
34
64
  def draw(self) -> None:
35
65
  self._draw_background()
@@ -51,9 +81,17 @@ class ControlsMenuView(PanelMenuView):
51
81
  self._small_font = load_small_font(self._state.assets_dir, missing_assets)
52
82
  return self._small_font
53
83
 
54
- def _content_layout(self) -> dict[str, float]:
55
- panel_scale, _local_shift = self._menu_item_scale(0)
84
+ def _draw_panel(self) -> None:
85
+ assets = self._assets
86
+ if assets is None or assets.panel is None:
87
+ return
88
+ panel = assets.panel
89
+
90
+ fx_detail = bool(self._state.config.data.get("fx_detail_0", 0))
91
+ panel_scale, _local_y_shift = self._menu_item_scale(0)
56
92
  panel_w = MENU_PANEL_WIDTH * panel_scale
93
+
94
+ # Left (controls options) panel: standard 254px height => a single quad.
57
95
  _angle_rad, slide_x = MenuView._ui_element_anim(
58
96
  self,
59
97
  index=1,
@@ -61,23 +99,93 @@ class ControlsMenuView(PanelMenuView):
61
99
  end_ms=PANEL_TIMELINE_END_MS,
62
100
  width=panel_w,
63
101
  )
64
- panel_x = self._panel_pos_x + slide_x
65
- panel_y = self._panel_pos_y + self._widescreen_y_shift
66
- origin_x = -(MENU_PANEL_OFFSET_X * panel_scale)
67
- origin_y = -(MENU_PANEL_OFFSET_Y * panel_scale)
68
- panel_left = panel_x - origin_x
69
- panel_top = panel_y - origin_y
70
- base_x = panel_left + 212.0 * panel_scale
71
- base_y = panel_top + 32.0 * panel_scale
72
- label_x = base_x + 8.0 * panel_scale
73
- return {
74
- "base_x": base_x,
75
- "base_y": base_y,
76
- "label_x": label_x,
77
- "scale": panel_scale,
78
- }
79
-
80
- def _build_lines(self) -> list[str]:
102
+ left_x0 = self._panel_pos_x + slide_x + MENU_PANEL_OFFSET_X * panel_scale
103
+ left_y0 = self._panel_pos_y + self._widescreen_y_shift + MENU_PANEL_OFFSET_Y * panel_scale
104
+ left_h = MENU_PANEL_HEIGHT * panel_scale
105
+ draw_classic_menu_panel(panel, dst=rl.Rectangle(left_x0, left_y0, panel_w, left_h), tint=rl.WHITE, shadow=fx_detail)
106
+
107
+ # Right (configured bindings) panel: tall 378px panel rendered as 3 vertical slices.
108
+ _angle_rad, slide_x = MenuView._ui_element_anim(
109
+ self,
110
+ index=3,
111
+ start_ms=PANEL_TIMELINE_START_MS,
112
+ end_ms=PANEL_TIMELINE_END_MS,
113
+ width=panel_w,
114
+ direction_flag=1,
115
+ )
116
+ right_x0 = CONTROLS_RIGHT_PANEL_POS_X + slide_x + MENU_PANEL_OFFSET_X * panel_scale
117
+ right_y0 = CONTROLS_RIGHT_PANEL_POS_Y + self._widescreen_y_shift + MENU_PANEL_OFFSET_Y * panel_scale
118
+ right_h = float(CONTROLS_RIGHT_PANEL_HEIGHT) * panel_scale
119
+ draw_classic_menu_panel(panel, dst=rl.Rectangle(right_x0, right_y0, panel_w, right_h), tint=rl.WHITE, shadow=fx_detail)
120
+
121
+ def _draw_contents(self) -> None:
122
+ # Positions are expressed relative to the panel top-left corners and scaled with the panel scale.
123
+ panel_scale, _local_y_shift = self._menu_item_scale(0)
124
+
125
+ left_x0 = self._panel_pos_x + MENU_PANEL_OFFSET_X * panel_scale
126
+ left_y0 = self._panel_pos_y + self._widescreen_y_shift + MENU_PANEL_OFFSET_Y * panel_scale
127
+ right_x0 = CONTROLS_RIGHT_PANEL_POS_X + MENU_PANEL_OFFSET_X * panel_scale
128
+ right_y0 = CONTROLS_RIGHT_PANEL_POS_Y + self._widescreen_y_shift + MENU_PANEL_OFFSET_Y * panel_scale
129
+
130
+ font = self._ensure_small_font()
131
+ text_color = rl.Color(255, 255, 255, 255)
132
+
133
+ # --- Left panel: "Configure for" + method selectors (state_3 in trace) ---
134
+ if self._text_controls is not None:
135
+ MenuView._draw_ui_quad(
136
+ texture=self._text_controls,
137
+ src=rl.Rectangle(0.0, 0.0, float(self._text_controls.width), float(self._text_controls.height)),
138
+ dst=rl.Rectangle(left_x0 + 206.0 * panel_scale, left_y0 + 44.0 * panel_scale, 128.0 * panel_scale, 32.0 * panel_scale),
139
+ origin=rl.Vector2(0.0, 0.0),
140
+ rotation_deg=0.0,
141
+ tint=rl.WHITE,
142
+ )
143
+
144
+ draw_small_text(font, "Configure for:", left_x0 + 339.0 * panel_scale, left_y0 + 41.0 * panel_scale, 1.0 * panel_scale, text_color)
145
+ draw_small_text(font, f"Player {int(self._config_player)}", left_x0 + 344.0 * panel_scale, left_y0 + 57.0 * panel_scale, 1.0 * panel_scale, text_color)
146
+
147
+ draw_small_text(font, "Aiming method:", left_x0 + 213.0 * panel_scale, left_y0 + 86.0 * panel_scale, 1.0 * panel_scale, text_color)
148
+ draw_small_text(font, "Mouse", left_x0 + 218.0 * panel_scale, left_y0 + 103.0 * panel_scale, 1.0 * panel_scale, text_color)
149
+
150
+ draw_small_text(font, "Moving method:", left_x0 + 213.0 * panel_scale, left_y0 + 128.0 * panel_scale, 1.0 * panel_scale, text_color)
151
+ draw_small_text(font, "Static", left_x0 + 218.0 * panel_scale, left_y0 + 145.0 * panel_scale, 1.0 * panel_scale, text_color)
152
+
153
+ check_tex = self._check_on
154
+ if check_tex is not None:
155
+ MenuView._draw_ui_quad(
156
+ texture=check_tex,
157
+ src=rl.Rectangle(0.0, 0.0, float(check_tex.width), float(check_tex.height)),
158
+ dst=rl.Rectangle(left_x0 + 213.0 * panel_scale, left_y0 + 174.0 * panel_scale, 16.0 * panel_scale, 16.0 * panel_scale),
159
+ origin=rl.Vector2(0.0, 0.0),
160
+ rotation_deg=0.0,
161
+ tint=rl.WHITE,
162
+ )
163
+ draw_small_text(
164
+ font,
165
+ "Show direction arrow",
166
+ left_x0 + 235.0 * panel_scale,
167
+ left_y0 + 175.0 * panel_scale,
168
+ 1.0 * panel_scale,
169
+ text_color,
170
+ )
171
+
172
+ drop_tex = self._drop_off
173
+ if drop_tex is not None:
174
+ for ox, oy in (
175
+ (418.0, 56.0), # player dropdown
176
+ (336.0, 102.0), # aiming dropdown
177
+ (336.0, 144.0), # moving dropdown
178
+ ):
179
+ MenuView._draw_ui_quad(
180
+ texture=drop_tex,
181
+ src=rl.Rectangle(0.0, 0.0, float(drop_tex.width), float(drop_tex.height)),
182
+ dst=rl.Rectangle(left_x0 + ox * panel_scale, left_y0 + oy * panel_scale, 16.0 * panel_scale, 16.0 * panel_scale),
183
+ origin=rl.Vector2(0.0, 0.0),
184
+ rotation_deg=0.0,
185
+ tint=rl.WHITE,
186
+ )
187
+
188
+ # --- Right panel: configured bindings list ---
81
189
  config = self._state.config
82
190
  pick_perk_key = int(config.data.get("keybind_pick_perk", 0x101) or 0x101)
83
191
  reload_key = int(config.data.get("keybind_reload", 0x102) or 0x102)
@@ -87,44 +195,25 @@ class ControlsMenuView(PanelMenuView):
87
195
  keybinds = (0x11, 0x1F, 0x1E, 0x20, 0x100) + (0x17E,) * 11 + (0xC8, 0xD0, 0xCB, 0xCD, 0x9D)
88
196
 
89
197
  p1_up, p1_down, p1_left, p1_right, p1_fire = player_move_fire_binds(keybinds, 0)
90
- p2_up, p2_down, p2_left, p2_right, p2_fire = player_move_fire_binds(keybinds, 1)
91
-
92
- return [
93
- f"Level up: {input_code_name(pick_perk_key)} / Space / KeyPad+",
94
- f"Reload: {input_code_name(reload_key)}",
95
- "",
96
- "Player 1:",
97
- f" Up: {input_code_name(p1_up)}",
98
- f" Down: {input_code_name(p1_down)}",
99
- f" Left: {input_code_name(p1_left)}",
100
- f" Right: {input_code_name(p1_right)}",
101
- f" Fire: {input_code_name(p1_fire)}",
102
- "",
103
- "Player 2:",
104
- f" Up: {input_code_name(p2_up)}",
105
- f" Down: {input_code_name(p2_down)}",
106
- f" Left: {input_code_name(p2_left)}",
107
- f" Right: {input_code_name(p2_right)}",
108
- f" Fire: {input_code_name(p2_fire)}",
109
- ]
110
198
 
111
- def _draw_contents(self) -> None:
112
- layout = self._content_layout()
113
- base_x = layout["base_x"]
114
- base_y = layout["base_y"]
115
- label_x = layout["label_x"]
116
- scale = layout["scale"]
117
-
118
- font = self._ensure_small_font()
119
- title_scale = 1.2 * scale
120
- text_scale = 1.0 * scale
121
-
122
- title_color = rl.Color(255, 255, 255, 255)
123
- text_color = rl.Color(255, 255, 255, int(255 * 0.8))
124
-
125
- draw_small_text(font, "CONTROLS", base_x, base_y, title_scale, title_color)
126
- line_y = base_y + 44.0 * scale
127
- line_step = (font.cell_size + 4.0) * scale
128
- for line in self._lines:
129
- draw_small_text(font, line, label_x, line_y, text_scale, text_color)
130
- line_y += line_step
199
+ draw_small_text(font, "Configured controls", right_x0 + 120.0 * panel_scale, right_y0 + 38.0 * panel_scale, 1.0 * panel_scale, text_color)
200
+
201
+ draw_small_text(font, "Aiming", right_x0 + 44.0 * panel_scale, right_y0 + 64.0 * panel_scale, 1.0 * panel_scale, text_color)
202
+ draw_small_text(font, "Fire:", right_x0 + 52.0 * panel_scale, right_y0 + 82.0 * panel_scale, 1.0 * panel_scale, text_color)
203
+ draw_small_text(font, input_code_name(p1_fire), right_x0 + 180.0 * panel_scale, right_y0 + 82.0 * panel_scale, 1.0 * panel_scale, text_color)
204
+
205
+ draw_small_text(font, "Moving", right_x0 + 44.0 * panel_scale, right_y0 + 106.0 * panel_scale, 1.0 * panel_scale, text_color)
206
+ draw_small_text(font, "Move Up:", right_x0 + 52.0 * panel_scale, right_y0 + 124.0 * panel_scale, 1.0 * panel_scale, text_color)
207
+ draw_small_text(font, input_code_name(p1_up), right_x0 + 180.0 * panel_scale, right_y0 + 124.0 * panel_scale, 1.0 * panel_scale, text_color)
208
+ draw_small_text(font, "Move Down:", right_x0 + 52.0 * panel_scale, right_y0 + 140.0 * panel_scale, 1.0 * panel_scale, text_color)
209
+ draw_small_text(font, input_code_name(p1_down), right_x0 + 180.0 * panel_scale, right_y0 + 140.0 * panel_scale, 1.0 * panel_scale, text_color)
210
+ draw_small_text(font, "Move Left:", right_x0 + 52.0 * panel_scale, right_y0 + 156.0 * panel_scale, 1.0 * panel_scale, text_color)
211
+ draw_small_text(font, input_code_name(p1_left), right_x0 + 180.0 * panel_scale, right_y0 + 156.0 * panel_scale, 1.0 * panel_scale, text_color)
212
+ draw_small_text(font, "Move Right:", right_x0 + 52.0 * panel_scale, right_y0 + 172.0 * panel_scale, 1.0 * panel_scale, text_color)
213
+ draw_small_text(font, input_code_name(p1_right), right_x0 + 180.0 * panel_scale, right_y0 + 172.0 * panel_scale, 1.0 * panel_scale, text_color)
214
+
215
+ draw_small_text(font, "Misc", right_x0 + 44.0 * panel_scale, right_y0 + 196.0 * panel_scale, 1.0 * panel_scale, text_color)
216
+ draw_small_text(font, "Level Up:", right_x0 + 52.0 * panel_scale, right_y0 + 214.0 * panel_scale, 1.0 * panel_scale, text_color)
217
+ draw_small_text(font, input_code_name(pick_perk_key), right_x0 + 180.0 * panel_scale, right_y0 + 214.0 * panel_scale, 1.0 * panel_scale, text_color)
218
+ draw_small_text(font, "Reload:", right_x0 + 52.0 * panel_scale, right_y0 + 230.0 * panel_scale, 1.0 * panel_scale, text_color)
219
+ draw_small_text(font, input_code_name(reload_key), right_x0 + 180.0 * panel_scale, right_y0 + 230.0 * panel_scale, 1.0 * panel_scale, text_color)