crimsonland 0.1.0.dev15__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 (75) hide show
  1. crimson/cli.py +61 -0
  2. crimson/creatures/damage.py +111 -36
  3. crimson/creatures/runtime.py +246 -156
  4. crimson/creatures/spawn.py +7 -3
  5. crimson/demo.py +38 -45
  6. crimson/effects.py +7 -13
  7. crimson/frontend/high_scores_layout.py +81 -0
  8. crimson/frontend/panels/base.py +4 -1
  9. crimson/frontend/panels/controls.py +0 -15
  10. crimson/frontend/panels/databases.py +291 -3
  11. crimson/frontend/panels/mods.py +0 -15
  12. crimson/frontend/panels/play_game.py +0 -16
  13. crimson/game.py +441 -1
  14. crimson/gameplay.py +905 -569
  15. crimson/modes/base_gameplay_mode.py +33 -12
  16. crimson/modes/components/__init__.py +2 -0
  17. crimson/modes/components/highscore_record_builder.py +58 -0
  18. crimson/modes/components/perk_menu_controller.py +325 -0
  19. crimson/modes/quest_mode.py +58 -273
  20. crimson/modes/rush_mode.py +12 -43
  21. crimson/modes/survival_mode.py +71 -328
  22. crimson/modes/tutorial_mode.py +46 -247
  23. crimson/modes/typo_mode.py +11 -38
  24. crimson/oracle.py +396 -0
  25. crimson/perks.py +5 -2
  26. crimson/player_damage.py +94 -37
  27. crimson/projectiles.py +539 -320
  28. crimson/render/projectile_draw_registry.py +637 -0
  29. crimson/render/projectile_render_registry.py +110 -0
  30. crimson/render/secondary_projectile_draw_registry.py +206 -0
  31. crimson/render/world_renderer.py +58 -707
  32. crimson/sim/world_state.py +118 -61
  33. crimson/typo/spawns.py +5 -12
  34. crimson/ui/demo_trial_overlay.py +3 -11
  35. crimson/ui/formatting.py +24 -0
  36. crimson/ui/game_over.py +12 -58
  37. crimson/ui/hud.py +72 -39
  38. crimson/ui/layout.py +20 -0
  39. crimson/ui/perk_menu.py +9 -34
  40. crimson/ui/quest_results.py +12 -64
  41. crimson/ui/text_input.py +20 -0
  42. crimson/views/_ui_helpers.py +27 -0
  43. crimson/views/aim_debug.py +15 -32
  44. crimson/views/animations.py +18 -28
  45. crimson/views/arsenal_debug.py +22 -32
  46. crimson/views/bonuses.py +23 -36
  47. crimson/views/camera_debug.py +16 -29
  48. crimson/views/camera_shake.py +9 -33
  49. crimson/views/corpse_stamp_debug.py +13 -21
  50. crimson/views/decals_debug.py +36 -23
  51. crimson/views/fonts.py +8 -25
  52. crimson/views/ground.py +4 -21
  53. crimson/views/lighting_debug.py +42 -45
  54. crimson/views/particles.py +33 -42
  55. crimson/views/perk_menu_debug.py +3 -10
  56. crimson/views/player.py +50 -44
  57. crimson/views/player_sprite_debug.py +24 -31
  58. crimson/views/projectile_fx.py +57 -52
  59. crimson/views/projectile_render_debug.py +24 -33
  60. crimson/views/projectiles.py +24 -37
  61. crimson/views/spawn_plan.py +13 -29
  62. crimson/views/sprites.py +14 -29
  63. crimson/views/terrain.py +6 -23
  64. crimson/views/ui.py +7 -24
  65. crimson/views/wicons.py +28 -33
  66. {crimsonland-0.1.0.dev15.dist-info → crimsonland-0.1.0.dev16.dist-info}/METADATA +1 -1
  67. {crimsonland-0.1.0.dev15.dist-info → crimsonland-0.1.0.dev16.dist-info}/RECORD +72 -64
  68. {crimsonland-0.1.0.dev15.dist-info → crimsonland-0.1.0.dev16.dist-info}/WHEEL +2 -2
  69. grim/config.py +29 -1
  70. grim/console.py +7 -10
  71. grim/math.py +12 -0
  72. crimson/.DS_Store +0 -0
  73. crimson/creatures/.DS_Store +0 -0
  74. grim/.DS_Store +0 -0
  75. {crimsonland-0.1.0.dev15.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.dev15
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
@@ -1,58 +1,60 @@
1
- crimson/.DS_Store,sha256=wzeuDdLmWdcG-N9ol7JzTcv0_ctH28Aaeq1C1fe8ZYw,6148
2
1
  crimson/__init__.py,sha256=dij6OQ6Wctqur9P00ojTTZw6IaUNeZagPX4-2Qqr-Kw,367
3
2
  crimson/assets_fetch.py,sha256=ScrxzSkbs0TkaUtIi-WLC4NN1nIL9J8RloSH_Uz4HGo,2356
4
3
  crimson/atlas.py,sha256=hEcCHhPvguXAI6eH_G9Q8rpiX7M5akZ8fgJjMogmYrA,2401
5
4
  crimson/audio_router.py,sha256=4lccGu5044WQ5sMz9yfZd4loSgEMDqXJWGvMmHyMGt0,5449
6
5
  crimson/bonuses.py,sha256=owwYIRHRu1Kymtt4eEvpd62JwWAg8LOe20vDuPFB5SU,5094
7
6
  crimson/camera.py,sha256=VxTNXTh0qHh5VR1OpkiXr-QcgEWPrWw0A3PFyQFqDkY,2278
8
- crimson/cli.py,sha256=3OvfDrVJyeiL0hjEYRAxfy2u4Yle36xNAm8ZkbvnkLo,14707
9
- crimson/creatures/.DS_Store,sha256=sAyNySnK01L93nKof3NyiBn3DTcel6MPhjblBP1p1Uo,6148
7
+ crimson/cli.py,sha256=V9hE6BZ27yHT0C4w6Q9eCcWiUS44LjydeI0WyoZtNAQ,17076
10
8
  crimson/creatures/__init__.py,sha256=RJwwR_w98zC_kHF9CwkhzSlf0xjpiP0JU87W4awdAAM,233
11
9
  crimson/creatures/ai.py,sha256=oCuUkDe6Kxya1dThUthEy8GIuObAUjDv8WPfe17HYV4,6353
12
10
  crimson/creatures/anim.py,sha256=k_jEpyfwFcJSC9jY2xuhuxtQ8KvE6fSeuRSBLTTAxWo,5016
13
- crimson/creatures/damage.py,sha256=pjKIX32nGDVPnFaWCce0LNZ-UZXZqJpNvwHwq-DCWbE,3211
14
- crimson/creatures/runtime.py,sha256=wfSicwqkSovM_mn_7AMQwxWY_-pY1u6Qa1E_qmQ8c94,41490
15
- crimson/creatures/spawn.py,sha256=ikgtr4sM2KdA2-eyxYdVmobcuZN6aA7xK7ceaIl7RSw,90059
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
16
14
  crimson/debug.py,sha256=Hcg0I4oHCtbwDMacnhCnY9gRmueorVctAOpuVgFmwcQ,348
17
- crimson/demo.py,sha256=5sjQiUGGohm7t0s69-My_S9HwG84T3jDCl682UsffOE,55053
15
+ crimson/demo.py,sha256=l0Vv9osy4NJEm-C9veYthqN4VD87PhHbIhiIVluLjhg,55225
18
16
  crimson/demo_trial.py,sha256=BuoKB1DB-cPZ8jBp4x9gmxWF6tvhXMYRqJ9hMYrhxH4,4651
19
- crimson/effects.py,sha256=56YajT1g3MF1UOly1nsjbT0wkKusjAeyalT3eXFBQIE,35384
17
+ crimson/effects.py,sha256=OyXkz0-MFNdd7EAY8AOw274a4GUUrmvEhrQQXMXO2Uw,35258
20
18
  crimson/effects_atlas.py,sha256=Ko1O7z-1jGkH_KSeb8RrR2EtAs4V8vfo70ofhqbFak4,2104
21
19
  crimson/frontend/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
22
20
  crimson/frontend/assets.py,sha256=JHxOID6Ti6bD2LercdRJ7sSSr0nRX3WWeuRPDQwwbsY,1343
23
21
  crimson/frontend/boot.py,sha256=qZKJba3krNS-SODPAIk7Yl75hCzM0zLlC-Oxuy5ctcM,15334
24
- crimson/frontend/high_scores_layout.py,sha256=1HaeD8GghlOdmwChrJm_KDHJaepfElmn3lVY4Fvyvm4,793
22
+ crimson/frontend/high_scores_layout.py,sha256=jVDYVvH8J4pCfByiHOV3j5c1JIdWY_vO_JLKeDhJTtw,4146
25
23
  crimson/frontend/menu.py,sha256=7s_0Pu9Y09Eh3I3wti8cxqODB--4GXXVh_GrLXtq3SI,26308
26
24
  crimson/frontend/panels/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
27
- crimson/frontend/panels/base.py,sha256=c0A-vNlsnAxy-jz1cZtO-R2EpVEEL90zfKy6KVRpKcA,14862
28
- 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
29
27
  crimson/frontend/panels/credits.py,sha256=RlOG953MzqNU171MpjaH1tFZ_A4tunh9UT9Gfgpltmc,8429
30
- crimson/frontend/panels/databases.py,sha256=T5IoAljC-UtJsf_aVc36H9fYa0og2G21qDhJ_783838,11603
31
- 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
32
30
  crimson/frontend/panels/options.py,sha256=v-tEvifvCeb1_tw_sqoQxHrld1rd1gIYQMW1ZA-9Pro,16014
33
- crimson/frontend/panels/play_game.py,sha256=BiO8oDhb6YQZqs3nZEJqUvajMeC6VRQ577doc50xwSY,24149
31
+ crimson/frontend/panels/play_game.py,sha256=xNelGPekQfe-M5kuZmT5nabquA8J5vMqXJ-11Bgit5U,23670
34
32
  crimson/frontend/panels/stats.py,sha256=1-q9TezFVPADkTmPSAg_c_drkrlMOY3jYHjtAm3XGNE,12573
35
33
  crimson/frontend/pause_menu.py,sha256=iM08blMUbgFnV-aGpTHxwieqSQzCnsS66WFMT3lr5vI,16365
36
34
  crimson/frontend/transitions.py,sha256=-sAJUDqNZ943zXlqtvJ6jCg2YH8dSi8k7qK8caAfOKI,883
37
- crimson/game.py,sha256=juwTTwSBB2xBhFprsGpqOYrVSnIkULsOucNOAPwfpIk,110800
35
+ crimson/game.py,sha256=6C-CErcC8Xr4PDiRFfpo_TDzMSbZbu23FF9QhL9ei-8,126233
38
36
  crimson/game_modes.py,sha256=qW7Tt97lSBmGrt0F17Ni5h8vRyngBzyS9XwWM1TFIEI,255
39
37
  crimson/game_world.py,sha256=nfKGcm3LHChPGLHJsurDFAATrHmhRvTmgxcLzUN9m5I,25440
40
- crimson/gameplay.py,sha256=cghfd7Z3xYDOdI06de6qMPRLlPMVN3wOw2B6wf-cRaE,91602
38
+ crimson/gameplay.py,sha256=IPf6y4yivRGw0-rzf0yzIpDsfgNvyn1D1s-mY0sXs0I,100628
41
39
  crimson/input_codes.py,sha256=PmSWFZIit8unTBWk3uwifpHWMuk0qMg1ueKX3MGC7D0,5379
42
40
  crimson/modes/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
43
- crimson/modes/base_gameplay_mode.py,sha256=0hAtdpXLYuhP304qC1GvbQ2rBAALpJTgScDgOs_nRwU,10190
44
- crimson/modes/quest_mode.py,sha256=90SPy0Q4TR8NHZaWfAK0PiAibuIrWwqYSxgvvqAlzv8,40039
45
- crimson/modes/rush_mode.py,sha256=l4TAvjOvOA-Z-liMDXp_HGfszfghTmJUyVSkiPkfHQ0,11527
46
- crimson/modes/survival_mode.py,sha256=LmCwkLxCoMPraeywNxF7h14eo9k4mr1awGWDyrbJO_k,35120
47
- crimson/modes/tutorial_mode.py,sha256=rWrVSCjM8G-fHn1_0iVWIzGTeLnCFSNktuoRNSX3cg4,27634
48
- 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
49
51
  crimson/paths.py,sha256=JCKauCxHJnP4IIy5ocgs6tvbaSMkMUByQ76Zoz2UGZM,653
50
- crimson/perks.py,sha256=JHNhKPOUq2w8h23gU7jpkx-erFKTO4Z8l8aHU8vrkO0,37068
52
+ crimson/perks.py,sha256=40YkPA4V7pkrmocoxEcqyhWsZx-cUK5hBYpUMp_UYN0,37281
51
53
  crimson/persistence/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
52
54
  crimson/persistence/highscores.py,sha256=FyWXTU8faNxYshkbn7Cf3lrxUxiI1VcgGZOq9U9dT8g,13114
53
55
  crimson/persistence/save_status.py,sha256=s-FZONO6JVYRULewtlxoIwATTy3P7rLy-vsVBfSKPk4,7748
54
- crimson/player_damage.py,sha256=UyGs6SjJBxB6zECr78jUvI7LlGRg0E4kOBESSLBcyaY,2263
55
- crimson/projectiles.py,sha256=56yocC2XYC69bixrmAgHud4YiSIgezMf2blCQw_YekM,51304
56
+ crimson/player_damage.py,sha256=mKPu78jrS3uzWYnn9znvc43w2eFPEPLx7fzSa6jykYc,3793
57
+ crimson/projectiles.py,sha256=fxvz2DVbOSSYl2G9OXLhhn32o0L9pohQGPgsIO-7Ego,55629
56
58
  crimson/quests/__init__.py,sha256=pKCkH0o1XIGDN9h6yNNaqvWek2CybEZRpejYRooULj8,375
57
59
  crimson/quests/helpers.py,sha256=TeZWhIy2x8Zs9S-vYRBOEZ7pkHNMr5YJ-wi4vYQ2q2M,3625
58
60
  crimson/quests/registry.py,sha256=Cees1QBN0VYTB-XyQtvZ1b4SykB-i4tAnWF6WSV-1pg,1478
@@ -66,76 +68,82 @@ crimson/quests/tier5.py,sha256=sZSz7VBxOpkwO-wQAMOvYgwstkvQ361_vQzux271bWs,23510
66
68
  crimson/quests/timeline.py,sha256=leK898fPt3zq52v-O6dK4c-wJBcY-E6v-y57Fk3kJ3Q,4021
67
69
  crimson/quests/types.py,sha256=iSrz8VSiRZh1pUDSyq37ir7B28c0HF8DjdF6OJ3FoBo,1772
68
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
69
74
  crimson/render/terrain_fx.py,sha256=MpBV6ukGwGqDluIO86BQhHRVWUvcFOi8MV-z_TfLsiw,2705
70
- crimson/render/world_renderer.py,sha256=SXu9VYhjF5PPBTOT15u_hWsGn92BuCZ_1Z9VDBylUgc,88654
75
+ crimson/render/world_renderer.py,sha256=jGPjtH_DyqWm0KC5_U2YfY3l86QW6a2wSaADM7FpLwI,61030
71
76
  crimson/sim/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
72
77
  crimson/sim/world_defs.py,sha256=HiMl--THnII3BTpt6mWAd20Xu-SRzCyHcs5pCR8aMbU,2195
73
- crimson/sim/world_state.py,sha256=_DA0S6sFMk1YEA7N4dvcXgsft9HaGfTIFXR5ir-w5nI,15798
78
+ crimson/sim/world_state.py,sha256=hvCOAm1ajFM128r6xuxGv4ITLX8b0-7G1hIibFHseUk,16821
74
79
  crimson/terrain_assets.py,sha256=X19LN3EZSkiz4uRvQfra3NtAXKAA8SMQ-nvOBlrspwE,670
75
80
  crimson/tutorial/__init__.py,sha256=SDDZKRpkQBqyVMU9U03DN242t8lo8ThLuWHmbVrP69k,333
76
81
  crimson/tutorial/timeline.py,sha256=aJDtASfkCSCL1RH4AZX-7xOZml9E4AORTAX6lI6A578,11307
77
82
  crimson/typo/__init__.py,sha256=PHh4jqD7i0aL8W8hXThczKcT4xsNZiXanBxOH5IOW5I,36
78
83
  crimson/typo/names.py,sha256=SslKyngsp81iHJPEdMJakvaenIkTskZIjLKuEmrt7d0,6320
79
84
  crimson/typo/player.py,sha256=2cnyiOY9WzJadxvvYdnc9BQhmUifFfdRCUjq5LLiby0,1119
80
- crimson/typo/spawns.py,sha256=KWcBD2VkUpJGzDPUcPolT30RBWI4sIFJLEMAptzW9jk,1830
85
+ crimson/typo/spawns.py,sha256=Da2Rflye_ionEsNCUgZi8qES7_uEGN1orBHEHdEKvHY,1705
81
86
  crimson/typo/typing.py,sha256=-h9udu7s-zGKlXxd6Xi7vbaiHj3pNuHqbL_0jqoTR9s,1284
82
87
  crimson/ui/__init__.py,sha256=0-of-3kMbUcm08RgaXNBkTaWHsqYtG0bk1b0ztpLyww,77
83
88
  crimson/ui/cursor.py,sha256=_6EJ7tnsW_Q4kPUrqBO5FInxhpHKUGGyVpDET5EG38I,2842
84
- crimson/ui/demo_trial_overlay.py,sha256=yrxkpNYanQLaYOofFW01nelKE_bqqYFTunmHSpnbEgA,8818
85
- crimson/ui/game_over.py,sha256=pkHDGE47yBraHY-BTnZzOFdRGUJ4ravF0cL1HBdA300,30267
86
- 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
87
94
  crimson/ui/menu_panel.py,sha256=ko1NErvQ5Ystq4f-AL0_eB6FaWoT_n3uonX-X1Ya_6o,4578
88
- crimson/ui/perk_menu.py,sha256=Idz7Ps8JzhBqUZQQH-n1dS_DviX5LDWRrhWFO0Qc9Ac,13787
89
- crimson/ui/quest_results.py,sha256=PLq5XD6hAdQf3qpHWZe2OhiIv7TdC38qr8alPasq4LM,29721
95
+ crimson/ui/perk_menu.py,sha256=swSpQT5Y55hOcjHpiWTABvc0kTfEtlqJcpCk31dav_0,13236
96
+ crimson/ui/quest_results.py,sha256=TSnZjyaSF9rWn1n8NGDyesa-T6fJIwjJD6MY2vQfq1U,28585
90
97
  crimson/ui/shadow.py,sha256=P6B8lZCu8W0YPhLcqi8H413D5oSNeJYwnroYAw4ZGYI,1090
98
+ crimson/ui/text_input.py,sha256=qYhzLsnkFR7S1FrLrMR_IpGWgoY7vZJz-52yFcAM0Qc,465
91
99
  crimson/views/__init__.py,sha256=1UWCzBSsgIeOtcKxqM4Vf12JEfPHKfb9KRZgl2TB84Q,1880
92
- crimson/views/aim_debug.py,sha256=2ldQ1MJO8AeG0i9x4ZJ3YLyp1X-HY_nJ0E1mY8jFF7Q,10873
93
- crimson/views/animations.py,sha256=iI6uTpYS-lbjnpqz_ihETm5q09V6RqjO7YHqaGjovPc,10660
94
- 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
95
104
  crimson/views/audio_bootstrap.py,sha256=a2qM91biyI-LlSiIhEceJ8ptYJy-xQ2-b-YjeyXWx7w,1408
96
- crimson/views/bonuses.py,sha256=dbGx0IBjMMpqrnuVjBUkscxHq6uErCxAkEAb3uDhFqQ,7454
97
- crimson/views/camera_debug.py,sha256=Vi6jANGQpXMK0bpL7hX_QQI_6Rl97ykElaoAuXd06YY,14025
98
- crimson/views/camera_shake.py,sha256=miYxPJcVChv5P2AdbAWTEsrjZR0SAszqClLMbmrgg-0,8148
99
- crimson/views/corpse_stamp_debug.py,sha256=1iLqiCQZpl8kbqfadgxbtVUiRFoGTnZfUwUXt3rVNq0,11716
100
- 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
101
110
  crimson/views/empty.py,sha256=ieyD6jk5KKqVdo90HXDm-ytewlIR087TJPj_7PmnaDI,358
102
- crimson/views/fonts.py,sha256=MkAQz4boPsYa0vUBV5t2ddLVT5pRa-JKiAd0VHYglAo,3890
111
+ crimson/views/fonts.py,sha256=81I3h8hrHp5-gbIWpjUUTwAV4AscZmwshjfCvnqWNGg,3596
103
112
  crimson/views/game_over.py,sha256=R7K7ENM7-ObcsZ5DqPHkrC8fuzAKLOFLZf3j7K5cvDE,4080
104
- crimson/views/ground.py,sha256=_QzsoFSPKA2qIj8OTvJFr2mqT_sM5_w05ucL4a9cCZQ,10226
105
- crimson/views/lighting_debug.py,sha256=T9ce224ZrJtztKTSFUn1G29MY0KYuHVhNdcDU7hlrFc,45502
106
- crimson/views/particles.py,sha256=Yp4OfuYAlDa0zB93OZm5gKBNIEeOGJ7kP5mSZ2wZXvc,10109
107
- 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
108
117
  crimson/views/perks.py,sha256=iravMuB9QzZyrroyciFkTOB5Pnzt4vJz6AjTaOQd3-Y,15091
109
- crimson/views/player.py,sha256=TYcWqNyat5Sl1kU8cYRdCey5R65UaBJpGoct57Oc6qI,16584
110
- crimson/views/player_sprite_debug.py,sha256=DDU6kl9sfhZ2nVXzBbsPSUKdIutHf5YNs2DrNQPRb2Q,11158
111
- crimson/views/projectile_fx.py,sha256=pmMiXm2hJ1XeGf40VtdPk2TbVJX56aATBYTCRekYOdU,23177
112
- crimson/views/projectile_render_debug.py,sha256=gogOiEGT1P_5qD5rMcuxqPac3-WrPJmbJGvg6USvoxE,14347
113
- 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
114
123
  crimson/views/quest_title_overlay.py,sha256=EbMvXvYqagLLXmhaM7PC0fhxxhHGYGYI2ytgYiWqAd4,3338
115
124
  crimson/views/registry.py,sha256=Kxc_aQMWOAjI6Uq_SRkb0AmYQxyVmM6rxT3UF74irzs,930
116
125
  crimson/views/rush.py,sha256=61XavUpHgwc6Kw9e9Y-OkDt_XfY6iHoDrcpxjMbe1ms,298
117
126
  crimson/views/small_font_debug.py,sha256=c-9qw7QL-nY-ajVOgDNjMGOnGqmVx_j-Iiy5DQhOlz0,7712
118
- crimson/views/spawn_plan.py,sha256=Xo2vw3VwNYqdbNJ6K8d3PJ81sJjLdrXhYEQLTwrxAdM,13378
119
- 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
120
129
  crimson/views/survival.py,sha256=6yuhPe6-bC4IDaAbv74PStiAX9cBbg7HFbSr12ytQAw,333
121
- crimson/views/terrain.py,sha256=ku3R7igsvtfLdeh_uBbY41Tumi9BaNa1C6IAe6vKUOY,4763
122
- crimson/views/ui.py,sha256=2gGyCiI_JnlHzG9CWH8nomQIgCthfLwP7bTsDyqAyx4,4294
123
- 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
124
133
  crimson/weapon_sfx.py,sha256=_JAFpXi-c7jFNz3hxKygAYwqAR6zC94QnNHQYDCHnOY,1717
125
134
  crimson/weapons.py,sha256=dfKiVrLGw6EaUo1K0-twDowA4S7tFoPy_sRTENrWJGI,22084
126
- grim/.DS_Store,sha256=QLue9_bBPqaUhApqMqZyfVv_whyhZNPO1nSyW8sjcpo,6148
127
135
  grim/__init__.py,sha256=Cn4f7JY6bscS1gwjDPaWvIvj_vneuUXaiu7wdJB6EVg,262
128
136
  grim/app.py,sha256=WQfJLaCn7-NT1SFQs7Fwm7EgYySiVZkJsf_NPDoiR0o,2798
129
137
  grim/assets.py,sha256=k2rFqNYfcUZfRjFL7r_UBGf1RlcP-urChXCUJ6GzEsI,7661
130
138
  grim/audio.py,sha256=V_TrnfrCb_0e2jeOhN7_kGBu8uMdMsFbk-REoUeWY7Q,3189
131
- grim/config.py,sha256=eQk_3ls_na9AiQr1yqbdyNRc2venM3_NS7Cqz75V08g,9644
132
- 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
133
141
  grim/fonts/__init__.py,sha256=yd2yLa0C-LTfjzZHpBl_AglynL3-PmPHePkulMiqLh0,81
134
142
  grim/fonts/grim_mono.py,sha256=DdTAuzGyliJF9ufI5YP039yfYYMWnJp3b6j7u9yvd8Q,3587
135
143
  grim/fonts/small.py,sha256=8Fgqhs-iejqXLyPxo2if2jqfKy9YvM2AZRTBj91M4Rs,4495
136
144
  grim/input.py,sha256=kiJ0AcOIT7slGA8snkfiKeAP7GyGDMF0dvZz2ePcG4I,1156
137
145
  grim/jaz.py,sha256=HcuJR9cj0RLhANlv9fzDuyLh8U6ktYoCiSq8hqg6Sx8,2870
138
- grim/math.py,sha256=xf6K1NKduWNHpKV1KE3Oet_uZW4pF4w0HhaXk7eGMm0,343
146
+ grim/math.py,sha256=pcqNGhjaPt6S1uk3aVufuwPv-c3RyPtcVV1YLnil7z0,638
139
147
  grim/music.py,sha256=UGZ8W3a3Hus78O2N6WRf24_BYn9Eg9mj7RLi6jB5feo,12760
140
148
  grim/paq.py,sha256=KKQRueYP4HiqF9hNEk7dSem-4bn0J4OH2TJDg2CjbnA,1952
141
149
  grim/rand.py,sha256=TTxAe2o92XLloLOdMwLbE0lwdHXd8LPgWsrZCX2-nVU,862
@@ -143,7 +151,7 @@ grim/sfx.py,sha256=cpn2Mmeio7BSDgbStSft-eZchO9Ot2MrK6iXJqxlLqU,7836
143
151
  grim/sfx_map.py,sha256=FM5iBzKkG30Vtu78SRavVNgXMbGK7ZFcQ8i6lgMlzVw,4697
144
152
  grim/terrain_render.py,sha256=EZ7ySYJyTZwXcrJx1mKbY3ewZtPi7Y270XnZgGJyZG8,31509
145
153
  grim/view.py,sha256=oF4pHZehBqOxPjKMU28TDg3qATh_amMIRJp-vMQnpn4,334
146
- crimsonland-0.1.0.dev15.dist-info/WHEEL,sha256=ZyFSCYkV2BrxH6-HRVRg3R9Fo7MALzer9KiPYqNxSbo,79
147
- crimsonland-0.1.0.dev15.dist-info/entry_points.txt,sha256=jzzcExxiE9xpt4Iw2nbB1lwTv2Zj4H14WJTIPMkAjoE,77
148
- crimsonland-0.1.0.dev15.dist-info/METADATA,sha256=iyGs5qMssJ8szJDMfYv0jRbZnycT3rFPOTs_lI9B7nU,5262
149
- crimsonland-0.1.0.dev15.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.18
2
+ Generator: uv 0.9.29
3
3
  Root-Is-Purelib: true
4
- Tag: py3-none-any
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