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
|
@@ -7,8 +7,9 @@ from pathlib import Path
|
|
|
7
7
|
import pyray as rl
|
|
8
8
|
|
|
9
9
|
from grim.assets import resolve_asset_path
|
|
10
|
-
from grim.fonts.small import SmallFontData,
|
|
10
|
+
from grim.fonts.small import SmallFontData, load_small_font
|
|
11
11
|
from grim.view import View, ViewContext
|
|
12
|
+
from ._ui_helpers import draw_ui_text, ui_line_height
|
|
12
13
|
from .registry import register_view
|
|
13
14
|
|
|
14
15
|
|
|
@@ -54,24 +55,6 @@ class PlayerSpriteDebugView:
|
|
|
54
55
|
self._show_shadow = True
|
|
55
56
|
self._use_torso_offset = True
|
|
56
57
|
|
|
57
|
-
def _ui_line_height(self, scale: float = UI_TEXT_SCALE) -> int:
|
|
58
|
-
if self._small is not None:
|
|
59
|
-
return int(self._small.cell_size * scale)
|
|
60
|
-
return int(20 * scale)
|
|
61
|
-
|
|
62
|
-
def _draw_ui_text(
|
|
63
|
-
self,
|
|
64
|
-
text: str,
|
|
65
|
-
x: float,
|
|
66
|
-
y: float,
|
|
67
|
-
color: rl.Color,
|
|
68
|
-
scale: float = UI_TEXT_SCALE,
|
|
69
|
-
) -> None:
|
|
70
|
-
if self._small is not None:
|
|
71
|
-
draw_small_text(self._small, text, x, y, scale, color)
|
|
72
|
-
else:
|
|
73
|
-
rl.draw_text(text, int(x), int(y), int(20 * scale), color)
|
|
74
|
-
|
|
75
58
|
def _frame_src(self, texture: rl.Texture, frame_index: int) -> rl.Rectangle:
|
|
76
59
|
cell = float(texture.width) / float(SPRITE_GRID)
|
|
77
60
|
pad = SPRITE_PAD_PX
|
|
@@ -204,7 +187,7 @@ class PlayerSpriteDebugView:
|
|
|
204
187
|
def draw(self) -> None:
|
|
205
188
|
rl.clear_background(rl.Color(10, 10, 12, 255))
|
|
206
189
|
if self._assets is None:
|
|
207
|
-
self.
|
|
190
|
+
draw_ui_text(self._small, "Trooper sprite not loaded.", 16, 16, scale=UI_TEXT_SCALE, color=UI_ERROR_COLOR)
|
|
208
191
|
return
|
|
209
192
|
|
|
210
193
|
cam_x = float(rl.get_screen_width()) * 0.5 - self._player_x
|
|
@@ -271,41 +254,51 @@ class PlayerSpriteDebugView:
|
|
|
271
254
|
|
|
272
255
|
hud_x = 16.0
|
|
273
256
|
hud_y = 16.0
|
|
274
|
-
line = self.
|
|
275
|
-
|
|
257
|
+
line = ui_line_height(self._small, scale=UI_TEXT_SCALE)
|
|
258
|
+
draw_ui_text(
|
|
259
|
+
self._small,
|
|
276
260
|
f"legs frame={leg_frame} (base {self._leg_base}, count {self._frame_count})",
|
|
277
261
|
hud_x,
|
|
278
262
|
hud_y,
|
|
279
|
-
|
|
263
|
+
scale=UI_TEXT_SCALE,
|
|
264
|
+
color=UI_TEXT_COLOR,
|
|
280
265
|
)
|
|
281
266
|
hud_y += line
|
|
282
267
|
torso_label = "offset" if self._use_torso_offset else "match"
|
|
283
|
-
|
|
268
|
+
draw_ui_text(
|
|
269
|
+
self._small,
|
|
284
270
|
f"torso frame={torso_frame} (base {self._torso_base}, mode {torso_label})",
|
|
285
271
|
hud_x,
|
|
286
272
|
hud_y,
|
|
287
|
-
|
|
273
|
+
scale=UI_TEXT_SCALE,
|
|
274
|
+
color=UI_TEXT_COLOR,
|
|
288
275
|
)
|
|
289
276
|
hud_y += line
|
|
290
|
-
|
|
277
|
+
draw_ui_text(
|
|
278
|
+
self._small,
|
|
291
279
|
f"move_heading={self._move_heading:.2f} aim_heading={self._aim_heading:.2f}",
|
|
292
280
|
hud_x,
|
|
293
281
|
hud_y,
|
|
294
|
-
|
|
282
|
+
scale=UI_TEXT_SCALE,
|
|
283
|
+
color=UI_TEXT_COLOR,
|
|
295
284
|
)
|
|
296
285
|
hud_y += line
|
|
297
|
-
|
|
286
|
+
draw_ui_text(
|
|
287
|
+
self._small,
|
|
298
288
|
"WASD move, mouse aim, LMB recoil, F1 grid, F2 shadow, F3 torso mode",
|
|
299
289
|
hud_x,
|
|
300
290
|
hud_y,
|
|
301
|
-
|
|
291
|
+
scale=UI_TEXT_SCALE,
|
|
292
|
+
color=UI_HINT_COLOR,
|
|
302
293
|
)
|
|
303
294
|
hud_y += line
|
|
304
|
-
|
|
295
|
+
draw_ui_text(
|
|
296
|
+
self._small,
|
|
305
297
|
"[/] torso base, ;/' legs base, ,/. frame count, R reset",
|
|
306
298
|
hud_x,
|
|
307
299
|
hud_y,
|
|
308
|
-
|
|
300
|
+
scale=UI_TEXT_SCALE,
|
|
301
|
+
color=UI_HINT_COLOR,
|
|
309
302
|
)
|
|
310
303
|
|
|
311
304
|
|
crimson/views/projectile_fx.py
CHANGED
|
@@ -5,8 +5,8 @@ import math
|
|
|
5
5
|
|
|
6
6
|
import pyray as rl
|
|
7
7
|
|
|
8
|
-
from .
|
|
9
|
-
from grim.
|
|
8
|
+
from grim.fonts.small import SmallFontData, load_small_font
|
|
9
|
+
from grim.math import clamp
|
|
10
10
|
from grim.view import View, ViewContext
|
|
11
11
|
|
|
12
12
|
from ..bonuses import BonusId
|
|
@@ -18,6 +18,8 @@ from ..weapons import (
|
|
|
18
18
|
WEAPON_TABLE,
|
|
19
19
|
weapon_entry_for_projectile_type_id,
|
|
20
20
|
)
|
|
21
|
+
from ._ui_helpers import draw_ui_text, ui_line_height
|
|
22
|
+
from .registry import register_view
|
|
21
23
|
|
|
22
24
|
WORLD_SIZE = 1024.0
|
|
23
25
|
|
|
@@ -34,7 +36,7 @@ class DummyCreature:
|
|
|
34
36
|
y: float
|
|
35
37
|
hp: float
|
|
36
38
|
size: float = 42.0
|
|
37
|
-
|
|
39
|
+
plague_infected: bool = False
|
|
38
40
|
|
|
39
41
|
|
|
40
42
|
@dataclass(slots=True)
|
|
@@ -81,14 +83,6 @@ _BEAM_TYPES = frozenset(
|
|
|
81
83
|
)
|
|
82
84
|
|
|
83
85
|
|
|
84
|
-
def _clamp(value: float, lo: float, hi: float) -> float:
|
|
85
|
-
if value < lo:
|
|
86
|
-
return lo
|
|
87
|
-
if value > hi:
|
|
88
|
-
return hi
|
|
89
|
-
return value
|
|
90
|
-
|
|
91
|
-
|
|
92
86
|
def _lerp(a: float, b: float, t: float) -> float:
|
|
93
87
|
return a + (b - a) * t
|
|
94
88
|
|
|
@@ -134,24 +128,6 @@ class ProjectileFxView:
|
|
|
134
128
|
self._beams: list[BeamFx] = []
|
|
135
129
|
self._effects: list[EffectFx] = []
|
|
136
130
|
|
|
137
|
-
def _ui_line_height(self, scale: float = UI_TEXT_SCALE) -> int:
|
|
138
|
-
if self._small is not None:
|
|
139
|
-
return int(self._small.cell_size * scale)
|
|
140
|
-
return int(20 * scale)
|
|
141
|
-
|
|
142
|
-
def _draw_ui_text(
|
|
143
|
-
self,
|
|
144
|
-
text: str,
|
|
145
|
-
x: float,
|
|
146
|
-
y: float,
|
|
147
|
-
color: rl.Color,
|
|
148
|
-
scale: float = UI_TEXT_SCALE,
|
|
149
|
-
) -> None:
|
|
150
|
-
if self._small is not None:
|
|
151
|
-
draw_small_text(self._small, text, x, y, scale, color)
|
|
152
|
-
else:
|
|
153
|
-
rl.draw_text(text, int(x), int(y), int(20 * scale), color)
|
|
154
|
-
|
|
155
131
|
def _camera_world_to_screen(self, x: float, y: float) -> tuple[float, float]:
|
|
156
132
|
return self._camera_x + x, self._camera_y + y
|
|
157
133
|
|
|
@@ -180,7 +156,7 @@ class ProjectileFxView:
|
|
|
180
156
|
if desired_y < min_y:
|
|
181
157
|
desired_y = min_y
|
|
182
158
|
|
|
183
|
-
t =
|
|
159
|
+
t = clamp(dt * 6.0, 0.0, 1.0)
|
|
184
160
|
self._camera_x = _lerp(self._camera_x, desired_x, t)
|
|
185
161
|
self._camera_y = _lerp(self._camera_y, desired_y, t)
|
|
186
162
|
|
|
@@ -319,8 +295,8 @@ class ProjectileFxView:
|
|
|
319
295
|
angle = _angle_to_target(self._origin_x, self._origin_y, aim_x, aim_y)
|
|
320
296
|
|
|
321
297
|
if rl.is_mouse_button_pressed(rl.MouseButton.MOUSE_BUTTON_RIGHT):
|
|
322
|
-
self._origin_x =
|
|
323
|
-
self._origin_y =
|
|
298
|
+
self._origin_x = clamp(aim_x, 0.0, WORLD_SIZE)
|
|
299
|
+
self._origin_y = clamp(aim_y, 0.0, WORLD_SIZE)
|
|
324
300
|
|
|
325
301
|
if rl.is_mouse_button_pressed(rl.MouseButton.MOUSE_BUTTON_LEFT):
|
|
326
302
|
self._spawn_projectile(type_id=self._selected_type_id(), angle=angle, owner_id=-1)
|
|
@@ -467,7 +443,7 @@ class ProjectileFxView:
|
|
|
467
443
|
)
|
|
468
444
|
return
|
|
469
445
|
|
|
470
|
-
alpha = int(
|
|
446
|
+
alpha = int(clamp(life / 0.4, 0.0, 1.0) * 255)
|
|
471
447
|
tint = rl.Color(color.r, color.g, color.b, alpha)
|
|
472
448
|
self._draw_atlas_sprite(texture, grid=grid, frame=frame, x=sx, y=sy, scale=0.6, rotation_rad=angle, tint=tint)
|
|
473
449
|
|
|
@@ -475,7 +451,7 @@ class ProjectileFxView:
|
|
|
475
451
|
rl.clear_background(rl.Color(10, 10, 12, 255))
|
|
476
452
|
if self._missing_assets and self._projs is None:
|
|
477
453
|
message = "Missing assets: " + ", ".join(self._missing_assets)
|
|
478
|
-
self.
|
|
454
|
+
draw_ui_text(self._small, message, 24, 24, scale=UI_TEXT_SCALE, color=UI_ERROR_COLOR)
|
|
479
455
|
return
|
|
480
456
|
|
|
481
457
|
# World bounds.
|
|
@@ -491,7 +467,11 @@ class ProjectileFxView:
|
|
|
491
467
|
# Creatures.
|
|
492
468
|
for creature in self._creatures:
|
|
493
469
|
cx, cy = self._camera_world_to_screen(creature.x, creature.y)
|
|
494
|
-
color =
|
|
470
|
+
color = (
|
|
471
|
+
rl.Color(220, 90, 90, 255)
|
|
472
|
+
if not creature.plague_infected
|
|
473
|
+
else rl.Color(240, 180, 90, 255)
|
|
474
|
+
)
|
|
495
475
|
rl.draw_circle(int(cx), int(cy), float(creature.size * 0.5), color)
|
|
496
476
|
rl.draw_circle_lines(int(cx), int(cy), float(creature.size * 0.5), rl.Color(40, 40, 55, 255))
|
|
497
477
|
|
|
@@ -517,7 +497,7 @@ class ProjectileFxView:
|
|
|
517
497
|
|
|
518
498
|
# Beam flashes from hit events.
|
|
519
499
|
for beam in self._beams:
|
|
520
|
-
t =
|
|
500
|
+
t = clamp(beam.life / 0.08, 0.0, 1.0)
|
|
521
501
|
alpha = int(200 * t)
|
|
522
502
|
x0s, y0s = self._camera_world_to_screen(beam.x0, beam.y0)
|
|
523
503
|
x1s, y1s = self._camera_world_to_screen(beam.x1, beam.y1)
|
|
@@ -539,10 +519,10 @@ class ProjectileFxView:
|
|
|
539
519
|
if src is None:
|
|
540
520
|
continue
|
|
541
521
|
life = max(0.0, fx.life)
|
|
542
|
-
alpha = int(
|
|
522
|
+
alpha = int(clamp(life / 0.35, 0.0, 1.0) * 220)
|
|
543
523
|
tint = rl.Color(255, 255, 255, alpha)
|
|
544
524
|
sx, sy = self._camera_world_to_screen(fx.x, fx.y)
|
|
545
|
-
dst_scale = fx.scale * (1.0 + (0.7 -
|
|
525
|
+
dst_scale = fx.scale * (1.0 + (0.7 - clamp(life, 0.0, 0.7)) * 0.6)
|
|
546
526
|
dst = rl.Rectangle(float(sx), float(sy), src[2] * dst_scale, src[3] * dst_scale)
|
|
547
527
|
origin = rl.Vector2(dst.width * 0.5, dst.height * 0.5)
|
|
548
528
|
rl.draw_texture_pro(
|
|
@@ -562,46 +542,71 @@ class ProjectileFxView:
|
|
|
562
542
|
margin = 18
|
|
563
543
|
x = float(margin)
|
|
564
544
|
y = float(margin)
|
|
565
|
-
line = self.
|
|
545
|
+
line = ui_line_height(self._small, scale=UI_TEXT_SCALE)
|
|
566
546
|
|
|
567
547
|
type_id = self._selected_type_id()
|
|
568
548
|
weapon = WEAPON_BY_ID.get(int(type_id))
|
|
569
549
|
label = weapon.name if weapon is not None and weapon.name else f"type_{type_id}"
|
|
570
|
-
|
|
550
|
+
draw_ui_text(
|
|
551
|
+
self._small, f"{label} (type_id {type_id} / 0x{type_id:02x})", x, y, scale=UI_TEXT_SCALE, color=UI_TEXT_COLOR
|
|
552
|
+
)
|
|
571
553
|
y += line + 4
|
|
572
554
|
|
|
573
555
|
if self._show_debug:
|
|
574
556
|
meta = self._projectile_meta_for(type_id)
|
|
575
557
|
dmg = self._damage_scale_by_type.get(type_id, 1.0)
|
|
576
558
|
pellets = int(weapon.pellet_count) if weapon is not None and weapon.pellet_count is not None else 1
|
|
577
|
-
|
|
559
|
+
draw_ui_text(
|
|
560
|
+
self._small,
|
|
561
|
+
f"meta {meta:.1f} dmg_scale {dmg:.2f} pellet_count {pellets}",
|
|
562
|
+
x,
|
|
563
|
+
y,
|
|
564
|
+
scale=UI_TEXT_SCALE,
|
|
565
|
+
color=UI_HINT_COLOR,
|
|
566
|
+
)
|
|
578
567
|
y += line + 4
|
|
579
|
-
|
|
568
|
+
draw_ui_text(
|
|
569
|
+
self._small,
|
|
580
570
|
f"shock_chain links {self._state.shock_chain_links_left} proj {self._state.shock_chain_projectile_id}",
|
|
581
571
|
x,
|
|
582
572
|
y,
|
|
583
|
-
|
|
573
|
+
scale=UI_TEXT_SCALE,
|
|
574
|
+
color=UI_HINT_COLOR,
|
|
584
575
|
)
|
|
585
576
|
y += line + 8
|
|
586
577
|
|
|
587
578
|
if self._show_help:
|
|
588
|
-
self.
|
|
579
|
+
draw_ui_text(self._small, "controls:", x, y, scale=UI_TEXT_SCALE, color=UI_ACCENT_COLOR)
|
|
589
580
|
y += line + 2
|
|
590
|
-
self.
|
|
581
|
+
draw_ui_text(self._small, "- left/right: select projectile type", x, y, scale=UI_TEXT_SCALE, color=UI_HINT_COLOR)
|
|
591
582
|
y += line + 2
|
|
592
|
-
self.
|
|
583
|
+
draw_ui_text(self._small, "- mouse wheel: select type", x, y, scale=UI_TEXT_SCALE, color=UI_HINT_COLOR)
|
|
593
584
|
y += line + 2
|
|
594
|
-
self.
|
|
585
|
+
draw_ui_text(self._small, "- LMB: spawn projectile toward mouse", x, y, scale=UI_TEXT_SCALE, color=UI_HINT_COLOR)
|
|
595
586
|
y += line + 2
|
|
596
|
-
self.
|
|
587
|
+
draw_ui_text(self._small, "- RMB: move spawn origin", x, y, scale=UI_TEXT_SCALE, color=UI_HINT_COLOR)
|
|
597
588
|
y += line + 2
|
|
598
|
-
self.
|
|
589
|
+
draw_ui_text(self._small, "- space: spawn ring", x, y, scale=UI_TEXT_SCALE, color=UI_HINT_COLOR)
|
|
599
590
|
y += line + 2
|
|
600
|
-
|
|
591
|
+
draw_ui_text(
|
|
592
|
+
self._small,
|
|
593
|
+
"- F: fire-bullets volley (uses pellet_count)",
|
|
594
|
+
x,
|
|
595
|
+
y,
|
|
596
|
+
scale=UI_TEXT_SCALE,
|
|
597
|
+
color=UI_HINT_COLOR,
|
|
598
|
+
)
|
|
601
599
|
y += line + 2
|
|
602
|
-
self.
|
|
600
|
+
draw_ui_text(self._small, "- S: apply Shock Chain bonus", x, y, scale=UI_TEXT_SCALE, color=UI_HINT_COLOR)
|
|
603
601
|
y += line + 2
|
|
604
|
-
|
|
602
|
+
draw_ui_text(
|
|
603
|
+
self._small,
|
|
604
|
+
"- R: reset Tab: pause H: hide help F3: toggle debug",
|
|
605
|
+
x,
|
|
606
|
+
y,
|
|
607
|
+
scale=0.9,
|
|
608
|
+
color=UI_HINT_COLOR,
|
|
609
|
+
)
|
|
605
610
|
|
|
606
611
|
|
|
607
612
|
@register_view("projectile_fx", "Projectile FX lab")
|
|
@@ -7,13 +7,15 @@ import random
|
|
|
7
7
|
import pyray as rl
|
|
8
8
|
|
|
9
9
|
from grim.audio import AudioState, shutdown_audio
|
|
10
|
-
from grim.fonts.small import SmallFontData,
|
|
10
|
+
from grim.fonts.small import SmallFontData, load_small_font
|
|
11
|
+
from grim.math import clamp
|
|
11
12
|
from grim.view import View, ViewContext
|
|
12
13
|
|
|
13
14
|
from ..game_world import GameWorld
|
|
14
15
|
from ..gameplay import PlayerInput, player_update, weapon_assign_player
|
|
15
16
|
from ..ui.cursor import draw_aim_cursor
|
|
16
17
|
from ..weapons import WEAPON_TABLE
|
|
18
|
+
from ._ui_helpers import draw_ui_text, ui_line_height
|
|
17
19
|
from .audio_bootstrap import init_view_audio
|
|
18
20
|
from .registry import register_view
|
|
19
21
|
|
|
@@ -39,14 +41,6 @@ class TargetDummy:
|
|
|
39
41
|
size: float = 56.0
|
|
40
42
|
|
|
41
43
|
|
|
42
|
-
def _clamp(value: float, lo: float, hi: float) -> float:
|
|
43
|
-
if value < lo:
|
|
44
|
-
return lo
|
|
45
|
-
if value > hi:
|
|
46
|
-
return hi
|
|
47
|
-
return value
|
|
48
|
-
|
|
49
|
-
|
|
50
44
|
class ProjectileRenderDebugView:
|
|
51
45
|
def __init__(self, ctx: ViewContext) -> None:
|
|
52
46
|
self._assets_root = ctx.assets_dir
|
|
@@ -75,17 +69,6 @@ class ProjectileRenderDebugView:
|
|
|
75
69
|
self._paused = False
|
|
76
70
|
self._screenshot_requested = False
|
|
77
71
|
|
|
78
|
-
def _ui_line_height(self, scale: float = 1.0) -> int:
|
|
79
|
-
if self._small is not None:
|
|
80
|
-
return int(self._small.cell_size * scale)
|
|
81
|
-
return int(20 * scale)
|
|
82
|
-
|
|
83
|
-
def _draw_ui_text(self, text: str, x: float, y: float, color: rl.Color, scale: float = 1.0) -> None:
|
|
84
|
-
if self._small is not None:
|
|
85
|
-
draw_small_text(self._small, text, x, y, scale, color)
|
|
86
|
-
else:
|
|
87
|
-
rl.draw_text(text, int(x), int(y), int(20 * scale), color)
|
|
88
|
-
|
|
89
72
|
def _selected_weapon_id(self) -> int:
|
|
90
73
|
if not self._weapon_ids:
|
|
91
74
|
return 0
|
|
@@ -103,8 +86,8 @@ class ProjectileRenderDebugView:
|
|
|
103
86
|
ring = 260.0
|
|
104
87
|
for idx in range(10):
|
|
105
88
|
angle = float(idx) / 10.0 * math.tau
|
|
106
|
-
x =
|
|
107
|
-
y =
|
|
89
|
+
x = clamp(base_x + math.cos(angle) * ring, 40.0, WORLD_SIZE - 40.0)
|
|
90
|
+
y = clamp(base_y + math.sin(angle) * ring, 40.0, WORLD_SIZE - 40.0)
|
|
108
91
|
self._targets.append(TargetDummy(x=x, y=y, hp=260.0, size=64.0))
|
|
109
92
|
|
|
110
93
|
def _reset_scene(self) -> None:
|
|
@@ -301,16 +284,17 @@ class ProjectileRenderDebugView:
|
|
|
301
284
|
|
|
302
285
|
warn_x = 24.0
|
|
303
286
|
warn_y = 24.0
|
|
304
|
-
warn_line = float(self.
|
|
287
|
+
warn_line = float(ui_line_height(self._small))
|
|
305
288
|
if self._missing_assets:
|
|
306
|
-
self.
|
|
289
|
+
draw_ui_text(self._small, "Missing assets (ui): " + ", ".join(self._missing_assets), warn_x, warn_y, color=UI_ERROR)
|
|
307
290
|
warn_y += warn_line
|
|
308
291
|
if self._world.missing_assets:
|
|
309
|
-
|
|
292
|
+
draw_ui_text(
|
|
293
|
+
self._small,
|
|
310
294
|
"Missing assets (world): " + ", ".join(self._world.missing_assets),
|
|
311
295
|
warn_x,
|
|
312
296
|
warn_y,
|
|
313
|
-
UI_ERROR,
|
|
297
|
+
color=UI_ERROR,
|
|
314
298
|
)
|
|
315
299
|
warn_y += warn_line
|
|
316
300
|
|
|
@@ -363,26 +347,33 @@ class ProjectileRenderDebugView:
|
|
|
363
347
|
# UI.
|
|
364
348
|
x = 16.0
|
|
365
349
|
y = 12.0
|
|
366
|
-
line = float(self.
|
|
350
|
+
line = float(ui_line_height(self._small))
|
|
367
351
|
|
|
368
352
|
weapon_id = int(player.weapon_id) if player is not None else 0
|
|
369
353
|
weapon_name = next((w.name for w in WEAPON_TABLE if w.weapon_id == weapon_id), None) or f"weapon_{weapon_id}"
|
|
370
|
-
self.
|
|
354
|
+
draw_ui_text(self._small, "Projectile render debug", x, y, color=UI_TEXT)
|
|
371
355
|
y += line
|
|
372
|
-
self.
|
|
356
|
+
draw_ui_text(self._small, f"{weapon_name} (weapon_id={weapon_id})", x, y, color=UI_TEXT)
|
|
373
357
|
y += line
|
|
374
358
|
if player is not None:
|
|
375
|
-
|
|
359
|
+
draw_ui_text(
|
|
360
|
+
self._small,
|
|
376
361
|
f"ammo {player.ammo}/{player.clip_size} reload {player.reload_timer:.2f}/{player.reload_timer_max:.2f}",
|
|
377
362
|
x,
|
|
378
363
|
y,
|
|
379
|
-
UI_TEXT,
|
|
364
|
+
color=UI_TEXT,
|
|
380
365
|
)
|
|
381
366
|
y += line
|
|
382
367
|
y += 6.0
|
|
383
|
-
|
|
368
|
+
draw_ui_text(
|
|
369
|
+
self._small,
|
|
370
|
+
"WASD move LMB fire R reload [/] cycle weapons Space pause P screenshot",
|
|
371
|
+
x,
|
|
372
|
+
y,
|
|
373
|
+
color=UI_HINT,
|
|
374
|
+
)
|
|
384
375
|
y += line
|
|
385
|
-
self.
|
|
376
|
+
draw_ui_text(self._small, "T reset targets Backspace reset scene Esc quit", x, y, color=UI_HINT)
|
|
386
377
|
|
|
387
378
|
mouse = rl.get_mouse_position()
|
|
388
379
|
draw_aim_cursor(self._world.particles_texture, self._aim_texture, x=float(mouse.x), y=float(mouse.y))
|
crimson/views/projectiles.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,
|
|
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
|
|
@@ -55,24 +56,6 @@ class ProjectileView:
|
|
|
55
56
|
self._small: SmallFontData | None = None
|
|
56
57
|
self._grid = 4
|
|
57
58
|
|
|
58
|
-
def _ui_line_height(self, scale: float = UI_TEXT_SCALE) -> int:
|
|
59
|
-
if self._small is not None:
|
|
60
|
-
return int(self._small.cell_size * scale)
|
|
61
|
-
return int(20 * scale)
|
|
62
|
-
|
|
63
|
-
def _draw_ui_text(
|
|
64
|
-
self,
|
|
65
|
-
text: str,
|
|
66
|
-
x: float,
|
|
67
|
-
y: float,
|
|
68
|
-
color: rl.Color,
|
|
69
|
-
scale: float = UI_TEXT_SCALE,
|
|
70
|
-
) -> None:
|
|
71
|
-
if self._small is not None:
|
|
72
|
-
draw_small_text(self._small, text, x, y, scale, color)
|
|
73
|
-
else:
|
|
74
|
-
rl.draw_text(text, int(x), int(y), int(20 * scale), color)
|
|
75
|
-
|
|
76
59
|
def open(self) -> None:
|
|
77
60
|
self._missing_assets.clear()
|
|
78
61
|
self._small = load_small_font(self._assets_root, self._missing_assets)
|
|
@@ -105,10 +88,10 @@ class ProjectileView:
|
|
|
105
88
|
rl.clear_background(rl.Color(12, 12, 14, 255))
|
|
106
89
|
if self._missing_assets:
|
|
107
90
|
message = "Missing assets: " + ", ".join(self._missing_assets)
|
|
108
|
-
self.
|
|
91
|
+
draw_ui_text(self._small, message, 24, 24, scale=UI_TEXT_SCALE, color=UI_ERROR_COLOR)
|
|
109
92
|
return
|
|
110
93
|
if self._texture is None:
|
|
111
|
-
self.
|
|
94
|
+
draw_ui_text(self._small, "No projectile texture loaded.", 24, 24, scale=UI_TEXT_SCALE, color=UI_TEXT_COLOR)
|
|
112
95
|
return
|
|
113
96
|
|
|
114
97
|
self._handle_input()
|
|
@@ -179,41 +162,45 @@ class ProjectileView:
|
|
|
179
162
|
|
|
180
163
|
info_x = x + draw_w + panel_gap
|
|
181
164
|
info_y = margin
|
|
182
|
-
|
|
165
|
+
draw_ui_text(
|
|
166
|
+
self._small,
|
|
183
167
|
f"projs.png (grid {self._grid}x{self._grid})",
|
|
184
168
|
info_x,
|
|
185
169
|
info_y,
|
|
186
|
-
|
|
170
|
+
scale=UI_TEXT_SCALE,
|
|
171
|
+
color=UI_TEXT_COLOR,
|
|
187
172
|
)
|
|
188
|
-
info_y += self.
|
|
189
|
-
self.
|
|
190
|
-
info_y += self.
|
|
173
|
+
info_y += ui_line_height(self._small, scale=UI_TEXT_SCALE) + 6
|
|
174
|
+
draw_ui_text(self._small, "2/4: grid G: toggle", info_x, info_y, scale=UI_TEXT_SCALE, color=UI_HINT_COLOR)
|
|
175
|
+
info_y += ui_line_height(self._small, scale=UI_TEXT_SCALE) + 12
|
|
191
176
|
|
|
192
177
|
if hovered_index is not None:
|
|
193
|
-
self.
|
|
194
|
-
info_y += self.
|
|
178
|
+
draw_ui_text(self._small, f"frame {hovered_index:02d}", info_x, info_y, scale=UI_TEXT_SCALE, color=UI_TEXT_COLOR)
|
|
179
|
+
info_y += ui_line_height(self._small, scale=UI_TEXT_SCALE) + 6
|
|
195
180
|
entries = known_frames.get(hovered_index, [])
|
|
196
181
|
if entries:
|
|
197
182
|
for entry in entries:
|
|
198
|
-
|
|
183
|
+
draw_ui_text(
|
|
184
|
+
self._small,
|
|
199
185
|
f"0x{entry.type_id:02x} {entry.label}",
|
|
200
186
|
info_x,
|
|
201
187
|
info_y,
|
|
202
|
-
|
|
188
|
+
scale=UI_TEXT_SCALE,
|
|
189
|
+
color=UI_TEXT_COLOR,
|
|
203
190
|
)
|
|
204
|
-
info_y += self.
|
|
191
|
+
info_y += ui_line_height(self._small, scale=UI_TEXT_SCALE) + 4
|
|
205
192
|
else:
|
|
206
|
-
self.
|
|
207
|
-
info_y += self.
|
|
193
|
+
draw_ui_text(self._small, "no known mapping", info_x, info_y, scale=UI_TEXT_SCALE, color=UI_HINT_COLOR)
|
|
194
|
+
info_y += ui_line_height(self._small, scale=UI_TEXT_SCALE) + 4
|
|
208
195
|
info_y += 8
|
|
209
196
|
|
|
210
|
-
self.
|
|
211
|
-
info_y += self.
|
|
197
|
+
draw_ui_text(self._small, "Known frames", info_x, info_y, scale=UI_TEXT_SCALE, color=UI_TEXT_COLOR)
|
|
198
|
+
info_y += ui_line_height(self._small, scale=UI_TEXT_SCALE) + 6
|
|
212
199
|
for frame_index in sorted(known_frames.keys()):
|
|
213
200
|
entries = known_frames[frame_index]
|
|
214
201
|
labels = ", ".join(f"0x{entry.type_id:02x} {entry.label}" for entry in entries)
|
|
215
|
-
self.
|
|
216
|
-
info_y += self.
|
|
202
|
+
draw_ui_text(self._small, f"{frame_index:02d}: {labels}", info_x, info_y, scale=UI_TEXT_SCALE, color=UI_HINT_COLOR)
|
|
203
|
+
info_y += ui_line_height(self._small, scale=UI_TEXT_SCALE) + 4
|
|
217
204
|
|
|
218
205
|
|
|
219
206
|
@register_view("projectiles", "Projectile atlas preview")
|
crimson/views/spawn_plan.py
CHANGED
|
@@ -15,8 +15,9 @@ from ..creatures.spawn import (
|
|
|
15
15
|
spawn_id_label,
|
|
16
16
|
tick_spawn_slot,
|
|
17
17
|
)
|
|
18
|
+
from ._ui_helpers import draw_ui_text, ui_line_height
|
|
18
19
|
from .registry import register_view
|
|
19
|
-
from grim.fonts.small import SmallFontData,
|
|
20
|
+
from grim.fonts.small import SmallFontData, load_small_font, measure_small_text_width
|
|
20
21
|
from grim.view import View, ViewContext
|
|
21
22
|
|
|
22
23
|
|
|
@@ -93,29 +94,11 @@ class SpawnPlanView:
|
|
|
93
94
|
rl.unload_texture(self._small.texture)
|
|
94
95
|
self._small = None
|
|
95
96
|
|
|
96
|
-
def _ui_line_height(self, scale: float = UI_TEXT_SCALE) -> int:
|
|
97
|
-
if self._small is not None:
|
|
98
|
-
return int(self._small.cell_size * scale)
|
|
99
|
-
return int(20 * scale)
|
|
100
|
-
|
|
101
|
-
def _draw_ui_text(
|
|
102
|
-
self,
|
|
103
|
-
text: str,
|
|
104
|
-
x: float,
|
|
105
|
-
y: float,
|
|
106
|
-
color: rl.Color,
|
|
107
|
-
scale: float = UI_TEXT_SCALE,
|
|
108
|
-
) -> None:
|
|
109
|
-
if self._small is not None:
|
|
110
|
-
draw_small_text(self._small, text, x, y, scale, color)
|
|
111
|
-
else:
|
|
112
|
-
rl.draw_text(text, int(x), int(y), int(20 * scale), color)
|
|
113
|
-
|
|
114
97
|
def _draw_ui_label(self, label: str, value: str, x: float, y: float) -> None:
|
|
115
98
|
label_text = f"{label}: "
|
|
116
|
-
self.
|
|
99
|
+
draw_ui_text(self._small, label_text, x, y, scale=UI_TEXT_SCALE, color=UI_HINT_COLOR)
|
|
117
100
|
label_w = measure_small_text_width(self._small, label_text, UI_TEXT_SCALE) if self._small else 0.0
|
|
118
|
-
self.
|
|
101
|
+
draw_ui_text(self._small, value, x + label_w, y, scale=UI_TEXT_SCALE, color=UI_TEXT_COLOR)
|
|
119
102
|
|
|
120
103
|
def _rebuild_plan(self) -> None:
|
|
121
104
|
spawn_id = self._template_ids[self._index]
|
|
@@ -261,18 +244,19 @@ class SpawnPlanView:
|
|
|
261
244
|
self._draw_grid()
|
|
262
245
|
|
|
263
246
|
margin = 16.0
|
|
264
|
-
line_h = float(self.
|
|
247
|
+
line_h = float(ui_line_height(self._small, scale=UI_TEXT_SCALE))
|
|
265
248
|
|
|
266
249
|
spawn_id = self._template_ids[self._index] if self._template_ids else 0
|
|
267
|
-
|
|
250
|
+
draw_ui_text(
|
|
251
|
+
self._small,
|
|
268
252
|
f"spawn-plan view (template 0x{spawn_id:02x})",
|
|
269
253
|
margin,
|
|
270
254
|
margin,
|
|
271
|
-
UI_TEXT_COLOR,
|
|
272
255
|
scale=0.8,
|
|
256
|
+
color=UI_TEXT_COLOR,
|
|
273
257
|
)
|
|
274
258
|
hints = "Left/Right: id Up/Down: seed R: random seed [,]: scale H: hardcore D: demo-mode ,/.: difficulty Space: sim Backspace: reset"
|
|
275
|
-
self.
|
|
259
|
+
draw_ui_text(self._small, hints, margin, margin + line_h, scale=UI_TEXT_SCALE, color=UI_HINT_COLOR)
|
|
276
260
|
|
|
277
261
|
y = margin + line_h * 2.0 + 4.0
|
|
278
262
|
self._draw_ui_label("seed", f"0x{self._seed:08x}", margin, y)
|
|
@@ -287,10 +271,10 @@ class SpawnPlanView:
|
|
|
287
271
|
y += line_h
|
|
288
272
|
|
|
289
273
|
if self._error is not None:
|
|
290
|
-
self.
|
|
274
|
+
draw_ui_text(self._small, self._error, margin, y + 6.0, scale=UI_TEXT_SCALE, color=UI_ERROR_COLOR)
|
|
291
275
|
return
|
|
292
276
|
if self._plan is None or self._plan_summary is None:
|
|
293
|
-
self.
|
|
277
|
+
draw_ui_text(self._small, "No plan.", margin, y + 6.0, scale=UI_TEXT_SCALE, color=UI_ERROR_COLOR)
|
|
294
278
|
return
|
|
295
279
|
|
|
296
280
|
summary = self._plan_summary
|
|
@@ -313,10 +297,10 @@ class SpawnPlanView:
|
|
|
313
297
|
)
|
|
314
298
|
y += line_h
|
|
315
299
|
if self._sim_events:
|
|
316
|
-
self.
|
|
300
|
+
draw_ui_text(self._small, "events:", margin, y + 2.0, scale=UI_TEXT_SCALE, color=UI_HINT_COLOR)
|
|
317
301
|
y += line_h
|
|
318
302
|
for ev in self._sim_events[-5:]:
|
|
319
|
-
self.
|
|
303
|
+
draw_ui_text(self._small, ev, margin, y, scale=UI_TEXT_SCALE, color=UI_TEXT_COLOR)
|
|
320
304
|
y += line_h
|
|
321
305
|
|
|
322
306
|
# Link lines.
|