crimsonland 0.1.0.dev15__py3-none-any.whl → 0.1.0.dev16__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- crimson/cli.py +61 -0
- crimson/creatures/damage.py +111 -36
- crimson/creatures/runtime.py +246 -156
- crimson/creatures/spawn.py +7 -3
- 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 +441 -1
- crimson/gameplay.py +905 -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 +58 -273
- crimson/modes/rush_mode.py +12 -43
- crimson/modes/survival_mode.py +71 -328
- 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 +94 -37
- 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 +12 -64
- 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.dev15.dist-info → crimsonland-0.1.0.dev16.dist-info}/METADATA +1 -1
- {crimsonland-0.1.0.dev15.dist-info → crimsonland-0.1.0.dev16.dist-info}/RECORD +72 -64
- {crimsonland-0.1.0.dev15.dist-info → crimsonland-0.1.0.dev16.dist-info}/WHEEL +2 -2
- grim/config.py +29 -1
- grim/console.py +7 -10
- grim/math.py +12 -0
- crimson/.DS_Store +0 -0
- crimson/creatures/.DS_Store +0 -0
- grim/.DS_Store +0 -0
- {crimsonland-0.1.0.dev15.dist-info → crimsonland-0.1.0.dev16.dist-info}/entry_points.txt +0 -0
crimson/game.py
CHANGED
|
@@ -57,12 +57,78 @@ from .frontend.high_scores_layout import (
|
|
|
57
57
|
HS_BUTTON_STEP_Y,
|
|
58
58
|
HS_BUTTON_X,
|
|
59
59
|
HS_BUTTON_Y0,
|
|
60
|
+
HS_LOCAL_DATE_X,
|
|
61
|
+
HS_LOCAL_DATE_Y,
|
|
62
|
+
HS_LOCAL_FRAGS_X,
|
|
63
|
+
HS_LOCAL_FRAGS_Y,
|
|
64
|
+
HS_LOCAL_HIT_X,
|
|
65
|
+
HS_LOCAL_HIT_Y,
|
|
66
|
+
HS_LOCAL_LABEL_X,
|
|
67
|
+
HS_LOCAL_LABEL_Y,
|
|
68
|
+
HS_LOCAL_NAME_X,
|
|
69
|
+
HS_LOCAL_NAME_Y,
|
|
70
|
+
HS_LOCAL_RANK_X,
|
|
71
|
+
HS_LOCAL_RANK_Y,
|
|
72
|
+
HS_LOCAL_SCORE_LABEL_X,
|
|
73
|
+
HS_LOCAL_SCORE_LABEL_Y,
|
|
74
|
+
HS_LOCAL_SCORE_VALUE_X,
|
|
75
|
+
HS_LOCAL_SCORE_VALUE_Y,
|
|
76
|
+
HS_LOCAL_TIME_LABEL_X,
|
|
77
|
+
HS_LOCAL_TIME_LABEL_Y,
|
|
78
|
+
HS_LOCAL_TIME_VALUE_X,
|
|
79
|
+
HS_LOCAL_TIME_VALUE_Y,
|
|
80
|
+
HS_LOCAL_WEAPON_X,
|
|
81
|
+
HS_LOCAL_WEAPON_Y,
|
|
82
|
+
HS_LOCAL_WICON_X,
|
|
83
|
+
HS_LOCAL_WICON_Y,
|
|
60
84
|
HS_LEFT_PANEL_HEIGHT,
|
|
61
85
|
HS_LEFT_PANEL_POS_X,
|
|
62
86
|
HS_LEFT_PANEL_POS_Y,
|
|
87
|
+
HS_QUEST_ARROW_X,
|
|
88
|
+
HS_QUEST_ARROW_Y,
|
|
89
|
+
HS_RIGHT_CHECK_X,
|
|
90
|
+
HS_RIGHT_CHECK_Y,
|
|
63
91
|
HS_RIGHT_PANEL_HEIGHT,
|
|
64
92
|
HS_RIGHT_PANEL_POS_X,
|
|
65
93
|
HS_RIGHT_PANEL_POS_Y,
|
|
94
|
+
HS_RIGHT_GAME_MODE_DROP_X,
|
|
95
|
+
HS_RIGHT_GAME_MODE_DROP_Y,
|
|
96
|
+
HS_RIGHT_GAME_MODE_VALUE_X,
|
|
97
|
+
HS_RIGHT_GAME_MODE_VALUE_Y,
|
|
98
|
+
HS_RIGHT_GAME_MODE_WIDGET_W,
|
|
99
|
+
HS_RIGHT_GAME_MODE_WIDGET_X,
|
|
100
|
+
HS_RIGHT_GAME_MODE_WIDGET_Y,
|
|
101
|
+
HS_RIGHT_GAME_MODE_X,
|
|
102
|
+
HS_RIGHT_GAME_MODE_Y,
|
|
103
|
+
HS_RIGHT_NUMBER_PLAYERS_X,
|
|
104
|
+
HS_RIGHT_NUMBER_PLAYERS_Y,
|
|
105
|
+
HS_RIGHT_PLAYER_COUNT_DROP_X,
|
|
106
|
+
HS_RIGHT_PLAYER_COUNT_DROP_Y,
|
|
107
|
+
HS_RIGHT_PLAYER_COUNT_VALUE_X,
|
|
108
|
+
HS_RIGHT_PLAYER_COUNT_VALUE_Y,
|
|
109
|
+
HS_RIGHT_PLAYER_COUNT_WIDGET_W,
|
|
110
|
+
HS_RIGHT_PLAYER_COUNT_WIDGET_X,
|
|
111
|
+
HS_RIGHT_PLAYER_COUNT_WIDGET_Y,
|
|
112
|
+
HS_RIGHT_SCORE_LIST_DROP_X,
|
|
113
|
+
HS_RIGHT_SCORE_LIST_DROP_Y,
|
|
114
|
+
HS_RIGHT_SCORE_LIST_VALUE_X,
|
|
115
|
+
HS_RIGHT_SCORE_LIST_VALUE_Y,
|
|
116
|
+
HS_RIGHT_SCORE_LIST_WIDGET_W,
|
|
117
|
+
HS_RIGHT_SCORE_LIST_WIDGET_X,
|
|
118
|
+
HS_RIGHT_SCORE_LIST_WIDGET_Y,
|
|
119
|
+
HS_RIGHT_SCORE_LIST_X,
|
|
120
|
+
HS_RIGHT_SCORE_LIST_Y,
|
|
121
|
+
HS_RIGHT_SHOW_INTERNET_X,
|
|
122
|
+
HS_RIGHT_SHOW_INTERNET_Y,
|
|
123
|
+
HS_RIGHT_SHOW_SCORES_DROP_X,
|
|
124
|
+
HS_RIGHT_SHOW_SCORES_DROP_Y,
|
|
125
|
+
HS_RIGHT_SHOW_SCORES_VALUE_X,
|
|
126
|
+
HS_RIGHT_SHOW_SCORES_VALUE_Y,
|
|
127
|
+
HS_RIGHT_SHOW_SCORES_WIDGET_W,
|
|
128
|
+
HS_RIGHT_SHOW_SCORES_WIDGET_X,
|
|
129
|
+
HS_RIGHT_SHOW_SCORES_WIDGET_Y,
|
|
130
|
+
HS_RIGHT_SHOW_SCORES_X,
|
|
131
|
+
HS_RIGHT_SHOW_SCORES_Y,
|
|
66
132
|
)
|
|
67
133
|
from .frontend.menu import (
|
|
68
134
|
MENU_PANEL_HEIGHT,
|
|
@@ -1801,6 +1867,10 @@ class HighScoresView:
|
|
|
1801
1867
|
self._small_font: SmallFontData | None = None
|
|
1802
1868
|
self._button_tex: rl.Texture2D | None = None
|
|
1803
1869
|
self._button_textures: UiButtonTextureSet | None = None
|
|
1870
|
+
self._check_on: rl.Texture2D | None = None
|
|
1871
|
+
self._drop_off: rl.Texture2D | None = None
|
|
1872
|
+
self._arrow_tex: rl.Texture2D | None = None
|
|
1873
|
+
self._wicons_tex: rl.Texture2D | None = None
|
|
1804
1874
|
self._update_button = UiButtonState("Update scores", force_wide=True)
|
|
1805
1875
|
self._play_button = UiButtonState("Play a game", force_wide=True)
|
|
1806
1876
|
self._back_button = UiButtonState("Back", force_wide=False)
|
|
@@ -1831,6 +1901,16 @@ class HighScoresView:
|
|
|
1831
1901
|
self._button_tex = cache.get_or_load("ui_buttonMd", "ui/ui_button_128x32.jaz").texture
|
|
1832
1902
|
button_sm = cache.get_or_load("ui_buttonSm", "ui/ui_button_64x32.jaz").texture
|
|
1833
1903
|
self._button_textures = UiButtonTextureSet(button_sm=button_sm, button_md=self._button_tex)
|
|
1904
|
+
self._check_on = cache.get_or_load("ui_checkOn", "ui/ui_checkOn.jaz").texture
|
|
1905
|
+
self._drop_off = cache.get_or_load("ui_dropOff", "ui/ui_dropDownOff.jaz").texture
|
|
1906
|
+
self._arrow_tex = cache.get_or_load("ui_arrow", "ui/ui_arrow.jaz").texture
|
|
1907
|
+
|
|
1908
|
+
if self._wicons_tex is not None:
|
|
1909
|
+
rl.unload_texture(self._wicons_tex)
|
|
1910
|
+
self._wicons_tex = None
|
|
1911
|
+
wicons_path = self._state.assets_dir / "crimson" / "ui" / "ui_wicons.png"
|
|
1912
|
+
if wicons_path.is_file():
|
|
1913
|
+
self._wicons_tex = rl.load_texture(str(wicons_path))
|
|
1834
1914
|
|
|
1835
1915
|
request = self._state.pending_high_scores
|
|
1836
1916
|
self._state.pending_high_scores = None
|
|
@@ -1866,9 +1946,15 @@ class HighScoresView:
|
|
|
1866
1946
|
if self._small_font is not None:
|
|
1867
1947
|
rl.unload_texture(self._small_font.texture)
|
|
1868
1948
|
self._small_font = None
|
|
1949
|
+
if self._wicons_tex is not None:
|
|
1950
|
+
rl.unload_texture(self._wicons_tex)
|
|
1951
|
+
self._wicons_tex = None
|
|
1869
1952
|
self._assets = None
|
|
1870
1953
|
self._button_tex = None
|
|
1871
1954
|
self._button_textures = None
|
|
1955
|
+
self._check_on = None
|
|
1956
|
+
self._drop_off = None
|
|
1957
|
+
self._arrow_tex = None
|
|
1872
1958
|
self._request = None
|
|
1873
1959
|
self._records = []
|
|
1874
1960
|
self._scroll_index = 0
|
|
@@ -2022,10 +2108,22 @@ class HighScoresView:
|
|
|
2022
2108
|
)
|
|
2023
2109
|
|
|
2024
2110
|
title = "High scores - Quests" if int(mode_id) == 3 else f"High scores - {self._mode_label(mode_id, quest_major, quest_minor)}"
|
|
2025
|
-
|
|
2111
|
+
title_x = 269.0
|
|
2112
|
+
if int(mode_id) == 1:
|
|
2113
|
+
# state_14:High scores - Survival title at x=168 (panel left_x0 is -98).
|
|
2114
|
+
title_x = 266.0
|
|
2115
|
+
draw_small_text(font, title, left_x0 + title_x * scale, left_y0 + 41.0 * scale, 1.0 * scale, rl.Color(255, 255, 255, 255))
|
|
2026
2116
|
if int(mode_id) == 3:
|
|
2027
2117
|
quest_label = f"{int(quest_major)}.{int(quest_minor)}: {self._quest_title(quest_major, quest_minor)}"
|
|
2028
2118
|
draw_small_text(font, quest_label, left_x0 + 236.0 * scale, left_y0 + 63.0 * scale, 1.0 * scale, rl.Color(255, 255, 255, 255))
|
|
2119
|
+
arrow = self._arrow_tex
|
|
2120
|
+
if arrow is not None:
|
|
2121
|
+
dst_w = float(arrow.width) * scale
|
|
2122
|
+
dst_h = float(arrow.height) * scale
|
|
2123
|
+
# state_14 draws ui_arrow.jaz flipped (uv 1..0) to point left.
|
|
2124
|
+
src = rl.Rectangle(float(arrow.width), 0.0, -float(arrow.width), float(arrow.height))
|
|
2125
|
+
dst = rl.Rectangle(left_x0 + HS_QUEST_ARROW_X * scale, left_y0 + HS_QUEST_ARROW_Y * scale, dst_w, dst_h)
|
|
2126
|
+
rl.draw_texture_pro(arrow, src, dst, rl.Vector2(0.0, 0.0), 0.0, rl.WHITE)
|
|
2029
2127
|
|
|
2030
2128
|
header_color = rl.Color(255, 255, 255, int(255 * 0.85))
|
|
2031
2129
|
row_y0 = left_y0 + 84.0 * scale
|
|
@@ -2084,9 +2182,351 @@ class HighScoresView:
|
|
|
2084
2182
|
scale=scale,
|
|
2085
2183
|
)
|
|
2086
2184
|
|
|
2185
|
+
self._draw_right_panel(font=font, right_x0=right_x0, right_y0=right_y0, scale=scale, mode_id=mode_id, highlight_rank=highlight_rank)
|
|
2087
2186
|
self._draw_sign(assets)
|
|
2088
2187
|
_draw_menu_cursor(self._state, pulse_time=self._cursor_pulse_time)
|
|
2089
2188
|
|
|
2189
|
+
def _draw_right_panel(
|
|
2190
|
+
self,
|
|
2191
|
+
*,
|
|
2192
|
+
font: SmallFontData,
|
|
2193
|
+
right_x0: float,
|
|
2194
|
+
right_y0: float,
|
|
2195
|
+
scale: float,
|
|
2196
|
+
mode_id: int,
|
|
2197
|
+
highlight_rank: int | None,
|
|
2198
|
+
) -> None:
|
|
2199
|
+
if int(mode_id) == 3:
|
|
2200
|
+
self._draw_right_panel_quest_options(font=font, right_x0=right_x0, right_y0=right_y0, scale=scale)
|
|
2201
|
+
return
|
|
2202
|
+
self._draw_right_panel_local_score(
|
|
2203
|
+
font=font,
|
|
2204
|
+
right_x0=right_x0,
|
|
2205
|
+
right_y0=right_y0,
|
|
2206
|
+
scale=scale,
|
|
2207
|
+
highlight_rank=highlight_rank,
|
|
2208
|
+
)
|
|
2209
|
+
|
|
2210
|
+
def _draw_right_panel_quest_options(self, *, font: SmallFontData, right_x0: float, right_y0: float, scale: float) -> None:
|
|
2211
|
+
text_scale = 1.0 * scale
|
|
2212
|
+
text_color = rl.Color(255, 255, 255, int(255 * 0.8))
|
|
2213
|
+
|
|
2214
|
+
check_on = self._check_on
|
|
2215
|
+
if check_on is not None:
|
|
2216
|
+
check_w = float(check_on.width) * scale
|
|
2217
|
+
check_h = float(check_on.height) * scale
|
|
2218
|
+
rl.draw_texture_pro(
|
|
2219
|
+
check_on,
|
|
2220
|
+
rl.Rectangle(0.0, 0.0, float(check_on.width), float(check_on.height)),
|
|
2221
|
+
rl.Rectangle(right_x0 + HS_RIGHT_CHECK_X * scale, right_y0 + HS_RIGHT_CHECK_Y * scale, check_w, check_h),
|
|
2222
|
+
rl.Vector2(0.0, 0.0),
|
|
2223
|
+
0.0,
|
|
2224
|
+
rl.WHITE,
|
|
2225
|
+
)
|
|
2226
|
+
draw_small_text(
|
|
2227
|
+
font,
|
|
2228
|
+
"Show internet scores",
|
|
2229
|
+
right_x0 + HS_RIGHT_SHOW_INTERNET_X * scale,
|
|
2230
|
+
right_y0 + HS_RIGHT_SHOW_INTERNET_Y * scale,
|
|
2231
|
+
text_scale,
|
|
2232
|
+
text_color,
|
|
2233
|
+
)
|
|
2234
|
+
draw_small_text(
|
|
2235
|
+
font,
|
|
2236
|
+
"Number of players",
|
|
2237
|
+
right_x0 + HS_RIGHT_NUMBER_PLAYERS_X * scale,
|
|
2238
|
+
right_y0 + HS_RIGHT_NUMBER_PLAYERS_Y * scale,
|
|
2239
|
+
text_scale,
|
|
2240
|
+
text_color,
|
|
2241
|
+
)
|
|
2242
|
+
draw_small_text(
|
|
2243
|
+
font,
|
|
2244
|
+
"Game mode",
|
|
2245
|
+
right_x0 + HS_RIGHT_GAME_MODE_X * scale,
|
|
2246
|
+
right_y0 + HS_RIGHT_GAME_MODE_Y * scale,
|
|
2247
|
+
text_scale,
|
|
2248
|
+
text_color,
|
|
2249
|
+
)
|
|
2250
|
+
draw_small_text(
|
|
2251
|
+
font,
|
|
2252
|
+
"Show scores:",
|
|
2253
|
+
right_x0 + HS_RIGHT_SHOW_SCORES_X * scale,
|
|
2254
|
+
right_y0 + HS_RIGHT_SHOW_SCORES_Y * scale,
|
|
2255
|
+
text_scale,
|
|
2256
|
+
text_color,
|
|
2257
|
+
)
|
|
2258
|
+
draw_small_text(
|
|
2259
|
+
font,
|
|
2260
|
+
"Selected score list:",
|
|
2261
|
+
right_x0 + HS_RIGHT_SCORE_LIST_X * scale,
|
|
2262
|
+
right_y0 + HS_RIGHT_SCORE_LIST_Y * scale,
|
|
2263
|
+
text_scale,
|
|
2264
|
+
text_color,
|
|
2265
|
+
)
|
|
2266
|
+
|
|
2267
|
+
# Closed list widgets (state_14 quest variant): white border + black fill.
|
|
2268
|
+
widget_h = 16.0 * scale
|
|
2269
|
+
for wx, wy, ww in (
|
|
2270
|
+
(HS_RIGHT_PLAYER_COUNT_WIDGET_X, HS_RIGHT_PLAYER_COUNT_WIDGET_Y, HS_RIGHT_PLAYER_COUNT_WIDGET_W),
|
|
2271
|
+
(HS_RIGHT_GAME_MODE_WIDGET_X, HS_RIGHT_GAME_MODE_WIDGET_Y, HS_RIGHT_GAME_MODE_WIDGET_W),
|
|
2272
|
+
(HS_RIGHT_SHOW_SCORES_WIDGET_X, HS_RIGHT_SHOW_SCORES_WIDGET_Y, HS_RIGHT_SHOW_SCORES_WIDGET_W),
|
|
2273
|
+
(HS_RIGHT_SCORE_LIST_WIDGET_X, HS_RIGHT_SCORE_LIST_WIDGET_Y, HS_RIGHT_SCORE_LIST_WIDGET_W),
|
|
2274
|
+
):
|
|
2275
|
+
x = right_x0 + float(wx) * scale
|
|
2276
|
+
y = right_y0 + float(wy) * scale
|
|
2277
|
+
w = float(ww) * scale
|
|
2278
|
+
rl.draw_rectangle(int(x), int(y), int(w), int(widget_h), rl.WHITE)
|
|
2279
|
+
rl.draw_rectangle(int(x) + 1, int(y) + 1, max(0, int(w) - 2), max(0, int(widget_h) - 2), rl.BLACK)
|
|
2280
|
+
|
|
2281
|
+
# Values (static in the oracle).
|
|
2282
|
+
draw_small_text(
|
|
2283
|
+
font,
|
|
2284
|
+
"1 player",
|
|
2285
|
+
right_x0 + HS_RIGHT_PLAYER_COUNT_VALUE_X * scale,
|
|
2286
|
+
right_y0 + HS_RIGHT_PLAYER_COUNT_VALUE_Y * scale,
|
|
2287
|
+
text_scale,
|
|
2288
|
+
text_color,
|
|
2289
|
+
)
|
|
2290
|
+
draw_small_text(
|
|
2291
|
+
font,
|
|
2292
|
+
"Quests",
|
|
2293
|
+
right_x0 + HS_RIGHT_GAME_MODE_VALUE_X * scale,
|
|
2294
|
+
right_y0 + HS_RIGHT_GAME_MODE_VALUE_Y * scale,
|
|
2295
|
+
text_scale,
|
|
2296
|
+
text_color,
|
|
2297
|
+
)
|
|
2298
|
+
draw_small_text(
|
|
2299
|
+
font,
|
|
2300
|
+
"Best of all time",
|
|
2301
|
+
right_x0 + HS_RIGHT_SHOW_SCORES_VALUE_X * scale,
|
|
2302
|
+
right_y0 + HS_RIGHT_SHOW_SCORES_VALUE_Y * scale,
|
|
2303
|
+
text_scale,
|
|
2304
|
+
text_color,
|
|
2305
|
+
)
|
|
2306
|
+
draw_small_text(
|
|
2307
|
+
font,
|
|
2308
|
+
"default",
|
|
2309
|
+
right_x0 + HS_RIGHT_SCORE_LIST_VALUE_X * scale,
|
|
2310
|
+
right_y0 + HS_RIGHT_SCORE_LIST_VALUE_Y * scale,
|
|
2311
|
+
text_scale,
|
|
2312
|
+
text_color,
|
|
2313
|
+
)
|
|
2314
|
+
|
|
2315
|
+
drop_off = self._drop_off
|
|
2316
|
+
if drop_off is None:
|
|
2317
|
+
return
|
|
2318
|
+
drop_w = float(drop_off.width) * scale
|
|
2319
|
+
drop_h = float(drop_off.height) * scale
|
|
2320
|
+
for dx, dy in (
|
|
2321
|
+
(HS_RIGHT_PLAYER_COUNT_DROP_X, HS_RIGHT_PLAYER_COUNT_DROP_Y),
|
|
2322
|
+
(HS_RIGHT_GAME_MODE_DROP_X, HS_RIGHT_GAME_MODE_DROP_Y),
|
|
2323
|
+
(HS_RIGHT_SHOW_SCORES_DROP_X, HS_RIGHT_SHOW_SCORES_DROP_Y),
|
|
2324
|
+
(HS_RIGHT_SCORE_LIST_DROP_X, HS_RIGHT_SCORE_LIST_DROP_Y),
|
|
2325
|
+
):
|
|
2326
|
+
rl.draw_texture_pro(
|
|
2327
|
+
drop_off,
|
|
2328
|
+
rl.Rectangle(0.0, 0.0, float(drop_off.width), float(drop_off.height)),
|
|
2329
|
+
rl.Rectangle(right_x0 + float(dx) * scale, right_y0 + float(dy) * scale, drop_w, drop_h),
|
|
2330
|
+
rl.Vector2(0.0, 0.0),
|
|
2331
|
+
0.0,
|
|
2332
|
+
rl.WHITE,
|
|
2333
|
+
)
|
|
2334
|
+
|
|
2335
|
+
def _draw_right_panel_local_score(
|
|
2336
|
+
self,
|
|
2337
|
+
*,
|
|
2338
|
+
font: SmallFontData,
|
|
2339
|
+
right_x0: float,
|
|
2340
|
+
right_y0: float,
|
|
2341
|
+
scale: float,
|
|
2342
|
+
highlight_rank: int | None,
|
|
2343
|
+
) -> None:
|
|
2344
|
+
if not self._records:
|
|
2345
|
+
return
|
|
2346
|
+
idx = int(highlight_rank) if highlight_rank is not None else int(self._scroll_index)
|
|
2347
|
+
if idx < 0:
|
|
2348
|
+
idx = 0
|
|
2349
|
+
if idx >= len(self._records):
|
|
2350
|
+
idx = len(self._records) - 1
|
|
2351
|
+
entry = self._records[idx]
|
|
2352
|
+
|
|
2353
|
+
text_scale = 1.0 * scale
|
|
2354
|
+
text_color = rl.Color(255, 255, 255, int(255 * 0.8))
|
|
2355
|
+
|
|
2356
|
+
name = ""
|
|
2357
|
+
try:
|
|
2358
|
+
name = str(entry.name())
|
|
2359
|
+
except Exception:
|
|
2360
|
+
name = ""
|
|
2361
|
+
if not name:
|
|
2362
|
+
name = "???"
|
|
2363
|
+
draw_small_text(font, name, right_x0 + HS_LOCAL_NAME_X * scale, right_y0 + HS_LOCAL_NAME_Y * scale, text_scale, text_color)
|
|
2364
|
+
draw_small_text(
|
|
2365
|
+
font,
|
|
2366
|
+
"Local score",
|
|
2367
|
+
right_x0 + HS_LOCAL_LABEL_X * scale,
|
|
2368
|
+
right_y0 + HS_LOCAL_LABEL_Y * scale,
|
|
2369
|
+
text_scale,
|
|
2370
|
+
text_color,
|
|
2371
|
+
)
|
|
2372
|
+
|
|
2373
|
+
date_text = self._format_score_date(entry)
|
|
2374
|
+
if date_text:
|
|
2375
|
+
draw_small_text(
|
|
2376
|
+
font,
|
|
2377
|
+
date_text,
|
|
2378
|
+
right_x0 + HS_LOCAL_DATE_X * scale,
|
|
2379
|
+
right_y0 + HS_LOCAL_DATE_Y * scale,
|
|
2380
|
+
text_scale,
|
|
2381
|
+
text_color,
|
|
2382
|
+
)
|
|
2383
|
+
|
|
2384
|
+
draw_small_text(
|
|
2385
|
+
font,
|
|
2386
|
+
"Score",
|
|
2387
|
+
right_x0 + HS_LOCAL_SCORE_LABEL_X * scale,
|
|
2388
|
+
right_y0 + HS_LOCAL_SCORE_LABEL_Y * scale,
|
|
2389
|
+
text_scale,
|
|
2390
|
+
text_color,
|
|
2391
|
+
)
|
|
2392
|
+
draw_small_text(
|
|
2393
|
+
font,
|
|
2394
|
+
"Game time",
|
|
2395
|
+
right_x0 + HS_LOCAL_TIME_LABEL_X * scale,
|
|
2396
|
+
right_y0 + HS_LOCAL_TIME_LABEL_Y * scale,
|
|
2397
|
+
text_scale,
|
|
2398
|
+
text_color,
|
|
2399
|
+
)
|
|
2400
|
+
|
|
2401
|
+
score_value = f"{int(getattr(entry, 'score_xp', 0))}"
|
|
2402
|
+
draw_small_text(
|
|
2403
|
+
font,
|
|
2404
|
+
score_value,
|
|
2405
|
+
right_x0 + HS_LOCAL_SCORE_VALUE_X * scale,
|
|
2406
|
+
right_y0 + HS_LOCAL_SCORE_VALUE_Y * scale,
|
|
2407
|
+
text_scale,
|
|
2408
|
+
text_color,
|
|
2409
|
+
)
|
|
2410
|
+
|
|
2411
|
+
elapsed_ms = int(getattr(entry, "survival_elapsed_ms", 0) or 0)
|
|
2412
|
+
draw_small_text(
|
|
2413
|
+
font,
|
|
2414
|
+
self._format_elapsed_mm_ss(elapsed_ms),
|
|
2415
|
+
right_x0 + HS_LOCAL_TIME_VALUE_X * scale,
|
|
2416
|
+
right_y0 + HS_LOCAL_TIME_VALUE_Y * scale,
|
|
2417
|
+
text_scale,
|
|
2418
|
+
text_color,
|
|
2419
|
+
)
|
|
2420
|
+
|
|
2421
|
+
draw_small_text(
|
|
2422
|
+
font,
|
|
2423
|
+
f"Rank: {self._ordinal(idx + 1)}",
|
|
2424
|
+
right_x0 + HS_LOCAL_RANK_X * scale,
|
|
2425
|
+
right_y0 + HS_LOCAL_RANK_Y * scale,
|
|
2426
|
+
text_scale,
|
|
2427
|
+
text_color,
|
|
2428
|
+
)
|
|
2429
|
+
|
|
2430
|
+
frags = int(getattr(entry, "creature_kill_count", 0) or 0)
|
|
2431
|
+
draw_small_text(
|
|
2432
|
+
font,
|
|
2433
|
+
f"Frags: {frags}",
|
|
2434
|
+
right_x0 + HS_LOCAL_FRAGS_X * scale,
|
|
2435
|
+
right_y0 + HS_LOCAL_FRAGS_Y * scale,
|
|
2436
|
+
text_scale,
|
|
2437
|
+
text_color,
|
|
2438
|
+
)
|
|
2439
|
+
|
|
2440
|
+
shots_fired = int(getattr(entry, "shots_fired", 0) or 0)
|
|
2441
|
+
shots_hit = int(getattr(entry, "shots_hit", 0) or 0)
|
|
2442
|
+
hit_pct = 0
|
|
2443
|
+
if shots_fired > 0:
|
|
2444
|
+
hit_pct = int((shots_hit * 100) // shots_fired)
|
|
2445
|
+
draw_small_text(
|
|
2446
|
+
font,
|
|
2447
|
+
f"Hit %: {hit_pct}%",
|
|
2448
|
+
right_x0 + HS_LOCAL_HIT_X * scale,
|
|
2449
|
+
right_y0 + HS_LOCAL_HIT_Y * scale,
|
|
2450
|
+
text_scale,
|
|
2451
|
+
text_color,
|
|
2452
|
+
)
|
|
2453
|
+
|
|
2454
|
+
weapon_id = int(getattr(entry, "most_used_weapon_id", 0) or 0)
|
|
2455
|
+
weapon_name, icon_index = self._weapon_label_and_icon(weapon_id)
|
|
2456
|
+
if icon_index is not None:
|
|
2457
|
+
self._draw_wicon(icon_index, x=right_x0 + HS_LOCAL_WICON_X * scale, y=right_y0 + HS_LOCAL_WICON_Y * scale, scale=scale)
|
|
2458
|
+
draw_small_text(
|
|
2459
|
+
font,
|
|
2460
|
+
weapon_name,
|
|
2461
|
+
right_x0 + HS_LOCAL_WEAPON_X * scale,
|
|
2462
|
+
right_y0 + HS_LOCAL_WEAPON_Y * scale,
|
|
2463
|
+
text_scale,
|
|
2464
|
+
text_color,
|
|
2465
|
+
)
|
|
2466
|
+
|
|
2467
|
+
def _draw_wicon(self, icon_index: int, *, x: float, y: float, scale: float) -> None:
|
|
2468
|
+
tex = self._wicons_tex
|
|
2469
|
+
if tex is None:
|
|
2470
|
+
return
|
|
2471
|
+
idx = int(icon_index)
|
|
2472
|
+
if idx < 0 or idx > 31:
|
|
2473
|
+
return
|
|
2474
|
+
cols = 4
|
|
2475
|
+
rows = 8
|
|
2476
|
+
icon_w = float(tex.width) / float(cols)
|
|
2477
|
+
icon_h = float(tex.height) / float(rows)
|
|
2478
|
+
src_x = float(idx % cols) * icon_w
|
|
2479
|
+
src_y = float(idx // cols) * icon_h
|
|
2480
|
+
rl.draw_texture_pro(
|
|
2481
|
+
tex,
|
|
2482
|
+
rl.Rectangle(src_x, src_y, icon_w, icon_h),
|
|
2483
|
+
rl.Rectangle(float(x), float(y), icon_w * scale, icon_h * scale),
|
|
2484
|
+
rl.Vector2(0.0, 0.0),
|
|
2485
|
+
0.0,
|
|
2486
|
+
rl.WHITE,
|
|
2487
|
+
)
|
|
2488
|
+
|
|
2489
|
+
@staticmethod
|
|
2490
|
+
def _ordinal(value: int) -> str:
|
|
2491
|
+
n = int(value)
|
|
2492
|
+
if 10 <= (n % 100) <= 20:
|
|
2493
|
+
return f"{n}th"
|
|
2494
|
+
suffix = {1: "st", 2: "nd", 3: "rd"}.get(n % 10, "th")
|
|
2495
|
+
return f"{n}{suffix}"
|
|
2496
|
+
|
|
2497
|
+
@staticmethod
|
|
2498
|
+
def _format_elapsed_mm_ss(value_ms: int) -> str:
|
|
2499
|
+
total = max(0, int(value_ms)) // 1000
|
|
2500
|
+
minutes, seconds = divmod(total, 60)
|
|
2501
|
+
return f"{minutes}:{seconds:02d}"
|
|
2502
|
+
|
|
2503
|
+
@staticmethod
|
|
2504
|
+
def _format_score_date(entry: object) -> str:
|
|
2505
|
+
try:
|
|
2506
|
+
day = int(getattr(entry, "day", 0) or 0)
|
|
2507
|
+
month = int(getattr(entry, "month", 0) or 0)
|
|
2508
|
+
year_off = int(getattr(entry, "year_offset", 0) or 0)
|
|
2509
|
+
except Exception:
|
|
2510
|
+
return ""
|
|
2511
|
+
if day <= 0 or month <= 0:
|
|
2512
|
+
return ""
|
|
2513
|
+
months = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
|
|
2514
|
+
month_name = months[month - 1] if 1 <= month <= 12 else f"{month}"
|
|
2515
|
+
year = 2000 + year_off if year_off >= 0 else 2000
|
|
2516
|
+
return f"{day}. {month_name} {year}"
|
|
2517
|
+
|
|
2518
|
+
@staticmethod
|
|
2519
|
+
def _weapon_label_and_icon(weapon_id: int) -> tuple[str, int | None]:
|
|
2520
|
+
try:
|
|
2521
|
+
from .weapons import WEAPON_BY_ID
|
|
2522
|
+
except Exception:
|
|
2523
|
+
WEAPON_BY_ID = {}
|
|
2524
|
+
weapon = WEAPON_BY_ID.get(int(weapon_id))
|
|
2525
|
+
if weapon is None:
|
|
2526
|
+
return f"Weapon {int(weapon_id)}", None
|
|
2527
|
+
name = weapon.name or f"weapon_{int(weapon.weapon_id)}"
|
|
2528
|
+
return name, weapon.icon_index
|
|
2529
|
+
|
|
2090
2530
|
def _draw_sign(self, assets: MenuAssets) -> None:
|
|
2091
2531
|
if assets.sign is None:
|
|
2092
2532
|
return
|