crimsonland 0.1.0.dev7__py3-none-any.whl → 0.1.0.dev9__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/creatures/anim.py +1 -0
- crimson/game.py +5 -0
- crimson/gameplay.py +33 -8
- 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/render/world_renderer.py +12 -16
- crimson/ui/hud.py +274 -51
- crimson/views/arsenal_debug.py +46 -1
- crimson/views/player.py +2 -2
- {crimsonland-0.1.0.dev7.dist-info → crimsonland-0.1.0.dev9.dist-info}/METADATA +1 -1
- {crimsonland-0.1.0.dev7.dist-info → crimsonland-0.1.0.dev9.dist-info}/RECORD +18 -18
- grim/console.py +14 -0
- {crimsonland-0.1.0.dev7.dist-info → crimsonland-0.1.0.dev9.dist-info}/WHEEL +0 -0
- {crimsonland-0.1.0.dev7.dist-info → crimsonland-0.1.0.dev9.dist-info}/entry_points.txt +0 -0
crimson/modes/survival_mode.py
CHANGED
|
@@ -7,6 +7,7 @@ import pyray as rl
|
|
|
7
7
|
|
|
8
8
|
from grim.assets import PaqTextureCache
|
|
9
9
|
from grim.audio import AudioState
|
|
10
|
+
from grim.console import ConsoleState
|
|
10
11
|
from grim.config import CrimsonConfig
|
|
11
12
|
from grim.view import ViewContext
|
|
12
13
|
|
|
@@ -17,7 +18,7 @@ from ..gameplay import PlayerInput, most_used_weapon_id_for_player, perk_selecti
|
|
|
17
18
|
from ..persistence.highscores import HighScoreRecord
|
|
18
19
|
from ..perks import PerkId, perk_display_description, perk_display_name
|
|
19
20
|
from ..ui.cursor import draw_aim_cursor, draw_menu_cursor
|
|
20
|
-
from ..ui.hud import draw_hud_overlay
|
|
21
|
+
from ..ui.hud import draw_hud_overlay, hud_flags_for_game_mode
|
|
21
22
|
from ..input_codes import config_keybinds, input_code_is_down, input_code_is_pressed, player_move_fire_binds
|
|
22
23
|
from ..ui.perk_menu import (
|
|
23
24
|
PerkMenuLayout,
|
|
@@ -85,6 +86,7 @@ class SurvivalMode(BaseGameplayMode):
|
|
|
85
86
|
*,
|
|
86
87
|
texture_cache: PaqTextureCache | None = None,
|
|
87
88
|
config: CrimsonConfig | None = None,
|
|
89
|
+
console: ConsoleState | None = None,
|
|
88
90
|
audio: AudioState | None = None,
|
|
89
91
|
audio_rng: random.Random | None = None,
|
|
90
92
|
) -> None:
|
|
@@ -97,6 +99,7 @@ class SurvivalMode(BaseGameplayMode):
|
|
|
97
99
|
hardcore=False,
|
|
98
100
|
texture_cache=texture_cache,
|
|
99
101
|
config=config,
|
|
102
|
+
console=console,
|
|
100
103
|
audio=audio,
|
|
101
104
|
audio_rng=audio_rng,
|
|
102
105
|
)
|
|
@@ -744,6 +747,8 @@ class SurvivalMode(BaseGameplayMode):
|
|
|
744
747
|
hud_bottom = 0.0
|
|
745
748
|
if (not self._game_over_active) and (not perk_menu_active) and self._hud_assets is not None:
|
|
746
749
|
hud_alpha = _clamp(self._hud_fade_ms / PERK_MENU_TRANSITION_MS, 0.0, 1.0)
|
|
750
|
+
hud_flags = hud_flags_for_game_mode(self._config_game_mode_id())
|
|
751
|
+
self._draw_target_health_bar(alpha=hud_alpha)
|
|
747
752
|
hud_bottom = draw_hud_overlay(
|
|
748
753
|
self._hud_assets,
|
|
749
754
|
player=self._player,
|
|
@@ -754,9 +759,15 @@ class SurvivalMode(BaseGameplayMode):
|
|
|
754
759
|
font=self._small,
|
|
755
760
|
alpha=hud_alpha,
|
|
756
761
|
frame_dt_ms=self._last_dt_ms,
|
|
762
|
+
show_health=hud_flags.show_health,
|
|
763
|
+
show_weapon=hud_flags.show_weapon,
|
|
764
|
+
show_xp=hud_flags.show_xp,
|
|
765
|
+
show_time=hud_flags.show_time,
|
|
766
|
+
show_quest_hud=hud_flags.show_quest_hud,
|
|
767
|
+
small_indicators=self._hud_small_indicators(),
|
|
757
768
|
)
|
|
758
769
|
|
|
759
|
-
if (not self._game_over_active) and (not perk_menu_active):
|
|
770
|
+
if debug_enabled() and (not self._game_over_active) and (not perk_menu_active):
|
|
760
771
|
# Minimal debug text.
|
|
761
772
|
x = 18.0
|
|
762
773
|
y = max(18.0, hud_bottom + 10.0)
|
crimson/modes/tutorial_mode.py
CHANGED
|
@@ -8,6 +8,7 @@ import pyray as rl
|
|
|
8
8
|
|
|
9
9
|
from grim.assets import PaqTextureCache
|
|
10
10
|
from grim.audio import AudioState
|
|
11
|
+
from grim.console import ConsoleState
|
|
11
12
|
from grim.config import CrimsonConfig
|
|
12
13
|
from grim.view import ViewContext
|
|
13
14
|
|
|
@@ -19,7 +20,7 @@ from ..input_codes import config_keybinds, input_code_is_down, input_code_is_pre
|
|
|
19
20
|
from ..perks import PerkId, perk_display_description, perk_display_name
|
|
20
21
|
from ..tutorial.timeline import TutorialFrameActions, TutorialState, tick_tutorial_timeline
|
|
21
22
|
from ..ui.cursor import draw_aim_cursor, draw_menu_cursor
|
|
22
|
-
from ..ui.hud import draw_hud_overlay, hud_ui_scale
|
|
23
|
+
from ..ui.hud import draw_hud_overlay, hud_flags_for_game_mode, hud_ui_scale
|
|
23
24
|
from ..ui.perk_menu import (
|
|
24
25
|
PerkMenuAssets,
|
|
25
26
|
PerkMenuLayout,
|
|
@@ -69,6 +70,7 @@ class TutorialMode(BaseGameplayMode):
|
|
|
69
70
|
demo_mode_active: bool = False,
|
|
70
71
|
texture_cache: PaqTextureCache | None = None,
|
|
71
72
|
config: CrimsonConfig | None = None,
|
|
73
|
+
console: ConsoleState | None = None,
|
|
72
74
|
audio: AudioState | None = None,
|
|
73
75
|
audio_rng: random.Random | None = None,
|
|
74
76
|
) -> None:
|
|
@@ -81,6 +83,7 @@ class TutorialMode(BaseGameplayMode):
|
|
|
81
83
|
hardcore=False,
|
|
82
84
|
texture_cache=texture_cache,
|
|
83
85
|
config=config,
|
|
86
|
+
console=console,
|
|
84
87
|
audio=audio,
|
|
85
88
|
audio_rng=audio_rng,
|
|
86
89
|
)
|
|
@@ -453,6 +456,8 @@ class TutorialMode(BaseGameplayMode):
|
|
|
453
456
|
|
|
454
457
|
hud_bottom = 0.0
|
|
455
458
|
if (not perk_menu_active) and self._hud_assets is not None:
|
|
459
|
+
hud_flags = hud_flags_for_game_mode(self._config_game_mode_id())
|
|
460
|
+
self._draw_target_health_bar()
|
|
456
461
|
hud_bottom = draw_hud_overlay(
|
|
457
462
|
self._hud_assets,
|
|
458
463
|
player=self._player,
|
|
@@ -463,6 +468,12 @@ class TutorialMode(BaseGameplayMode):
|
|
|
463
468
|
font=self._small,
|
|
464
469
|
alpha=1.0,
|
|
465
470
|
frame_dt_ms=self._last_dt_ms,
|
|
471
|
+
show_health=hud_flags.show_health,
|
|
472
|
+
show_weapon=hud_flags.show_weapon,
|
|
473
|
+
show_xp=hud_flags.show_xp,
|
|
474
|
+
show_time=hud_flags.show_time,
|
|
475
|
+
show_quest_hud=hud_flags.show_quest_hud,
|
|
476
|
+
small_indicators=self._hud_small_indicators(),
|
|
466
477
|
)
|
|
467
478
|
|
|
468
479
|
self._draw_tutorial_prompts(hud_bottom=hud_bottom)
|
crimson/modes/typo_mode.py
CHANGED
|
@@ -8,6 +8,7 @@ import pyray as rl
|
|
|
8
8
|
|
|
9
9
|
from grim.assets import PaqTextureCache
|
|
10
10
|
from grim.audio import AudioState
|
|
11
|
+
from grim.console import ConsoleState
|
|
11
12
|
from grim.config import CrimsonConfig
|
|
12
13
|
from grim.view import ViewContext
|
|
13
14
|
|
|
@@ -20,7 +21,7 @@ from ..typo.names import CreatureNameTable, load_typo_dictionary
|
|
|
20
21
|
from ..typo.spawns import tick_typo_spawns
|
|
21
22
|
from ..typo.typing import TypingBuffer
|
|
22
23
|
from ..ui.cursor import draw_aim_cursor, draw_menu_cursor
|
|
23
|
-
from ..ui.hud import draw_hud_overlay
|
|
24
|
+
from ..ui.hud import draw_hud_overlay, hud_flags_for_game_mode
|
|
24
25
|
from ..ui.perk_menu import load_perk_menu_assets
|
|
25
26
|
from .base_gameplay_mode import BaseGameplayMode
|
|
26
27
|
|
|
@@ -56,6 +57,7 @@ class TypoShooterMode(BaseGameplayMode):
|
|
|
56
57
|
*,
|
|
57
58
|
texture_cache: PaqTextureCache | None = None,
|
|
58
59
|
config: CrimsonConfig | None = None,
|
|
60
|
+
console: ConsoleState | None = None,
|
|
59
61
|
audio: AudioState | None = None,
|
|
60
62
|
audio_rng: random.Random | None = None,
|
|
61
63
|
) -> None:
|
|
@@ -68,6 +70,7 @@ class TypoShooterMode(BaseGameplayMode):
|
|
|
68
70
|
hardcore=False,
|
|
69
71
|
texture_cache=texture_cache,
|
|
70
72
|
config=config,
|
|
73
|
+
console=console,
|
|
71
74
|
audio=audio,
|
|
72
75
|
audio_rng=audio_rng,
|
|
73
76
|
)
|
|
@@ -434,6 +437,8 @@ class TypoShooterMode(BaseGameplayMode):
|
|
|
434
437
|
self._draw_name_labels()
|
|
435
438
|
|
|
436
439
|
if show_gameplay_ui and self._hud_assets is not None:
|
|
440
|
+
hud_flags = hud_flags_for_game_mode(self._config_game_mode_id())
|
|
441
|
+
self._draw_target_health_bar()
|
|
437
442
|
draw_hud_overlay(
|
|
438
443
|
self._hud_assets,
|
|
439
444
|
player=self._player,
|
|
@@ -442,9 +447,12 @@ class TypoShooterMode(BaseGameplayMode):
|
|
|
442
447
|
elapsed_ms=float(self._typo.elapsed_ms),
|
|
443
448
|
font=self._small,
|
|
444
449
|
frame_dt_ms=self._last_dt_ms,
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
450
|
+
show_health=hud_flags.show_health,
|
|
451
|
+
show_weapon=hud_flags.show_weapon,
|
|
452
|
+
show_xp=hud_flags.show_xp,
|
|
453
|
+
show_time=hud_flags.show_time,
|
|
454
|
+
show_quest_hud=hud_flags.show_quest_hud,
|
|
455
|
+
small_indicators=self._hud_small_indicators(),
|
|
448
456
|
)
|
|
449
457
|
|
|
450
458
|
if show_gameplay_ui:
|
crimson/render/world_renderer.py
CHANGED
|
@@ -939,24 +939,20 @@ class WorldRenderer:
|
|
|
939
939
|
# Native: chain reach is derived from the streak scale (`fVar29 * perk_scale * 40.0`).
|
|
940
940
|
radius = effect_scale * perk_scale * 40.0
|
|
941
941
|
|
|
942
|
-
#
|
|
943
|
-
|
|
944
|
-
for creature in self.creatures.entries:
|
|
945
|
-
if not creature.active
|
|
942
|
+
# Native iterates via creature_find_in_radius(pos, radius, start_index) in pool order.
|
|
943
|
+
targets: list[object] = []
|
|
944
|
+
for creature in self.creatures.entries[1:]:
|
|
945
|
+
if not creature.active:
|
|
946
946
|
continue
|
|
947
|
-
if float(getattr(creature, "hitbox_size", 0.0))
|
|
947
|
+
if float(getattr(creature, "hitbox_size", 0.0)) <= 5.0:
|
|
948
948
|
continue
|
|
949
949
|
d = math.hypot(float(creature.x) - pos_x, float(creature.y) - pos_y)
|
|
950
950
|
threshold = float(creature.size) * 0.142857149 + 3.0
|
|
951
|
-
if d
|
|
952
|
-
|
|
953
|
-
candidates.append((d, creature))
|
|
954
|
-
|
|
955
|
-
candidates.sort(key=lambda item: item[0])
|
|
956
|
-
targets = [creature for _d, creature in candidates[:8]]
|
|
951
|
+
if d - radius < threshold:
|
|
952
|
+
targets.append(creature)
|
|
957
953
|
|
|
958
|
-
|
|
959
|
-
|
|
954
|
+
inner_half = 10.0 * perk_scale * scale
|
|
955
|
+
outer_half = 14.0 * perk_scale * scale
|
|
960
956
|
u = 0.625
|
|
961
957
|
v0 = 0.0
|
|
962
958
|
v1 = 0.25
|
|
@@ -980,7 +976,7 @@ class WorldRenderer:
|
|
|
980
976
|
py = nx
|
|
981
977
|
|
|
982
978
|
# Outer strip (softer).
|
|
983
|
-
half =
|
|
979
|
+
half = outer_half
|
|
984
980
|
off_x = px * half
|
|
985
981
|
off_y = py * half
|
|
986
982
|
x0 = sx - off_x
|
|
@@ -992,7 +988,7 @@ class WorldRenderer:
|
|
|
992
988
|
x3 = tx - off_x
|
|
993
989
|
y3 = ty - off_y
|
|
994
990
|
|
|
995
|
-
outer_tint = self._color_from_rgba((0.5, 0.6, 1.0, base_alpha
|
|
991
|
+
outer_tint = self._color_from_rgba((0.5, 0.6, 1.0, base_alpha))
|
|
996
992
|
rl.rl_color4ub(outer_tint.r, outer_tint.g, outer_tint.b, outer_tint.a)
|
|
997
993
|
rl.rl_tex_coord2f(u, v0)
|
|
998
994
|
rl.rl_vertex2f(x0, y0)
|
|
@@ -1004,7 +1000,7 @@ class WorldRenderer:
|
|
|
1004
1000
|
rl.rl_vertex2f(x3, y3)
|
|
1005
1001
|
|
|
1006
1002
|
# Inner strip (brighter).
|
|
1007
|
-
half =
|
|
1003
|
+
half = inner_half
|
|
1008
1004
|
off_x = px * half
|
|
1009
1005
|
off_y = py * half
|
|
1010
1006
|
x0 = sx - off_x
|
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
|