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
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from ..projectiles import ProjectileTypeId
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass(frozen=True, slots=True)
|
|
9
|
+
class PlasmaProjectileRenderConfig:
|
|
10
|
+
rgb: tuple[float, float, float]
|
|
11
|
+
spacing: float
|
|
12
|
+
seg_limit: int
|
|
13
|
+
tail_size: float
|
|
14
|
+
head_size: float
|
|
15
|
+
head_alpha_mul: float
|
|
16
|
+
aura_rgb: tuple[float, float, float]
|
|
17
|
+
aura_size: float
|
|
18
|
+
aura_alpha_mul: float
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
_DEFAULT_PLASMA_RENDER_CONFIG = PlasmaProjectileRenderConfig(
|
|
22
|
+
rgb=(1.0, 1.0, 1.0),
|
|
23
|
+
spacing=2.1,
|
|
24
|
+
seg_limit=3,
|
|
25
|
+
tail_size=12.0,
|
|
26
|
+
head_size=16.0,
|
|
27
|
+
head_alpha_mul=0.45,
|
|
28
|
+
aura_rgb=(1.0, 1.0, 1.0),
|
|
29
|
+
aura_size=120.0,
|
|
30
|
+
aura_alpha_mul=0.15,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
PLASMA_PROJECTILE_RENDER_CONFIG_BY_TYPE_ID: dict[int, PlasmaProjectileRenderConfig] = {
|
|
35
|
+
int(ProjectileTypeId.PLASMA_RIFLE): PlasmaProjectileRenderConfig(
|
|
36
|
+
rgb=(1.0, 1.0, 1.0),
|
|
37
|
+
spacing=2.5,
|
|
38
|
+
seg_limit=8,
|
|
39
|
+
tail_size=22.0,
|
|
40
|
+
head_size=56.0,
|
|
41
|
+
head_alpha_mul=0.45,
|
|
42
|
+
aura_rgb=(1.0, 1.0, 1.0),
|
|
43
|
+
aura_size=256.0,
|
|
44
|
+
aura_alpha_mul=0.3,
|
|
45
|
+
),
|
|
46
|
+
int(ProjectileTypeId.PLASMA_MINIGUN): _DEFAULT_PLASMA_RENDER_CONFIG,
|
|
47
|
+
int(ProjectileTypeId.PLASMA_CANNON): PlasmaProjectileRenderConfig(
|
|
48
|
+
rgb=(1.0, 1.0, 1.0),
|
|
49
|
+
spacing=2.6,
|
|
50
|
+
seg_limit=18,
|
|
51
|
+
tail_size=44.0,
|
|
52
|
+
head_size=84.0,
|
|
53
|
+
head_alpha_mul=0.45,
|
|
54
|
+
aura_rgb=(1.0, 1.0, 1.0),
|
|
55
|
+
aura_size=256.0,
|
|
56
|
+
aura_alpha_mul=0.4,
|
|
57
|
+
),
|
|
58
|
+
int(ProjectileTypeId.SPIDER_PLASMA): PlasmaProjectileRenderConfig(
|
|
59
|
+
rgb=(0.3, 1.0, 0.3),
|
|
60
|
+
spacing=_DEFAULT_PLASMA_RENDER_CONFIG.spacing,
|
|
61
|
+
seg_limit=_DEFAULT_PLASMA_RENDER_CONFIG.seg_limit,
|
|
62
|
+
tail_size=_DEFAULT_PLASMA_RENDER_CONFIG.tail_size,
|
|
63
|
+
head_size=_DEFAULT_PLASMA_RENDER_CONFIG.head_size,
|
|
64
|
+
head_alpha_mul=_DEFAULT_PLASMA_RENDER_CONFIG.head_alpha_mul,
|
|
65
|
+
aura_rgb=(0.3, 1.0, 0.3),
|
|
66
|
+
aura_size=_DEFAULT_PLASMA_RENDER_CONFIG.aura_size,
|
|
67
|
+
aura_alpha_mul=_DEFAULT_PLASMA_RENDER_CONFIG.aura_alpha_mul,
|
|
68
|
+
),
|
|
69
|
+
int(ProjectileTypeId.SHRINKIFIER): PlasmaProjectileRenderConfig(
|
|
70
|
+
rgb=(0.3, 0.3, 1.0),
|
|
71
|
+
spacing=_DEFAULT_PLASMA_RENDER_CONFIG.spacing,
|
|
72
|
+
seg_limit=_DEFAULT_PLASMA_RENDER_CONFIG.seg_limit,
|
|
73
|
+
tail_size=_DEFAULT_PLASMA_RENDER_CONFIG.tail_size,
|
|
74
|
+
head_size=_DEFAULT_PLASMA_RENDER_CONFIG.head_size,
|
|
75
|
+
head_alpha_mul=_DEFAULT_PLASMA_RENDER_CONFIG.head_alpha_mul,
|
|
76
|
+
aura_rgb=(0.3, 0.3, 1.0),
|
|
77
|
+
aura_size=_DEFAULT_PLASMA_RENDER_CONFIG.aura_size,
|
|
78
|
+
aura_alpha_mul=_DEFAULT_PLASMA_RENDER_CONFIG.aura_alpha_mul,
|
|
79
|
+
),
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def plasma_projectile_render_config(type_id: int) -> PlasmaProjectileRenderConfig:
|
|
84
|
+
return PLASMA_PROJECTILE_RENDER_CONFIG_BY_TYPE_ID.get(int(type_id), _DEFAULT_PLASMA_RENDER_CONFIG)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
BEAM_EFFECT_SCALE_BY_TYPE_ID: dict[int, float] = {
|
|
88
|
+
int(ProjectileTypeId.ION_MINIGUN): 1.05,
|
|
89
|
+
int(ProjectileTypeId.ION_RIFLE): 2.2,
|
|
90
|
+
int(ProjectileTypeId.ION_CANNON): 3.5,
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def beam_effect_scale(type_id: int) -> float:
|
|
95
|
+
return float(BEAM_EFFECT_SCALE_BY_TYPE_ID.get(int(type_id), 0.8))
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
KNOWN_PROJ_RGB_BY_TYPE_ID: dict[int, tuple[int, int, int]] = {
|
|
99
|
+
int(ProjectileTypeId.ION_RIFLE): (120, 200, 255),
|
|
100
|
+
int(ProjectileTypeId.ION_MINIGUN): (120, 200, 255),
|
|
101
|
+
int(ProjectileTypeId.ION_CANNON): (120, 200, 255),
|
|
102
|
+
int(ProjectileTypeId.FIRE_BULLETS): (255, 170, 90),
|
|
103
|
+
int(ProjectileTypeId.SHRINKIFIER): (160, 255, 170),
|
|
104
|
+
int(ProjectileTypeId.BLADE_GUN): (240, 120, 255),
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def known_proj_rgb(type_id: int) -> tuple[int, int, int]:
|
|
109
|
+
return KNOWN_PROJ_RGB_BY_TYPE_ID.get(int(type_id), (240, 220, 160))
|
|
110
|
+
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
import math
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
import pyray as rl
|
|
8
|
+
|
|
9
|
+
from grim.math import clamp
|
|
10
|
+
|
|
11
|
+
from ..effects_atlas import EFFECT_ID_ATLAS_TABLE_BY_ID, SIZE_CODE_GRID
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from .world_renderer import WorldRenderer
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass(frozen=True, slots=True)
|
|
18
|
+
class SecondaryProjectileDrawCtx:
|
|
19
|
+
renderer: WorldRenderer
|
|
20
|
+
proj: object
|
|
21
|
+
proj_type: int
|
|
22
|
+
sx: float
|
|
23
|
+
sy: float
|
|
24
|
+
angle: float
|
|
25
|
+
scale: float
|
|
26
|
+
alpha: float
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _draw_secondary_rocket_like(ctx: SecondaryProjectileDrawCtx) -> bool:
|
|
30
|
+
renderer = ctx.renderer
|
|
31
|
+
proj_type = int(ctx.proj_type)
|
|
32
|
+
if proj_type not in (1, 2, 4):
|
|
33
|
+
return False
|
|
34
|
+
|
|
35
|
+
texture = renderer.projs_texture
|
|
36
|
+
if texture is None:
|
|
37
|
+
return False
|
|
38
|
+
|
|
39
|
+
cell_w = float(texture.width) / 4.0
|
|
40
|
+
if cell_w <= 1e-6:
|
|
41
|
+
return True
|
|
42
|
+
|
|
43
|
+
alpha = float(ctx.alpha)
|
|
44
|
+
base_alpha = clamp(alpha * 0.9, 0.0, 1.0)
|
|
45
|
+
base_tint = renderer._color_from_rgba((0.8, 0.8, 0.8, base_alpha))
|
|
46
|
+
base_size = 14.0
|
|
47
|
+
if proj_type == 2:
|
|
48
|
+
base_size = 10.0
|
|
49
|
+
elif proj_type == 4:
|
|
50
|
+
base_size = 8.0
|
|
51
|
+
sprite_scale = (base_size * float(ctx.scale)) / cell_w
|
|
52
|
+
|
|
53
|
+
fx_detail_1 = bool(renderer.config.data.get("fx_detail_1", 0)) if renderer.config is not None else True
|
|
54
|
+
if fx_detail_1 and renderer.particles_texture is not None:
|
|
55
|
+
particles_texture = renderer.particles_texture
|
|
56
|
+
atlas = EFFECT_ID_ATLAS_TABLE_BY_ID.get(0x0D)
|
|
57
|
+
if atlas is not None:
|
|
58
|
+
grid = SIZE_CODE_GRID.get(int(atlas.size_code))
|
|
59
|
+
if grid:
|
|
60
|
+
particle_cell_w = float(particles_texture.width) / float(grid)
|
|
61
|
+
particle_cell_h = float(particles_texture.height) / float(grid)
|
|
62
|
+
frame = int(atlas.frame)
|
|
63
|
+
col = frame % grid
|
|
64
|
+
row = frame // grid
|
|
65
|
+
src = rl.Rectangle(
|
|
66
|
+
particle_cell_w * float(col),
|
|
67
|
+
particle_cell_h * float(row),
|
|
68
|
+
max(0.0, particle_cell_w - 2.0),
|
|
69
|
+
max(0.0, particle_cell_h - 2.0),
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
angle = float(ctx.angle)
|
|
73
|
+
dir_x = math.cos(angle - math.pi / 2.0)
|
|
74
|
+
dir_y = math.sin(angle - math.pi / 2.0)
|
|
75
|
+
|
|
76
|
+
sx = float(ctx.sx)
|
|
77
|
+
sy = float(ctx.sy)
|
|
78
|
+
scale = float(ctx.scale)
|
|
79
|
+
|
|
80
|
+
def _draw_rocket_fx(
|
|
81
|
+
*,
|
|
82
|
+
size: float,
|
|
83
|
+
offset: float,
|
|
84
|
+
rgba: tuple[float, float, float, float],
|
|
85
|
+
) -> None:
|
|
86
|
+
fx_alpha = rgba[3]
|
|
87
|
+
if fx_alpha <= 1e-3:
|
|
88
|
+
return
|
|
89
|
+
tint = renderer._color_from_rgba(rgba)
|
|
90
|
+
fx_sx = sx - dir_x * offset * scale
|
|
91
|
+
fx_sy = sy - dir_y * offset * scale
|
|
92
|
+
dst_size = float(size) * scale
|
|
93
|
+
dst = rl.Rectangle(float(fx_sx), float(fx_sy), float(dst_size), float(dst_size))
|
|
94
|
+
origin = rl.Vector2(dst_size * 0.5, dst_size * 0.5)
|
|
95
|
+
rl.draw_texture_pro(particles_texture, src, dst, origin, 0.0, tint)
|
|
96
|
+
|
|
97
|
+
rl.begin_blend_mode(rl.BLEND_ADDITIVE)
|
|
98
|
+
# Large bloom around the rocket (effect_id=0x0D).
|
|
99
|
+
_draw_rocket_fx(size=140.0, offset=5.0, rgba=(1.0, 1.0, 1.0, alpha * 0.48))
|
|
100
|
+
|
|
101
|
+
if proj_type == 4:
|
|
102
|
+
_draw_rocket_fx(size=30.0, offset=9.0, rgba=(0.7, 0.7, 1.0, alpha * 0.158))
|
|
103
|
+
elif proj_type == 2:
|
|
104
|
+
_draw_rocket_fx(size=40.0, offset=9.0, rgba=(1.0, 1.0, 1.0, alpha * 0.58))
|
|
105
|
+
else:
|
|
106
|
+
_draw_rocket_fx(size=60.0, offset=9.0, rgba=(1.0, 1.0, 1.0, alpha * 0.68))
|
|
107
|
+
|
|
108
|
+
rl.end_blend_mode()
|
|
109
|
+
|
|
110
|
+
renderer._draw_atlas_sprite(
|
|
111
|
+
texture,
|
|
112
|
+
grid=4,
|
|
113
|
+
frame=3,
|
|
114
|
+
x=float(ctx.sx),
|
|
115
|
+
y=float(ctx.sy),
|
|
116
|
+
scale=sprite_scale,
|
|
117
|
+
rotation_rad=float(ctx.angle),
|
|
118
|
+
tint=base_tint,
|
|
119
|
+
)
|
|
120
|
+
return True
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _draw_secondary_type4_fallback(ctx: SecondaryProjectileDrawCtx) -> bool:
|
|
124
|
+
if int(ctx.proj_type) != 4:
|
|
125
|
+
return False
|
|
126
|
+
rl.draw_circle(
|
|
127
|
+
int(ctx.sx),
|
|
128
|
+
int(ctx.sy),
|
|
129
|
+
max(1.0, 12.0 * float(ctx.scale)),
|
|
130
|
+
rl.Color(200, 120, 255, int(255 * float(ctx.alpha) + 0.5)),
|
|
131
|
+
)
|
|
132
|
+
return True
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _draw_secondary_detonation(ctx: SecondaryProjectileDrawCtx) -> bool:
|
|
136
|
+
renderer = ctx.renderer
|
|
137
|
+
if int(ctx.proj_type) != 3:
|
|
138
|
+
return False
|
|
139
|
+
|
|
140
|
+
# Secondary projectile detonation visuals (secondary_projectile_update + render).
|
|
141
|
+
t = clamp(float(getattr(ctx.proj, "vel_x", 0.0)), 0.0, 1.0)
|
|
142
|
+
det_scale = float(getattr(ctx.proj, "vel_y", 1.0))
|
|
143
|
+
fade = (1.0 - t) * float(ctx.alpha)
|
|
144
|
+
if fade <= 1e-3 or det_scale <= 1e-6:
|
|
145
|
+
return True
|
|
146
|
+
|
|
147
|
+
sx = float(ctx.sx)
|
|
148
|
+
sy = float(ctx.sy)
|
|
149
|
+
scale = float(ctx.scale)
|
|
150
|
+
if renderer.particles_texture is None:
|
|
151
|
+
radius = det_scale * t * 80.0
|
|
152
|
+
alpha_byte = int(clamp((1.0 - t) * 180.0 * float(ctx.alpha), 0.0, 255.0) + 0.5)
|
|
153
|
+
color = rl.Color(255, 180, 100, alpha_byte)
|
|
154
|
+
rl.draw_circle_lines(int(sx), int(sy), max(1.0, radius * scale), color)
|
|
155
|
+
return True
|
|
156
|
+
|
|
157
|
+
atlas = EFFECT_ID_ATLAS_TABLE_BY_ID.get(0x0D)
|
|
158
|
+
if atlas is None:
|
|
159
|
+
return True
|
|
160
|
+
grid = SIZE_CODE_GRID.get(int(atlas.size_code))
|
|
161
|
+
if not grid:
|
|
162
|
+
return True
|
|
163
|
+
frame = int(atlas.frame)
|
|
164
|
+
col = frame % grid
|
|
165
|
+
row = frame // grid
|
|
166
|
+
cell_w = float(renderer.particles_texture.width) / float(grid)
|
|
167
|
+
cell_h = float(renderer.particles_texture.height) / float(grid)
|
|
168
|
+
src = rl.Rectangle(
|
|
169
|
+
cell_w * float(col),
|
|
170
|
+
cell_h * float(row),
|
|
171
|
+
max(0.0, cell_w - 2.0),
|
|
172
|
+
max(0.0, cell_h - 2.0),
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
def _draw_detonation_quad(*, size: float, alpha_mul: float) -> None:
|
|
176
|
+
a = fade * alpha_mul
|
|
177
|
+
if a <= 1e-3:
|
|
178
|
+
return
|
|
179
|
+
dst_size = float(size) * scale
|
|
180
|
+
if dst_size <= 1e-3:
|
|
181
|
+
return
|
|
182
|
+
tint = renderer._color_from_rgba((1.0, 0.6, 0.1, a))
|
|
183
|
+
dst = rl.Rectangle(float(sx), float(sy), float(dst_size), float(dst_size))
|
|
184
|
+
origin = rl.Vector2(float(dst_size) * 0.5, float(dst_size) * 0.5)
|
|
185
|
+
rl.draw_texture_pro(renderer.particles_texture, src, dst, origin, 0.0, tint)
|
|
186
|
+
|
|
187
|
+
rl.begin_blend_mode(rl.BLEND_ADDITIVE)
|
|
188
|
+
_draw_detonation_quad(size=det_scale * t * 64.0, alpha_mul=1.0)
|
|
189
|
+
_draw_detonation_quad(size=det_scale * t * 200.0, alpha_mul=0.3)
|
|
190
|
+
rl.end_blend_mode()
|
|
191
|
+
return True
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
SECONDARY_PROJECTILE_DRAW_HANDLERS = (
|
|
195
|
+
_draw_secondary_rocket_like,
|
|
196
|
+
_draw_secondary_type4_fallback,
|
|
197
|
+
_draw_secondary_detonation,
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def draw_secondary_projectile_from_registry(ctx: SecondaryProjectileDrawCtx) -> bool:
|
|
202
|
+
for handler in SECONDARY_PROJECTILE_DRAW_HANDLERS:
|
|
203
|
+
if handler(ctx):
|
|
204
|
+
return True
|
|
205
|
+
return False
|
|
206
|
+
|