crimsonland 0.1.0.dev5__py3-none-any.whl → 0.1.0.dev11__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/audio_router.py +12 -2
- crimson/creatures/anim.py +1 -0
- crimson/demo.py +79 -37
- crimson/effects.py +1 -1
- crimson/game.py +5 -0
- crimson/gameplay.py +91 -31
- crimson/modes/base_gameplay_mode.py +75 -1
- crimson/modes/quest_mode.py +471 -44
- crimson/modes/rush_mode.py +12 -3
- crimson/modes/survival_mode.py +13 -2
- crimson/modes/tutorial_mode.py +12 -1
- crimson/modes/typo_mode.py +12 -4
- crimson/projectiles.py +224 -61
- crimson/render/world_renderer.py +172 -36
- crimson/ui/hud.py +274 -51
- crimson/views/arsenal_debug.py +46 -1
- crimson/views/player.py +2 -2
- {crimsonland-0.1.0.dev5.dist-info → crimsonland-0.1.0.dev11.dist-info}/METADATA +1 -1
- {crimsonland-0.1.0.dev5.dist-info → crimsonland-0.1.0.dev11.dist-info}/RECORD +22 -22
- grim/console.py +14 -0
- {crimsonland-0.1.0.dev5.dist-info → crimsonland-0.1.0.dev11.dist-info}/WHEEL +0 -0
- {crimsonland-0.1.0.dev5.dist-info → crimsonland-0.1.0.dev11.dist-info}/entry_points.txt +0 -0
crimson/ui/hud.py
CHANGED
|
@@ -8,6 +8,7 @@ import pyray as rl
|
|
|
8
8
|
|
|
9
9
|
from grim.assets import TextureLoader
|
|
10
10
|
from grim.fonts.small import SmallFontData, draw_small_text
|
|
11
|
+
from ..game_modes import GameMode
|
|
11
12
|
from ..gameplay import BonusHudState, PlayerState, survival_level_threshold
|
|
12
13
|
from ..weapons import WEAPON_BY_ID
|
|
13
14
|
|
|
@@ -53,6 +54,7 @@ HUD_BONUS_TEXT_OFFSET = (36.0, 6.0)
|
|
|
53
54
|
HUD_BONUS_SPACING = 52.0
|
|
54
55
|
HUD_BONUS_PANEL_OFFSET_Y = -11.0
|
|
55
56
|
HUD_XP_BAR_RGBA = (0.1, 0.3, 0.6, 1.0)
|
|
57
|
+
HUD_QUEST_LEFT_Y_SHIFT = 80.0
|
|
56
58
|
|
|
57
59
|
_SURVIVAL_XP_SMOOTHED = 0
|
|
58
60
|
|
|
@@ -74,6 +76,60 @@ class HudAssets:
|
|
|
74
76
|
missing: list[str] = field(default_factory=list)
|
|
75
77
|
|
|
76
78
|
|
|
79
|
+
@dataclass(frozen=True, slots=True)
|
|
80
|
+
class HudRenderFlags:
|
|
81
|
+
show_health: bool
|
|
82
|
+
show_weapon: bool
|
|
83
|
+
show_xp: bool
|
|
84
|
+
show_time: bool
|
|
85
|
+
show_quest_hud: bool
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def hud_flags_for_game_mode(game_mode_id: int) -> HudRenderFlags:
|
|
89
|
+
"""Match `hud_update_and_render` (0x0041ca90) flag mapping."""
|
|
90
|
+
|
|
91
|
+
mode = int(game_mode_id)
|
|
92
|
+
if mode == int(GameMode.QUESTS):
|
|
93
|
+
return HudRenderFlags(
|
|
94
|
+
show_health=True,
|
|
95
|
+
show_weapon=True,
|
|
96
|
+
show_xp=True,
|
|
97
|
+
show_time=False,
|
|
98
|
+
show_quest_hud=True,
|
|
99
|
+
)
|
|
100
|
+
if mode == int(GameMode.SURVIVAL):
|
|
101
|
+
return HudRenderFlags(
|
|
102
|
+
show_health=True,
|
|
103
|
+
show_weapon=True,
|
|
104
|
+
show_xp=True,
|
|
105
|
+
show_time=False,
|
|
106
|
+
show_quest_hud=False,
|
|
107
|
+
)
|
|
108
|
+
if mode == int(GameMode.RUSH):
|
|
109
|
+
return HudRenderFlags(
|
|
110
|
+
show_health=True,
|
|
111
|
+
show_weapon=False,
|
|
112
|
+
show_xp=False,
|
|
113
|
+
show_time=True,
|
|
114
|
+
show_quest_hud=False,
|
|
115
|
+
)
|
|
116
|
+
if mode == int(GameMode.TYPO):
|
|
117
|
+
return HudRenderFlags(
|
|
118
|
+
show_health=True,
|
|
119
|
+
show_weapon=False,
|
|
120
|
+
show_xp=True,
|
|
121
|
+
show_time=True,
|
|
122
|
+
show_quest_hud=False,
|
|
123
|
+
)
|
|
124
|
+
return HudRenderFlags(
|
|
125
|
+
show_health=False,
|
|
126
|
+
show_weapon=False,
|
|
127
|
+
show_xp=False,
|
|
128
|
+
show_time=False,
|
|
129
|
+
show_quest_hud=False,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
|
|
77
133
|
def hud_ui_scale(screen_w: float, screen_h: float) -> float:
|
|
78
134
|
scale = min(screen_w / HUD_BASE_WIDTH, screen_h / HUD_BASE_HEIGHT)
|
|
79
135
|
if scale < 0.75:
|
|
@@ -171,6 +227,18 @@ def _draw_progress_bar(x: float, y: float, width: float, ratio: float, rgba: tup
|
|
|
171
227
|
rl.draw_rectangle(int(x + scale), int(y + scale), int(inner_w), int(inner_h), fg_color)
|
|
172
228
|
|
|
173
229
|
|
|
230
|
+
def draw_target_health_bar(*, x: float, y: float, width: float, ratio: float, alpha: float = 1.0, scale: float = 1.0) -> None:
|
|
231
|
+
ratio = max(0.0, min(1.0, float(ratio)))
|
|
232
|
+
alpha = max(0.0, min(1.0, float(alpha)))
|
|
233
|
+
scale = max(0.1, float(scale))
|
|
234
|
+
|
|
235
|
+
# Matches `hud_update_and_render` (0x0041ca90): color shifts from red->green as ratio increases.
|
|
236
|
+
r = (1.0 - ratio) * 0.9 + 0.1
|
|
237
|
+
g = ratio * 0.9 + 0.1
|
|
238
|
+
rgba = (r, g, 0.7, 0.2 * alpha)
|
|
239
|
+
_draw_progress_bar(float(x), float(y), float(width), ratio, rgba, scale)
|
|
240
|
+
|
|
241
|
+
|
|
174
242
|
def _weapon_icon_index(weapon_id: int) -> int | None:
|
|
175
243
|
entry = WEAPON_BY_ID.get(int(weapon_id))
|
|
176
244
|
icon_index = entry.icon_index if entry is not None else None
|
|
@@ -215,9 +283,13 @@ def draw_hud_overlay(
|
|
|
215
283
|
font: SmallFontData | None = None,
|
|
216
284
|
alpha: float = 1.0,
|
|
217
285
|
frame_dt_ms: float | None = None,
|
|
286
|
+
show_health: bool = True,
|
|
218
287
|
show_weapon: bool = True,
|
|
219
288
|
show_xp: bool = True,
|
|
220
289
|
show_time: bool = False,
|
|
290
|
+
show_quest_hud: bool = False,
|
|
291
|
+
quest_progress_ratio: float | None = None,
|
|
292
|
+
small_indicators: bool = False,
|
|
221
293
|
) -> float:
|
|
222
294
|
if frame_dt_ms is None:
|
|
223
295
|
frame_dt_ms = max(0.0, float(rl.get_frame_time()) * 1000.0)
|
|
@@ -241,8 +313,8 @@ def draw_hud_overlay(
|
|
|
241
313
|
max_y = 0.0
|
|
242
314
|
alpha = max(0.0, min(1.0, float(alpha)))
|
|
243
315
|
text_color = _with_alpha(HUD_TEXT_COLOR, alpha)
|
|
244
|
-
accent_color = _with_alpha(HUD_ACCENT_COLOR, alpha)
|
|
245
316
|
panel_text_color = _with_alpha(HUD_TEXT_COLOR, alpha * HUD_PANEL_ALPHA)
|
|
317
|
+
hud_y_shift = HUD_QUEST_LEFT_Y_SHIFT if show_quest_hud else 0.0
|
|
246
318
|
|
|
247
319
|
# Top bar background.
|
|
248
320
|
if assets.game_top is not None:
|
|
@@ -265,7 +337,7 @@ def draw_hud_overlay(
|
|
|
265
337
|
max_y = max(max_y, dst.y + dst.height)
|
|
266
338
|
|
|
267
339
|
# Pulsing heart.
|
|
268
|
-
if assets.life_heart is not None:
|
|
340
|
+
if show_health and assets.life_heart is not None:
|
|
269
341
|
t = max(0.0, elapsed_ms) / 1000.0
|
|
270
342
|
src = rl.Rectangle(0.0, 0.0, float(assets.life_heart.width), float(assets.life_heart.height))
|
|
271
343
|
if player_count == 1:
|
|
@@ -301,7 +373,7 @@ def draw_hud_overlay(
|
|
|
301
373
|
max_y = max(max_y, dst.y + dst.height)
|
|
302
374
|
|
|
303
375
|
# Health bar.
|
|
304
|
-
if assets.ind_life is not None:
|
|
376
|
+
if show_health and assets.ind_life is not None:
|
|
305
377
|
bar_x, bar_y = HUD_HEALTH_BAR_POS
|
|
306
378
|
bar_w, bar_h = HUD_HEALTH_BAR_SIZE
|
|
307
379
|
bg_src = rl.Rectangle(0.0, 0.0, float(assets.ind_life.width), float(assets.ind_life.height))
|
|
@@ -427,11 +499,91 @@ def draw_hud_overlay(
|
|
|
427
499
|
text_y = base_y + HUD_AMMO_TEXT_OFFSET[1]
|
|
428
500
|
_draw_text(font, f"+ {extra}", sx(text_x), sy(text_y), text_scale, text_color)
|
|
429
501
|
|
|
502
|
+
# Quest HUD panels (mm:ss timer + progress).
|
|
503
|
+
if show_quest_hud:
|
|
504
|
+
time_ms = max(0.0, float(elapsed_ms))
|
|
505
|
+
slide_x = 0.0
|
|
506
|
+
if time_ms < 1000.0:
|
|
507
|
+
slide_x = (1000.0 - time_ms) * -0.128
|
|
508
|
+
|
|
509
|
+
quest_panel_alpha = alpha * 0.7
|
|
510
|
+
quest_text_color = _with_alpha(HUD_TEXT_COLOR, quest_panel_alpha)
|
|
511
|
+
|
|
512
|
+
if assets.ind_panel is not None:
|
|
513
|
+
src = rl.Rectangle(0.0, 0.0, float(assets.ind_panel.width), float(assets.ind_panel.height))
|
|
514
|
+
|
|
515
|
+
# Sliding top panel (first second).
|
|
516
|
+
dst = rl.Rectangle(sx(slide_x - 90.0), sy(67.0), sx(182.0), sy(53.0))
|
|
517
|
+
rl.draw_texture_pro(
|
|
518
|
+
assets.ind_panel,
|
|
519
|
+
src,
|
|
520
|
+
dst,
|
|
521
|
+
rl.Vector2(0.0, 0.0),
|
|
522
|
+
0.0,
|
|
523
|
+
rl.Color(255, 255, 255, int(255 * quest_panel_alpha)),
|
|
524
|
+
)
|
|
525
|
+
max_y = max(max_y, dst.y + dst.height)
|
|
526
|
+
|
|
527
|
+
# Static progress panel.
|
|
528
|
+
dst = rl.Rectangle(sx(-80.0), sy(107.0), sx(182.0), sy(53.0))
|
|
529
|
+
rl.draw_texture_pro(
|
|
530
|
+
assets.ind_panel,
|
|
531
|
+
src,
|
|
532
|
+
dst,
|
|
533
|
+
rl.Vector2(0.0, 0.0),
|
|
534
|
+
0.0,
|
|
535
|
+
rl.Color(255, 255, 255, int(255 * quest_panel_alpha)),
|
|
536
|
+
)
|
|
537
|
+
max_y = max(max_y, dst.y + dst.height)
|
|
538
|
+
|
|
539
|
+
# Clock table + pointer inside the sliding panel.
|
|
540
|
+
clock_alpha = alpha * HUD_CLOCK_ALPHA
|
|
541
|
+
if assets.clock_table is not None:
|
|
542
|
+
dst = rl.Rectangle(sx(slide_x + 2.0), sy(78.0), sx(32.0), sy(32.0))
|
|
543
|
+
src = rl.Rectangle(0.0, 0.0, float(assets.clock_table.width), float(assets.clock_table.height))
|
|
544
|
+
rl.draw_texture_pro(
|
|
545
|
+
assets.clock_table,
|
|
546
|
+
src,
|
|
547
|
+
dst,
|
|
548
|
+
rl.Vector2(0.0, 0.0),
|
|
549
|
+
0.0,
|
|
550
|
+
rl.Color(255, 255, 255, int(255 * clock_alpha)),
|
|
551
|
+
)
|
|
552
|
+
|
|
553
|
+
if assets.clock_pointer is not None:
|
|
554
|
+
# NOTE: Raylib's draw_texture_pro uses dst.x/y as the rotation origin position;
|
|
555
|
+
# offset by half-size so the 32x32 quad stays aligned with the table.
|
|
556
|
+
dst = rl.Rectangle(sx(slide_x + 2.0 + 16.0), sy(78.0 + 16.0), sx(32.0), sy(32.0))
|
|
557
|
+
src = rl.Rectangle(0.0, 0.0, float(assets.clock_pointer.width), float(assets.clock_pointer.height))
|
|
558
|
+
rotation = time_ms / 1000.0 * 6.0
|
|
559
|
+
origin = rl.Vector2(sx(16.0), sy(16.0))
|
|
560
|
+
rl.draw_texture_pro(
|
|
561
|
+
assets.clock_pointer,
|
|
562
|
+
src,
|
|
563
|
+
dst,
|
|
564
|
+
origin,
|
|
565
|
+
rotation,
|
|
566
|
+
rl.Color(255, 255, 255, int(255 * clock_alpha)),
|
|
567
|
+
)
|
|
568
|
+
|
|
569
|
+
total_seconds = max(0, int(time_ms) // 1000)
|
|
570
|
+
minutes = total_seconds // 60
|
|
571
|
+
seconds = total_seconds % 60
|
|
572
|
+
_draw_text(font, f"{minutes}:{seconds:02d}", sx(slide_x + 32.0), sy(86.0), text_scale, quest_text_color)
|
|
573
|
+
|
|
574
|
+
_draw_text(font, "Progress", sx(18.0), sy(122.0), text_scale, quest_text_color)
|
|
575
|
+
|
|
576
|
+
if quest_progress_ratio is not None:
|
|
577
|
+
ratio = max(0.0, min(1.0, float(quest_progress_ratio)))
|
|
578
|
+
quest_bar_rgba = (0.2, 0.8, 0.3, alpha * 0.8)
|
|
579
|
+
_draw_progress_bar(sx(10.0), sy(139.0), sx(70.0), ratio, quest_bar_rgba, scale)
|
|
580
|
+
|
|
430
581
|
# Survival XP panel.
|
|
431
582
|
xp_target = int(player.experience if score is None else score)
|
|
432
583
|
xp_display = _smooth_xp(xp_target, frame_dt_ms) if show_xp else xp_target
|
|
433
584
|
if show_xp and assets.ind_panel is not None:
|
|
434
585
|
panel_x, panel_y = HUD_SURV_PANEL_POS
|
|
586
|
+
panel_y += hud_y_shift
|
|
435
587
|
panel_w, panel_h = HUD_SURV_PANEL_SIZE
|
|
436
588
|
dst = rl.Rectangle(sx(panel_x), sy(panel_y), sx(panel_w), sy(panel_h))
|
|
437
589
|
src = rl.Rectangle(0.0, 0.0, float(assets.ind_panel.width), float(assets.ind_panel.height))
|
|
@@ -450,7 +602,7 @@ def draw_hud_overlay(
|
|
|
450
602
|
font,
|
|
451
603
|
"Xp",
|
|
452
604
|
sx(HUD_SURV_XP_LABEL_POS[0]),
|
|
453
|
-
sy(HUD_SURV_XP_LABEL_POS[1]),
|
|
605
|
+
sy(HUD_SURV_XP_LABEL_POS[1] + hud_y_shift),
|
|
454
606
|
text_scale,
|
|
455
607
|
panel_text_color,
|
|
456
608
|
)
|
|
@@ -458,7 +610,7 @@ def draw_hud_overlay(
|
|
|
458
610
|
font,
|
|
459
611
|
f"{xp_display}",
|
|
460
612
|
sx(HUD_SURV_XP_VALUE_POS[0]),
|
|
461
|
-
sy(HUD_SURV_XP_VALUE_POS[1]),
|
|
613
|
+
sy(HUD_SURV_XP_VALUE_POS[1] + hud_y_shift),
|
|
462
614
|
text_scale,
|
|
463
615
|
panel_text_color,
|
|
464
616
|
)
|
|
@@ -466,7 +618,7 @@ def draw_hud_overlay(
|
|
|
466
618
|
font,
|
|
467
619
|
f"{int(player.level)}",
|
|
468
620
|
sx(HUD_SURV_LVL_VALUE_POS[0]),
|
|
469
|
-
sy(HUD_SURV_LVL_VALUE_POS[1]),
|
|
621
|
+
sy(HUD_SURV_LVL_VALUE_POS[1] + hud_y_shift),
|
|
470
622
|
text_scale,
|
|
471
623
|
panel_text_color,
|
|
472
624
|
)
|
|
@@ -478,6 +630,7 @@ def draw_hud_overlay(
|
|
|
478
630
|
if next_threshold > prev_threshold:
|
|
479
631
|
progress_ratio = (xp_target - prev_threshold) / float(next_threshold - prev_threshold)
|
|
480
632
|
bar_x, bar_y = HUD_SURV_PROGRESS_POS
|
|
633
|
+
bar_y += hud_y_shift
|
|
481
634
|
bar_w = HUD_SURV_PROGRESS_WIDTH
|
|
482
635
|
bar_rgba = (HUD_XP_BAR_RGBA[0], HUD_XP_BAR_RGBA[1], HUD_XP_BAR_RGBA[2], HUD_XP_BAR_RGBA[3] * alpha)
|
|
483
636
|
_draw_progress_bar(sx(bar_x), sy(bar_y), sx(bar_w), progress_ratio, bar_rgba, scale)
|
|
@@ -528,35 +681,61 @@ def draw_hud_overlay(
|
|
|
528
681
|
_draw_text(font, time_text, sx(255.0), sy(10.0), text_scale, text_color)
|
|
529
682
|
max_y = max(max_y, sy(10.0 + line_h))
|
|
530
683
|
|
|
531
|
-
# Bonus HUD slots (
|
|
532
|
-
|
|
533
|
-
if
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
684
|
+
# Bonus HUD slots (icon + timers), slide in/out from the left.
|
|
685
|
+
bonus_bottom_y = float(HUD_BONUS_BASE_Y + hud_y_shift)
|
|
686
|
+
if bonus_hud is not None:
|
|
687
|
+
bonus_y = float(HUD_BONUS_BASE_Y + hud_y_shift)
|
|
688
|
+
bonus_panel_alpha = alpha * 0.7
|
|
689
|
+
bonus_text_color = _with_alpha(HUD_TEXT_COLOR, bonus_panel_alpha)
|
|
690
|
+
bar_rgba = (HUD_XP_BAR_RGBA[0], HUD_XP_BAR_RGBA[1], HUD_XP_BAR_RGBA[2], bonus_panel_alpha)
|
|
691
|
+
|
|
692
|
+
slots = bonus_hud.slots[:16]
|
|
693
|
+
for slot in slots:
|
|
694
|
+
if not slot.active:
|
|
695
|
+
continue
|
|
696
|
+
|
|
697
|
+
if slot.slide_x < -184.0:
|
|
698
|
+
bonus_y += HUD_BONUS_SPACING
|
|
699
|
+
continue
|
|
700
|
+
|
|
701
|
+
has_alt = slot.timer_ref_alt is not None and player_count > 1
|
|
702
|
+
timer = float(slot.timer_value)
|
|
703
|
+
timer_alt = float(slot.timer_value_alt) if has_alt else 0.0
|
|
704
|
+
|
|
705
|
+
# Slot panel.
|
|
537
706
|
if assets.ind_panel is not None:
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
707
|
+
if not small_indicators:
|
|
708
|
+
panel_x = slot.slide_x
|
|
709
|
+
panel_y = bonus_y + HUD_BONUS_PANEL_OFFSET_Y
|
|
710
|
+
panel_w = 182.0
|
|
711
|
+
panel_h = 53.0
|
|
712
|
+
else:
|
|
713
|
+
panel_x = (slot.slide_x - 100.0) + 4.0
|
|
714
|
+
panel_y = bonus_y + 5.0
|
|
715
|
+
panel_w = 182.0
|
|
716
|
+
panel_h = 26.5
|
|
717
|
+
|
|
545
718
|
src = rl.Rectangle(0.0, 0.0, float(assets.ind_panel.width), float(assets.ind_panel.height))
|
|
719
|
+
dst = rl.Rectangle(sx(panel_x), sy(panel_y), sx(panel_w), sy(panel_h))
|
|
546
720
|
rl.draw_texture_pro(
|
|
547
721
|
assets.ind_panel,
|
|
548
722
|
src,
|
|
549
723
|
dst,
|
|
550
724
|
rl.Vector2(0.0, 0.0),
|
|
551
725
|
0.0,
|
|
552
|
-
rl.Color(255, 255, 255, int(255 *
|
|
726
|
+
rl.Color(255, 255, 255, int(255 * bonus_panel_alpha)),
|
|
553
727
|
)
|
|
554
728
|
max_y = max(max_y, dst.y + dst.height)
|
|
555
729
|
|
|
556
|
-
|
|
730
|
+
# Slot icon.
|
|
557
731
|
if assets.bonuses is not None and slot.icon_id >= 0:
|
|
558
732
|
src = _bonus_icon_src(assets.bonuses, slot.icon_id)
|
|
559
|
-
dst = rl.Rectangle(
|
|
733
|
+
dst = rl.Rectangle(
|
|
734
|
+
sx(slot.slide_x - 1.0),
|
|
735
|
+
sy(bonus_y),
|
|
736
|
+
sx(HUD_BONUS_ICON_SIZE),
|
|
737
|
+
sy(HUD_BONUS_ICON_SIZE),
|
|
738
|
+
)
|
|
560
739
|
rl.draw_texture_pro(
|
|
561
740
|
assets.bonuses,
|
|
562
741
|
src,
|
|
@@ -565,37 +744,81 @@ def draw_hud_overlay(
|
|
|
565
744
|
0.0,
|
|
566
745
|
rl.Color(255, 255, 255, int(255 * alpha)),
|
|
567
746
|
)
|
|
568
|
-
label_x = bonus_x + sx(HUD_BONUS_TEXT_OFFSET[0])
|
|
569
|
-
icon_drawn = True
|
|
570
747
|
max_y = max(max_y, dst.y + dst.height)
|
|
748
|
+
|
|
749
|
+
# Slot timer bars.
|
|
750
|
+
if not small_indicators:
|
|
751
|
+
if not has_alt:
|
|
752
|
+
_draw_progress_bar(sx(slot.slide_x + 36.0), sy(bonus_y + 21.0), sx(100.0), timer * 0.05, bar_rgba, scale)
|
|
753
|
+
_draw_text(font, slot.label, sx(slot.slide_x + 36.0), sy(bonus_y + 6.0), text_scale, bonus_text_color)
|
|
754
|
+
else:
|
|
755
|
+
_draw_progress_bar(sx(slot.slide_x + 36.0), sy(bonus_y + 17.0), sx(100.0), timer * 0.05, bar_rgba, scale)
|
|
756
|
+
_draw_progress_bar(sx(slot.slide_x + 36.0), sy(bonus_y + 23.0), sx(100.0), timer_alt * 0.05, bar_rgba, scale)
|
|
757
|
+
_draw_text(font, slot.label, sx(slot.slide_x + 36.0), sy(bonus_y + 2.0), text_scale, bonus_text_color)
|
|
571
758
|
else:
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
759
|
+
if not has_alt:
|
|
760
|
+
_draw_progress_bar(sx(slot.slide_x + 36.0), sy(bonus_y + 17.0), sx(32.0), timer * 0.05, bar_rgba, scale)
|
|
761
|
+
else:
|
|
762
|
+
_draw_progress_bar(sx(slot.slide_x + 36.0), sy(bonus_y + 13.0), sx(32.0), timer * 0.05, bar_rgba, scale)
|
|
763
|
+
_draw_progress_bar(sx(slot.slide_x + 36.0), sy(bonus_y + 19.0), sx(32.0), timer_alt * 0.05, bar_rgba, scale)
|
|
764
|
+
|
|
765
|
+
bonus_y += HUD_BONUS_SPACING
|
|
766
|
+
max_y = max(max_y, sy(bonus_y))
|
|
767
|
+
bonus_bottom_y = bonus_y
|
|
768
|
+
|
|
769
|
+
# Weapon aux timer overlay (weapon name popup).
|
|
770
|
+
if assets.ind_panel is not None and assets.wicons is not None:
|
|
771
|
+
aux_base_y = float(bonus_bottom_y)
|
|
772
|
+
aux_step_y = 32.0
|
|
773
|
+
for idx, hud_player in enumerate(hud_players):
|
|
774
|
+
aux_timer = float(hud_player.aux_timer)
|
|
775
|
+
if aux_timer <= 0.0:
|
|
776
|
+
continue
|
|
777
|
+
|
|
778
|
+
fade = 2.0 - aux_timer if aux_timer > 1.0 else aux_timer
|
|
779
|
+
fade = max(0.0, min(1.0, fade)) * alpha
|
|
780
|
+
if fade <= 1e-3:
|
|
781
|
+
continue
|
|
782
|
+
|
|
783
|
+
panel_alpha = fade * 0.8
|
|
784
|
+
text_alpha = fade
|
|
785
|
+
|
|
786
|
+
panel_x = -12.0
|
|
787
|
+
panel_y = (aux_base_y - 17.0) + float(idx) * aux_step_y
|
|
788
|
+
panel_w = 182.0
|
|
789
|
+
panel_h = 53.0
|
|
790
|
+
|
|
791
|
+
src = rl.Rectangle(0.0, 0.0, float(assets.ind_panel.width), float(assets.ind_panel.height))
|
|
792
|
+
dst = rl.Rectangle(sx(panel_x), sy(panel_y), sx(panel_w), sy(panel_h))
|
|
793
|
+
rl.draw_texture_pro(
|
|
794
|
+
assets.ind_panel,
|
|
795
|
+
src,
|
|
796
|
+
dst,
|
|
797
|
+
rl.Vector2(0.0, 0.0),
|
|
798
|
+
0.0,
|
|
799
|
+
rl.Color(255, 255, 255, int(255 * panel_alpha)),
|
|
597
800
|
)
|
|
598
|
-
|
|
599
|
-
|
|
801
|
+
max_y = max(max_y, dst.y + dst.height)
|
|
802
|
+
|
|
803
|
+
icon_index = _weapon_icon_index(hud_player.weapon_id)
|
|
804
|
+
if icon_index is not None:
|
|
805
|
+
src = _weapon_icon_src(assets.wicons, icon_index)
|
|
806
|
+
icon_x = 105.0
|
|
807
|
+
icon_y = (aux_base_y - 5.0) + float(idx) * aux_step_y
|
|
808
|
+
dst = rl.Rectangle(sx(icon_x), sy(icon_y), sx(60.0), sy(30.0))
|
|
809
|
+
rl.draw_texture_pro(
|
|
810
|
+
assets.wicons,
|
|
811
|
+
src,
|
|
812
|
+
dst,
|
|
813
|
+
rl.Vector2(0.0, 0.0),
|
|
814
|
+
0.0,
|
|
815
|
+
rl.Color(255, 255, 255, int(255 * panel_alpha)),
|
|
816
|
+
)
|
|
817
|
+
max_y = max(max_y, dst.y + dst.height)
|
|
818
|
+
|
|
819
|
+
weapon_entry = WEAPON_BY_ID.get(int(hud_player.weapon_id))
|
|
820
|
+
weapon_name = weapon_entry.name if weapon_entry is not None else f"weapon_{int(hud_player.weapon_id)}"
|
|
821
|
+
weapon_color = _with_alpha(HUD_TEXT_COLOR, text_alpha)
|
|
822
|
+
_draw_text(font, weapon_name, sx(8.0), sy((aux_base_y + 1.0) + float(idx) * aux_step_y), text_scale, weapon_color)
|
|
600
823
|
|
|
601
824
|
return max_y
|
crimson/views/arsenal_debug.py
CHANGED
|
@@ -6,9 +6,11 @@ import random
|
|
|
6
6
|
import pyray as rl
|
|
7
7
|
|
|
8
8
|
from grim.audio import AudioState, shutdown_audio, update_audio
|
|
9
|
+
from grim.console import ConsoleState
|
|
9
10
|
from grim.fonts.small import SmallFontData, draw_small_text, load_small_font
|
|
10
11
|
from grim.view import View, ViewContext
|
|
11
12
|
|
|
13
|
+
from ..bonuses import BONUS_TABLE, BonusId
|
|
12
14
|
from ..creatures.spawn import SpawnId
|
|
13
15
|
from ..game_modes import GameMode
|
|
14
16
|
from ..game_world import GameWorld
|
|
@@ -36,6 +38,7 @@ UI_ERROR = rl.Color(240, 80, 80, 255)
|
|
|
36
38
|
|
|
37
39
|
ARSENAL_PLAYER_MOVE_SPEED_MULTIPLIER = 6.0
|
|
38
40
|
ARSENAL_PLAYER_INVULNERABLE_SHIELD_TIMER = 1e-3
|
|
41
|
+
ARSENAL_BONUS_RING_RADIUS = 140.0
|
|
39
42
|
|
|
40
43
|
DEFAULT_SPAWN_IDS = (
|
|
41
44
|
SpawnId.ZOMBIE_CONST_GREY_42,
|
|
@@ -192,6 +195,45 @@ class ArsenalDebugView:
|
|
|
192
195
|
rand=self._world.state.rng.rand,
|
|
193
196
|
)
|
|
194
197
|
|
|
198
|
+
def _spawn_all_bonuses(self) -> None:
|
|
199
|
+
player = self._player
|
|
200
|
+
if player is None:
|
|
201
|
+
return
|
|
202
|
+
|
|
203
|
+
bonus_pool = self._world.state.bonus_pool
|
|
204
|
+
bonus_pool.reset()
|
|
205
|
+
|
|
206
|
+
bonus_ids = [int(entry.bonus_id) for entry in BONUS_TABLE if int(entry.bonus_id) != int(BonusId.UNUSED)]
|
|
207
|
+
count = max(1, len(bonus_ids))
|
|
208
|
+
|
|
209
|
+
base_x = float(player.pos_x)
|
|
210
|
+
base_y = float(player.pos_y)
|
|
211
|
+
rng = self._world.state.rng.rand
|
|
212
|
+
current_weapon_id = int(player.weapon_id)
|
|
213
|
+
|
|
214
|
+
for idx, bonus_id in enumerate(bonus_ids):
|
|
215
|
+
angle = float(idx) / float(count) * math.tau
|
|
216
|
+
x = base_x + math.cos(angle) * float(ARSENAL_BONUS_RING_RADIUS)
|
|
217
|
+
y = base_y + math.sin(angle) * float(ARSENAL_BONUS_RING_RADIUS)
|
|
218
|
+
|
|
219
|
+
amount_override = -1
|
|
220
|
+
if bonus_id == int(BonusId.WEAPON) and self._weapon_ids:
|
|
221
|
+
weapon_id = int(current_weapon_id)
|
|
222
|
+
for _ in range(8):
|
|
223
|
+
weapon_id = int(self._weapon_ids[int(rng()) % len(self._weapon_ids)])
|
|
224
|
+
if weapon_id != current_weapon_id:
|
|
225
|
+
break
|
|
226
|
+
amount_override = int(weapon_id)
|
|
227
|
+
|
|
228
|
+
bonus_pool.spawn_at(
|
|
229
|
+
x,
|
|
230
|
+
y,
|
|
231
|
+
bonus_id,
|
|
232
|
+
duration_override=int(amount_override),
|
|
233
|
+
world_width=float(WORLD_SIZE),
|
|
234
|
+
world_height=float(WORLD_SIZE),
|
|
235
|
+
)
|
|
236
|
+
|
|
195
237
|
def _handle_debug_input(self) -> None:
|
|
196
238
|
if rl.is_key_pressed(rl.KeyboardKey.KEY_ESCAPE):
|
|
197
239
|
self.close_requested = True
|
|
@@ -209,6 +251,9 @@ class ArsenalDebugView:
|
|
|
209
251
|
if rl.is_key_pressed(rl.KeyboardKey.KEY_T):
|
|
210
252
|
self._reset_creatures()
|
|
211
253
|
|
|
254
|
+
if rl.is_key_pressed(rl.KeyboardKey.KEY_B):
|
|
255
|
+
self._spawn_all_bonuses()
|
|
256
|
+
|
|
212
257
|
if rl.is_key_pressed(rl.KeyboardKey.KEY_BACKSPACE):
|
|
213
258
|
self._reset_scene()
|
|
214
259
|
|
|
@@ -387,7 +432,7 @@ class ArsenalDebugView:
|
|
|
387
432
|
|
|
388
433
|
y += 6.0
|
|
389
434
|
self._draw_ui_text(
|
|
390
|
-
"WASD move LMB fire R reload [/] cycle weapons Space pause T respawn Backspace reset Esc quit",
|
|
435
|
+
"WASD move LMB fire R reload [/] cycle weapons Space pause T respawn B spawn all bonuses Backspace reset Esc quit",
|
|
391
436
|
x,
|
|
392
437
|
y,
|
|
393
438
|
UI_HINT,
|
crimson/views/player.py
CHANGED
|
@@ -206,7 +206,7 @@ class PlayerSandboxView:
|
|
|
206
206
|
self._player.shield_timer = 0.0
|
|
207
207
|
self._player.speed_bonus_timer = 0.0
|
|
208
208
|
self._player.fire_bullets_timer = 0.0
|
|
209
|
-
bonus_hud_update(self._state, [self._player])
|
|
209
|
+
bonus_hud_update(self._state, [self._player], dt=0.0)
|
|
210
210
|
|
|
211
211
|
def _camera_world_to_screen(self, x: float, y: float) -> tuple[float, float]:
|
|
212
212
|
return self._camera_x + x, self._camera_y + y
|
|
@@ -308,7 +308,7 @@ class PlayerSandboxView:
|
|
|
308
308
|
input_state = self._build_input()
|
|
309
309
|
player_update(self._player, input_state, dt, self._state, world_size=WORLD_SIZE)
|
|
310
310
|
|
|
311
|
-
bonus_hud_update(self._state, [self._player])
|
|
311
|
+
bonus_hud_update(self._state, [self._player], dt=dt)
|
|
312
312
|
self._update_camera(dt)
|
|
313
313
|
|
|
314
314
|
def draw(self) -> None:
|