crimsonland 0.1.0.dev5__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/__init__.py +24 -0
- crimson/assets_fetch.py +60 -0
- crimson/atlas.py +92 -0
- crimson/audio_router.py +155 -0
- crimson/bonuses.py +167 -0
- crimson/camera.py +75 -0
- crimson/cli.py +380 -0
- crimson/creatures/__init__.py +8 -0
- crimson/creatures/ai.py +186 -0
- crimson/creatures/anim.py +173 -0
- crimson/creatures/damage.py +103 -0
- crimson/creatures/runtime.py +1019 -0
- crimson/creatures/spawn.py +2871 -0
- crimson/debug.py +7 -0
- crimson/demo.py +1360 -0
- crimson/demo_trial.py +140 -0
- crimson/effects.py +1086 -0
- crimson/effects_atlas.py +73 -0
- crimson/frontend/__init__.py +1 -0
- crimson/frontend/assets.py +43 -0
- crimson/frontend/boot.py +424 -0
- crimson/frontend/menu.py +700 -0
- crimson/frontend/panels/__init__.py +1 -0
- crimson/frontend/panels/base.py +410 -0
- crimson/frontend/panels/controls.py +132 -0
- crimson/frontend/panels/mods.py +128 -0
- crimson/frontend/panels/options.py +409 -0
- crimson/frontend/panels/play_game.py +627 -0
- crimson/frontend/panels/stats.py +351 -0
- crimson/frontend/transitions.py +31 -0
- crimson/game.py +2533 -0
- crimson/game_modes.py +15 -0
- crimson/game_world.py +652 -0
- crimson/gameplay.py +2467 -0
- crimson/input_codes.py +176 -0
- crimson/modes/__init__.py +1 -0
- crimson/modes/base_gameplay_mode.py +219 -0
- crimson/modes/quest_mode.py +502 -0
- crimson/modes/rush_mode.py +300 -0
- crimson/modes/survival_mode.py +792 -0
- crimson/modes/tutorial_mode.py +648 -0
- crimson/modes/typo_mode.py +472 -0
- crimson/paths.py +23 -0
- crimson/perks.py +828 -0
- crimson/persistence/__init__.py +1 -0
- crimson/persistence/highscores.py +385 -0
- crimson/persistence/save_status.py +245 -0
- crimson/player_damage.py +77 -0
- crimson/projectiles.py +1133 -0
- crimson/quests/__init__.py +18 -0
- crimson/quests/helpers.py +147 -0
- crimson/quests/registry.py +49 -0
- crimson/quests/results.py +164 -0
- crimson/quests/runtime.py +91 -0
- crimson/quests/tier1.py +620 -0
- crimson/quests/tier2.py +652 -0
- crimson/quests/tier3.py +579 -0
- crimson/quests/tier4.py +721 -0
- crimson/quests/tier5.py +886 -0
- crimson/quests/timeline.py +115 -0
- crimson/quests/types.py +70 -0
- crimson/render/__init__.py +1 -0
- crimson/render/terrain_fx.py +88 -0
- crimson/render/world_renderer.py +1941 -0
- crimson/sim/__init__.py +1 -0
- crimson/sim/world_defs.py +67 -0
- crimson/sim/world_state.py +422 -0
- crimson/terrain_assets.py +19 -0
- crimson/tutorial/__init__.py +12 -0
- crimson/tutorial/timeline.py +291 -0
- crimson/typo/__init__.py +2 -0
- crimson/typo/names.py +233 -0
- crimson/typo/player.py +43 -0
- crimson/typo/spawns.py +73 -0
- crimson/typo/typing.py +52 -0
- crimson/ui/__init__.py +3 -0
- crimson/ui/cursor.py +95 -0
- crimson/ui/demo_trial_overlay.py +235 -0
- crimson/ui/game_over.py +660 -0
- crimson/ui/hud.py +601 -0
- crimson/ui/perk_menu.py +388 -0
- crimson/views/__init__.py +40 -0
- crimson/views/aim_debug.py +276 -0
- crimson/views/animations.py +274 -0
- crimson/views/arsenal_debug.py +404 -0
- crimson/views/audio_bootstrap.py +47 -0
- crimson/views/bonuses.py +201 -0
- crimson/views/camera_debug.py +359 -0
- crimson/views/camera_shake.py +229 -0
- crimson/views/corpse_stamp_debug.py +324 -0
- crimson/views/decals_debug.py +739 -0
- crimson/views/empty.py +19 -0
- crimson/views/fonts.py +114 -0
- crimson/views/game_over.py +117 -0
- crimson/views/ground.py +259 -0
- crimson/views/lighting_debug.py +1166 -0
- crimson/views/particles.py +293 -0
- crimson/views/perk_menu_debug.py +430 -0
- crimson/views/perks.py +398 -0
- crimson/views/player.py +434 -0
- crimson/views/player_sprite_debug.py +314 -0
- crimson/views/projectile_fx.py +609 -0
- crimson/views/projectile_render_debug.py +393 -0
- crimson/views/projectiles.py +221 -0
- crimson/views/quest_title_overlay.py +108 -0
- crimson/views/registry.py +34 -0
- crimson/views/rush.py +16 -0
- crimson/views/small_font_debug.py +204 -0
- crimson/views/spawn_plan.py +363 -0
- crimson/views/sprites.py +214 -0
- crimson/views/survival.py +15 -0
- crimson/views/terrain.py +132 -0
- crimson/views/ui.py +123 -0
- crimson/views/wicons.py +166 -0
- crimson/weapon_sfx.py +63 -0
- crimson/weapons.py +860 -0
- crimsonland-0.1.0.dev5.dist-info/METADATA +9 -0
- crimsonland-0.1.0.dev5.dist-info/RECORD +139 -0
- crimsonland-0.1.0.dev5.dist-info/WHEEL +4 -0
- crimsonland-0.1.0.dev5.dist-info/entry_points.txt +4 -0
- grim/__init__.py +20 -0
- grim/app.py +92 -0
- grim/assets.py +231 -0
- grim/audio.py +106 -0
- grim/config.py +294 -0
- grim/console.py +737 -0
- grim/fonts/__init__.py +7 -0
- grim/fonts/grim_mono.py +111 -0
- grim/fonts/small.py +120 -0
- grim/input.py +44 -0
- grim/jaz.py +103 -0
- grim/math.py +17 -0
- grim/music.py +403 -0
- grim/paq.py +76 -0
- grim/rand.py +37 -0
- grim/sfx.py +276 -0
- grim/sfx_map.py +103 -0
- grim/terrain_render.py +840 -0
- grim/view.py +16 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
crimson/__init__.py,sha256=dij6OQ6Wctqur9P00ojTTZw6IaUNeZagPX4-2Qqr-Kw,367
|
|
2
|
+
crimson/assets_fetch.py,sha256=z4vFH9h-RIwc2o6uKGzEtUaOdhUDSX6Art-WU6tNjd0,1864
|
|
3
|
+
crimson/atlas.py,sha256=hEcCHhPvguXAI6eH_G9Q8rpiX7M5akZ8fgJjMogmYrA,2401
|
|
4
|
+
crimson/audio_router.py,sha256=XauJvjT_qAooPKBo4d8NVe9HRWHzZDD8PCzmsWrASic,4729
|
|
5
|
+
crimson/bonuses.py,sha256=owwYIRHRu1Kymtt4eEvpd62JwWAg8LOe20vDuPFB5SU,5094
|
|
6
|
+
crimson/camera.py,sha256=VxTNXTh0qHh5VR1OpkiXr-QcgEWPrWw0A3PFyQFqDkY,2278
|
|
7
|
+
crimson/cli.py,sha256=Pu4RM_bjGtUgIE_5zZs0uWFY9O8YkhJDseRcVMMPJ8k,14595
|
|
8
|
+
crimson/creatures/__init__.py,sha256=RJwwR_w98zC_kHF9CwkhzSlf0xjpiP0JU87W4awdAAM,233
|
|
9
|
+
crimson/creatures/ai.py,sha256=oCuUkDe6Kxya1dThUthEy8GIuObAUjDv8WPfe17HYV4,6353
|
|
10
|
+
crimson/creatures/anim.py,sha256=E7MAR9vFBrvmIYrOfPr36UohsfROZZL00jgRvZQf6nc,4971
|
|
11
|
+
crimson/creatures/damage.py,sha256=pjKIX32nGDVPnFaWCce0LNZ-UZXZqJpNvwHwq-DCWbE,3211
|
|
12
|
+
crimson/creatures/runtime.py,sha256=1FagJNwGWJuOXZEv4VaWak2IktNskSof82WCYJqui-U,40733
|
|
13
|
+
crimson/creatures/spawn.py,sha256=ikgtr4sM2KdA2-eyxYdVmobcuZN6aA7xK7ceaIl7RSw,90059
|
|
14
|
+
crimson/debug.py,sha256=vtfr0_HQHpiB5h57jAsl9cWyYxErSbZQ2uazcL1sJhU,127
|
|
15
|
+
crimson/demo.py,sha256=rQG6Wdwy6t8sXZRt52vAmexpmgEyjRXuKs1sNx3wMoI,52500
|
|
16
|
+
crimson/demo_trial.py,sha256=BuoKB1DB-cPZ8jBp4x9gmxWF6tvhXMYRqJ9hMYrhxH4,4651
|
|
17
|
+
crimson/effects.py,sha256=6-v23jb5-Xs_gu3EezjRJLCGAU8obSUR6b2opdTLTvc,33999
|
|
18
|
+
crimson/effects_atlas.py,sha256=Ko1O7z-1jGkH_KSeb8RrR2EtAs4V8vfo70ofhqbFak4,2104
|
|
19
|
+
crimson/frontend/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
|
|
20
|
+
crimson/frontend/assets.py,sha256=JHxOID6Ti6bD2LercdRJ7sSSr0nRX3WWeuRPDQwwbsY,1343
|
|
21
|
+
crimson/frontend/boot.py,sha256=BUT8O9DAsAKOARBpoc7VhUQsV7IzpKVmbYtaEwkxu7M,15288
|
|
22
|
+
crimson/frontend/menu.py,sha256=2qqUdQ4UhjFViHUBVcsmitRXE2MU2UYXZuh4acY6aRA,26759
|
|
23
|
+
crimson/frontend/panels/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
|
|
24
|
+
crimson/frontend/panels/base.py,sha256=bHmNUGeHm9Y69x75VKFfgK88Y0PK937ta2CPpkSkGaA,14697
|
|
25
|
+
crimson/frontend/panels/controls.py,sha256=JhyylkqUIcq073VtxsrqhEaQYLU4Yf0yQ79ep5PLwpA,4763
|
|
26
|
+
crimson/frontend/panels/mods.py,sha256=GI6KZID2UnWHVm6VcxH6-p3tUx46mJtRPpzV8DK0PU0,4144
|
|
27
|
+
crimson/frontend/panels/options.py,sha256=0oBAGs9_nnP_H_JRa2hHZ6o-NaaavnuyzTSmeQyGUBA,15905
|
|
28
|
+
crimson/frontend/panels/play_game.py,sha256=_Tqw-vFVzgDUd-H1Q8txyw-sTSZKCEDf3aU0Iw9B26I,24299
|
|
29
|
+
crimson/frontend/panels/stats.py,sha256=jtIRRfffR4u_q6ayLvwCZ6u2YDdFC6Ei_ytQbxY-Bpo,12713
|
|
30
|
+
crimson/frontend/transitions.py,sha256=-sAJUDqNZ943zXlqtvJ6jCg2YH8dSi8k7qK8caAfOKI,883
|
|
31
|
+
crimson/game.py,sha256=_nPXvZDgu2sqEPk00ww9qx7nD8eQIXlIvU-yKfBuUA8,97537
|
|
32
|
+
crimson/game_modes.py,sha256=qW7Tt97lSBmGrt0F17Ni5h8vRyngBzyS9XwWM1TFIEI,255
|
|
33
|
+
crimson/game_world.py,sha256=nfKGcm3LHChPGLHJsurDFAATrHmhRvTmgxcLzUN9m5I,25440
|
|
34
|
+
crimson/gameplay.py,sha256=QsxHKgGTp79jAOIRoUn_L1jbN9EK2MIdCksLQ-KCqY4,87575
|
|
35
|
+
crimson/input_codes.py,sha256=PmSWFZIit8unTBWk3uwifpHWMuk0qMg1ueKX3MGC7D0,5379
|
|
36
|
+
crimson/modes/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
|
|
37
|
+
crimson/modes/base_gameplay_mode.py,sha256=kmXJxkGnCKV5QZL_y5ML7r-p4bw7hMswKseG9XUn2jo,7555
|
|
38
|
+
crimson/modes/quest_mode.py,sha256=hcq_n3Vi9CtED899ELi5JZKZWXWvzmDcIBBerVExz7w,19153
|
|
39
|
+
crimson/modes/rush_mode.py,sha256=ZspTGjLIyjxXtP9lbEFXQJv_PQEyj52xTNicNEfRSBk,10932
|
|
40
|
+
crimson/modes/survival_mode.py,sha256=kuY8s1wDWOII2wE4JfMmSB4_4kbkRxzOYeMbcJebELM,32691
|
|
41
|
+
crimson/modes/tutorial_mode.py,sha256=fVYPSZbAsUARI95QP3GamPRMf-v6ix5SKfCoa_0nfAY,26422
|
|
42
|
+
crimson/modes/typo_mode.py,sha256=JoiOqGjft922ZtjOzFpLeIy1hv35N7eHO-nsWVlSooY,17396
|
|
43
|
+
crimson/paths.py,sha256=JCKauCxHJnP4IIy5ocgs6tvbaSMkMUByQ76Zoz2UGZM,653
|
|
44
|
+
crimson/perks.py,sha256=JHNhKPOUq2w8h23gU7jpkx-erFKTO4Z8l8aHU8vrkO0,37068
|
|
45
|
+
crimson/persistence/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
|
|
46
|
+
crimson/persistence/highscores.py,sha256=i3eU_Vlu-Bn6kZHDWNMzUoJXvzkqOnPp_UFOeZXclYU,13026
|
|
47
|
+
crimson/persistence/save_status.py,sha256=s-FZONO6JVYRULewtlxoIwATTy3P7rLy-vsVBfSKPk4,7748
|
|
48
|
+
crimson/player_damage.py,sha256=cECZO65NJwARoYdtsbvZBM8vQNs_8AVO4xa0omX0pGg,2215
|
|
49
|
+
crimson/projectiles.py,sha256=44sL_2ElYAtNHHo8bzcx3t2NDq-yix56Pfui8zNGOeo,43644
|
|
50
|
+
crimson/quests/__init__.py,sha256=pKCkH0o1XIGDN9h6yNNaqvWek2CybEZRpejYRooULj8,375
|
|
51
|
+
crimson/quests/helpers.py,sha256=TeZWhIy2x8Zs9S-vYRBOEZ7pkHNMr5YJ-wi4vYQ2q2M,3625
|
|
52
|
+
crimson/quests/registry.py,sha256=Cees1QBN0VYTB-XyQtvZ1b4SykB-i4tAnWF6WSV-1pg,1478
|
|
53
|
+
crimson/quests/results.py,sha256=nwVk4CafEIqLvI2s8i4RueGiW48pnbwNmsoaoWPNebU,5279
|
|
54
|
+
crimson/quests/runtime.py,sha256=r0ANBiaCe1sY3_OUesd9gbPqRF4yeTeR-nududZgF-o,2668
|
|
55
|
+
crimson/quests/tier1.py,sha256=D4VQ0KqkTlp3j627a7hB13nB3WUJcviINCva9U6jrWc,17459
|
|
56
|
+
crimson/quests/tier2.py,sha256=zNF1lVnO1C3Yzq3EdVtsmeTqUZwqN7DWZuMTwmcp5pA,18249
|
|
57
|
+
crimson/quests/tier3.py,sha256=LzaQaxv3pb4JSwAS7BONtY8mBhrQBbcHuHhAFEt1r3g,16635
|
|
58
|
+
crimson/quests/tier4.py,sha256=wInwikrYb02KHf3-eK17vTHDHj9dvZMBJptj0x5vBzA,19644
|
|
59
|
+
crimson/quests/tier5.py,sha256=sZSz7VBxOpkwO-wQAMOvYgwstkvQ361_vQzux271bWs,23510
|
|
60
|
+
crimson/quests/timeline.py,sha256=leK898fPt3zq52v-O6dK4c-wJBcY-E6v-y57Fk3kJ3Q,4021
|
|
61
|
+
crimson/quests/types.py,sha256=iSrz8VSiRZh1pUDSyq37ir7B28c0HF8DjdF6OJ3FoBo,1772
|
|
62
|
+
crimson/render/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
|
|
63
|
+
crimson/render/terrain_fx.py,sha256=MpBV6ukGwGqDluIO86BQhHRVWUvcFOi8MV-z_TfLsiw,2705
|
|
64
|
+
crimson/render/world_renderer.py,sha256=wSipGqm900eJaBNctXO9WDRSdM6ruOBXsG-TDXWSyCE,83776
|
|
65
|
+
crimson/sim/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
|
|
66
|
+
crimson/sim/world_defs.py,sha256=HiMl--THnII3BTpt6mWAd20Xu-SRzCyHcs5pCR8aMbU,2195
|
|
67
|
+
crimson/sim/world_state.py,sha256=h_PPaomj-1KPscPsW3zZ07tVFb3DYPM-FQq3pepMGng,15653
|
|
68
|
+
crimson/terrain_assets.py,sha256=X19LN3EZSkiz4uRvQfra3NtAXKAA8SMQ-nvOBlrspwE,670
|
|
69
|
+
crimson/tutorial/__init__.py,sha256=SDDZKRpkQBqyVMU9U03DN242t8lo8ThLuWHmbVrP69k,333
|
|
70
|
+
crimson/tutorial/timeline.py,sha256=aJDtASfkCSCL1RH4AZX-7xOZml9E4AORTAX6lI6A578,11307
|
|
71
|
+
crimson/typo/__init__.py,sha256=PHh4jqD7i0aL8W8hXThczKcT4xsNZiXanBxOH5IOW5I,36
|
|
72
|
+
crimson/typo/names.py,sha256=SslKyngsp81iHJPEdMJakvaenIkTskZIjLKuEmrt7d0,6320
|
|
73
|
+
crimson/typo/player.py,sha256=2cnyiOY9WzJadxvvYdnc9BQhmUifFfdRCUjq5LLiby0,1119
|
|
74
|
+
crimson/typo/spawns.py,sha256=63lYhgR8iFcE80YBYP_Z2Xvg7xKo1G1swRPLqM0JBS0,1852
|
|
75
|
+
crimson/typo/typing.py,sha256=-h9udu7s-zGKlXxd6Xi7vbaiHj3pNuHqbL_0jqoTR9s,1284
|
|
76
|
+
crimson/ui/__init__.py,sha256=0-of-3kMbUcm08RgaXNBkTaWHsqYtG0bk1b0ztpLyww,77
|
|
77
|
+
crimson/ui/cursor.py,sha256=_6EJ7tnsW_Q4kPUrqBO5FInxhpHKUGGyVpDET5EG38I,2842
|
|
78
|
+
crimson/ui/demo_trial_overlay.py,sha256=DugDImlPKx6DGe6gaXmA2s7dssjS6E9PMTi_3mOshx8,8724
|
|
79
|
+
crimson/ui/game_over.py,sha256=hXgV0v4L9peohj2xUIipOSlY1gMRsmAPCxlToo8dj08,29610
|
|
80
|
+
crimson/ui/hud.py,sha256=MnCBZGdI2nLMp9JOxaJBA0inErW2X7W95LtNb80vVIo,22283
|
|
81
|
+
crimson/ui/perk_menu.py,sha256=FdbwG_B7UyZmPVdvZho0nJNvkAVc0VVHM2TSrY4eTfM,12740
|
|
82
|
+
crimson/views/__init__.py,sha256=1UWCzBSsgIeOtcKxqM4Vf12JEfPHKfb9KRZgl2TB84Q,1880
|
|
83
|
+
crimson/views/aim_debug.py,sha256=2ldQ1MJO8AeG0i9x4ZJ3YLyp1X-HY_nJ0E1mY8jFF7Q,10873
|
|
84
|
+
crimson/views/animations.py,sha256=iI6uTpYS-lbjnpqz_ihETm5q09V6RqjO7YHqaGjovPc,10660
|
|
85
|
+
crimson/views/arsenal_debug.py,sha256=bS_FV6ffknOgSPBcAEZFDJ8CBjWitBziWVanjwXvMfs,14130
|
|
86
|
+
crimson/views/audio_bootstrap.py,sha256=a2qM91biyI-LlSiIhEceJ8ptYJy-xQ2-b-YjeyXWx7w,1408
|
|
87
|
+
crimson/views/bonuses.py,sha256=dbGx0IBjMMpqrnuVjBUkscxHq6uErCxAkEAb3uDhFqQ,7454
|
|
88
|
+
crimson/views/camera_debug.py,sha256=Vi6jANGQpXMK0bpL7hX_QQI_6Rl97ykElaoAuXd06YY,14025
|
|
89
|
+
crimson/views/camera_shake.py,sha256=miYxPJcVChv5P2AdbAWTEsrjZR0SAszqClLMbmrgg-0,8148
|
|
90
|
+
crimson/views/corpse_stamp_debug.py,sha256=1iLqiCQZpl8kbqfadgxbtVUiRFoGTnZfUwUXt3rVNq0,11716
|
|
91
|
+
crimson/views/decals_debug.py,sha256=tE-WUZIJ-skPiDB0kByQfyWS3XP371y4u-s7DT2fl08,27841
|
|
92
|
+
crimson/views/empty.py,sha256=ieyD6jk5KKqVdo90HXDm-ytewlIR087TJPj_7PmnaDI,358
|
|
93
|
+
crimson/views/fonts.py,sha256=MkAQz4boPsYa0vUBV5t2ddLVT5pRa-JKiAd0VHYglAo,3890
|
|
94
|
+
crimson/views/game_over.py,sha256=R7K7ENM7-ObcsZ5DqPHkrC8fuzAKLOFLZf3j7K5cvDE,4080
|
|
95
|
+
crimson/views/ground.py,sha256=_QzsoFSPKA2qIj8OTvJFr2mqT_sM5_w05ucL4a9cCZQ,10226
|
|
96
|
+
crimson/views/lighting_debug.py,sha256=T9ce224ZrJtztKTSFUn1G29MY0KYuHVhNdcDU7hlrFc,45502
|
|
97
|
+
crimson/views/particles.py,sha256=z3nFPEyItv9aAY_RbByl-jDlwvH22fG30sIMWiaR1aM,10109
|
|
98
|
+
crimson/views/perk_menu_debug.py,sha256=q4rn3R4tJASlep5jeAXwrBffj5_akJ4a4veq7FIpRiU,17831
|
|
99
|
+
crimson/views/perks.py,sha256=Uac31DVvHZvjDmMrHpfvkg7LVpXw76xKL1BqwaLAsHU,15052
|
|
100
|
+
crimson/views/player.py,sha256=cMZiFbJK_um8yAFR1pFW7Hdq4_Tl6RZmGmZk1FwAiZE,16569
|
|
101
|
+
crimson/views/player_sprite_debug.py,sha256=DDU6kl9sfhZ2nVXzBbsPSUKdIutHf5YNs2DrNQPRb2Q,11158
|
|
102
|
+
crimson/views/projectile_fx.py,sha256=pmMiXm2hJ1XeGf40VtdPk2TbVJX56aATBYTCRekYOdU,23177
|
|
103
|
+
crimson/views/projectile_render_debug.py,sha256=gogOiEGT1P_5qD5rMcuxqPac3-WrPJmbJGvg6USvoxE,14347
|
|
104
|
+
crimson/views/projectiles.py,sha256=k5zD_9614_-M4qYpnwKUS23fUUrjJS2Wzm7ZalOSKnU,8067
|
|
105
|
+
crimson/views/quest_title_overlay.py,sha256=EbMvXvYqagLLXmhaM7PC0fhxxhHGYGYI2ytgYiWqAd4,3338
|
|
106
|
+
crimson/views/registry.py,sha256=Kxc_aQMWOAjI6Uq_SRkb0AmYQxyVmM6rxT3UF74irzs,930
|
|
107
|
+
crimson/views/rush.py,sha256=61XavUpHgwc6Kw9e9Y-OkDt_XfY6iHoDrcpxjMbe1ms,298
|
|
108
|
+
crimson/views/small_font_debug.py,sha256=c-9qw7QL-nY-ajVOgDNjMGOnGqmVx_j-Iiy5DQhOlz0,7712
|
|
109
|
+
crimson/views/spawn_plan.py,sha256=Xo2vw3VwNYqdbNJ6K8d3PJ81sJjLdrXhYEQLTwrxAdM,13378
|
|
110
|
+
crimson/views/sprites.py,sha256=_DMjuXaRKvzgGRkv9gieaSubJFJraKNZ01C7iNg1niE,7372
|
|
111
|
+
crimson/views/survival.py,sha256=6yuhPe6-bC4IDaAbv74PStiAX9cBbg7HFbSr12ytQAw,333
|
|
112
|
+
crimson/views/terrain.py,sha256=ku3R7igsvtfLdeh_uBbY41Tumi9BaNa1C6IAe6vKUOY,4763
|
|
113
|
+
crimson/views/ui.py,sha256=2gGyCiI_JnlHzG9CWH8nomQIgCthfLwP7bTsDyqAyx4,4294
|
|
114
|
+
crimson/views/wicons.py,sha256=bGbmE25q_pYJZTiPt6Q5Sy1Ub667KvUIFp1a5rVxhi0,5783
|
|
115
|
+
crimson/weapon_sfx.py,sha256=_JAFpXi-c7jFNz3hxKygAYwqAR6zC94QnNHQYDCHnOY,1717
|
|
116
|
+
crimson/weapons.py,sha256=FSyOmOQbmGBS5KTZuyBQ5hd5prFp6V1LtIQRoGc8pqQ,23666
|
|
117
|
+
grim/__init__.py,sha256=Cn4f7JY6bscS1gwjDPaWvIvj_vneuUXaiu7wdJB6EVg,262
|
|
118
|
+
grim/app.py,sha256=Wae-tQcpDA0mI99GRupHXoxKnC5F6xfLGxVV8KOxcx4,2702
|
|
119
|
+
grim/assets.py,sha256=k2rFqNYfcUZfRjFL7r_UBGf1RlcP-urChXCUJ6GzEsI,7661
|
|
120
|
+
grim/audio.py,sha256=V_TrnfrCb_0e2jeOhN7_kGBu8uMdMsFbk-REoUeWY7Q,3189
|
|
121
|
+
grim/config.py,sha256=eQk_3ls_na9AiQr1yqbdyNRc2venM3_NS7Cqz75V08g,9644
|
|
122
|
+
grim/console.py,sha256=bdhAedOwMpk9yKqwMfMoUsoLG5RQqOET6Ya0Zu2eWro,26598
|
|
123
|
+
grim/fonts/__init__.py,sha256=yd2yLa0C-LTfjzZHpBl_AglynL3-PmPHePkulMiqLh0,81
|
|
124
|
+
grim/fonts/grim_mono.py,sha256=DdTAuzGyliJF9ufI5YP039yfYYMWnJp3b6j7u9yvd8Q,3587
|
|
125
|
+
grim/fonts/small.py,sha256=8Fgqhs-iejqXLyPxo2if2jqfKy9YvM2AZRTBj91M4Rs,4495
|
|
126
|
+
grim/input.py,sha256=kiJ0AcOIT7slGA8snkfiKeAP7GyGDMF0dvZz2ePcG4I,1156
|
|
127
|
+
grim/jaz.py,sha256=HcuJR9cj0RLhANlv9fzDuyLh8U6ktYoCiSq8hqg6Sx8,2870
|
|
128
|
+
grim/math.py,sha256=xf6K1NKduWNHpKV1KE3Oet_uZW4pF4w0HhaXk7eGMm0,343
|
|
129
|
+
grim/music.py,sha256=UGZ8W3a3Hus78O2N6WRf24_BYn9Eg9mj7RLi6jB5feo,12760
|
|
130
|
+
grim/paq.py,sha256=KKQRueYP4HiqF9hNEk7dSem-4bn0J4OH2TJDg2CjbnA,1952
|
|
131
|
+
grim/rand.py,sha256=TTxAe2o92XLloLOdMwLbE0lwdHXd8LPgWsrZCX2-nVU,862
|
|
132
|
+
grim/sfx.py,sha256=cpn2Mmeio7BSDgbStSft-eZchO9Ot2MrK6iXJqxlLqU,7836
|
|
133
|
+
grim/sfx_map.py,sha256=FM5iBzKkG30Vtu78SRavVNgXMbGK7ZFcQ8i6lgMlzVw,4697
|
|
134
|
+
grim/terrain_render.py,sha256=EZ7ySYJyTZwXcrJx1mKbY3ewZtPi7Y270XnZgGJyZG8,31509
|
|
135
|
+
grim/view.py,sha256=oF4pHZehBqOxPjKMU28TDg3qATh_amMIRJp-vMQnpn4,334
|
|
136
|
+
crimsonland-0.1.0.dev5.dist-info/WHEEL,sha256=fAguSjoiATBe7TNBkJwOjyL1Tt4wwiaQGtNtjRPNMQA,80
|
|
137
|
+
crimsonland-0.1.0.dev5.dist-info/entry_points.txt,sha256=jzzcExxiE9xpt4Iw2nbB1lwTv2Zj4H14WJTIPMkAjoE,77
|
|
138
|
+
crimsonland-0.1.0.dev5.dist-info/METADATA,sha256=kBl208VLbh6OZaSSjTWXJ3pMc2q9tFXkDEJYhjg1BZc,243
|
|
139
|
+
crimsonland-0.1.0.dev5.dist-info/RECORD,,
|
grim/__init__.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
__all__ = [
|
|
4
|
+
"app",
|
|
5
|
+
"assets",
|
|
6
|
+
"audio",
|
|
7
|
+
"config",
|
|
8
|
+
"console",
|
|
9
|
+
"fonts",
|
|
10
|
+
"input",
|
|
11
|
+
"jaz",
|
|
12
|
+
"math",
|
|
13
|
+
"music",
|
|
14
|
+
"paq",
|
|
15
|
+
"rand",
|
|
16
|
+
"sfx",
|
|
17
|
+
"sfx_map",
|
|
18
|
+
"terrain_render",
|
|
19
|
+
"view",
|
|
20
|
+
]
|
grim/app.py
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import shutil
|
|
5
|
+
|
|
6
|
+
import pyray as rl
|
|
7
|
+
|
|
8
|
+
from .view import View
|
|
9
|
+
|
|
10
|
+
SCREENSHOT_DIR = Path("screenshots")
|
|
11
|
+
SCREENSHOT_KEY = rl.KeyboardKey.KEY_F12
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _next_screenshot_index(directory: Path) -> int:
|
|
15
|
+
if not directory.exists():
|
|
16
|
+
return 1
|
|
17
|
+
max_index = 0
|
|
18
|
+
for entry in directory.glob("*.png"):
|
|
19
|
+
stem = entry.stem
|
|
20
|
+
if stem.isdigit():
|
|
21
|
+
max_index = max(max_index, int(stem))
|
|
22
|
+
return max_index + 1
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _view_should_close(view: View) -> bool:
|
|
26
|
+
should_close = getattr(view, "should_close", None)
|
|
27
|
+
if callable(should_close):
|
|
28
|
+
return bool(should_close())
|
|
29
|
+
return bool(getattr(view, "close_requested", False))
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def run_view(
|
|
33
|
+
view: View,
|
|
34
|
+
*,
|
|
35
|
+
width: int = 1280,
|
|
36
|
+
height: int = 720,
|
|
37
|
+
title: str = "Crimsonland",
|
|
38
|
+
fps: int = 60,
|
|
39
|
+
config_flags: int = 0,
|
|
40
|
+
) -> None:
|
|
41
|
+
"""Run a Raylib window with a pluggable debug view."""
|
|
42
|
+
if config_flags:
|
|
43
|
+
rl.set_config_flags(config_flags)
|
|
44
|
+
rl.init_window(width, height, title)
|
|
45
|
+
rl.set_target_fps(fps)
|
|
46
|
+
open_fn = getattr(view, "open", None)
|
|
47
|
+
if callable(open_fn):
|
|
48
|
+
open_fn()
|
|
49
|
+
screenshot_dir = SCREENSHOT_DIR if SCREENSHOT_DIR.is_absolute() else Path.cwd() / SCREENSHOT_DIR
|
|
50
|
+
screenshot_index = _next_screenshot_index(screenshot_dir)
|
|
51
|
+
while not rl.window_should_close():
|
|
52
|
+
dt = rl.get_frame_time()
|
|
53
|
+
view.update(dt)
|
|
54
|
+
take_screenshot = rl.is_key_pressed(SCREENSHOT_KEY)
|
|
55
|
+
consume_screenshot = getattr(view, "consume_screenshot_request", None)
|
|
56
|
+
if callable(consume_screenshot) and consume_screenshot():
|
|
57
|
+
take_screenshot = True
|
|
58
|
+
rl.begin_drawing()
|
|
59
|
+
view.draw()
|
|
60
|
+
rl.end_drawing()
|
|
61
|
+
if _view_should_close(view):
|
|
62
|
+
break
|
|
63
|
+
if take_screenshot:
|
|
64
|
+
screenshot_dir.mkdir(parents=True, exist_ok=True)
|
|
65
|
+
filename = f"{screenshot_index:05d}.png"
|
|
66
|
+
rl.take_screenshot(filename)
|
|
67
|
+
src = Path.cwd() / filename
|
|
68
|
+
if src.exists():
|
|
69
|
+
shutil.move(str(src), str(screenshot_dir / filename))
|
|
70
|
+
screenshot_index += 1
|
|
71
|
+
close_fn = getattr(view, "close", None)
|
|
72
|
+
if callable(close_fn):
|
|
73
|
+
close_fn()
|
|
74
|
+
rl.close_window()
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def run_window(
|
|
78
|
+
width: int = 1280,
|
|
79
|
+
height: int = 720,
|
|
80
|
+
title: str = "Crimsonland",
|
|
81
|
+
fps: int = 60,
|
|
82
|
+
) -> None:
|
|
83
|
+
"""Open a minimal Raylib window for the reference implementation."""
|
|
84
|
+
|
|
85
|
+
class _EmptyView:
|
|
86
|
+
def update(self, dt: float) -> None:
|
|
87
|
+
return None
|
|
88
|
+
|
|
89
|
+
def draw(self) -> None:
|
|
90
|
+
rl.clear_background(rl.BLACK)
|
|
91
|
+
|
|
92
|
+
run_view(_EmptyView(), width=width, height=height, title=title, fps=fps)
|
grim/assets.py
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
import io
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import pyray as rl
|
|
8
|
+
from PIL import Image
|
|
9
|
+
|
|
10
|
+
from . import jaz, paq
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
PAQ_NAME = "crimson.paq"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def find_paq_path(assets_root: Path, *, paq_name: str = PAQ_NAME) -> Path | None:
|
|
17
|
+
"""Return the first matching PAQ path for the given assets root.
|
|
18
|
+
|
|
19
|
+
The repo layout often keeps extracted assets under `artifacts/assets/` while
|
|
20
|
+
the runtime PAQ lives under `artifacts/runtime/`. Views typically point at
|
|
21
|
+
the extracted root, so we look for common sibling/parent layouts too.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
roots = (assets_root, assets_root.parent, assets_root.parent.parent)
|
|
25
|
+
for root in roots:
|
|
26
|
+
direct = root / paq_name
|
|
27
|
+
if direct.is_file():
|
|
28
|
+
return direct
|
|
29
|
+
runtime = root / "runtime" / paq_name
|
|
30
|
+
if runtime.is_file():
|
|
31
|
+
return runtime
|
|
32
|
+
return None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def resolve_asset_path(assets_root: Path, rel_path: str) -> Path | None:
|
|
36
|
+
direct = assets_root / rel_path
|
|
37
|
+
if direct.is_file():
|
|
38
|
+
return direct
|
|
39
|
+
legacy = assets_root / "crimson" / rel_path
|
|
40
|
+
if legacy.is_file():
|
|
41
|
+
return legacy
|
|
42
|
+
return None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass(slots=True)
|
|
46
|
+
class TextureLoader:
|
|
47
|
+
assets_root: Path
|
|
48
|
+
cache: PaqTextureCache | None = None
|
|
49
|
+
missing: list[str] = field(default_factory=list)
|
|
50
|
+
_fs_textures: dict[str, rl.Texture] = field(default_factory=dict)
|
|
51
|
+
|
|
52
|
+
@classmethod
|
|
53
|
+
def from_assets_root(cls, assets_root: Path) -> TextureLoader:
|
|
54
|
+
paq_path = find_paq_path(assets_root)
|
|
55
|
+
if paq_path is not None:
|
|
56
|
+
try:
|
|
57
|
+
entries = load_paq_entries_from_path(paq_path)
|
|
58
|
+
cache = PaqTextureCache(entries=entries, textures={})
|
|
59
|
+
return cls(assets_root=assets_root, cache=cache)
|
|
60
|
+
except Exception:
|
|
61
|
+
pass
|
|
62
|
+
return cls(assets_root=assets_root)
|
|
63
|
+
|
|
64
|
+
def resolve_path(self, rel_path: str) -> Path | None:
|
|
65
|
+
return resolve_asset_path(self.assets_root, rel_path)
|
|
66
|
+
|
|
67
|
+
def _record_missing(self, rel_path: str) -> None:
|
|
68
|
+
raise FileNotFoundError(f"Missing asset: {rel_path}")
|
|
69
|
+
|
|
70
|
+
def load_from_cache(self, name: str, rel_path: str) -> rl.Texture | None:
|
|
71
|
+
if self.cache is None:
|
|
72
|
+
return None
|
|
73
|
+
try:
|
|
74
|
+
asset = self.cache.get_or_load(name, rel_path)
|
|
75
|
+
except FileNotFoundError:
|
|
76
|
+
return None
|
|
77
|
+
if asset.texture is None:
|
|
78
|
+
return None
|
|
79
|
+
return asset.texture
|
|
80
|
+
|
|
81
|
+
def load_from_path(self, name: str, rel_path: str) -> rl.Texture | None:
|
|
82
|
+
if name in self._fs_textures:
|
|
83
|
+
return self._fs_textures[name]
|
|
84
|
+
path = resolve_asset_path(self.assets_root, rel_path)
|
|
85
|
+
if path is None:
|
|
86
|
+
self._record_missing(rel_path)
|
|
87
|
+
return None
|
|
88
|
+
texture = rl.load_texture(str(path))
|
|
89
|
+
self._fs_textures[name] = texture
|
|
90
|
+
return texture
|
|
91
|
+
|
|
92
|
+
def get(self, *, name: str, paq_rel: str, fs_rel: str | None = None) -> rl.Texture | None:
|
|
93
|
+
if self.cache is not None:
|
|
94
|
+
texture = self.load_from_cache(name, paq_rel)
|
|
95
|
+
if texture is not None:
|
|
96
|
+
return texture
|
|
97
|
+
if fs_rel is None:
|
|
98
|
+
fs_rel = paq_rel
|
|
99
|
+
return self.load_from_path(name, fs_rel)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@dataclass(slots=True)
|
|
103
|
+
class TextureAsset:
|
|
104
|
+
name: str
|
|
105
|
+
rel_path: str
|
|
106
|
+
texture: rl.Texture2D | None
|
|
107
|
+
|
|
108
|
+
def unload(self) -> None:
|
|
109
|
+
texture = self.texture
|
|
110
|
+
if texture is None:
|
|
111
|
+
return
|
|
112
|
+
rl.unload_texture(texture)
|
|
113
|
+
self.texture = None
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@dataclass(slots=True)
|
|
117
|
+
class LogoAssets:
|
|
118
|
+
backplasma: TextureAsset
|
|
119
|
+
mockup: TextureAsset
|
|
120
|
+
logo_esrb: TextureAsset
|
|
121
|
+
loading: TextureAsset
|
|
122
|
+
cl_logo: TextureAsset
|
|
123
|
+
|
|
124
|
+
def all(self) -> tuple[TextureAsset, ...]:
|
|
125
|
+
return (
|
|
126
|
+
self.backplasma,
|
|
127
|
+
self.mockup,
|
|
128
|
+
self.logo_esrb,
|
|
129
|
+
self.loading,
|
|
130
|
+
self.cl_logo,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
def loaded_count(self) -> int:
|
|
134
|
+
return sum(1 for asset in self.all() if asset.texture is not None)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@dataclass(slots=True)
|
|
138
|
+
class PaqTextureCache:
|
|
139
|
+
entries: dict[str, bytes]
|
|
140
|
+
textures: dict[str, TextureAsset]
|
|
141
|
+
|
|
142
|
+
def get(self, name: str) -> TextureAsset | None:
|
|
143
|
+
return self.textures.get(name)
|
|
144
|
+
|
|
145
|
+
def texture(self, name: str) -> rl.Texture2D | None:
|
|
146
|
+
asset = self.textures.get(name)
|
|
147
|
+
return asset.texture if asset is not None else None
|
|
148
|
+
|
|
149
|
+
def get_or_load(self, name: str, rel_path: str) -> TextureAsset:
|
|
150
|
+
if name in self.textures:
|
|
151
|
+
return self.textures[name]
|
|
152
|
+
asset = _load_texture_asset_from_bytes(name, rel_path, self.entries.get(rel_path))
|
|
153
|
+
self.textures[name] = asset
|
|
154
|
+
return asset
|
|
155
|
+
|
|
156
|
+
def loaded_count(self) -> int:
|
|
157
|
+
return sum(1 for asset in self.textures.values() if asset.texture is not None)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def load_paq_entries_from_path(paq_path: Path) -> dict[str, bytes]:
|
|
161
|
+
entries: dict[str, bytes] = {}
|
|
162
|
+
if not paq_path.exists():
|
|
163
|
+
raise FileNotFoundError(f"Missing PAQ archive: {paq_path}")
|
|
164
|
+
for name, data in paq.iter_entries(paq_path):
|
|
165
|
+
entries[name.replace("\\", "/")] = data
|
|
166
|
+
return entries
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def load_paq_entries(assets_dir: Path) -> dict[str, bytes]:
|
|
170
|
+
return load_paq_entries_from_path(assets_dir / PAQ_NAME)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _load_texture_from_bytes(data: bytes, fmt: str) -> rl.Texture2D:
|
|
174
|
+
image = rl.load_image_from_memory(fmt, data, len(data))
|
|
175
|
+
texture = rl.load_texture_from_image(image)
|
|
176
|
+
rl.unload_image(image)
|
|
177
|
+
rl.set_texture_filter(texture, rl.TEXTURE_FILTER_BILINEAR)
|
|
178
|
+
return texture
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def _load_texture_asset_from_bytes(name: str, rel_path: str, data: bytes | None) -> TextureAsset:
|
|
182
|
+
if data is None:
|
|
183
|
+
raise FileNotFoundError(f"Missing asset data: {rel_path}")
|
|
184
|
+
if rel_path.lower().endswith(".jaz"):
|
|
185
|
+
jaz_image = jaz.decode_jaz_bytes(data)
|
|
186
|
+
buf = io.BytesIO()
|
|
187
|
+
jaz_image.composite_image().save(buf, format="PNG")
|
|
188
|
+
return TextureAsset(
|
|
189
|
+
name=name,
|
|
190
|
+
rel_path=rel_path,
|
|
191
|
+
texture=_load_texture_from_bytes(buf.getvalue(), ".png"),
|
|
192
|
+
)
|
|
193
|
+
if rel_path.lower().endswith(".tga"):
|
|
194
|
+
img = Image.open(io.BytesIO(data))
|
|
195
|
+
buf = io.BytesIO()
|
|
196
|
+
img.save(buf, format="PNG")
|
|
197
|
+
return TextureAsset(
|
|
198
|
+
name=name,
|
|
199
|
+
rel_path=rel_path,
|
|
200
|
+
texture=_load_texture_from_bytes(buf.getvalue(), ".png"),
|
|
201
|
+
)
|
|
202
|
+
if rel_path.lower().endswith((".jpg", ".jpeg")):
|
|
203
|
+
img = Image.open(io.BytesIO(data))
|
|
204
|
+
buf = io.BytesIO()
|
|
205
|
+
img.save(buf, format="PNG")
|
|
206
|
+
return TextureAsset(
|
|
207
|
+
name=name,
|
|
208
|
+
rel_path=rel_path,
|
|
209
|
+
texture=_load_texture_from_bytes(buf.getvalue(), ".png"),
|
|
210
|
+
)
|
|
211
|
+
return TextureAsset(name=name, rel_path=rel_path, texture=None)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def load_logo_assets(assets_dir: Path, *, entries: dict[str, bytes] | None = None) -> LogoAssets:
|
|
215
|
+
if entries is None:
|
|
216
|
+
entries = load_paq_entries(assets_dir)
|
|
217
|
+
return LogoAssets(
|
|
218
|
+
backplasma=_load_texture_asset_from_bytes(
|
|
219
|
+
"backplasma", "load/backplasma.jaz", entries.get("load/backplasma.jaz")
|
|
220
|
+
),
|
|
221
|
+
mockup=_load_texture_asset_from_bytes("mockup", "load/mockup.jaz", entries.get("load/mockup.jaz")),
|
|
222
|
+
logo_esrb=_load_texture_asset_from_bytes(
|
|
223
|
+
"logo_esrb", "load/esrb_mature.jaz", entries.get("load/esrb_mature.jaz")
|
|
224
|
+
),
|
|
225
|
+
loading=_load_texture_asset_from_bytes("loading", "load/loading.jaz", entries.get("load/loading.jaz")),
|
|
226
|
+
cl_logo=_load_texture_asset_from_bytes(
|
|
227
|
+
"cl_logo",
|
|
228
|
+
"load/logo_crimsonland.tga",
|
|
229
|
+
entries.get("load/logo_crimsonland.tga"),
|
|
230
|
+
),
|
|
231
|
+
)
|
grim/audio.py
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from collections.abc import Callable
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import random
|
|
7
|
+
|
|
8
|
+
import pyray as rl
|
|
9
|
+
|
|
10
|
+
from .config import CrimsonConfig
|
|
11
|
+
from .console import ConsoleState
|
|
12
|
+
from . import music, sfx
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass(slots=True)
|
|
16
|
+
class AudioState:
|
|
17
|
+
ready: bool
|
|
18
|
+
music: music.MusicState
|
|
19
|
+
sfx: sfx.SfxState
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def init_audio_state(config: CrimsonConfig, assets_dir: Path, console: ConsoleState) -> AudioState:
|
|
23
|
+
music_disabled = int(config.data.get("music_disable", 0)) != 0
|
|
24
|
+
sound_disabled = int(config.data.get("sound_disable", 0)) != 0
|
|
25
|
+
music_volume = float(config.data.get("music_volume", 1.0))
|
|
26
|
+
sfx_volume = float(config.data.get("sfx_volume", 1.0))
|
|
27
|
+
|
|
28
|
+
music_enabled = not music_disabled
|
|
29
|
+
sfx_enabled = not sound_disabled
|
|
30
|
+
if not music_enabled and not sfx_enabled:
|
|
31
|
+
console.log.log("audio: disabled (music + sfx)")
|
|
32
|
+
console.log.flush()
|
|
33
|
+
return AudioState(
|
|
34
|
+
ready=False,
|
|
35
|
+
music=music.init_music_state(ready=False, enabled=False, volume=music_volume),
|
|
36
|
+
sfx=sfx.init_sfx_state(ready=False, enabled=False, volume=sfx_volume),
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
if not rl.is_audio_device_ready():
|
|
40
|
+
rl.init_audio_device()
|
|
41
|
+
ready = bool(rl.is_audio_device_ready())
|
|
42
|
+
if not ready:
|
|
43
|
+
console.log.log("audio: device init failed")
|
|
44
|
+
console.log.flush()
|
|
45
|
+
return AudioState(
|
|
46
|
+
ready=False,
|
|
47
|
+
music=music.init_music_state(ready=False, enabled=False, volume=music_volume),
|
|
48
|
+
sfx=sfx.init_sfx_state(ready=False, enabled=False, volume=sfx_volume),
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
state = AudioState(
|
|
52
|
+
ready=True,
|
|
53
|
+
music=music.init_music_state(ready=True, enabled=music_enabled, volume=music_volume),
|
|
54
|
+
sfx=sfx.init_sfx_state(ready=True, enabled=sfx_enabled, volume=sfx_volume),
|
|
55
|
+
)
|
|
56
|
+
sfx.load_sfx_index(state.sfx, assets_dir, console)
|
|
57
|
+
music.load_music_tracks(state.music, assets_dir, console)
|
|
58
|
+
return state
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def play_music(state: AudioState, track_name: str) -> None:
|
|
62
|
+
music.play_music(state.music, track_name)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def stop_music(state: AudioState) -> None:
|
|
66
|
+
music.stop_music(state.music)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def trigger_game_tune(state: AudioState, *, rand: Callable[[], int] | None = None) -> str | None:
|
|
70
|
+
return music.trigger_game_tune(state.music, rand=rand)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def play_sfx(
|
|
74
|
+
state: AudioState | None,
|
|
75
|
+
key: str | None,
|
|
76
|
+
*,
|
|
77
|
+
rng: random.Random | None = None,
|
|
78
|
+
allow_variants: bool = True,
|
|
79
|
+
) -> None:
|
|
80
|
+
if state is None:
|
|
81
|
+
return
|
|
82
|
+
sfx.play_sfx(state.sfx, key, rng=rng, allow_variants=allow_variants)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def set_sfx_volume(state: AudioState | None, volume: float) -> None:
|
|
86
|
+
if state is None:
|
|
87
|
+
return
|
|
88
|
+
sfx.set_sfx_volume(state.sfx, volume)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def set_music_volume(state: AudioState | None, volume: float) -> None:
|
|
92
|
+
if state is None:
|
|
93
|
+
return
|
|
94
|
+
music.set_music_volume(state.music, volume)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def update_audio(state: AudioState, dt: float) -> None:
|
|
98
|
+
music.update_music(state.music, dt)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def shutdown_audio(state: AudioState) -> None:
|
|
102
|
+
if not state.ready:
|
|
103
|
+
return
|
|
104
|
+
sfx.shutdown_sfx(state.sfx)
|
|
105
|
+
music.shutdown_music(state.music)
|
|
106
|
+
rl.close_audio_device()
|