crimsonland 0.1.0.dev14__py3-none-any.whl → 0.1.0.dev16__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.
Files changed (73) hide show
  1. crimson/cli.py +63 -0
  2. crimson/creatures/damage.py +111 -36
  3. crimson/creatures/runtime.py +246 -156
  4. crimson/creatures/spawn.py +7 -3
  5. crimson/debug.py +9 -0
  6. crimson/demo.py +38 -45
  7. crimson/effects.py +7 -13
  8. crimson/frontend/high_scores_layout.py +81 -0
  9. crimson/frontend/panels/base.py +4 -1
  10. crimson/frontend/panels/controls.py +0 -15
  11. crimson/frontend/panels/databases.py +291 -3
  12. crimson/frontend/panels/mods.py +0 -15
  13. crimson/frontend/panels/play_game.py +0 -16
  14. crimson/game.py +689 -3
  15. crimson/gameplay.py +921 -569
  16. crimson/modes/base_gameplay_mode.py +33 -12
  17. crimson/modes/components/__init__.py +2 -0
  18. crimson/modes/components/highscore_record_builder.py +58 -0
  19. crimson/modes/components/perk_menu_controller.py +325 -0
  20. crimson/modes/quest_mode.py +94 -272
  21. crimson/modes/rush_mode.py +12 -43
  22. crimson/modes/survival_mode.py +109 -330
  23. crimson/modes/tutorial_mode.py +46 -247
  24. crimson/modes/typo_mode.py +11 -38
  25. crimson/oracle.py +396 -0
  26. crimson/perks.py +5 -2
  27. crimson/player_damage.py +95 -36
  28. crimson/projectiles.py +539 -320
  29. crimson/render/projectile_draw_registry.py +637 -0
  30. crimson/render/projectile_render_registry.py +110 -0
  31. crimson/render/secondary_projectile_draw_registry.py +206 -0
  32. crimson/render/world_renderer.py +58 -707
  33. crimson/sim/world_state.py +118 -61
  34. crimson/typo/spawns.py +5 -12
  35. crimson/ui/demo_trial_overlay.py +3 -11
  36. crimson/ui/formatting.py +24 -0
  37. crimson/ui/game_over.py +12 -58
  38. crimson/ui/hud.py +72 -39
  39. crimson/ui/layout.py +20 -0
  40. crimson/ui/perk_menu.py +9 -34
  41. crimson/ui/quest_results.py +28 -70
  42. crimson/ui/text_input.py +20 -0
  43. crimson/views/_ui_helpers.py +27 -0
  44. crimson/views/aim_debug.py +15 -32
  45. crimson/views/animations.py +18 -28
  46. crimson/views/arsenal_debug.py +22 -32
  47. crimson/views/bonuses.py +23 -36
  48. crimson/views/camera_debug.py +16 -29
  49. crimson/views/camera_shake.py +9 -33
  50. crimson/views/corpse_stamp_debug.py +13 -21
  51. crimson/views/decals_debug.py +36 -23
  52. crimson/views/fonts.py +8 -25
  53. crimson/views/ground.py +4 -21
  54. crimson/views/lighting_debug.py +42 -45
  55. crimson/views/particles.py +33 -42
  56. crimson/views/perk_menu_debug.py +3 -10
  57. crimson/views/player.py +50 -44
  58. crimson/views/player_sprite_debug.py +24 -31
  59. crimson/views/projectile_fx.py +57 -52
  60. crimson/views/projectile_render_debug.py +24 -33
  61. crimson/views/projectiles.py +24 -37
  62. crimson/views/spawn_plan.py +13 -29
  63. crimson/views/sprites.py +14 -29
  64. crimson/views/terrain.py +6 -23
  65. crimson/views/ui.py +7 -24
  66. crimson/views/wicons.py +28 -33
  67. {crimsonland-0.1.0.dev14.dist-info → crimsonland-0.1.0.dev16.dist-info}/METADATA +1 -1
  68. {crimsonland-0.1.0.dev14.dist-info → crimsonland-0.1.0.dev16.dist-info}/RECORD +73 -62
  69. {crimsonland-0.1.0.dev14.dist-info → crimsonland-0.1.0.dev16.dist-info}/WHEEL +1 -1
  70. grim/config.py +29 -1
  71. grim/console.py +7 -10
  72. grim/math.py +12 -0
  73. {crimsonland-0.1.0.dev14.dist-info → crimsonland-0.1.0.dev16.dist-info}/entry_points.txt +0 -0
crimson/views/sprites.py CHANGED
@@ -4,8 +4,9 @@ from dataclasses import dataclass
4
4
 
5
5
  import pyray as rl
6
6
 
7
+ from ._ui_helpers import draw_ui_text, ui_line_height
7
8
  from .registry import register_view
8
- from grim.fonts.small import SmallFontData, draw_small_text, load_small_font
9
+ from grim.fonts.small import SmallFontData, load_small_font
9
10
  from grim.view import View, ViewContext
10
11
 
11
12
  UI_TEXT_SCALE = 1.0
@@ -51,24 +52,6 @@ class SpriteSheetView:
51
52
  self._index = 0
52
53
  self._small: SmallFontData | None = None
53
54
 
54
- def _ui_line_height(self, scale: float = UI_TEXT_SCALE) -> int:
55
- if self._small is not None:
56
- return int(self._small.cell_size * scale)
57
- return int(20 * scale)
58
-
59
- def _draw_ui_text(
60
- self,
61
- text: str,
62
- x: float,
63
- y: float,
64
- color: rl.Color,
65
- scale: float = UI_TEXT_SCALE,
66
- ) -> None:
67
- if self._small is not None:
68
- draw_small_text(self._small, text, x, y, scale, color)
69
- else:
70
- rl.draw_text(text, int(x), int(y), int(20 * scale), color)
71
-
72
55
  def open(self) -> None:
73
56
  self._missing_assets.clear()
74
57
  self._sheets.clear()
@@ -135,10 +118,10 @@ class SpriteSheetView:
135
118
  rl.clear_background(rl.Color(12, 12, 14, 255))
136
119
  if self._missing_assets:
137
120
  message = "Missing assets: " + ", ".join(self._missing_assets)
138
- self._draw_ui_text(message, 24, 24, UI_ERROR_COLOR)
121
+ draw_ui_text(self._small, message, 24, 24, scale=UI_TEXT_SCALE, color=UI_ERROR_COLOR)
139
122
  return
140
123
  if not self._sheets:
141
- self._draw_ui_text("No sprite sheets loaded.", 24, 24, UI_TEXT_COLOR)
124
+ draw_ui_text(self._small, "No sprite sheets loaded.", 24, 24, scale=UI_TEXT_SCALE, color=UI_TEXT_COLOR)
142
125
  return
143
126
 
144
127
  self._handle_input()
@@ -147,9 +130,16 @@ class SpriteSheetView:
147
130
 
148
131
  margin = 24
149
132
  info = f"{sheet.name} (grid {grid}x{grid})"
150
- self._draw_ui_text(info, margin, margin, UI_TEXT_COLOR)
133
+ draw_ui_text(self._small, info, margin, margin, scale=UI_TEXT_SCALE, color=UI_TEXT_COLOR)
151
134
  hint = "Left/Right: sheet Up/Down: grid 1/2/4/8: grid"
152
- self._draw_ui_text(hint, margin, margin + self._ui_line_height() + 6, UI_HINT_COLOR)
135
+ draw_ui_text(
136
+ self._small,
137
+ hint,
138
+ margin,
139
+ margin + ui_line_height(self._small, scale=UI_TEXT_SCALE) + 6,
140
+ scale=UI_TEXT_SCALE,
141
+ color=UI_HINT_COLOR,
142
+ )
153
143
 
154
144
  available_width = rl.get_screen_width() - margin * 2
155
145
  available_height = rl.get_screen_height() - margin * 2 - 60
@@ -201,12 +191,7 @@ class SpriteSheetView:
201
191
  float(cell_h),
202
192
  )
203
193
  rl.draw_rectangle_lines_ex(hl, 2, rl.Color(240, 200, 80, 255))
204
- self._draw_ui_text(
205
- f"frame {index:02d}",
206
- x,
207
- y + draw_h + 10,
208
- UI_TEXT_COLOR,
209
- )
194
+ draw_ui_text(self._small, f"frame {index:02d}", x, y + draw_h + 10, scale=UI_TEXT_SCALE, color=UI_TEXT_COLOR)
210
195
 
211
196
 
212
197
  @register_view("sprites", "Sprite atlas preview")
crimson/views/terrain.py CHANGED
@@ -4,8 +4,9 @@ from dataclasses import dataclass
4
4
 
5
5
  import pyray as rl
6
6
 
7
+ from ._ui_helpers import draw_ui_text, ui_line_height
7
8
  from .registry import register_view
8
- from grim.fonts.small import SmallFontData, draw_small_text, load_small_font
9
+ from grim.fonts.small import SmallFontData, load_small_font
9
10
  from grim.view import View, ViewContext
10
11
 
11
12
  UI_TEXT_SCALE = 1.0
@@ -43,24 +44,6 @@ class TerrainView:
43
44
  self._textures: list[TerrainTexture] = []
44
45
  self._small: SmallFontData | None = None
45
46
 
46
- def _ui_line_height(self, scale: float = UI_TEXT_SCALE) -> int:
47
- if self._small is not None:
48
- return int(self._small.cell_size * scale)
49
- return int(20 * scale)
50
-
51
- def _draw_ui_text(
52
- self,
53
- text: str,
54
- x: float,
55
- y: float,
56
- color: rl.Color,
57
- scale: float = UI_TEXT_SCALE,
58
- ) -> None:
59
- if self._small is not None:
60
- draw_small_text(self._small, text, x, y, scale, color)
61
- else:
62
- rl.draw_text(text, int(x), int(y), int(20 * scale), color)
63
-
64
47
  def open(self) -> None:
65
48
  self._missing_assets.clear()
66
49
  self._textures.clear()
@@ -90,10 +73,10 @@ class TerrainView:
90
73
  rl.clear_background(rl.Color(12, 12, 14, 255))
91
74
  if self._missing_assets:
92
75
  message = "Missing assets: " + ", ".join(self._missing_assets)
93
- self._draw_ui_text(message, 24, 24, UI_ERROR_COLOR)
76
+ draw_ui_text(self._small, message, 24, 24, scale=UI_TEXT_SCALE, color=UI_ERROR_COLOR)
94
77
  return
95
78
  if not self._textures:
96
- self._draw_ui_text("No terrain textures loaded.", 24, 24, UI_TEXT_COLOR)
79
+ draw_ui_text(self._small, "No terrain textures loaded.", 24, 24, scale=UI_TEXT_SCALE, color=UI_TEXT_COLOR)
97
80
  return
98
81
 
99
82
  cols = 4
@@ -101,7 +84,7 @@ class TerrainView:
101
84
  margin = 24
102
85
  gap_x = 16
103
86
  gap_y = 20
104
- label_height = self._ui_line_height()
87
+ label_height = ui_line_height(self._small, scale=UI_TEXT_SCALE)
105
88
 
106
89
  cell_w = max(entry.texture.width for entry in self._textures)
107
90
  cell_h = max(entry.texture.height for entry in self._textures)
@@ -116,7 +99,7 @@ class TerrainView:
116
99
  x = margin + col * (cell_w * scale + gap_x)
117
100
  y = margin + row * (cell_h * scale + gap_y + label_height)
118
101
  label = f"{entry.terrain_id:02d} {entry.name}"
119
- self._draw_ui_text(label, x, y, UI_TEXT_COLOR)
102
+ draw_ui_text(self._small, label, x, y, scale=UI_TEXT_SCALE, color=UI_TEXT_COLOR)
120
103
  dst = rl.Rectangle(
121
104
  float(x),
122
105
  float(y + label_height),
crimson/views/ui.py CHANGED
@@ -4,8 +4,9 @@ from dataclasses import dataclass
4
4
 
5
5
  import pyray as rl
6
6
 
7
+ from ._ui_helpers import draw_ui_text, ui_line_height
7
8
  from .registry import register_view
8
- from grim.fonts.small import SmallFontData, draw_small_text, load_small_font
9
+ from grim.fonts.small import SmallFontData, load_small_font
9
10
  from grim.view import View, ViewContext
10
11
 
11
12
  UI_TEXT_SCALE = 1.0
@@ -28,24 +29,6 @@ class UiTextureView:
28
29
  self._index = 0
29
30
  self._small: SmallFontData | None = None
30
31
 
31
- def _ui_line_height(self, scale: float = UI_TEXT_SCALE) -> int:
32
- if self._small is not None:
33
- return int(self._small.cell_size * scale)
34
- return int(20 * scale)
35
-
36
- def _draw_ui_text(
37
- self,
38
- text: str,
39
- x: float,
40
- y: float,
41
- color: rl.Color,
42
- scale: float = UI_TEXT_SCALE,
43
- ) -> None:
44
- if self._small is not None:
45
- draw_small_text(self._small, text, x, y, scale, color)
46
- else:
47
- rl.draw_text(text, int(x), int(y), int(20 * scale), color)
48
-
49
32
  def open(self) -> None:
50
33
  self._missing_assets.clear()
51
34
  self._textures.clear()
@@ -84,10 +67,10 @@ class UiTextureView:
84
67
  rl.clear_background(rl.Color(12, 12, 14, 255))
85
68
  if self._missing_assets:
86
69
  message = "Missing assets: " + ", ".join(self._missing_assets)
87
- self._draw_ui_text(message, 24, 24, UI_ERROR_COLOR)
70
+ draw_ui_text(self._small, message, 24, 24, scale=UI_TEXT_SCALE, color=UI_ERROR_COLOR)
88
71
  return
89
72
  if not self._textures:
90
- self._draw_ui_text("No UI textures loaded.", 24, 24, UI_TEXT_COLOR)
73
+ draw_ui_text(self._small, "No UI textures loaded.", 24, 24, scale=UI_TEXT_SCALE, color=UI_TEXT_COLOR)
91
74
  return
92
75
 
93
76
  self._handle_input()
@@ -95,11 +78,11 @@ class UiTextureView:
95
78
 
96
79
  margin = 24
97
80
  header_y = margin
98
- line_height = self._ui_line_height()
81
+ line_height = ui_line_height(self._small, scale=UI_TEXT_SCALE)
99
82
  title = f"{self._index + 1}/{len(self._textures)} {entry.name}"
100
- self._draw_ui_text(title, margin, header_y, UI_TEXT_COLOR)
83
+ draw_ui_text(self._small, title, margin, header_y, scale=UI_TEXT_SCALE, color=UI_TEXT_COLOR)
101
84
  header_y += line_height + 6
102
- self._draw_ui_text("Left/Right: texture", margin, header_y, UI_HINT_COLOR)
85
+ draw_ui_text(self._small, "Left/Right: texture", margin, header_y, scale=UI_TEXT_SCALE, color=UI_HINT_COLOR)
103
86
 
104
87
  available_width = rl.get_screen_width() - margin * 2
105
88
  available_height = rl.get_screen_height() - (header_y + line_height + margin)
crimson/views/wicons.py CHANGED
@@ -5,8 +5,9 @@ from dataclasses import dataclass
5
5
  import pyray as rl
6
6
 
7
7
  from ..weapons import WEAPON_TABLE, Weapon
8
+ from ._ui_helpers import draw_ui_text, ui_line_height
8
9
  from .registry import register_view
9
- from grim.fonts.small import SmallFontData, draw_small_text, load_small_font
10
+ from grim.fonts.small import SmallFontData, load_small_font
10
11
  from grim.view import View, ViewContext
11
12
 
12
13
  UI_TEXT_SCALE = 1.0
@@ -45,24 +46,6 @@ class WeaponIconView:
45
46
  self._texture: rl.Texture | None = None
46
47
  self._small: SmallFontData | None = None
47
48
 
48
- def _ui_line_height(self, scale: float = UI_TEXT_SCALE) -> int:
49
- if self._small is not None:
50
- return int(self._small.cell_size * scale)
51
- return int(20 * scale)
52
-
53
- def _draw_ui_text(
54
- self,
55
- text: str,
56
- x: float,
57
- y: float,
58
- color: rl.Color,
59
- scale: float = UI_TEXT_SCALE,
60
- ) -> None:
61
- if self._small is not None:
62
- draw_small_text(self._small, text, x, y, scale, color)
63
- else:
64
- rl.draw_text(text, int(x), int(y), int(20 * scale), color)
65
-
66
49
  def open(self) -> None:
67
50
  self._missing_assets.clear()
68
51
  self._small = load_small_font(self._assets_root, self._missing_assets)
@@ -87,10 +70,17 @@ class WeaponIconView:
87
70
  rl.clear_background(rl.Color(12, 12, 14, 255))
88
71
  if self._missing_assets:
89
72
  message = "Missing assets: " + ", ".join(self._missing_assets)
90
- self._draw_ui_text(message, 24, 24, UI_ERROR_COLOR)
73
+ draw_ui_text(self._small, message, 24, 24, scale=UI_TEXT_SCALE, color=UI_ERROR_COLOR)
91
74
  return
92
75
  if self._texture is None:
93
- self._draw_ui_text("No weapon icon texture loaded.", 24, 24, UI_TEXT_COLOR)
76
+ draw_ui_text(
77
+ self._small,
78
+ "No weapon icon texture loaded.",
79
+ 24,
80
+ 24,
81
+ scale=UI_TEXT_SCALE,
82
+ color=UI_TEXT_COLOR,
83
+ )
94
84
  return
95
85
 
96
86
  margin = 24
@@ -123,42 +113,47 @@ class WeaponIconView:
123
113
  hovered_index = idx
124
114
  rl.draw_rectangle_lines_ex(dst, 3, UI_HOVER_COLOR)
125
115
 
126
- self._draw_ui_text(
116
+ draw_ui_text(
117
+ self._small,
127
118
  f"{idx:02d}",
128
119
  dst_x + 4,
129
120
  dst_y + 4,
130
- UI_HINT_COLOR,
131
121
  scale=0.75,
122
+ color=UI_HINT_COLOR,
132
123
  )
133
124
 
134
125
  info_x = x + cols * icon_w * scale + panel_gap
135
126
  info_y = margin
136
- self._draw_ui_text(
127
+ draw_ui_text(
128
+ self._small,
137
129
  "ui_wicons.png (8x8 grid, 2x1 subrects)",
138
130
  info_x,
139
131
  info_y,
140
- UI_TEXT_COLOR,
132
+ scale=UI_TEXT_SCALE,
133
+ color=UI_TEXT_COLOR,
141
134
  )
142
- info_y += self._ui_line_height() + 12
135
+ info_y += ui_line_height(self._small, scale=UI_TEXT_SCALE) + 12
143
136
 
144
137
  if hovered_index is not None:
145
138
  frame = hovered_index * 2
146
- self._draw_ui_text(
139
+ draw_ui_text(
140
+ self._small,
147
141
  f"icon_index {hovered_index} frame {frame}",
148
142
  info_x,
149
143
  info_y,
150
- UI_TEXT_COLOR,
144
+ scale=UI_TEXT_SCALE,
145
+ color=UI_TEXT_COLOR,
151
146
  )
152
- info_y += self._ui_line_height() + 6
147
+ info_y += ui_line_height(self._small, scale=UI_TEXT_SCALE) + 6
153
148
  group = WEAPON_ICON_GROUPS.get(hovered_index)
154
149
  if group is None:
155
- self._draw_ui_text("no weapon mapping", info_x, info_y, UI_HINT_COLOR)
156
- info_y += self._ui_line_height() + 6
150
+ draw_ui_text(self._small, "no weapon mapping", info_x, info_y, scale=UI_TEXT_SCALE, color=UI_HINT_COLOR)
151
+ info_y += ui_line_height(self._small, scale=UI_TEXT_SCALE) + 6
157
152
  else:
158
153
  for weapon in group.weapons:
159
154
  name = weapon.name or f"weapon_{weapon.weapon_id}"
160
- self._draw_ui_text(name, info_x, info_y, UI_TEXT_COLOR)
161
- info_y += self._ui_line_height() + 4
155
+ draw_ui_text(self._small, name, info_x, info_y, scale=UI_TEXT_SCALE, color=UI_TEXT_COLOR)
156
+ info_y += ui_line_height(self._small, scale=UI_TEXT_SCALE) + 4
162
157
 
163
158
 
164
159
  @register_view("wicons", "Weapon icon preview")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: crimsonland
3
- Version: 0.1.0.dev14
3
+ Version: 0.1.0.dev16
4
4
  Requires-Dist: construct>=2.10.70
5
5
  Requires-Dist: pillow>=12.1.0
6
6
  Requires-Dist: platformdirs>=4.5.1
@@ -4,53 +4,57 @@ crimson/atlas.py,sha256=hEcCHhPvguXAI6eH_G9Q8rpiX7M5akZ8fgJjMogmYrA,2401
4
4
  crimson/audio_router.py,sha256=4lccGu5044WQ5sMz9yfZd4loSgEMDqXJWGvMmHyMGt0,5449
5
5
  crimson/bonuses.py,sha256=owwYIRHRu1Kymtt4eEvpd62JwWAg8LOe20vDuPFB5SU,5094
6
6
  crimson/camera.py,sha256=VxTNXTh0qHh5VR1OpkiXr-QcgEWPrWw0A3PFyQFqDkY,2278
7
- crimson/cli.py,sha256=Pu4RM_bjGtUgIE_5zZs0uWFY9O8YkhJDseRcVMMPJ8k,14595
7
+ crimson/cli.py,sha256=V9hE6BZ27yHT0C4w6Q9eCcWiUS44LjydeI0WyoZtNAQ,17076
8
8
  crimson/creatures/__init__.py,sha256=RJwwR_w98zC_kHF9CwkhzSlf0xjpiP0JU87W4awdAAM,233
9
9
  crimson/creatures/ai.py,sha256=oCuUkDe6Kxya1dThUthEy8GIuObAUjDv8WPfe17HYV4,6353
10
10
  crimson/creatures/anim.py,sha256=k_jEpyfwFcJSC9jY2xuhuxtQ8KvE6fSeuRSBLTTAxWo,5016
11
- crimson/creatures/damage.py,sha256=pjKIX32nGDVPnFaWCce0LNZ-UZXZqJpNvwHwq-DCWbE,3211
12
- crimson/creatures/runtime.py,sha256=wfSicwqkSovM_mn_7AMQwxWY_-pY1u6Qa1E_qmQ8c94,41490
13
- crimson/creatures/spawn.py,sha256=ikgtr4sM2KdA2-eyxYdVmobcuZN6aA7xK7ceaIl7RSw,90059
14
- crimson/debug.py,sha256=vtfr0_HQHpiB5h57jAsl9cWyYxErSbZQ2uazcL1sJhU,127
15
- crimson/demo.py,sha256=5sjQiUGGohm7t0s69-My_S9HwG84T3jDCl682UsffOE,55053
11
+ crimson/creatures/damage.py,sha256=PV3_hQ7b3f3sxKdDVNlf5WtO5iAy_uJmbii3P0zoTYY,5167
12
+ crimson/creatures/runtime.py,sha256=i3GEFP0T74Leb1eb_z30DpxJnrKgRsJlyScDomk6Pu4,42741
13
+ crimson/creatures/spawn.py,sha256=7eRKQWRHYFnWb2HNm0ydRfYYdmbhCCUK3zj8Qq2edmg,90255
14
+ crimson/debug.py,sha256=Hcg0I4oHCtbwDMacnhCnY9gRmueorVctAOpuVgFmwcQ,348
15
+ crimson/demo.py,sha256=l0Vv9osy4NJEm-C9veYthqN4VD87PhHbIhiIVluLjhg,55225
16
16
  crimson/demo_trial.py,sha256=BuoKB1DB-cPZ8jBp4x9gmxWF6tvhXMYRqJ9hMYrhxH4,4651
17
- crimson/effects.py,sha256=56YajT1g3MF1UOly1nsjbT0wkKusjAeyalT3eXFBQIE,35384
17
+ crimson/effects.py,sha256=OyXkz0-MFNdd7EAY8AOw274a4GUUrmvEhrQQXMXO2Uw,35258
18
18
  crimson/effects_atlas.py,sha256=Ko1O7z-1jGkH_KSeb8RrR2EtAs4V8vfo70ofhqbFak4,2104
19
19
  crimson/frontend/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
20
20
  crimson/frontend/assets.py,sha256=JHxOID6Ti6bD2LercdRJ7sSSr0nRX3WWeuRPDQwwbsY,1343
21
21
  crimson/frontend/boot.py,sha256=qZKJba3krNS-SODPAIk7Yl75hCzM0zLlC-Oxuy5ctcM,15334
22
- crimson/frontend/high_scores_layout.py,sha256=1HaeD8GghlOdmwChrJm_KDHJaepfElmn3lVY4Fvyvm4,793
22
+ crimson/frontend/high_scores_layout.py,sha256=jVDYVvH8J4pCfByiHOV3j5c1JIdWY_vO_JLKeDhJTtw,4146
23
23
  crimson/frontend/menu.py,sha256=7s_0Pu9Y09Eh3I3wti8cxqODB--4GXXVh_GrLXtq3SI,26308
24
24
  crimson/frontend/panels/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
25
- crimson/frontend/panels/base.py,sha256=c0A-vNlsnAxy-jz1cZtO-R2EpVEEL90zfKy6KVRpKcA,14862
26
- crimson/frontend/panels/controls.py,sha256=Ve-xQ3tmJCzifIEMdqrVhPQ8mm2vNKX8YEV0lYlhr0E,11236
25
+ crimson/frontend/panels/base.py,sha256=wP_RtKQ59hcOgJ_4X2RiAeVLcjQcZmwkPxOymB-yFis,14931
26
+ crimson/frontend/panels/controls.py,sha256=PJMpPRr_qvB0uwJKvNAU31pIn01T-kctarWEWCBom90,10758
27
27
  crimson/frontend/panels/credits.py,sha256=RlOG953MzqNU171MpjaH1tFZ_A4tunh9UT9Gfgpltmc,8429
28
- crimson/frontend/panels/databases.py,sha256=T5IoAljC-UtJsf_aVc36H9fYa0og2G21qDhJ_783838,11603
29
- crimson/frontend/panels/mods.py,sha256=Hw6JESTZqHB67KtRSixBtv8YyvTT9sMNW32ecxYJ3rU,4061
28
+ crimson/frontend/panels/databases.py,sha256=k8u4IQKsjBZjgR82Pj9VTXqMRnIq8yl_qBcER6V2nXc,21673
29
+ crimson/frontend/panels/mods.py,sha256=VQ8vQoJMo3miksgKjGlPOlv7yKS1wLAVRF9n93ho0iU,3583
30
30
  crimson/frontend/panels/options.py,sha256=v-tEvifvCeb1_tw_sqoQxHrld1rd1gIYQMW1ZA-9Pro,16014
31
- crimson/frontend/panels/play_game.py,sha256=BiO8oDhb6YQZqs3nZEJqUvajMeC6VRQ577doc50xwSY,24149
31
+ crimson/frontend/panels/play_game.py,sha256=xNelGPekQfe-M5kuZmT5nabquA8J5vMqXJ-11Bgit5U,23670
32
32
  crimson/frontend/panels/stats.py,sha256=1-q9TezFVPADkTmPSAg_c_drkrlMOY3jYHjtAm3XGNE,12573
33
33
  crimson/frontend/pause_menu.py,sha256=iM08blMUbgFnV-aGpTHxwieqSQzCnsS66WFMT3lr5vI,16365
34
34
  crimson/frontend/transitions.py,sha256=-sAJUDqNZ943zXlqtvJ6jCg2YH8dSi8k7qK8caAfOKI,883
35
- crimson/game.py,sha256=j8RI1-r67P81wV4_Wy9pKUtqHh8IZTiE-q3yH972z0s,99035
35
+ crimson/game.py,sha256=6C-CErcC8Xr4PDiRFfpo_TDzMSbZbu23FF9QhL9ei-8,126233
36
36
  crimson/game_modes.py,sha256=qW7Tt97lSBmGrt0F17Ni5h8vRyngBzyS9XwWM1TFIEI,255
37
37
  crimson/game_world.py,sha256=nfKGcm3LHChPGLHJsurDFAATrHmhRvTmgxcLzUN9m5I,25440
38
- crimson/gameplay.py,sha256=UHsoxVj6jcdClVLdLM1q1o4NhwSTQqpHSQQ6GBPlT-s,90848
38
+ crimson/gameplay.py,sha256=IPf6y4yivRGw0-rzf0yzIpDsfgNvyn1D1s-mY0sXs0I,100628
39
39
  crimson/input_codes.py,sha256=PmSWFZIit8unTBWk3uwifpHWMuk0qMg1ueKX3MGC7D0,5379
40
40
  crimson/modes/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
41
- crimson/modes/base_gameplay_mode.py,sha256=0hAtdpXLYuhP304qC1GvbQ2rBAALpJTgScDgOs_nRwU,10190
42
- crimson/modes/quest_mode.py,sha256=DUUH5pfACNmFbcT4F0_yhtyuyOZqx-rizKNx_sL3HDE,38322
43
- crimson/modes/rush_mode.py,sha256=l4TAvjOvOA-Z-liMDXp_HGfszfghTmJUyVSkiPkfHQ0,11527
44
- crimson/modes/survival_mode.py,sha256=ZIPjKf2plu_9CDrJp_WLRIGwUCmDo9_imDqa6h7zLD0,33612
45
- crimson/modes/tutorial_mode.py,sha256=rWrVSCjM8G-fHn1_0iVWIzGTeLnCFSNktuoRNSX3cg4,27634
46
- crimson/modes/typo_mode.py,sha256=G3zpg2J7WafXpIYsVV1LeO1gjCCmb40_cbxa_m2kx0U,17957
41
+ crimson/modes/base_gameplay_mode.py,sha256=gpsv9zgYDXaoLojp6d5m0sjJV5-Ig6v1rgnv6ZuBdrg,10975
42
+ crimson/modes/components/__init__.py,sha256=bzqnQPPBuXJQ4piemSWYF8LDGXTPSwQQvyBUzWuq7Bo,43
43
+ crimson/modes/components/highscore_record_builder.py,sha256=cgZQ6LiQEnIPuen_OUrD7RgGvTIcBLAqOfK1Cz6DbbM,1748
44
+ crimson/modes/components/perk_menu_controller.py,sha256=-gd6cC-Uy6JHn3h2RZM0WnBHzyBhx8G-hgccNJL3urU,11581
45
+ crimson/modes/quest_mode.py,sha256=7vYtCDlok7glf0CJID3TpJXSlzNJIssEIEIvzxBEIRI,31133
46
+ crimson/modes/rush_mode.py,sha256=IGtQo3c8FdV0_c7_kCM5gPQ56I439PhTMtVw3b4fKXU,10139
47
+ crimson/modes/survival_mode.py,sha256=JU_naqzq10s0FAQXTesnj-ulgc_BVL1LJNdWXpyxPsM,24661
48
+ crimson/modes/tutorial_mode.py,sha256=StJHXrz_LNU6Q_a-hroVWdZpwvTZCdbiAMg59Lh_Xrg,19373
49
+ crimson/modes/typo_mode.py,sha256=Q0m5bkrm2oUpfE4LWLxGvtJsdD0-hlvSBm9JF5Bhbf8,16961
50
+ crimson/oracle.py,sha256=5Nab_BTDV7qlhO__iuwTrhX8oy5lHUDcsGBzP1mphUk,12953
47
51
  crimson/paths.py,sha256=JCKauCxHJnP4IIy5ocgs6tvbaSMkMUByQ76Zoz2UGZM,653
48
- crimson/perks.py,sha256=JHNhKPOUq2w8h23gU7jpkx-erFKTO4Z8l8aHU8vrkO0,37068
52
+ crimson/perks.py,sha256=40YkPA4V7pkrmocoxEcqyhWsZx-cUK5hBYpUMp_UYN0,37281
49
53
  crimson/persistence/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
50
54
  crimson/persistence/highscores.py,sha256=FyWXTU8faNxYshkbn7Cf3lrxUxiI1VcgGZOq9U9dT8g,13114
51
55
  crimson/persistence/save_status.py,sha256=s-FZONO6JVYRULewtlxoIwATTy3P7rLy-vsVBfSKPk4,7748
52
- crimson/player_damage.py,sha256=cECZO65NJwARoYdtsbvZBM8vQNs_8AVO4xa0omX0pGg,2215
53
- crimson/projectiles.py,sha256=56yocC2XYC69bixrmAgHud4YiSIgezMf2blCQw_YekM,51304
56
+ crimson/player_damage.py,sha256=mKPu78jrS3uzWYnn9znvc43w2eFPEPLx7fzSa6jykYc,3793
57
+ crimson/projectiles.py,sha256=fxvz2DVbOSSYl2G9OXLhhn32o0L9pohQGPgsIO-7Ego,55629
54
58
  crimson/quests/__init__.py,sha256=pKCkH0o1XIGDN9h6yNNaqvWek2CybEZRpejYRooULj8,375
55
59
  crimson/quests/helpers.py,sha256=TeZWhIy2x8Zs9S-vYRBOEZ7pkHNMr5YJ-wi4vYQ2q2M,3625
56
60
  crimson/quests/registry.py,sha256=Cees1QBN0VYTB-XyQtvZ1b4SykB-i4tAnWF6WSV-1pg,1478
@@ -64,75 +68,82 @@ crimson/quests/tier5.py,sha256=sZSz7VBxOpkwO-wQAMOvYgwstkvQ361_vQzux271bWs,23510
64
68
  crimson/quests/timeline.py,sha256=leK898fPt3zq52v-O6dK4c-wJBcY-E6v-y57Fk3kJ3Q,4021
65
69
  crimson/quests/types.py,sha256=iSrz8VSiRZh1pUDSyq37ir7B28c0HF8DjdF6OJ3FoBo,1772
66
70
  crimson/render/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
71
+ crimson/render/projectile_draw_registry.py,sha256=uHSZhqhbfmwxH9Gbc_7KgunY71VhP1_5hdL43X0DwFo,21899
72
+ crimson/render/projectile_render_registry.py,sha256=pB3Ib86sLoQsNvyAAERSdIyXw9dZHQ44oAyXLhwriKs,3635
73
+ crimson/render/secondary_projectile_draw_registry.py,sha256=uJcpdwp-w_9KXDi74sKCVRsRWK5Ef5h6PSF_tc0V3Ns,6924
67
74
  crimson/render/terrain_fx.py,sha256=MpBV6ukGwGqDluIO86BQhHRVWUvcFOi8MV-z_TfLsiw,2705
68
- crimson/render/world_renderer.py,sha256=SXu9VYhjF5PPBTOT15u_hWsGn92BuCZ_1Z9VDBylUgc,88654
75
+ crimson/render/world_renderer.py,sha256=jGPjtH_DyqWm0KC5_U2YfY3l86QW6a2wSaADM7FpLwI,61030
69
76
  crimson/sim/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
70
77
  crimson/sim/world_defs.py,sha256=HiMl--THnII3BTpt6mWAd20Xu-SRzCyHcs5pCR8aMbU,2195
71
- crimson/sim/world_state.py,sha256=_DA0S6sFMk1YEA7N4dvcXgsft9HaGfTIFXR5ir-w5nI,15798
78
+ crimson/sim/world_state.py,sha256=hvCOAm1ajFM128r6xuxGv4ITLX8b0-7G1hIibFHseUk,16821
72
79
  crimson/terrain_assets.py,sha256=X19LN3EZSkiz4uRvQfra3NtAXKAA8SMQ-nvOBlrspwE,670
73
80
  crimson/tutorial/__init__.py,sha256=SDDZKRpkQBqyVMU9U03DN242t8lo8ThLuWHmbVrP69k,333
74
81
  crimson/tutorial/timeline.py,sha256=aJDtASfkCSCL1RH4AZX-7xOZml9E4AORTAX6lI6A578,11307
75
82
  crimson/typo/__init__.py,sha256=PHh4jqD7i0aL8W8hXThczKcT4xsNZiXanBxOH5IOW5I,36
76
83
  crimson/typo/names.py,sha256=SslKyngsp81iHJPEdMJakvaenIkTskZIjLKuEmrt7d0,6320
77
84
  crimson/typo/player.py,sha256=2cnyiOY9WzJadxvvYdnc9BQhmUifFfdRCUjq5LLiby0,1119
78
- crimson/typo/spawns.py,sha256=KWcBD2VkUpJGzDPUcPolT30RBWI4sIFJLEMAptzW9jk,1830
85
+ crimson/typo/spawns.py,sha256=Da2Rflye_ionEsNCUgZi8qES7_uEGN1orBHEHdEKvHY,1705
79
86
  crimson/typo/typing.py,sha256=-h9udu7s-zGKlXxd6Xi7vbaiHj3pNuHqbL_0jqoTR9s,1284
80
87
  crimson/ui/__init__.py,sha256=0-of-3kMbUcm08RgaXNBkTaWHsqYtG0bk1b0ztpLyww,77
81
88
  crimson/ui/cursor.py,sha256=_6EJ7tnsW_Q4kPUrqBO5FInxhpHKUGGyVpDET5EG38I,2842
82
- crimson/ui/demo_trial_overlay.py,sha256=yrxkpNYanQLaYOofFW01nelKE_bqqYFTunmHSpnbEgA,8818
83
- crimson/ui/game_over.py,sha256=pkHDGE47yBraHY-BTnZzOFdRGUJ4ravF0cL1HBdA300,30267
84
- crimson/ui/hud.py,sha256=sVJhh7iAmDISMAcB2AALw1tM0828mlddpAFUXJm8E8c,31123
89
+ crimson/ui/demo_trial_overlay.py,sha256=oqi2-Shc2p8C6ty9FAc855y-R2kR1CjXpZ5XJnfraLQ,8693
90
+ crimson/ui/formatting.py,sha256=PwhQAd7z8-aOIa6DpXyZgZ3N-yHUmr7YxmSaCFHo_7c,552
91
+ crimson/ui/game_over.py,sha256=WuuQ5PHrnyJlBgfOSnh0Qu1tHQEc3At-R2flrv3WJpY,29247
92
+ crimson/ui/hud.py,sha256=WTEmcPGPXv6nW9z5hTIYuPp5UGurk0LgbTjz7Jt2DmI,32098
93
+ crimson/ui/layout.py,sha256=8r7xyNTpT2-BNGF9A5LpPnA6ZxsCdhtahwEVADMPtn4,502
85
94
  crimson/ui/menu_panel.py,sha256=ko1NErvQ5Ystq4f-AL0_eB6FaWoT_n3uonX-X1Ya_6o,4578
86
- crimson/ui/perk_menu.py,sha256=Idz7Ps8JzhBqUZQQH-n1dS_DviX5LDWRrhWFO0Qc9Ac,13787
87
- crimson/ui/quest_results.py,sha256=lbd9uDNyCSNy-KZlNmrCv_S4-JVGioK3DLN65j63PWA,29152
95
+ crimson/ui/perk_menu.py,sha256=swSpQT5Y55hOcjHpiWTABvc0kTfEtlqJcpCk31dav_0,13236
96
+ crimson/ui/quest_results.py,sha256=TSnZjyaSF9rWn1n8NGDyesa-T6fJIwjJD6MY2vQfq1U,28585
88
97
  crimson/ui/shadow.py,sha256=P6B8lZCu8W0YPhLcqi8H413D5oSNeJYwnroYAw4ZGYI,1090
98
+ crimson/ui/text_input.py,sha256=qYhzLsnkFR7S1FrLrMR_IpGWgoY7vZJz-52yFcAM0Qc,465
89
99
  crimson/views/__init__.py,sha256=1UWCzBSsgIeOtcKxqM4Vf12JEfPHKfb9KRZgl2TB84Q,1880
90
- crimson/views/aim_debug.py,sha256=2ldQ1MJO8AeG0i9x4ZJ3YLyp1X-HY_nJ0E1mY8jFF7Q,10873
91
- crimson/views/animations.py,sha256=iI6uTpYS-lbjnpqz_ihETm5q09V6RqjO7YHqaGjovPc,10660
92
- crimson/views/arsenal_debug.py,sha256=zqwBFOCFawPeGDgSVL4OPieRWvDldEeJhExEbSZImI0,15810
100
+ crimson/views/_ui_helpers.py,sha256=9bD8EXbSq4JbiTAy7hH1OEigq5NTrDybnZEv-9fOezA,636
101
+ crimson/views/aim_debug.py,sha256=h6RLYFiJqi1BME22J1O2VZJnXMHZa6EdOekio4bQh1U,10470
102
+ crimson/views/animations.py,sha256=VsBNZbY8mkT6UReGO8B5AWBEtQU6SosWq59wVxLPSgk,10555
103
+ crimson/views/arsenal_debug.py,sha256=oBd9OgllHzl9iKsU0SmwOGHR5UnwUkiS5Mq-2qruNuw,15606
93
104
  crimson/views/audio_bootstrap.py,sha256=a2qM91biyI-LlSiIhEceJ8ptYJy-xQ2-b-YjeyXWx7w,1408
94
- crimson/views/bonuses.py,sha256=dbGx0IBjMMpqrnuVjBUkscxHq6uErCxAkEAb3uDhFqQ,7454
95
- crimson/views/camera_debug.py,sha256=Vi6jANGQpXMK0bpL7hX_QQI_6Rl97ykElaoAuXd06YY,14025
96
- crimson/views/camera_shake.py,sha256=miYxPJcVChv5P2AdbAWTEsrjZR0SAszqClLMbmrgg-0,8148
97
- crimson/views/corpse_stamp_debug.py,sha256=1iLqiCQZpl8kbqfadgxbtVUiRFoGTnZfUwUXt3rVNq0,11716
98
- crimson/views/decals_debug.py,sha256=tE-WUZIJ-skPiDB0kByQfyWS3XP371y4u-s7DT2fl08,27841
105
+ crimson/views/bonuses.py,sha256=kjFz2M9rtSDvCApCgo3bikt21jd_w3H8SUVVSV_3gUY,7508
106
+ crimson/views/camera_debug.py,sha256=qP90Z8-gyYL1LMLM-O0b9btLH0jRIRuHvPtEOntx7Ls,13804
107
+ crimson/views/camera_shake.py,sha256=qW0GPrLVK2r3UP8ZkgnfM0NexYc3z5wSvw2nVXcWbak,7632
108
+ crimson/views/corpse_stamp_debug.py,sha256=OxeGUMP4iXaFE7fCh9AwAwmzoEWjKC8TJg4W5uS0ytQ,11462
109
+ crimson/views/decals_debug.py,sha256=0nQxdgwG9NU6D8cH20UGHbn9SEGgn1c9y1oOyUpZj8o,28045
99
110
  crimson/views/empty.py,sha256=ieyD6jk5KKqVdo90HXDm-ytewlIR087TJPj_7PmnaDI,358
100
- crimson/views/fonts.py,sha256=MkAQz4boPsYa0vUBV5t2ddLVT5pRa-JKiAd0VHYglAo,3890
111
+ crimson/views/fonts.py,sha256=81I3h8hrHp5-gbIWpjUUTwAV4AscZmwshjfCvnqWNGg,3596
101
112
  crimson/views/game_over.py,sha256=R7K7ENM7-ObcsZ5DqPHkrC8fuzAKLOFLZf3j7K5cvDE,4080
102
- crimson/views/ground.py,sha256=_QzsoFSPKA2qIj8OTvJFr2mqT_sM5_w05ucL4a9cCZQ,10226
103
- crimson/views/lighting_debug.py,sha256=T9ce224ZrJtztKTSFUn1G29MY0KYuHVhNdcDU7hlrFc,45502
104
- crimson/views/particles.py,sha256=Yp4OfuYAlDa0zB93OZm5gKBNIEeOGJ7kP5mSZ2wZXvc,10109
105
- crimson/views/perk_menu_debug.py,sha256=aW_1Pvk96FSlxIsMcX8ZUdOGXjY9frqWwdS420_452c,17870
113
+ crimson/views/ground.py,sha256=rpUgs0xhPZQ-bXLgNpElrZEvmPqiive0Y-eY45meYNU,9766
114
+ crimson/views/lighting_debug.py,sha256=gf0EQ5DwK_EInK0Rx-StuOGF_t2AeCxMWfCnHS6JZtA,45280
115
+ crimson/views/particles.py,sha256=Pazfwx6I_TiIOWH-ZIFu_QQ1raVzXFH_91VVO8_5w3M,10273
116
+ crimson/views/perk_menu_debug.py,sha256=yCkraqVadCXxy_pi3Gin0qqJjlK8KSMH1bBhm7T30vQ,17746
106
117
  crimson/views/perks.py,sha256=iravMuB9QzZyrroyciFkTOB5Pnzt4vJz6AjTaOQd3-Y,15091
107
- crimson/views/player.py,sha256=TYcWqNyat5Sl1kU8cYRdCey5R65UaBJpGoct57Oc6qI,16584
108
- crimson/views/player_sprite_debug.py,sha256=DDU6kl9sfhZ2nVXzBbsPSUKdIutHf5YNs2DrNQPRb2Q,11158
109
- crimson/views/projectile_fx.py,sha256=pmMiXm2hJ1XeGf40VtdPk2TbVJX56aATBYTCRekYOdU,23177
110
- crimson/views/projectile_render_debug.py,sha256=gogOiEGT1P_5qD5rMcuxqPac3-WrPJmbJGvg6USvoxE,14347
111
- crimson/views/projectiles.py,sha256=k5zD_9614_-M4qYpnwKUS23fUUrjJS2Wzm7ZalOSKnU,8067
118
+ crimson/views/player.py,sha256=FL82b0hA5JxQmZtN0Io2RxjTZfS1relR0GtUL6Nn1O0,16772
119
+ crimson/views/player_sprite_debug.py,sha256=aE1OLmrfL7n0pdYVf-zKPYo1BEu5rlGU2pnmxT3PIGQ,10996
120
+ crimson/views/projectile_fx.py,sha256=y1dDaipSuuCIafQMxLVyDpmFFzCd-HRzLVyrlda_ZCc,23440
121
+ crimson/views/projectile_render_debug.py,sha256=tbuvxaSmFWpRWhD6gtcBTj6OQzXBQ2GwInEE0vDbSow,13990
122
+ crimson/views/projectiles.py,sha256=_tED5ZIAMFhxUz3xaNzaX9XW6fpiapBGPXAX-Zc4Mw8,8115
112
123
  crimson/views/quest_title_overlay.py,sha256=EbMvXvYqagLLXmhaM7PC0fhxxhHGYGYI2ytgYiWqAd4,3338
113
124
  crimson/views/registry.py,sha256=Kxc_aQMWOAjI6Uq_SRkb0AmYQxyVmM6rxT3UF74irzs,930
114
125
  crimson/views/rush.py,sha256=61XavUpHgwc6Kw9e9Y-OkDt_XfY6iHoDrcpxjMbe1ms,298
115
126
  crimson/views/small_font_debug.py,sha256=c-9qw7QL-nY-ajVOgDNjMGOnGqmVx_j-Iiy5DQhOlz0,7712
116
- crimson/views/spawn_plan.py,sha256=Xo2vw3VwNYqdbNJ6K8d3PJ81sJjLdrXhYEQLTwrxAdM,13378
117
- crimson/views/sprites.py,sha256=_DMjuXaRKvzgGRkv9gieaSubJFJraKNZ01C7iNg1niE,7372
127
+ crimson/views/spawn_plan.py,sha256=0a6-rZSa3bVcNhO3xUtBYXTkKGqqeQebLTaNQPwdg_Q,13155
128
+ crimson/views/sprites.py,sha256=MwUJmaZj-0DCSOV-znPGsJ6n5oCCL85TbODmBxOAQlQ,7040
118
129
  crimson/views/survival.py,sha256=6yuhPe6-bC4IDaAbv74PStiAX9cBbg7HFbSr12ytQAw,333
119
- crimson/views/terrain.py,sha256=ku3R7igsvtfLdeh_uBbY41Tumi9BaNa1C6IAe6vKUOY,4763
120
- crimson/views/ui.py,sha256=2gGyCiI_JnlHzG9CWH8nomQIgCthfLwP7bTsDyqAyx4,4294
121
- crimson/views/wicons.py,sha256=bGbmE25q_pYJZTiPt6Q5Sy1Ub667KvUIFp1a5rVxhi0,5783
130
+ crimson/views/terrain.py,sha256=CW3UWIjuzE3Ozbe8KUmVvIMszaElX4s_3ajajWa8ozE,4379
131
+ crimson/views/ui.py,sha256=O7hu9Q1yPyQWI-kyKNTR7Nu9o3PuKOkVZ2av7Dm09A8,3944
132
+ crimson/views/wicons.py,sha256=02HEyPPwZdw_vnhR1En8cq1WW6be2oslNpuApHHT3mk,5775
122
133
  crimson/weapon_sfx.py,sha256=_JAFpXi-c7jFNz3hxKygAYwqAR6zC94QnNHQYDCHnOY,1717
123
134
  crimson/weapons.py,sha256=dfKiVrLGw6EaUo1K0-twDowA4S7tFoPy_sRTENrWJGI,22084
124
135
  grim/__init__.py,sha256=Cn4f7JY6bscS1gwjDPaWvIvj_vneuUXaiu7wdJB6EVg,262
125
136
  grim/app.py,sha256=WQfJLaCn7-NT1SFQs7Fwm7EgYySiVZkJsf_NPDoiR0o,2798
126
137
  grim/assets.py,sha256=k2rFqNYfcUZfRjFL7r_UBGf1RlcP-urChXCUJ6GzEsI,7661
127
138
  grim/audio.py,sha256=V_TrnfrCb_0e2jeOhN7_kGBu8uMdMsFbk-REoUeWY7Q,3189
128
- grim/config.py,sha256=eQk_3ls_na9AiQr1yqbdyNRc2venM3_NS7Cqz75V08g,9644
129
- grim/console.py,sha256=pqx-Vqq4OAdNrSV2RIl00X-rDf-tw2sASxcXdHYYwFQ,27371
139
+ grim/config.py,sha256=9U4k0q4wl8LIHP464Yq-coh8iDKRrD422ieVk4uh33Y,10669
140
+ grim/console.py,sha256=IRoI_yiBVPEKKoQA_puY6icBn2L_yRrkJ3QWQBtx68s,27293
130
141
  grim/fonts/__init__.py,sha256=yd2yLa0C-LTfjzZHpBl_AglynL3-PmPHePkulMiqLh0,81
131
142
  grim/fonts/grim_mono.py,sha256=DdTAuzGyliJF9ufI5YP039yfYYMWnJp3b6j7u9yvd8Q,3587
132
143
  grim/fonts/small.py,sha256=8Fgqhs-iejqXLyPxo2if2jqfKy9YvM2AZRTBj91M4Rs,4495
133
144
  grim/input.py,sha256=kiJ0AcOIT7slGA8snkfiKeAP7GyGDMF0dvZz2ePcG4I,1156
134
145
  grim/jaz.py,sha256=HcuJR9cj0RLhANlv9fzDuyLh8U6ktYoCiSq8hqg6Sx8,2870
135
- grim/math.py,sha256=xf6K1NKduWNHpKV1KE3Oet_uZW4pF4w0HhaXk7eGMm0,343
146
+ grim/math.py,sha256=pcqNGhjaPt6S1uk3aVufuwPv-c3RyPtcVV1YLnil7z0,638
136
147
  grim/music.py,sha256=UGZ8W3a3Hus78O2N6WRf24_BYn9Eg9mj7RLi6jB5feo,12760
137
148
  grim/paq.py,sha256=KKQRueYP4HiqF9hNEk7dSem-4bn0J4OH2TJDg2CjbnA,1952
138
149
  grim/rand.py,sha256=TTxAe2o92XLloLOdMwLbE0lwdHXd8LPgWsrZCX2-nVU,862
@@ -140,7 +151,7 @@ grim/sfx.py,sha256=cpn2Mmeio7BSDgbStSft-eZchO9Ot2MrK6iXJqxlLqU,7836
140
151
  grim/sfx_map.py,sha256=FM5iBzKkG30Vtu78SRavVNgXMbGK7ZFcQ8i6lgMlzVw,4697
141
152
  grim/terrain_render.py,sha256=EZ7ySYJyTZwXcrJx1mKbY3ewZtPi7Y270XnZgGJyZG8,31509
142
153
  grim/view.py,sha256=oF4pHZehBqOxPjKMU28TDg3qATh_amMIRJp-vMQnpn4,334
143
- crimsonland-0.1.0.dev14.dist-info/WHEEL,sha256=fAguSjoiATBe7TNBkJwOjyL1Tt4wwiaQGtNtjRPNMQA,80
144
- crimsonland-0.1.0.dev14.dist-info/entry_points.txt,sha256=jzzcExxiE9xpt4Iw2nbB1lwTv2Zj4H14WJTIPMkAjoE,77
145
- crimsonland-0.1.0.dev14.dist-info/METADATA,sha256=oXFIziqtI4gQTabCnabSQ9Q9omr3LkcdySpATsnsuqA,5262
146
- crimsonland-0.1.0.dev14.dist-info/RECORD,,
154
+ crimsonland-0.1.0.dev16.dist-info/WHEEL,sha256=5DEXXimM34_d4Gx1AuF9ysMr1_maoEtGKjaILM3s4w4,80
155
+ crimsonland-0.1.0.dev16.dist-info/entry_points.txt,sha256=jzzcExxiE9xpt4Iw2nbB1lwTv2Zj4H14WJTIPMkAjoE,77
156
+ crimsonland-0.1.0.dev16.dist-info/METADATA,sha256=KYLtLB_ux96J1rL0XhYghHdCNwRb9udX5iuGKQ3v66k,5262
157
+ crimsonland-0.1.0.dev16.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: uv 0.9.28
2
+ Generator: uv 0.9.29
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
grim/config.py CHANGED
@@ -7,6 +7,8 @@ from construct import Byte, Bytes, Float32l, Int32ul, Struct
7
7
 
8
8
  CRIMSON_CFG_NAME = "crimson.cfg"
9
9
  CRIMSON_CFG_SIZE = 0x480
10
+ PLAYER_NAME_SIZE = 0x20
11
+ PLAYER_NAME_MAX_BYTES = PLAYER_NAME_SIZE - 1
10
12
 
11
13
  CRIMSON_CFG_STRUCT = Struct(
12
14
  "sound_disable" / Byte,
@@ -35,7 +37,7 @@ CRIMSON_CFG_STRUCT = Struct(
35
37
  "saved_name_index" / Int32ul,
36
38
  "saved_name_order" / Bytes(0x20),
37
39
  "saved_names" / Bytes(0xD8),
38
- "player_name" / Bytes(0x20),
40
+ "player_name" / Bytes(PLAYER_NAME_SIZE),
39
41
  "player_name_len" / Int32ul,
40
42
  "unknown_1a4" / Int32ul,
41
43
  "unknown_1a8" / Int32ul,
@@ -117,6 +119,32 @@ class CrimsonConfig:
117
119
  def windowed_flag(self, value: int) -> None:
118
120
  self.data["windowed_flag"] = int(value) & 0xFF
119
121
 
122
+ @property
123
+ def player_name(self) -> str:
124
+ raw = bytes(self.data["player_name"])
125
+ return raw.split(b"\x00", 1)[0].decode("latin-1", errors="ignore")
126
+
127
+ @player_name.setter
128
+ def player_name(self, value: str) -> None:
129
+ self.set_player_name(value)
130
+
131
+ def set_player_name(self, name: str) -> None:
132
+ # Config stores a 0x20 buffer (latin-1) and a mirrored length integer.
133
+ encoded = name.encode("latin-1", errors="ignore")[:PLAYER_NAME_MAX_BYTES]
134
+ buf = bytearray(PLAYER_NAME_SIZE)
135
+ buf[: len(encoded)] = encoded
136
+ buf[min(len(encoded), PLAYER_NAME_MAX_BYTES)] = 0
137
+
138
+ # Match `highscore_save_record` trimming: strip trailing spaces in-place.
139
+ end = buf.index(0)
140
+ i = end - 1
141
+ while i > 0 and buf[i] == 0x20:
142
+ buf[i] = 0
143
+ i -= 1
144
+
145
+ self.data["player_name"] = bytes(buf)
146
+ self.data["player_name_len"] = int(len(encoded))
147
+
120
148
  def save(self) -> None:
121
149
  self.path.write_bytes(CRIMSON_CFG_STRUCT.build(self.data))
122
150