crimsonland 0.1.0.dev1__tar.gz → 0.1.0.dev7__tar.gz
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.
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/PKG-INFO +1 -1
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/pyproject.toml +1 -1
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/audio_router.py +15 -3
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/cli.py +5 -2
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/demo.py +2 -2
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/effects.py +1 -1
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/game_world.py +3 -14
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/gameplay.py +105 -55
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/projectiles.py +318 -61
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/render/world_renderer.py +789 -46
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/sim/world_defs.py +16 -5
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/sim/world_state.py +1 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/arsenal_debug.py +20 -30
- crimsonland-0.1.0.dev7/src/crimson/views/audio_bootstrap.py +47 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/player.py +1 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/projectile_fx.py +1 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/projectile_render_debug.py +18 -32
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/__init__.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/assets_fetch.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/atlas.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/bonuses.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/camera.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/creatures/__init__.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/creatures/ai.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/creatures/anim.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/creatures/damage.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/creatures/runtime.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/creatures/spawn.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/debug.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/demo_trial.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/effects_atlas.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/frontend/__init__.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/frontend/assets.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/frontend/boot.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/frontend/menu.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/frontend/panels/__init__.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/frontend/panels/base.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/frontend/panels/controls.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/frontend/panels/mods.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/frontend/panels/options.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/frontend/panels/play_game.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/frontend/panels/stats.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/frontend/transitions.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/game.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/game_modes.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/input_codes.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/modes/__init__.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/modes/base_gameplay_mode.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/modes/quest_mode.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/modes/rush_mode.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/modes/survival_mode.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/modes/tutorial_mode.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/modes/typo_mode.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/paths.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/perks.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/persistence/__init__.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/persistence/highscores.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/persistence/save_status.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/player_damage.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/quests/__init__.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/quests/helpers.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/quests/registry.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/quests/results.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/quests/runtime.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/quests/tier1.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/quests/tier2.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/quests/tier3.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/quests/tier4.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/quests/tier5.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/quests/timeline.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/quests/types.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/render/__init__.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/render/terrain_fx.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/sim/__init__.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/terrain_assets.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/tutorial/__init__.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/tutorial/timeline.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/typo/__init__.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/typo/names.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/typo/player.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/typo/spawns.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/typo/typing.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/ui/__init__.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/ui/cursor.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/ui/demo_trial_overlay.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/ui/game_over.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/ui/hud.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/ui/perk_menu.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/__init__.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/aim_debug.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/animations.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/bonuses.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/camera_debug.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/camera_shake.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/corpse_stamp_debug.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/decals_debug.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/empty.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/fonts.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/game_over.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/ground.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/lighting_debug.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/particles.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/perk_menu_debug.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/perks.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/player_sprite_debug.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/projectiles.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/quest_title_overlay.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/registry.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/rush.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/small_font_debug.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/spawn_plan.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/sprites.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/survival.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/terrain.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/ui.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/views/wicons.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/weapon_sfx.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/crimson/weapons.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/grim/__init__.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/grim/app.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/grim/assets.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/grim/audio.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/grim/config.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/grim/console.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/grim/fonts/__init__.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/grim/fonts/grim_mono.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/grim/fonts/small.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/grim/input.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/grim/jaz.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/grim/math.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/grim/music.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/grim/paq.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/grim/rand.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/grim/sfx.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/grim/sfx_map.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/grim/terrain_render.py +0 -0
- {crimsonland-0.1.0.dev1 → crimsonland-0.1.0.dev7}/src/grim/view.py +0 -0
|
@@ -9,7 +9,7 @@ from grim.audio import AudioState, play_sfx, trigger_game_tune
|
|
|
9
9
|
from .creatures.spawn import CreatureTypeId
|
|
10
10
|
from .game_modes import GameMode
|
|
11
11
|
from .weapon_sfx import resolve_weapon_sfx_ref
|
|
12
|
-
from .weapons import WEAPON_BY_ID
|
|
12
|
+
from .weapons import WEAPON_BY_ID, WeaponId
|
|
13
13
|
|
|
14
14
|
_MAX_HIT_SFX_PER_FRAME = 4
|
|
15
15
|
_MAX_DEATH_SFX_PER_FRAME = 3
|
|
@@ -96,7 +96,17 @@ class AudioRouter:
|
|
|
96
96
|
return
|
|
97
97
|
|
|
98
98
|
if int(getattr(player, "shot_seq", 0)) > int(prev_shot_seq):
|
|
99
|
-
|
|
99
|
+
if float(getattr(player, "fire_bullets_timer", 0.0)) > 0.0:
|
|
100
|
+
# player_update (crimsonland.exe): when Fire Bullets is active, the regular per-weapon
|
|
101
|
+
# shot sfx is suppressed and replaced by Fire Bullets + Plasma Minigun fire sfx.
|
|
102
|
+
fire_bullets = WEAPON_BY_ID.get(int(WeaponId.FIRE_BULLETS))
|
|
103
|
+
plasma_minigun = WEAPON_BY_ID.get(int(WeaponId.PLASMA_MINIGUN))
|
|
104
|
+
if fire_bullets is not None:
|
|
105
|
+
self.play_sfx(resolve_weapon_sfx_ref(fire_bullets.fire_sound))
|
|
106
|
+
if plasma_minigun is not None:
|
|
107
|
+
self.play_sfx(resolve_weapon_sfx_ref(plasma_minigun.fire_sound))
|
|
108
|
+
else:
|
|
109
|
+
self.play_sfx(resolve_weapon_sfx_ref(weapon.fire_sound))
|
|
100
110
|
|
|
101
111
|
reload_active = bool(getattr(player, "reload_active", False))
|
|
102
112
|
reload_timer = float(getattr(player, "reload_timer", 0.0))
|
|
@@ -111,7 +121,9 @@ class AudioRouter:
|
|
|
111
121
|
beam_types: frozenset[int],
|
|
112
122
|
rand: Callable[[], int],
|
|
113
123
|
) -> str | None:
|
|
114
|
-
|
|
124
|
+
weapon = WEAPON_BY_ID.get(int(type_id))
|
|
125
|
+
ammo_class = weapon.ammo_class if weapon is not None else None
|
|
126
|
+
if ammo_class == 4:
|
|
115
127
|
return "sfx_shock_hit_01"
|
|
116
128
|
return self._rand_choice(rand, _BULLET_HIT_SFX)
|
|
117
129
|
|
|
@@ -202,8 +202,9 @@ def cmd_view(
|
|
|
202
202
|
run_view(view, width=width, height=height, title=title, fps=fps)
|
|
203
203
|
|
|
204
204
|
|
|
205
|
-
@app.
|
|
205
|
+
@app.callback(invoke_without_command=True)
|
|
206
206
|
def cmd_game(
|
|
207
|
+
ctx: typer.Context,
|
|
207
208
|
width: int | None = typer.Option(None, help="window width (default: use crimson.cfg)"),
|
|
208
209
|
height: int | None = typer.Option(None, help="window height (default: use crimson.cfg)"),
|
|
209
210
|
fps: int = typer.Option(60, help="target fps"),
|
|
@@ -221,7 +222,9 @@ def cmd_game(
|
|
|
221
222
|
help="assets root (default: base-dir; missing .paq files are downloaded)",
|
|
222
223
|
),
|
|
223
224
|
) -> None:
|
|
224
|
-
"""Run the reimplementation game flow."""
|
|
225
|
+
"""Run the reimplementation game flow (default command)."""
|
|
226
|
+
if ctx.invoked_subcommand:
|
|
227
|
+
return
|
|
225
228
|
from .game import GameConfig, run_game
|
|
226
229
|
|
|
227
230
|
config = GameConfig(
|
|
@@ -690,8 +690,8 @@ class DemoView:
|
|
|
690
690
|
rl.draw_circle(int(sx), int(sy), radius, rl.Color(200, 120, 255, 255))
|
|
691
691
|
continue
|
|
692
692
|
if proj.type_id == 3:
|
|
693
|
-
t = _clamp(proj.
|
|
694
|
-
radius = proj.
|
|
693
|
+
t = _clamp(proj.vel_x, 0.0, 1.0)
|
|
694
|
+
radius = proj.vel_y * t * 80.0
|
|
695
695
|
alpha = int((1.0 - t) * 180.0)
|
|
696
696
|
color = rl.Color(200, 120, 255, alpha)
|
|
697
697
|
rl.draw_circle_lines(int(sx), int(sy), max(1.0, radius * scale), color)
|
|
@@ -261,7 +261,7 @@ class ParticlePool:
|
|
|
261
261
|
entry.age = alpha
|
|
262
262
|
entry.scale_x = shade
|
|
263
263
|
entry.scale_y = shade
|
|
264
|
-
|
|
264
|
+
# Native only updates scale_x/scale_y; scale_z stays at its spawn value (1.0).
|
|
265
265
|
|
|
266
266
|
alive = entry.intensity > (0.0 if style == 0 else 0.8)
|
|
267
267
|
if not alive:
|
|
@@ -31,7 +31,7 @@ from .render.world_renderer import WorldRenderer
|
|
|
31
31
|
from .audio_router import AudioRouter
|
|
32
32
|
from .perks import PerkId
|
|
33
33
|
from .projectiles import ProjectileTypeId
|
|
34
|
-
from .sim.world_defs import BEAM_TYPES, CREATURE_ASSET
|
|
34
|
+
from .sim.world_defs import BEAM_TYPES, CREATURE_ASSET, ION_TYPES
|
|
35
35
|
from .sim.world_state import ProjectileHit, WorldState
|
|
36
36
|
from .weapons import WEAPON_TABLE
|
|
37
37
|
from .game_modes import GameMode
|
|
@@ -510,19 +510,8 @@ class GameWorld:
|
|
|
510
510
|
pos_y=float(target_y) + dir_y * dist * 20.0,
|
|
511
511
|
rand=rand,
|
|
512
512
|
)
|
|
513
|
-
elif type_id in
|
|
514
|
-
|
|
515
|
-
size = float(int(rand()) % 18 + 18)
|
|
516
|
-
rotation = float(int(rand()) % 628) * 0.01
|
|
517
|
-
self.fx_queue.add(
|
|
518
|
-
effect_id=0x01,
|
|
519
|
-
pos_x=float(hit_x),
|
|
520
|
-
pos_y=float(hit_y),
|
|
521
|
-
width=size,
|
|
522
|
-
height=size,
|
|
523
|
-
rotation=rotation,
|
|
524
|
-
rgba=(0.7, 0.9, 1.0, 1.0),
|
|
525
|
-
)
|
|
513
|
+
elif type_id in ION_TYPES:
|
|
514
|
+
pass
|
|
526
515
|
elif not freeze_active:
|
|
527
516
|
for _ in range(3):
|
|
528
517
|
spread = float(int(rand()) % 0x14 - 10) * 0.1
|
|
@@ -64,8 +64,8 @@ class PlayerState:
|
|
|
64
64
|
health: float = 100.0
|
|
65
65
|
size: float = 50.0
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
speed_multiplier: float = 2.0
|
|
68
|
+
move_speed: float = 0.0
|
|
69
69
|
move_phase: float = 0.0
|
|
70
70
|
heading: float = 0.0
|
|
71
71
|
death_timer: float = 16.0
|
|
@@ -358,11 +358,49 @@ class BonusPool:
|
|
|
358
358
|
return None
|
|
359
359
|
|
|
360
360
|
rng = state.rng
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
361
|
+
# Native special-case: while any player has Pistol, 3/4 chance to force a Weapon drop.
|
|
362
|
+
if players and any(int(player.weapon_id) == int(WeaponId.PISTOL) for player in players):
|
|
363
|
+
if (int(rng.rand()) & 3) < 3:
|
|
364
|
+
entry = self.spawn_at_pos(
|
|
365
|
+
pos_x,
|
|
366
|
+
pos_y,
|
|
367
|
+
state=state,
|
|
368
|
+
players=players,
|
|
369
|
+
world_width=world_width,
|
|
370
|
+
world_height=world_height,
|
|
371
|
+
)
|
|
372
|
+
if entry is None:
|
|
373
|
+
return None
|
|
374
|
+
|
|
375
|
+
entry.bonus_id = int(BonusId.WEAPON)
|
|
376
|
+
weapon_id = int(weapon_pick_random_available(state))
|
|
377
|
+
entry.amount = int(weapon_id)
|
|
378
|
+
if weapon_id == int(WeaponId.PISTOL):
|
|
379
|
+
weapon_id = int(weapon_pick_random_available(state))
|
|
380
|
+
entry.amount = int(weapon_id)
|
|
381
|
+
|
|
382
|
+
matches = sum(1 for bonus in self._entries if bonus.bonus_id == entry.bonus_id)
|
|
383
|
+
if matches > 1:
|
|
384
|
+
self._clear_entry(entry)
|
|
385
|
+
return None
|
|
386
|
+
|
|
387
|
+
if entry.amount == int(WeaponId.PISTOL) or (players and perk_active(players[0], PerkId.MY_FAVOURITE_WEAPON)):
|
|
388
|
+
self._clear_entry(entry)
|
|
389
|
+
return None
|
|
390
|
+
|
|
391
|
+
return entry
|
|
392
|
+
|
|
393
|
+
base_roll = int(rng.rand())
|
|
394
|
+
if base_roll % 9 != 1:
|
|
395
|
+
allow_without_magnet = False
|
|
396
|
+
if players and int(players[0].weapon_id) == int(WeaponId.PISTOL):
|
|
397
|
+
allow_without_magnet = int(rng.rand()) % 5 == 1
|
|
398
|
+
|
|
399
|
+
if not allow_without_magnet:
|
|
400
|
+
if not (players and perk_active(players[0], PerkId.BONUS_MAGNET)):
|
|
401
|
+
return None
|
|
402
|
+
if int(rng.rand()) % 10 != 2:
|
|
403
|
+
return None
|
|
366
404
|
|
|
367
405
|
entry = self.spawn_at_pos(
|
|
368
406
|
pos_x,
|
|
@@ -377,11 +415,9 @@ class BonusPool:
|
|
|
377
415
|
|
|
378
416
|
if entry.bonus_id == int(BonusId.WEAPON):
|
|
379
417
|
near_sq = BONUS_WEAPON_NEAR_RADIUS * BONUS_WEAPON_NEAR_RADIUS
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
entry.amount = 100
|
|
384
|
-
break
|
|
418
|
+
if players and _distance_sq(pos_x, pos_y, players[0].pos_x, players[0].pos_y) < near_sq:
|
|
419
|
+
entry.bonus_id = int(BonusId.POINTS)
|
|
420
|
+
entry.amount = 100
|
|
385
421
|
|
|
386
422
|
if entry.bonus_id != int(BonusId.POINTS):
|
|
387
423
|
matches = sum(1 for bonus in self._entries if bonus.bonus_id == entry.bonus_id)
|
|
@@ -390,10 +426,9 @@ class BonusPool:
|
|
|
390
426
|
return None
|
|
391
427
|
|
|
392
428
|
if entry.bonus_id == int(BonusId.WEAPON):
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
return None
|
|
429
|
+
if players and entry.amount == players[0].weapon_id:
|
|
430
|
+
self._clear_entry(entry)
|
|
431
|
+
return None
|
|
397
432
|
|
|
398
433
|
return entry
|
|
399
434
|
|
|
@@ -1592,6 +1627,7 @@ def player_fire_weapon(player: PlayerState, input_state: PlayerInput, dt: float,
|
|
|
1592
1627
|
|
|
1593
1628
|
firing_during_reload = False
|
|
1594
1629
|
ammo_cost = 1.0
|
|
1630
|
+
is_fire_bullets = float(player.fire_bullets_timer) > 0.0
|
|
1595
1631
|
if player.reload_timer > 0.0:
|
|
1596
1632
|
if player.ammo <= 0 and player.experience > 0:
|
|
1597
1633
|
if perk_active(player, PerkId.REGRESSION_BULLETS):
|
|
@@ -1616,7 +1652,7 @@ def player_fire_weapon(player: PlayerState, input_state: PlayerInput, dt: float,
|
|
|
1616
1652
|
else:
|
|
1617
1653
|
return
|
|
1618
1654
|
|
|
1619
|
-
if player.ammo <= 0 and not firing_during_reload:
|
|
1655
|
+
if player.ammo <= 0 and not firing_during_reload and not is_fire_bullets:
|
|
1620
1656
|
player_start_reload(player, state)
|
|
1621
1657
|
return
|
|
1622
1658
|
|
|
@@ -1624,20 +1660,18 @@ def player_fire_weapon(player: PlayerState, input_state: PlayerInput, dt: float,
|
|
|
1624
1660
|
fire_bullets_weapon = weapon_entry_for_projectile_type_id(int(ProjectileTypeId.FIRE_BULLETS))
|
|
1625
1661
|
|
|
1626
1662
|
shot_cooldown = float(weapon.shot_cooldown) if weapon.shot_cooldown is not None else 0.0
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1663
|
+
spread_heat_base = float(weapon.spread_heat_inc) if weapon.spread_heat_inc is not None else 0.0
|
|
1664
|
+
if is_fire_bullets and pellet_count == 1 and fire_bullets_weapon is not None and fire_bullets_weapon.spread_heat_inc is not None:
|
|
1665
|
+
spread_heat_base = float(fire_bullets_weapon.spread_heat_inc)
|
|
1666
|
+
|
|
1667
|
+
if is_fire_bullets and pellet_count == 1 and fire_bullets_weapon is not None:
|
|
1630
1668
|
shot_cooldown = (
|
|
1631
1669
|
float(fire_bullets_weapon.shot_cooldown)
|
|
1632
1670
|
if fire_bullets_weapon.shot_cooldown is not None
|
|
1633
1671
|
else 0.0
|
|
1634
1672
|
)
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
if fire_bullets_weapon.spread_heat_inc is not None
|
|
1638
|
-
else 0.0
|
|
1639
|
-
)
|
|
1640
|
-
spread_inc *= 1.3
|
|
1673
|
+
|
|
1674
|
+
spread_inc = spread_heat_base * 1.3
|
|
1641
1675
|
|
|
1642
1676
|
if perk_active(player, PerkId.FASTSHOT):
|
|
1643
1677
|
shot_cooldown *= 0.88
|
|
@@ -1657,6 +1691,7 @@ def player_fire_weapon(player: PlayerState, input_state: PlayerInput, dt: float,
|
|
|
1657
1691
|
aim_jitter_x = aim_x + math.cos(dir_angle) * offset
|
|
1658
1692
|
aim_jitter_y = aim_y + math.sin(dir_angle) * offset
|
|
1659
1693
|
shot_angle = math.atan2(aim_jitter_y - float(player.pos_y), aim_jitter_x - float(player.pos_x)) + math.pi / 2.0
|
|
1694
|
+
particle_angle = shot_angle - math.pi / 2.0
|
|
1660
1695
|
|
|
1661
1696
|
muzzle_x = player.pos_x + player.aim_dir_x * 16.0
|
|
1662
1697
|
muzzle_y = player.pos_y + player.aim_dir_y * 16.0
|
|
@@ -1676,14 +1711,12 @@ def player_fire_weapon(player: PlayerState, input_state: PlayerInput, dt: float,
|
|
|
1676
1711
|
return 0.0013
|
|
1677
1712
|
return 0.0015
|
|
1678
1713
|
|
|
1679
|
-
if
|
|
1714
|
+
if is_fire_bullets:
|
|
1680
1715
|
pellets = max(1, int(pellet_count))
|
|
1681
1716
|
shot_count = pellets
|
|
1682
1717
|
meta = _projectile_meta_for_type_id(ProjectileTypeId.FIRE_BULLETS)
|
|
1683
1718
|
for _ in range(pellets):
|
|
1684
|
-
angle = shot_angle
|
|
1685
|
-
if pellets > 1:
|
|
1686
|
-
angle += float(int(state.rng.rand()) % 200 - 100) * 0.0015
|
|
1719
|
+
angle = shot_angle + float(int(state.rng.rand()) % 200 - 100) * 0.0015
|
|
1687
1720
|
state.projectiles.spawn(
|
|
1688
1721
|
pos_x=muzzle_x,
|
|
1689
1722
|
pos_y=muzzle_y,
|
|
@@ -1713,16 +1746,16 @@ def player_fire_weapon(player: PlayerState, input_state: PlayerInput, dt: float,
|
|
|
1713
1746
|
state.secondary_projectiles.spawn(pos_x=muzzle_x, pos_y=muzzle_y, angle=shot_angle, type_id=4, owner_id=owner_id)
|
|
1714
1747
|
elif weapon_id == WeaponId.FLAMETHROWER:
|
|
1715
1748
|
# Flamethrower -> fast particle weapon (style 0), fractional ammo drain.
|
|
1716
|
-
state.particles.spawn_particle(pos_x=muzzle_x, pos_y=muzzle_y, angle=
|
|
1749
|
+
state.particles.spawn_particle(pos_x=muzzle_x, pos_y=muzzle_y, angle=particle_angle, intensity=1.0, owner_id=owner_id)
|
|
1717
1750
|
ammo_cost = 0.1
|
|
1718
1751
|
elif weapon_id == WeaponId.BLOW_TORCH:
|
|
1719
1752
|
# Blow Torch -> fast particle weapon (style 1), fractional ammo drain.
|
|
1720
|
-
particle_id = state.particles.spawn_particle(pos_x=muzzle_x, pos_y=muzzle_y, angle=
|
|
1753
|
+
particle_id = state.particles.spawn_particle(pos_x=muzzle_x, pos_y=muzzle_y, angle=particle_angle, intensity=1.0, owner_id=owner_id)
|
|
1721
1754
|
state.particles.entries[particle_id].style_id = 1
|
|
1722
1755
|
ammo_cost = 0.05
|
|
1723
1756
|
elif weapon_id == WeaponId.HR_FLAMER:
|
|
1724
1757
|
# HR Flamer -> fast particle weapon (style 2), fractional ammo drain.
|
|
1725
|
-
particle_id = state.particles.spawn_particle(pos_x=muzzle_x, pos_y=muzzle_y, angle=
|
|
1758
|
+
particle_id = state.particles.spawn_particle(pos_x=muzzle_x, pos_y=muzzle_y, angle=particle_angle, intensity=1.0, owner_id=owner_id)
|
|
1726
1759
|
state.particles.entries[particle_id].style_id = 2
|
|
1727
1760
|
ammo_cost = 0.1
|
|
1728
1761
|
elif weapon_id == WeaponId.BUBBLEGUN:
|
|
@@ -1833,15 +1866,17 @@ def player_fire_weapon(player: PlayerState, input_state: PlayerInput, dt: float,
|
|
|
1833
1866
|
player.spread_heat = min(0.48, max(0.0, player.spread_heat + spread_inc))
|
|
1834
1867
|
|
|
1835
1868
|
muzzle_inc = float(weapon.spread_heat_inc) if weapon.spread_heat_inc is not None else 0.0
|
|
1869
|
+
if is_fire_bullets and pellet_count == 1 and fire_bullets_weapon is not None and fire_bullets_weapon.spread_heat_inc is not None:
|
|
1870
|
+
muzzle_inc = float(fire_bullets_weapon.spread_heat_inc)
|
|
1836
1871
|
player.muzzle_flash_alpha = min(1.0, player.muzzle_flash_alpha)
|
|
1837
1872
|
player.muzzle_flash_alpha = min(1.0, player.muzzle_flash_alpha + muzzle_inc)
|
|
1838
1873
|
player.muzzle_flash_alpha = min(0.8, player.muzzle_flash_alpha)
|
|
1839
1874
|
|
|
1840
1875
|
player.shot_seq += 1
|
|
1841
|
-
if not firing_during_reload and state.bonuses.reflex_boost <= 0.0:
|
|
1876
|
+
if (not firing_during_reload) and state.bonuses.reflex_boost <= 0.0 and not is_fire_bullets:
|
|
1842
1877
|
player.ammo = max(0.0, float(player.ammo) - float(ammo_cost))
|
|
1843
|
-
|
|
1844
|
-
|
|
1878
|
+
if (not firing_during_reload) and player.ammo <= 0.0 and player.reload_timer <= 0.0:
|
|
1879
|
+
player_start_reload(player, state)
|
|
1845
1880
|
|
|
1846
1881
|
|
|
1847
1882
|
def player_update(player: PlayerState, input_state: PlayerInput, dt: float, state: GameplayState, *, world_size: float = 1024.0) -> None:
|
|
@@ -1885,35 +1920,50 @@ def player_update(player: PlayerState, input_state: PlayerInput, dt: float, stat
|
|
|
1885
1920
|
player.aim_heading = math.atan2(aim_dir_y, aim_dir_x) + math.pi / 2.0
|
|
1886
1921
|
|
|
1887
1922
|
# Movement.
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1923
|
+
raw_move_x = float(input_state.move_x)
|
|
1924
|
+
raw_move_y = float(input_state.move_y)
|
|
1925
|
+
raw_mag = math.hypot(raw_move_x, raw_move_y)
|
|
1926
|
+
moving_input = raw_mag > 0.2
|
|
1927
|
+
|
|
1928
|
+
if moving_input:
|
|
1929
|
+
inv = 1.0 / raw_mag if raw_mag > 1e-9 else 0.0
|
|
1930
|
+
move_x = raw_move_x * inv
|
|
1931
|
+
move_y = raw_move_y * inv
|
|
1932
|
+
player.heading = math.atan2(move_y, move_x) + math.pi / 2.0
|
|
1933
|
+
if perk_active(player, PerkId.LONG_DISTANCE_RUNNER):
|
|
1934
|
+
if player.move_speed < 2.0:
|
|
1935
|
+
player.move_speed = float(player.move_speed + dt * 4.0)
|
|
1936
|
+
player.move_speed = float(player.move_speed + dt)
|
|
1937
|
+
if player.move_speed > 2.8:
|
|
1938
|
+
player.move_speed = 2.8
|
|
1894
1939
|
else:
|
|
1895
|
-
player.
|
|
1896
|
-
|
|
1940
|
+
player.move_speed = float(player.move_speed + dt * 5.0)
|
|
1941
|
+
if player.move_speed > 2.0:
|
|
1942
|
+
player.move_speed = 2.0
|
|
1897
1943
|
else:
|
|
1898
|
-
player.
|
|
1944
|
+
player.move_speed = float(player.move_speed - dt * 15.0)
|
|
1945
|
+
if player.move_speed < 0.0:
|
|
1946
|
+
player.move_speed = 0.0
|
|
1947
|
+
move_x = math.cos(player.heading - math.pi / 2.0)
|
|
1948
|
+
move_y = math.sin(player.heading - math.pi / 2.0)
|
|
1949
|
+
|
|
1950
|
+
if player.weapon_id == WeaponId.MEAN_MINIGUN and player.move_speed > 0.8:
|
|
1951
|
+
player.move_speed = 0.8
|
|
1899
1952
|
|
|
1900
|
-
speed_multiplier = float(player.
|
|
1953
|
+
speed_multiplier = float(player.speed_multiplier)
|
|
1901
1954
|
if player.speed_bonus_timer > 0.0:
|
|
1902
1955
|
speed_multiplier += 1.0
|
|
1903
|
-
|
|
1956
|
+
|
|
1957
|
+
speed = player.move_speed * speed_multiplier * 25.0
|
|
1958
|
+
if moving_input:
|
|
1959
|
+
speed *= min(1.0, raw_mag)
|
|
1904
1960
|
if perk_active(player, PerkId.ALTERNATE_WEAPON):
|
|
1905
1961
|
speed *= 0.8
|
|
1962
|
+
|
|
1906
1963
|
player.pos_x = _clamp(player.pos_x + move_x * speed * dt, 0.0, float(world_size))
|
|
1907
1964
|
player.pos_y = _clamp(player.pos_y + move_y * speed * dt, 0.0, float(world_size))
|
|
1908
1965
|
|
|
1909
|
-
|
|
1910
|
-
player.heading = math.atan2(move_y, move_x) + math.pi / 2.0
|
|
1911
|
-
|
|
1912
|
-
move_dist = math.hypot(player.pos_x - prev_x, player.pos_y - prev_y)
|
|
1913
|
-
if move_dist > 1e-9:
|
|
1914
|
-
# Port of `move_phase += frame_dt * move_speed * 19.0` (player_update).
|
|
1915
|
-
move_speed = move_dist / dt / 120.0
|
|
1916
|
-
player.move_phase += dt * move_speed * 19.0
|
|
1966
|
+
player.move_phase += dt * player.move_speed * 19.0
|
|
1917
1967
|
|
|
1918
1968
|
stationary = abs(player.pos_x - prev_x) <= 1e-9 and abs(player.pos_y - prev_y) <= 1e-9
|
|
1919
1969
|
reload_scale = 1.0
|