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.
- crimson/cli.py +63 -0
- crimson/creatures/damage.py +111 -36
- crimson/creatures/runtime.py +246 -156
- crimson/creatures/spawn.py +7 -3
- crimson/debug.py +9 -0
- crimson/demo.py +38 -45
- crimson/effects.py +7 -13
- crimson/frontend/high_scores_layout.py +81 -0
- crimson/frontend/panels/base.py +4 -1
- crimson/frontend/panels/controls.py +0 -15
- crimson/frontend/panels/databases.py +291 -3
- crimson/frontend/panels/mods.py +0 -15
- crimson/frontend/panels/play_game.py +0 -16
- crimson/game.py +689 -3
- crimson/gameplay.py +921 -569
- crimson/modes/base_gameplay_mode.py +33 -12
- crimson/modes/components/__init__.py +2 -0
- crimson/modes/components/highscore_record_builder.py +58 -0
- crimson/modes/components/perk_menu_controller.py +325 -0
- crimson/modes/quest_mode.py +94 -272
- crimson/modes/rush_mode.py +12 -43
- crimson/modes/survival_mode.py +109 -330
- crimson/modes/tutorial_mode.py +46 -247
- crimson/modes/typo_mode.py +11 -38
- crimson/oracle.py +396 -0
- crimson/perks.py +5 -2
- crimson/player_damage.py +95 -36
- crimson/projectiles.py +539 -320
- crimson/render/projectile_draw_registry.py +637 -0
- crimson/render/projectile_render_registry.py +110 -0
- crimson/render/secondary_projectile_draw_registry.py +206 -0
- crimson/render/world_renderer.py +58 -707
- crimson/sim/world_state.py +118 -61
- crimson/typo/spawns.py +5 -12
- crimson/ui/demo_trial_overlay.py +3 -11
- crimson/ui/formatting.py +24 -0
- crimson/ui/game_over.py +12 -58
- crimson/ui/hud.py +72 -39
- crimson/ui/layout.py +20 -0
- crimson/ui/perk_menu.py +9 -34
- crimson/ui/quest_results.py +28 -70
- crimson/ui/text_input.py +20 -0
- crimson/views/_ui_helpers.py +27 -0
- crimson/views/aim_debug.py +15 -32
- crimson/views/animations.py +18 -28
- crimson/views/arsenal_debug.py +22 -32
- crimson/views/bonuses.py +23 -36
- crimson/views/camera_debug.py +16 -29
- crimson/views/camera_shake.py +9 -33
- crimson/views/corpse_stamp_debug.py +13 -21
- crimson/views/decals_debug.py +36 -23
- crimson/views/fonts.py +8 -25
- crimson/views/ground.py +4 -21
- crimson/views/lighting_debug.py +42 -45
- crimson/views/particles.py +33 -42
- crimson/views/perk_menu_debug.py +3 -10
- crimson/views/player.py +50 -44
- crimson/views/player_sprite_debug.py +24 -31
- crimson/views/projectile_fx.py +57 -52
- crimson/views/projectile_render_debug.py +24 -33
- crimson/views/projectiles.py +24 -37
- crimson/views/spawn_plan.py +13 -29
- crimson/views/sprites.py +14 -29
- crimson/views/terrain.py +6 -23
- crimson/views/ui.py +7 -24
- crimson/views/wicons.py +28 -33
- {crimsonland-0.1.0.dev14.dist-info → crimsonland-0.1.0.dev16.dist-info}/METADATA +1 -1
- {crimsonland-0.1.0.dev14.dist-info → crimsonland-0.1.0.dev16.dist-info}/RECORD +73 -62
- {crimsonland-0.1.0.dev14.dist-info → crimsonland-0.1.0.dev16.dist-info}/WHEEL +1 -1
- grim/config.py +29 -1
- grim/console.py +7 -10
- grim/math.py +12 -0
- {crimsonland-0.1.0.dev14.dist-info → crimsonland-0.1.0.dev16.dist-info}/entry_points.txt +0 -0
crimson/views/lighting_debug.py
CHANGED
|
@@ -10,13 +10,15 @@ from dataclasses import dataclass
|
|
|
10
10
|
import pyray as rl
|
|
11
11
|
|
|
12
12
|
from grim.config import ensure_crimson_cfg
|
|
13
|
-
from grim.fonts.small import SmallFontData,
|
|
13
|
+
from grim.fonts.small import SmallFontData, load_small_font
|
|
14
|
+
from grim.math import clamp
|
|
14
15
|
from grim.view import ViewContext
|
|
15
16
|
|
|
16
17
|
from ..creatures.spawn import CreatureInit, CreatureTypeId
|
|
17
18
|
from ..game_world import GameWorld
|
|
18
19
|
from ..gameplay import PlayerInput
|
|
19
20
|
from ..paths import default_runtime_dir
|
|
21
|
+
from ._ui_helpers import draw_ui_text, ui_line_height
|
|
20
22
|
from .registry import register_view
|
|
21
23
|
|
|
22
24
|
WORLD_SIZE = 1024.0
|
|
@@ -200,14 +202,6 @@ void main()
|
|
|
200
202
|
"""
|
|
201
203
|
|
|
202
204
|
|
|
203
|
-
def _clamp(value: float, lo: float, hi: float) -> float:
|
|
204
|
-
if value < lo:
|
|
205
|
-
return lo
|
|
206
|
-
if value > hi:
|
|
207
|
-
return hi
|
|
208
|
-
return value
|
|
209
|
-
|
|
210
|
-
|
|
211
205
|
@dataclass
|
|
212
206
|
class _EmissiveProjectile:
|
|
213
207
|
x: float
|
|
@@ -308,9 +302,9 @@ class LightingDebugView:
|
|
|
308
302
|
base = self._ambient_base
|
|
309
303
|
m = max(0.0, float(self._ambient_mul))
|
|
310
304
|
self._ambient = rl.Color(
|
|
311
|
-
int(
|
|
312
|
-
int(
|
|
313
|
-
int(
|
|
305
|
+
int(clamp(float(base.r) * m, 0.0, 255.0)),
|
|
306
|
+
int(clamp(float(base.g) * m, 0.0, 255.0)),
|
|
307
|
+
int(clamp(float(base.b) * m, 0.0, 255.0)),
|
|
314
308
|
255,
|
|
315
309
|
)
|
|
316
310
|
|
|
@@ -336,8 +330,8 @@ class LightingDebugView:
|
|
|
336
330
|
c = palette[i % len(palette)]
|
|
337
331
|
if rng.random() < 0.5:
|
|
338
332
|
c = palette[int(rng.random() * len(palette)) % len(palette)]
|
|
339
|
-
x =
|
|
340
|
-
y =
|
|
333
|
+
x = clamp(px + math.cos(angle) * radius, 0.0, WORLD_SIZE)
|
|
334
|
+
y = clamp(py + math.sin(angle) * radius, 0.0, WORLD_SIZE)
|
|
341
335
|
r = float(self._fly_light_range) * (0.8 + rng.random() * 0.5)
|
|
342
336
|
sr = float(self._fly_light_source_radius) * (0.7 + rng.random() * 0.7)
|
|
343
337
|
self._fly_lights.append(
|
|
@@ -353,25 +347,14 @@ class LightingDebugView:
|
|
|
353
347
|
)
|
|
354
348
|
)
|
|
355
349
|
|
|
356
|
-
def _ui_line_height(self, scale: float = UI_TEXT_SCALE) -> int:
|
|
357
|
-
if self._small is not None:
|
|
358
|
-
return int(self._small.cell_size * scale)
|
|
359
|
-
return int(20 * scale)
|
|
360
|
-
|
|
361
|
-
def _draw_ui_text(self, text: str, x: float, y: float, color: rl.Color, scale: float = UI_TEXT_SCALE) -> None:
|
|
362
|
-
if self._small is not None:
|
|
363
|
-
draw_small_text(self._small, text, x, y, scale, color)
|
|
364
|
-
else:
|
|
365
|
-
rl.draw_text(text, int(x), int(y), int(20 * scale), color)
|
|
366
|
-
|
|
367
350
|
def _update_ui_mouse(self) -> None:
|
|
368
351
|
if self._debug_auto_dump:
|
|
369
352
|
return
|
|
370
353
|
mouse = rl.get_mouse_position()
|
|
371
354
|
screen_w = float(rl.get_screen_width())
|
|
372
355
|
screen_h = float(rl.get_screen_height())
|
|
373
|
-
self._ui_mouse_x =
|
|
374
|
-
self._ui_mouse_y =
|
|
356
|
+
self._ui_mouse_x = clamp(float(mouse.x), 0.0, max(0.0, screen_w - 1.0))
|
|
357
|
+
self._ui_mouse_y = clamp(float(mouse.y), 0.0, max(0.0, screen_h - 1.0))
|
|
375
358
|
|
|
376
359
|
def _handle_debug_input(self) -> None:
|
|
377
360
|
if rl.is_key_pressed(rl.KeyboardKey.KEY_ESCAPE):
|
|
@@ -401,18 +384,18 @@ class LightingDebugView:
|
|
|
401
384
|
occ_mul_step = 0.05 if not shift else 0.10
|
|
402
385
|
occ_pad_step = 1.0 if not shift else 4.0
|
|
403
386
|
if rl.is_key_pressed(rl.KeyboardKey.KEY_O):
|
|
404
|
-
self._occluder_radius_mul =
|
|
387
|
+
self._occluder_radius_mul = clamp(self._occluder_radius_mul - occ_mul_step, 0.25, 2.50)
|
|
405
388
|
if rl.is_key_pressed(rl.KeyboardKey.KEY_P):
|
|
406
|
-
self._occluder_radius_mul =
|
|
389
|
+
self._occluder_radius_mul = clamp(self._occluder_radius_mul + occ_mul_step, 0.25, 2.50)
|
|
407
390
|
if rl.is_key_pressed(rl.KeyboardKey.KEY_K):
|
|
408
|
-
self._occluder_radius_pad_px =
|
|
391
|
+
self._occluder_radius_pad_px = clamp(self._occluder_radius_pad_px - occ_pad_step, -20.0, 60.0)
|
|
409
392
|
if rl.is_key_pressed(rl.KeyboardKey.KEY_L):
|
|
410
|
-
self._occluder_radius_pad_px =
|
|
393
|
+
self._occluder_radius_pad_px = clamp(self._occluder_radius_pad_px + occ_pad_step, -20.0, 60.0)
|
|
411
394
|
|
|
412
395
|
if rl.is_key_pressed(rl.KeyboardKey.KEY_MINUS) or rl.is_key_pressed(rl.KeyboardKey.KEY_KP_SUBTRACT):
|
|
413
|
-
self._sdf_shadow_floor =
|
|
396
|
+
self._sdf_shadow_floor = clamp(self._sdf_shadow_floor - 0.05, 0.0, 0.9)
|
|
414
397
|
if rl.is_key_pressed(rl.KeyboardKey.KEY_EQUAL) or rl.is_key_pressed(rl.KeyboardKey.KEY_KP_ADD):
|
|
415
|
-
self._sdf_shadow_floor =
|
|
398
|
+
self._sdf_shadow_floor = clamp(self._sdf_shadow_floor + 0.05, 0.0, 0.9)
|
|
416
399
|
|
|
417
400
|
if rl.is_key_pressed(rl.KeyboardKey.KEY_LEFT_BRACKET):
|
|
418
401
|
if shift:
|
|
@@ -435,10 +418,10 @@ class LightingDebugView:
|
|
|
435
418
|
|
|
436
419
|
amb_step = 0.10 if not shift else 0.25
|
|
437
420
|
if rl.is_key_pressed(rl.KeyboardKey.KEY_N):
|
|
438
|
-
self._ambient_mul =
|
|
421
|
+
self._ambient_mul = clamp(self._ambient_mul - amb_step, 0.0, 8.0)
|
|
439
422
|
self._update_ambient()
|
|
440
423
|
if rl.is_key_pressed(rl.KeyboardKey.KEY_M):
|
|
441
|
-
self._ambient_mul =
|
|
424
|
+
self._ambient_mul = clamp(self._ambient_mul + amb_step, 0.0, 8.0)
|
|
442
425
|
self._update_ambient()
|
|
443
426
|
|
|
444
427
|
def _ensure_sdf_shader(self) -> rl.Shader | None:
|
|
@@ -534,8 +517,8 @@ class LightingDebugView:
|
|
|
534
517
|
radius = 120.0 + rng.random() * 260.0
|
|
535
518
|
x = center_x + math.cos(angle) * radius
|
|
536
519
|
y = center_y + math.sin(angle) * radius
|
|
537
|
-
x =
|
|
538
|
-
y =
|
|
520
|
+
x = clamp(x, 40.0, WORLD_SIZE - 40.0)
|
|
521
|
+
y = clamp(y, 40.0, WORLD_SIZE - 40.0)
|
|
539
522
|
init = CreatureInit(
|
|
540
523
|
origin_template_id=0,
|
|
541
524
|
pos_x=float(x),
|
|
@@ -656,8 +639,8 @@ class LightingDebugView:
|
|
|
656
639
|
fl.angle += fl.omega * dt_world
|
|
657
640
|
wobble = 1.0 + 0.10 * math.sin(fl.angle * 0.7)
|
|
658
641
|
r = fl.radius * wobble
|
|
659
|
-
fl.x =
|
|
660
|
-
fl.y =
|
|
642
|
+
fl.x = clamp(px + math.cos(fl.angle) * r, 0.0, WORLD_SIZE)
|
|
643
|
+
fl.y = clamp(py + math.sin(fl.angle) * r, 0.0, WORLD_SIZE)
|
|
661
644
|
|
|
662
645
|
keep: list[_EmissiveProjectile] = []
|
|
663
646
|
margin = 80.0
|
|
@@ -941,7 +924,7 @@ class LightingDebugView:
|
|
|
941
924
|
|
|
942
925
|
def proj_light(proj: _EmissiveProjectile) -> tuple[float, float, float, float, float, float, float]:
|
|
943
926
|
sx, sy = self._world.world_to_screen(float(proj.x), float(proj.y))
|
|
944
|
-
fade =
|
|
927
|
+
fade = clamp(1.0 - float(proj.age) / max(0.001, float(proj.ttl)), 0.0, 1.0)
|
|
945
928
|
pr = self._proj_light_tint
|
|
946
929
|
return (
|
|
947
930
|
float(sx),
|
|
@@ -1026,13 +1009,20 @@ class LightingDebugView:
|
|
|
1026
1009
|
def draw(self) -> None:
|
|
1027
1010
|
if self._player is None:
|
|
1028
1011
|
rl.clear_background(rl.Color(10, 10, 12, 255))
|
|
1029
|
-
self.
|
|
1012
|
+
draw_ui_text(self._small, "Lighting debug view: missing player", 16.0, 16.0, scale=UI_TEXT_SCALE, color=UI_ERROR_COLOR)
|
|
1030
1013
|
return
|
|
1031
1014
|
|
|
1032
1015
|
self._ensure_render_targets()
|
|
1033
1016
|
if self._light_rt is None:
|
|
1034
1017
|
rl.clear_background(rl.Color(10, 10, 12, 255))
|
|
1035
|
-
|
|
1018
|
+
draw_ui_text(
|
|
1019
|
+
self._small,
|
|
1020
|
+
"Lighting debug view: missing render targets",
|
|
1021
|
+
16.0,
|
|
1022
|
+
16.0,
|
|
1023
|
+
scale=UI_TEXT_SCALE,
|
|
1024
|
+
color=UI_ERROR_COLOR,
|
|
1025
|
+
)
|
|
1036
1026
|
return
|
|
1037
1027
|
|
|
1038
1028
|
light_x = float(self._ui_mouse_x)
|
|
@@ -1057,7 +1047,7 @@ class LightingDebugView:
|
|
|
1057
1047
|
rl.begin_blend_mode(rl.BLEND_ADDITIVE)
|
|
1058
1048
|
for proj in self._projectiles:
|
|
1059
1049
|
sx, sy = self._world.world_to_screen(float(proj.x), float(proj.y))
|
|
1060
|
-
fade =
|
|
1050
|
+
fade = clamp(1.0 - float(proj.age) / max(0.001, float(proj.ttl)), 0.0, 1.0)
|
|
1061
1051
|
c = self._proj_light_tint
|
|
1062
1052
|
rl.draw_circle(
|
|
1063
1053
|
int(sx),
|
|
@@ -1156,9 +1146,16 @@ class LightingDebugView:
|
|
|
1156
1146
|
lines.append("SDF uniforms missing: " + ", ".join(self._sdf_shader_missing))
|
|
1157
1147
|
x0 = 16.0
|
|
1158
1148
|
y0 = 16.0
|
|
1159
|
-
lh = float(self.
|
|
1149
|
+
lh = float(ui_line_height(self._small, scale=UI_TEXT_SCALE))
|
|
1160
1150
|
for idx, line in enumerate(lines):
|
|
1161
|
-
|
|
1151
|
+
draw_ui_text(
|
|
1152
|
+
self._small,
|
|
1153
|
+
line,
|
|
1154
|
+
x0,
|
|
1155
|
+
y0 + lh * float(idx),
|
|
1156
|
+
scale=UI_TEXT_SCALE,
|
|
1157
|
+
color=UI_TEXT_COLOR if idx < 5 else UI_HINT_COLOR,
|
|
1158
|
+
)
|
|
1162
1159
|
|
|
1163
1160
|
|
|
1164
1161
|
@register_view("lighting-debug", "Lighting (SDF)")
|
crimson/views/particles.py
CHANGED
|
@@ -4,9 +4,10 @@ from dataclasses import dataclass
|
|
|
4
4
|
|
|
5
5
|
import pyray as rl
|
|
6
6
|
|
|
7
|
-
from .registry import register_view
|
|
8
7
|
from ..effects_atlas import EFFECT_ID_ATLAS_TABLE, SIZE_CODE_GRID
|
|
9
|
-
from
|
|
8
|
+
from ._ui_helpers import draw_ui_text, ui_line_height
|
|
9
|
+
from .registry import register_view
|
|
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
|
|
@@ -77,24 +78,6 @@ class ParticleView:
|
|
|
77
78
|
self._grid = 8
|
|
78
79
|
self._show_uv_clamp = False
|
|
79
80
|
|
|
80
|
-
def _ui_line_height(self, scale: float = UI_TEXT_SCALE) -> int:
|
|
81
|
-
if self._small is not None:
|
|
82
|
-
return int(self._small.cell_size * scale)
|
|
83
|
-
return int(20 * scale)
|
|
84
|
-
|
|
85
|
-
def _draw_ui_text(
|
|
86
|
-
self,
|
|
87
|
-
text: str,
|
|
88
|
-
x: float,
|
|
89
|
-
y: float,
|
|
90
|
-
color: rl.Color,
|
|
91
|
-
scale: float = UI_TEXT_SCALE,
|
|
92
|
-
) -> None:
|
|
93
|
-
if self._small is not None:
|
|
94
|
-
draw_small_text(self._small, text, x, y, scale, color)
|
|
95
|
-
else:
|
|
96
|
-
rl.draw_text(text, int(x), int(y), int(20 * scale), color)
|
|
97
|
-
|
|
98
81
|
def open(self) -> None:
|
|
99
82
|
self._missing_assets.clear()
|
|
100
83
|
self._small = load_small_font(self._assets_root, self._missing_assets)
|
|
@@ -139,10 +122,10 @@ class ParticleView:
|
|
|
139
122
|
rl.clear_background(rl.Color(12, 12, 14, 255))
|
|
140
123
|
if self._missing_assets:
|
|
141
124
|
message = "Missing assets: " + ", ".join(self._missing_assets)
|
|
142
|
-
self.
|
|
125
|
+
draw_ui_text(self._small, message, 24, 24, scale=UI_TEXT_SCALE, color=UI_ERROR_COLOR)
|
|
143
126
|
return
|
|
144
127
|
if self._texture is None:
|
|
145
|
-
self.
|
|
128
|
+
draw_ui_text(self._small, "No particles texture loaded.", 24, 24, scale=UI_TEXT_SCALE, color=UI_TEXT_COLOR)
|
|
146
129
|
return
|
|
147
130
|
|
|
148
131
|
self._handle_input()
|
|
@@ -233,59 +216,67 @@ class ParticleView:
|
|
|
233
216
|
|
|
234
217
|
info_x = x + draw_w + panel_gap
|
|
235
218
|
info_y = margin
|
|
236
|
-
|
|
219
|
+
draw_ui_text(
|
|
220
|
+
self._small,
|
|
237
221
|
f"particles.png (grid {grid}x{grid})",
|
|
238
222
|
info_x,
|
|
239
223
|
info_y,
|
|
240
|
-
|
|
224
|
+
scale=UI_TEXT_SCALE,
|
|
225
|
+
color=UI_TEXT_COLOR,
|
|
241
226
|
)
|
|
242
|
-
info_y += self.
|
|
243
|
-
|
|
227
|
+
info_y += ui_line_height(self._small, scale=UI_TEXT_SCALE) + 6
|
|
228
|
+
draw_ui_text(
|
|
229
|
+
self._small,
|
|
244
230
|
"Up/Down: grid 2/4/8: direct 1: grid16 U: UV clamp",
|
|
245
231
|
info_x,
|
|
246
232
|
info_y,
|
|
247
|
-
|
|
233
|
+
scale=UI_TEXT_SCALE,
|
|
234
|
+
color=UI_HINT_COLOR,
|
|
248
235
|
)
|
|
249
|
-
info_y += self.
|
|
236
|
+
info_y += ui_line_height(self._small, scale=UI_TEXT_SCALE) + 12
|
|
250
237
|
if self._show_uv_clamp:
|
|
251
238
|
step_px = int(round(self._texture.width * step))
|
|
252
|
-
|
|
239
|
+
draw_ui_text(
|
|
240
|
+
self._small,
|
|
253
241
|
f"UV clamp: {step_px}px of {int(self._texture.width / grid)}px",
|
|
254
242
|
info_x,
|
|
255
243
|
info_y,
|
|
256
|
-
|
|
244
|
+
scale=UI_TEXT_SCALE,
|
|
245
|
+
color=UI_HINT_COLOR,
|
|
257
246
|
)
|
|
258
|
-
info_y += self.
|
|
247
|
+
info_y += ui_line_height(self._small, scale=UI_TEXT_SCALE) + 12
|
|
259
248
|
|
|
260
249
|
if hovered_index is not None:
|
|
261
|
-
self.
|
|
262
|
-
info_y += self.
|
|
250
|
+
draw_ui_text(self._small, f"frame {hovered_index:02d}", info_x, info_y, scale=UI_TEXT_SCALE, color=UI_TEXT_COLOR)
|
|
251
|
+
info_y += ui_line_height(self._small, scale=UI_TEXT_SCALE) + 6
|
|
263
252
|
entries = known_frames.get(hovered_index, [])
|
|
264
253
|
if entries:
|
|
265
254
|
for entry in entries:
|
|
266
255
|
label = f" {entry.label}" if entry.label else ""
|
|
267
|
-
|
|
256
|
+
draw_ui_text(
|
|
257
|
+
self._small,
|
|
268
258
|
f"0x{entry.effect_id:02x}{label}",
|
|
269
259
|
info_x,
|
|
270
260
|
info_y,
|
|
271
|
-
|
|
261
|
+
scale=UI_TEXT_SCALE,
|
|
262
|
+
color=UI_TEXT_COLOR,
|
|
272
263
|
)
|
|
273
|
-
info_y += self.
|
|
264
|
+
info_y += ui_line_height(self._small, scale=UI_TEXT_SCALE) + 4
|
|
274
265
|
else:
|
|
275
|
-
self.
|
|
276
|
-
info_y += self.
|
|
266
|
+
draw_ui_text(self._small, "no known mapping", info_x, info_y, scale=UI_TEXT_SCALE, color=UI_HINT_COLOR)
|
|
267
|
+
info_y += ui_line_height(self._small, scale=UI_TEXT_SCALE) + 4
|
|
277
268
|
info_y += 8
|
|
278
269
|
|
|
279
|
-
self.
|
|
280
|
-
info_y += self.
|
|
270
|
+
draw_ui_text(self._small, "Effect table", info_x, info_y, scale=UI_TEXT_SCALE, color=UI_TEXT_COLOR)
|
|
271
|
+
info_y += ui_line_height(self._small, scale=UI_TEXT_SCALE) + 6
|
|
281
272
|
for entry in EFFECT_ENTRIES:
|
|
282
273
|
grid_label = entry.grid
|
|
283
274
|
line = f"0x{entry.effect_id:02x} grid{grid_label} frame 0x{entry.frame:02x}"
|
|
284
275
|
if entry.label:
|
|
285
276
|
line += f" {entry.label}"
|
|
286
277
|
color = UI_TEXT_COLOR if entry.grid == grid else UI_HINT_COLOR
|
|
287
|
-
self.
|
|
288
|
-
info_y += self.
|
|
278
|
+
draw_ui_text(self._small, line, info_x, info_y, scale=UI_TEXT_SCALE, color=color)
|
|
279
|
+
info_y += ui_line_height(self._small, scale=UI_TEXT_SCALE) + 3
|
|
289
280
|
|
|
290
281
|
|
|
291
282
|
@register_view("particles", "Particle atlas preview")
|
crimson/views/perk_menu_debug.py
CHANGED
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import pyray as rl
|
|
4
4
|
|
|
5
5
|
from grim.fonts.small import SmallFontData, load_small_font, measure_small_text_width
|
|
6
|
+
from grim.math import clamp
|
|
6
7
|
from grim.view import View, ViewContext
|
|
7
8
|
|
|
8
9
|
from ..perks import PERK_BY_ID, PerkId, perk_display_description, perk_display_name
|
|
@@ -237,7 +238,7 @@ class PerkMenuDebugView:
|
|
|
237
238
|
if rl.is_key_down(rl.KeyboardKey.KEY_RIGHT):
|
|
238
239
|
self._panel_slide_x += step
|
|
239
240
|
|
|
240
|
-
self._panel_slide_x =
|
|
241
|
+
self._panel_slide_x = clamp(self._panel_slide_x, -self._layout.panel_w, 0.0)
|
|
241
242
|
|
|
242
243
|
self._prompt_hover = False
|
|
243
244
|
self._prompt_rect = None
|
|
@@ -250,7 +251,7 @@ class PerkMenuDebugView:
|
|
|
250
251
|
self._prompt_hover = rl.check_collision_point_rec(mouse, rect)
|
|
251
252
|
|
|
252
253
|
pulse_delta = dt_ms * (6.0 if self._prompt_hover else -2.0)
|
|
253
|
-
self._prompt_pulse =
|
|
254
|
+
self._prompt_pulse = clamp(self._prompt_pulse + pulse_delta, 0.0, 1000.0)
|
|
254
255
|
|
|
255
256
|
if not self._show_menu or self._assets is None:
|
|
256
257
|
return
|
|
@@ -411,14 +412,6 @@ class PerkMenuDebugView:
|
|
|
411
412
|
y += line_h
|
|
412
413
|
|
|
413
414
|
|
|
414
|
-
def _clamp(value: float, lo: float, hi: float) -> float:
|
|
415
|
-
if value < lo:
|
|
416
|
-
return lo
|
|
417
|
-
if value > hi:
|
|
418
|
-
return hi
|
|
419
|
-
return value
|
|
420
|
-
|
|
421
|
-
|
|
422
415
|
def _ui_text_width(font: SmallFontData | None, text: str, scale: float) -> float:
|
|
423
416
|
if font is None:
|
|
424
417
|
return float(rl.measure_text(text, int(20 * scale)))
|
crimson/views/player.py
CHANGED
|
@@ -5,7 +5,8 @@ from dataclasses import dataclass
|
|
|
5
5
|
import pyray as rl
|
|
6
6
|
|
|
7
7
|
from .registry import register_view
|
|
8
|
-
from grim.fonts.small import SmallFontData,
|
|
8
|
+
from grim.fonts.small import SmallFontData, load_small_font
|
|
9
|
+
from grim.math import clamp
|
|
9
10
|
from grim.view import View, ViewContext
|
|
10
11
|
|
|
11
12
|
from ..bonuses import BonusId
|
|
@@ -19,8 +20,9 @@ from ..gameplay import (
|
|
|
19
20
|
weapon_assign_player,
|
|
20
21
|
)
|
|
21
22
|
from ..perks import PerkId
|
|
22
|
-
from ..ui.hud import HudAssets, draw_hud_overlay, hud_ui_scale, load_hud_assets
|
|
23
|
+
from ..ui.hud import HudAssets, HudState, draw_hud_overlay, hud_ui_scale, load_hud_assets
|
|
23
24
|
from ..weapons import WEAPON_TABLE
|
|
25
|
+
from ._ui_helpers import draw_ui_text, ui_line_height
|
|
24
26
|
|
|
25
27
|
WORLD_SIZE = 1024.0
|
|
26
28
|
|
|
@@ -38,14 +40,6 @@ class DummyCreature:
|
|
|
38
40
|
size: float = 32.0
|
|
39
41
|
|
|
40
42
|
|
|
41
|
-
def _clamp(value: float, lo: float, hi: float) -> float:
|
|
42
|
-
if value < lo:
|
|
43
|
-
return lo
|
|
44
|
-
if value > hi:
|
|
45
|
-
return hi
|
|
46
|
-
return value
|
|
47
|
-
|
|
48
|
-
|
|
49
43
|
def _lerp(a: float, b: float, t: float) -> float:
|
|
50
44
|
return a + (b - a) * t
|
|
51
45
|
|
|
@@ -66,6 +60,7 @@ class PlayerSandboxView:
|
|
|
66
60
|
|
|
67
61
|
self._hud_assets: HudAssets | None = None
|
|
68
62
|
self._hud_missing: list[str] = []
|
|
63
|
+
self._hud_state = HudState()
|
|
69
64
|
self._elapsed_ms = 0.0
|
|
70
65
|
self._last_dt_ms = 0.0
|
|
71
66
|
|
|
@@ -81,24 +76,6 @@ class PlayerSandboxView:
|
|
|
81
76
|
continue
|
|
82
77
|
self._damage_scale_by_type[int(entry.weapon_id)] = float(entry.damage_scale or 1.0)
|
|
83
78
|
|
|
84
|
-
def _ui_line_height(self, scale: float = UI_TEXT_SCALE) -> int:
|
|
85
|
-
if self._small is not None:
|
|
86
|
-
return int(self._small.cell_size * scale)
|
|
87
|
-
return int(20 * scale)
|
|
88
|
-
|
|
89
|
-
def _draw_ui_text(
|
|
90
|
-
self,
|
|
91
|
-
text: str,
|
|
92
|
-
x: float,
|
|
93
|
-
y: float,
|
|
94
|
-
color: rl.Color,
|
|
95
|
-
scale: float = UI_TEXT_SCALE,
|
|
96
|
-
) -> None:
|
|
97
|
-
if self._small is not None:
|
|
98
|
-
draw_small_text(self._small, text, x, y, scale, color)
|
|
99
|
-
else:
|
|
100
|
-
rl.draw_text(text, int(x), int(y), int(20 * scale), color)
|
|
101
|
-
|
|
102
79
|
def _ensure_creatures(self, target_count: int) -> None:
|
|
103
80
|
while len(self._creatures) < target_count:
|
|
104
81
|
margin = 40.0
|
|
@@ -142,6 +119,7 @@ class PlayerSandboxView:
|
|
|
142
119
|
self._hud_assets = load_hud_assets(self._assets_root)
|
|
143
120
|
if self._hud_assets.missing:
|
|
144
121
|
self._hud_missing = list(self._hud_assets.missing)
|
|
122
|
+
self._hud_state = HudState()
|
|
145
123
|
|
|
146
124
|
self._state.rng.srand(0xBEEF)
|
|
147
125
|
self._creatures.clear()
|
|
@@ -239,7 +217,7 @@ class PlayerSandboxView:
|
|
|
239
217
|
if desired_y < min_y:
|
|
240
218
|
desired_y = min_y
|
|
241
219
|
|
|
242
|
-
t =
|
|
220
|
+
t = clamp(dt * 6.0, 0.0, 1.0)
|
|
243
221
|
self._camera_x = _lerp(self._camera_x, desired_x, t)
|
|
244
222
|
self._camera_y = _lerp(self._camera_y, desired_y, t)
|
|
245
223
|
|
|
@@ -315,7 +293,7 @@ class PlayerSandboxView:
|
|
|
315
293
|
rl.clear_background(rl.Color(10, 10, 12, 255))
|
|
316
294
|
if self._missing_assets:
|
|
317
295
|
message = "Missing assets: " + ", ".join(self._missing_assets)
|
|
318
|
-
self.
|
|
296
|
+
draw_ui_text(self._small, message, 24, 24, scale=UI_TEXT_SCALE, color=UI_ERROR_COLOR)
|
|
319
297
|
return
|
|
320
298
|
|
|
321
299
|
# World bounds.
|
|
@@ -353,6 +331,7 @@ class PlayerSandboxView:
|
|
|
353
331
|
if self._hud_assets is not None:
|
|
354
332
|
hud_bottom = draw_hud_overlay(
|
|
355
333
|
self._hud_assets,
|
|
334
|
+
state=self._hud_state,
|
|
356
335
|
player=self._player,
|
|
357
336
|
bonus_hud=self._state.bonus_hud,
|
|
358
337
|
elapsed_ms=self._elapsed_ms,
|
|
@@ -363,44 +342,64 @@ class PlayerSandboxView:
|
|
|
363
342
|
|
|
364
343
|
if self._hud_missing:
|
|
365
344
|
warn = "Missing HUD assets: " + ", ".join(self._hud_missing)
|
|
366
|
-
self.
|
|
345
|
+
draw_ui_text(self._small, warn, 24, rl.get_screen_height() - 28, scale=0.8, color=UI_ERROR_COLOR)
|
|
367
346
|
|
|
368
347
|
# UI.
|
|
369
348
|
scale = hud_ui_scale(float(rl.get_screen_width()), float(rl.get_screen_height()))
|
|
370
349
|
margin = 18
|
|
371
350
|
x = float(margin)
|
|
372
351
|
y = max(float(margin) + 110.0 * scale, hud_bottom + 12.0 * scale)
|
|
373
|
-
line = self.
|
|
352
|
+
line = ui_line_height(self._small, scale=UI_TEXT_SCALE)
|
|
374
353
|
|
|
375
354
|
weapon_id = self._player.weapon_id
|
|
376
355
|
weapon_name = next((w.name for w in WEAPON_TABLE if w.weapon_id == weapon_id), None) or f"weapon_{weapon_id}"
|
|
377
|
-
self.
|
|
356
|
+
draw_ui_text(self._small, f"{weapon_name} (id {weapon_id})", x, y, scale=UI_TEXT_SCALE, color=UI_TEXT_COLOR)
|
|
378
357
|
y += line + 4
|
|
379
|
-
|
|
358
|
+
draw_ui_text(
|
|
359
|
+
self._small,
|
|
380
360
|
f"ammo {self._player.ammo}/{self._player.clip_size} reload {self._player.reload_timer:.2f}/{self._player.reload_timer_max:.2f}",
|
|
381
361
|
x,
|
|
382
362
|
y,
|
|
383
|
-
|
|
363
|
+
scale=UI_TEXT_SCALE,
|
|
364
|
+
color=UI_TEXT_COLOR,
|
|
384
365
|
)
|
|
385
366
|
y += line + 4
|
|
386
|
-
|
|
367
|
+
draw_ui_text(
|
|
368
|
+
self._small,
|
|
387
369
|
f"cooldown {self._player.shot_cooldown:.3f} spread {self._player.spread_heat:.3f}",
|
|
388
370
|
x,
|
|
389
371
|
y,
|
|
390
|
-
|
|
372
|
+
scale=UI_TEXT_SCALE,
|
|
373
|
+
color=UI_TEXT_COLOR,
|
|
391
374
|
)
|
|
392
375
|
y += line + 8
|
|
393
376
|
|
|
394
|
-
|
|
377
|
+
draw_ui_text(
|
|
378
|
+
self._small,
|
|
379
|
+
"WASD move Mouse aim LMB fire R reload/swap Q/E weapon Tab pause",
|
|
380
|
+
x,
|
|
381
|
+
y,
|
|
382
|
+
scale=UI_TEXT_SCALE,
|
|
383
|
+
color=UI_HINT_COLOR,
|
|
384
|
+
)
|
|
395
385
|
y += line + 4
|
|
396
|
-
|
|
386
|
+
draw_ui_text(
|
|
387
|
+
self._small,
|
|
397
388
|
"1 Sharpshooter 2 Anxious 3 Stationary 4 Angry 5 Man Bomb 6 Hot Tempered 7 Fire Cough T Alt Weapon",
|
|
398
389
|
x,
|
|
399
390
|
y,
|
|
400
|
-
|
|
391
|
+
scale=UI_TEXT_SCALE,
|
|
392
|
+
color=UI_HINT_COLOR,
|
|
401
393
|
)
|
|
402
394
|
y += line + 4
|
|
403
|
-
|
|
395
|
+
draw_ui_text(
|
|
396
|
+
self._small,
|
|
397
|
+
"Z PowerUp X Shield C Speed V FireBullets B Fireblast Backspace clear bonuses",
|
|
398
|
+
x,
|
|
399
|
+
y,
|
|
400
|
+
scale=UI_TEXT_SCALE,
|
|
401
|
+
color=UI_HINT_COLOR,
|
|
402
|
+
)
|
|
404
403
|
y += line + 10
|
|
405
404
|
|
|
406
405
|
active_perks = []
|
|
@@ -416,16 +415,23 @@ class PlayerSandboxView:
|
|
|
416
415
|
):
|
|
417
416
|
if self._player.perk_counts[int(perk)]:
|
|
418
417
|
active_perks.append(perk.name.lower())
|
|
419
|
-
|
|
418
|
+
draw_ui_text(
|
|
419
|
+
self._small,
|
|
420
|
+
"perks: " + (", ".join(active_perks) if active_perks else "none"),
|
|
421
|
+
x,
|
|
422
|
+
y,
|
|
423
|
+
scale=UI_TEXT_SCALE,
|
|
424
|
+
color=UI_TEXT_COLOR,
|
|
425
|
+
)
|
|
420
426
|
y += line + 8
|
|
421
427
|
|
|
422
428
|
# Bonus HUD slots (text-only).
|
|
423
429
|
slots = [slot for slot in self._state.bonus_hud.slots if slot.active]
|
|
424
430
|
if slots:
|
|
425
|
-
self.
|
|
431
|
+
draw_ui_text(self._small, "bonuses:", x, y, scale=UI_TEXT_SCALE, color=UI_TEXT_COLOR)
|
|
426
432
|
y += line + 4
|
|
427
433
|
for slot in slots:
|
|
428
|
-
self.
|
|
434
|
+
draw_ui_text(self._small, f"- {slot.label}", x, y, scale=UI_TEXT_SCALE, color=UI_HINT_COLOR)
|
|
429
435
|
y += line + 2
|
|
430
436
|
|
|
431
437
|
|