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.
Files changed (139) hide show
  1. crimson/__init__.py +24 -0
  2. crimson/assets_fetch.py +60 -0
  3. crimson/atlas.py +92 -0
  4. crimson/audio_router.py +155 -0
  5. crimson/bonuses.py +167 -0
  6. crimson/camera.py +75 -0
  7. crimson/cli.py +380 -0
  8. crimson/creatures/__init__.py +8 -0
  9. crimson/creatures/ai.py +186 -0
  10. crimson/creatures/anim.py +173 -0
  11. crimson/creatures/damage.py +103 -0
  12. crimson/creatures/runtime.py +1019 -0
  13. crimson/creatures/spawn.py +2871 -0
  14. crimson/debug.py +7 -0
  15. crimson/demo.py +1360 -0
  16. crimson/demo_trial.py +140 -0
  17. crimson/effects.py +1086 -0
  18. crimson/effects_atlas.py +73 -0
  19. crimson/frontend/__init__.py +1 -0
  20. crimson/frontend/assets.py +43 -0
  21. crimson/frontend/boot.py +424 -0
  22. crimson/frontend/menu.py +700 -0
  23. crimson/frontend/panels/__init__.py +1 -0
  24. crimson/frontend/panels/base.py +410 -0
  25. crimson/frontend/panels/controls.py +132 -0
  26. crimson/frontend/panels/mods.py +128 -0
  27. crimson/frontend/panels/options.py +409 -0
  28. crimson/frontend/panels/play_game.py +627 -0
  29. crimson/frontend/panels/stats.py +351 -0
  30. crimson/frontend/transitions.py +31 -0
  31. crimson/game.py +2533 -0
  32. crimson/game_modes.py +15 -0
  33. crimson/game_world.py +652 -0
  34. crimson/gameplay.py +2467 -0
  35. crimson/input_codes.py +176 -0
  36. crimson/modes/__init__.py +1 -0
  37. crimson/modes/base_gameplay_mode.py +219 -0
  38. crimson/modes/quest_mode.py +502 -0
  39. crimson/modes/rush_mode.py +300 -0
  40. crimson/modes/survival_mode.py +792 -0
  41. crimson/modes/tutorial_mode.py +648 -0
  42. crimson/modes/typo_mode.py +472 -0
  43. crimson/paths.py +23 -0
  44. crimson/perks.py +828 -0
  45. crimson/persistence/__init__.py +1 -0
  46. crimson/persistence/highscores.py +385 -0
  47. crimson/persistence/save_status.py +245 -0
  48. crimson/player_damage.py +77 -0
  49. crimson/projectiles.py +1133 -0
  50. crimson/quests/__init__.py +18 -0
  51. crimson/quests/helpers.py +147 -0
  52. crimson/quests/registry.py +49 -0
  53. crimson/quests/results.py +164 -0
  54. crimson/quests/runtime.py +91 -0
  55. crimson/quests/tier1.py +620 -0
  56. crimson/quests/tier2.py +652 -0
  57. crimson/quests/tier3.py +579 -0
  58. crimson/quests/tier4.py +721 -0
  59. crimson/quests/tier5.py +886 -0
  60. crimson/quests/timeline.py +115 -0
  61. crimson/quests/types.py +70 -0
  62. crimson/render/__init__.py +1 -0
  63. crimson/render/terrain_fx.py +88 -0
  64. crimson/render/world_renderer.py +1941 -0
  65. crimson/sim/__init__.py +1 -0
  66. crimson/sim/world_defs.py +67 -0
  67. crimson/sim/world_state.py +422 -0
  68. crimson/terrain_assets.py +19 -0
  69. crimson/tutorial/__init__.py +12 -0
  70. crimson/tutorial/timeline.py +291 -0
  71. crimson/typo/__init__.py +2 -0
  72. crimson/typo/names.py +233 -0
  73. crimson/typo/player.py +43 -0
  74. crimson/typo/spawns.py +73 -0
  75. crimson/typo/typing.py +52 -0
  76. crimson/ui/__init__.py +3 -0
  77. crimson/ui/cursor.py +95 -0
  78. crimson/ui/demo_trial_overlay.py +235 -0
  79. crimson/ui/game_over.py +660 -0
  80. crimson/ui/hud.py +601 -0
  81. crimson/ui/perk_menu.py +388 -0
  82. crimson/views/__init__.py +40 -0
  83. crimson/views/aim_debug.py +276 -0
  84. crimson/views/animations.py +274 -0
  85. crimson/views/arsenal_debug.py +404 -0
  86. crimson/views/audio_bootstrap.py +47 -0
  87. crimson/views/bonuses.py +201 -0
  88. crimson/views/camera_debug.py +359 -0
  89. crimson/views/camera_shake.py +229 -0
  90. crimson/views/corpse_stamp_debug.py +324 -0
  91. crimson/views/decals_debug.py +739 -0
  92. crimson/views/empty.py +19 -0
  93. crimson/views/fonts.py +114 -0
  94. crimson/views/game_over.py +117 -0
  95. crimson/views/ground.py +259 -0
  96. crimson/views/lighting_debug.py +1166 -0
  97. crimson/views/particles.py +293 -0
  98. crimson/views/perk_menu_debug.py +430 -0
  99. crimson/views/perks.py +398 -0
  100. crimson/views/player.py +434 -0
  101. crimson/views/player_sprite_debug.py +314 -0
  102. crimson/views/projectile_fx.py +609 -0
  103. crimson/views/projectile_render_debug.py +393 -0
  104. crimson/views/projectiles.py +221 -0
  105. crimson/views/quest_title_overlay.py +108 -0
  106. crimson/views/registry.py +34 -0
  107. crimson/views/rush.py +16 -0
  108. crimson/views/small_font_debug.py +204 -0
  109. crimson/views/spawn_plan.py +363 -0
  110. crimson/views/sprites.py +214 -0
  111. crimson/views/survival.py +15 -0
  112. crimson/views/terrain.py +132 -0
  113. crimson/views/ui.py +123 -0
  114. crimson/views/wicons.py +166 -0
  115. crimson/weapon_sfx.py +63 -0
  116. crimson/weapons.py +860 -0
  117. crimsonland-0.1.0.dev5.dist-info/METADATA +9 -0
  118. crimsonland-0.1.0.dev5.dist-info/RECORD +139 -0
  119. crimsonland-0.1.0.dev5.dist-info/WHEEL +4 -0
  120. crimsonland-0.1.0.dev5.dist-info/entry_points.txt +4 -0
  121. grim/__init__.py +20 -0
  122. grim/app.py +92 -0
  123. grim/assets.py +231 -0
  124. grim/audio.py +106 -0
  125. grim/config.py +294 -0
  126. grim/console.py +737 -0
  127. grim/fonts/__init__.py +7 -0
  128. grim/fonts/grim_mono.py +111 -0
  129. grim/fonts/small.py +120 -0
  130. grim/input.py +44 -0
  131. grim/jaz.py +103 -0
  132. grim/math.py +17 -0
  133. grim/music.py +403 -0
  134. grim/paq.py +76 -0
  135. grim/rand.py +37 -0
  136. grim/sfx.py +276 -0
  137. grim/sfx_map.py +103 -0
  138. grim/terrain_render.py +840 -0
  139. grim/view.py +16 -0
@@ -0,0 +1,620 @@
1
+ from __future__ import annotations
2
+
3
+ import math
4
+ import random
5
+
6
+ from ..perks import PerkId
7
+ from ..creatures.spawn import SpawnId
8
+ from .helpers import (
9
+ center_point,
10
+ corner_points,
11
+ edge_midpoints,
12
+ heading_from_center,
13
+ random_angle,
14
+ spawn,
15
+ spawn_at,
16
+ )
17
+ from .registry import register_quest
18
+ from .types import QuestContext, SpawnEntry
19
+
20
+
21
+ @register_quest(
22
+ level="1.1",
23
+ title="Land Hostile",
24
+ time_limit_ms=120000,
25
+ start_weapon_id=1,
26
+ unlock_weapon_id=0x02,
27
+ builder_address=0x00435BD0,
28
+ )
29
+ def build_1_1_land_hostile(ctx: QuestContext) -> list[SpawnEntry]:
30
+ edges = edge_midpoints(ctx.width, ctx.height)
31
+ top_left, top_right, bottom_left, _bottom_right = corner_points(ctx.width, ctx.height)
32
+ return [
33
+ spawn_at(edges.bottom, heading=0.0, spawn_id=SpawnId.ALIEN_CONST_PALE_GREEN_26, trigger_ms=500, count=1),
34
+ spawn_at(bottom_left, heading=0.0, spawn_id=SpawnId.ALIEN_CONST_PALE_GREEN_26, trigger_ms=2500, count=2),
35
+ spawn_at(top_left, heading=0.0, spawn_id=SpawnId.ALIEN_CONST_PALE_GREEN_26, trigger_ms=6500, count=3),
36
+ spawn_at(top_right, heading=0.0, spawn_id=SpawnId.ALIEN_CONST_PALE_GREEN_26, trigger_ms=11500, count=4),
37
+ ]
38
+
39
+
40
+ @register_quest(
41
+ level="1.2",
42
+ title="Minor Alien Breach",
43
+ time_limit_ms=120000,
44
+ start_weapon_id=1,
45
+ unlock_weapon_id=0x03,
46
+ builder_address=0x00435CC0,
47
+ )
48
+ def build_1_2_minor_alien_breach(ctx: QuestContext) -> list[SpawnEntry]:
49
+ center_x, center_y = center_point(ctx.width, ctx.height)
50
+ edges = edge_midpoints(ctx.width, ctx.height)
51
+ entries = [
52
+ spawn(
53
+ x=256.0,
54
+ y=256.0,
55
+ heading=0.0,
56
+ spawn_id=SpawnId.ALIEN_CONST_PALE_GREEN_26,
57
+ trigger_ms=1000,
58
+ count=2,
59
+ ),
60
+ spawn(
61
+ x=256.0,
62
+ y=128.0,
63
+ heading=0.0,
64
+ spawn_id=SpawnId.ALIEN_CONST_PALE_GREEN_26,
65
+ trigger_ms=1700,
66
+ count=2,
67
+ ),
68
+ ]
69
+ for i in range(2, 18):
70
+ trigger = (i * 5 - 10) * 720
71
+ entries.append(
72
+ spawn_at(
73
+ edges.right,
74
+ heading=0.0,
75
+ spawn_id=SpawnId.ALIEN_CONST_PALE_GREEN_26,
76
+ trigger_ms=trigger,
77
+ count=1,
78
+ )
79
+ )
80
+ if i > 6:
81
+ entries.append(
82
+ spawn(
83
+ x=edges.right[0],
84
+ y=center_y - 256.0,
85
+ heading=0.0,
86
+ spawn_id=SpawnId.ALIEN_CONST_PALE_GREEN_26,
87
+ trigger_ms=trigger,
88
+ count=1,
89
+ )
90
+ )
91
+ if i == 13:
92
+ entries.append(
93
+ spawn_at(
94
+ edges.bottom,
95
+ heading=0.0,
96
+ spawn_id=SpawnId.ALIEN_CONST_GREY_BRUTE_29,
97
+ trigger_ms=39600,
98
+ count=1,
99
+ )
100
+ )
101
+ if i > 10:
102
+ entries.append(
103
+ spawn(
104
+ x=edges.left[0],
105
+ y=center_y + 256.0,
106
+ heading=0.0,
107
+ spawn_id=SpawnId.ALIEN_CONST_PALE_GREEN_26,
108
+ trigger_ms=trigger,
109
+ count=1,
110
+ )
111
+ )
112
+ return entries
113
+
114
+
115
+ @register_quest(
116
+ level="1.3",
117
+ title="Target Practice",
118
+ time_limit_ms=65000,
119
+ start_weapon_id=1,
120
+ unlock_perk_id=PerkId.URANIUM_FILLED_BULLETS,
121
+ builder_address=0x00437A00,
122
+ )
123
+ def build_1_3_target_practice(ctx: QuestContext, rng: random.Random | None = None) -> list[SpawnEntry]:
124
+ rng = rng or random.Random()
125
+ center_x, center_y = center_point(ctx.width, ctx.height)
126
+ entries: list[SpawnEntry] = []
127
+ trigger = 2000
128
+ step = 2000
129
+ while True:
130
+ angle = random_angle(rng)
131
+ radius = (rng.randrange(8) + 2) * 0x20
132
+ x = math.cos(angle) * radius + center_x
133
+ y = math.sin(angle) * radius + center_y
134
+ heading = heading_from_center(x, y, center_x, center_y)
135
+ entries.append(
136
+ spawn(
137
+ x=x,
138
+ y=y,
139
+ heading=heading,
140
+ spawn_id=SpawnId.ALIEN_AI7_ORBITER_36,
141
+ trigger_ms=trigger,
142
+ count=1,
143
+ )
144
+ )
145
+ trigger += max(step, 1100)
146
+ step -= 50
147
+ if step <= 500:
148
+ break
149
+ return entries
150
+
151
+
152
+ @register_quest(
153
+ level="1.4",
154
+ title="Frontline Assault",
155
+ time_limit_ms=300000,
156
+ start_weapon_id=1,
157
+ unlock_weapon_id=0x08,
158
+ builder_address=0x00437E10,
159
+ )
160
+ def build_1_4_frontline_assault(ctx: QuestContext) -> list[SpawnEntry]:
161
+ entries: list[SpawnEntry] = []
162
+ edges = edge_midpoints(ctx.width, ctx.height)
163
+ top_left, top_right, _bottom_left, _bottom_right = corner_points(ctx.width, ctx.height)
164
+ step = 2500
165
+ for i in range(2, 22):
166
+ if i < 5:
167
+ spawn_id = SpawnId.ALIEN_CONST_PALE_GREEN_26
168
+ elif i < 10:
169
+ spawn_id = SpawnId.AI1_ALIEN_BLUE_TINT_1A
170
+ else:
171
+ spawn_id = SpawnId.ALIEN_CONST_PALE_GREEN_26
172
+ trigger = i * step - 5000
173
+ entries.append(
174
+ spawn_at(
175
+ edges.bottom,
176
+ heading=0.0,
177
+ spawn_id=spawn_id,
178
+ trigger_ms=trigger,
179
+ count=1,
180
+ )
181
+ )
182
+ if i > 4:
183
+ entries.append(
184
+ spawn_at(
185
+ top_left,
186
+ heading=0.0,
187
+ spawn_id=SpawnId.ALIEN_CONST_PALE_GREEN_26,
188
+ trigger_ms=trigger,
189
+ count=1,
190
+ )
191
+ )
192
+ if i > 10:
193
+ entries.append(
194
+ spawn_at(
195
+ top_right,
196
+ heading=0.0,
197
+ spawn_id=SpawnId.ALIEN_CONST_PALE_GREEN_26,
198
+ trigger_ms=trigger,
199
+ count=1,
200
+ )
201
+ )
202
+ if i == 10:
203
+ burst_trigger = (step * 5 - 2500) * 2
204
+ entries.append(
205
+ spawn_at(
206
+ edges.right,
207
+ heading=0.0,
208
+ spawn_id=SpawnId.ALIEN_CONST_GREY_BRUTE_29,
209
+ trigger_ms=burst_trigger,
210
+ count=1,
211
+ )
212
+ )
213
+ entries.append(
214
+ spawn_at(
215
+ edges.left,
216
+ heading=0.0,
217
+ spawn_id=SpawnId.ALIEN_CONST_GREY_BRUTE_29,
218
+ trigger_ms=burst_trigger,
219
+ count=1,
220
+ )
221
+ )
222
+ step = max(step - 50, 1800)
223
+ return entries
224
+
225
+
226
+ @register_quest(
227
+ level="1.5",
228
+ title="Alien Dens",
229
+ time_limit_ms=180000,
230
+ start_weapon_id=1,
231
+ unlock_perk_id=PerkId.DOCTOR,
232
+ builder_address=0x00436720,
233
+ )
234
+ def build_1_5_alien_dens(ctx: QuestContext) -> list[SpawnEntry]:
235
+ return [
236
+ spawn(x=256.0, y=256.0, heading=0.0, spawn_id=SpawnId.ALIEN_SPAWNER_CHILD_1D_SLOW_08, trigger_ms=1500, count=1),
237
+ spawn(x=768.0, y=768.0, heading=0.0, spawn_id=SpawnId.ALIEN_SPAWNER_CHILD_1D_SLOW_08, trigger_ms=1500, count=1),
238
+ spawn(
239
+ x=512.0,
240
+ y=512.0,
241
+ heading=0.0,
242
+ spawn_id=SpawnId.ALIEN_SPAWNER_CHILD_1D_SLOW_08,
243
+ trigger_ms=23500,
244
+ count=ctx.player_count,
245
+ ),
246
+ spawn(
247
+ x=256.0,
248
+ y=768.0,
249
+ heading=0.0,
250
+ spawn_id=SpawnId.ALIEN_SPAWNER_CHILD_1D_SLOW_08,
251
+ trigger_ms=38500,
252
+ count=1,
253
+ ),
254
+ spawn(
255
+ x=768.0,
256
+ y=256.0,
257
+ heading=0.0,
258
+ spawn_id=SpawnId.ALIEN_SPAWNER_CHILD_1D_SLOW_08,
259
+ trigger_ms=38500,
260
+ count=1,
261
+ ),
262
+ ]
263
+
264
+
265
+ @register_quest(
266
+ level="1.6",
267
+ title="The Random Factor",
268
+ time_limit_ms=300000,
269
+ start_weapon_id=1,
270
+ unlock_weapon_id=0x05,
271
+ builder_address=0x00436350,
272
+ )
273
+ def build_1_6_the_random_factor(ctx: QuestContext, rng: random.Random | None = None) -> list[SpawnEntry]:
274
+ rng = rng or random.Random()
275
+ entries: list[SpawnEntry] = []
276
+ center_x, center_y = center_point(ctx.width, ctx.height)
277
+ edges = edge_midpoints(ctx.width, ctx.height)
278
+ trigger = 1500
279
+ while trigger < 101500:
280
+ entries.append(
281
+ spawn_at(
282
+ edges.right,
283
+ heading=0.0,
284
+ spawn_id=SpawnId.ALIEN_RANDOM_1D,
285
+ trigger_ms=trigger,
286
+ count=ctx.player_count * 2 + 4,
287
+ )
288
+ )
289
+ entries.append(
290
+ spawn_at(
291
+ edges.left,
292
+ heading=0.0,
293
+ spawn_id=SpawnId.ALIEN_RANDOM_1D,
294
+ trigger_ms=trigger + 200,
295
+ count=6,
296
+ )
297
+ )
298
+ if rng.randrange(5) == 3:
299
+ entries.append(
300
+ spawn(
301
+ x=center_x,
302
+ y=edges.bottom[1],
303
+ heading=0.0,
304
+ spawn_id=SpawnId.ALIEN_CONST_GREY_BRUTE_29,
305
+ trigger_ms=trigger,
306
+ count=ctx.player_count,
307
+ )
308
+ )
309
+ trigger += 10000
310
+ return entries
311
+
312
+
313
+ @register_quest(
314
+ level="1.7",
315
+ title="Spider Wave Syndrome",
316
+ time_limit_ms=240000,
317
+ start_weapon_id=1,
318
+ unlock_perk_id=PerkId.MONSTER_VISION,
319
+ builder_address=0x00436440,
320
+ )
321
+ def build_1_7_spider_wave_syndrome(ctx: QuestContext) -> list[SpawnEntry]:
322
+ entries: list[SpawnEntry] = []
323
+ edges = edge_midpoints(ctx.width, ctx.height)
324
+ trigger = 1500
325
+ while trigger < 100500:
326
+ entries.append(
327
+ spawn_at(
328
+ edges.left,
329
+ heading=0.0,
330
+ spawn_id=SpawnId.SPIDER_SP1_CONST_BLUE_40,
331
+ trigger_ms=trigger,
332
+ count=ctx.player_count * 2 + 6,
333
+ )
334
+ )
335
+ trigger += 5500
336
+ return entries
337
+
338
+
339
+ @register_quest(
340
+ level="1.8",
341
+ title="Alien Squads",
342
+ time_limit_ms=180000,
343
+ start_weapon_id=1,
344
+ unlock_weapon_id=0x06,
345
+ builder_address=0x00435EA0,
346
+ )
347
+ def build_1_8_alien_squads(ctx: QuestContext) -> list[SpawnEntry]:
348
+ entries = [
349
+ spawn(
350
+ x=-256.0,
351
+ y=256.0,
352
+ heading=0.0,
353
+ spawn_id=SpawnId.FORMATION_RING_ALIEN_8_12,
354
+ trigger_ms=1500,
355
+ count=1,
356
+ ),
357
+ spawn(
358
+ x=-256.0,
359
+ y=768.0,
360
+ heading=0.0,
361
+ spawn_id=SpawnId.FORMATION_RING_ALIEN_8_12,
362
+ trigger_ms=2500,
363
+ count=1,
364
+ ),
365
+ spawn(
366
+ x=768.0,
367
+ y=-256.0,
368
+ heading=0.0,
369
+ spawn_id=SpawnId.FORMATION_RING_ALIEN_8_12,
370
+ trigger_ms=5500,
371
+ count=1,
372
+ ),
373
+ spawn(
374
+ x=768.0,
375
+ y=1280.0,
376
+ heading=0.0,
377
+ spawn_id=SpawnId.FORMATION_RING_ALIEN_8_12,
378
+ trigger_ms=8500,
379
+ count=1,
380
+ ),
381
+ spawn(
382
+ x=1280.0,
383
+ y=1280.0,
384
+ heading=0.0,
385
+ spawn_id=SpawnId.FORMATION_RING_ALIEN_8_12,
386
+ trigger_ms=14500,
387
+ count=1,
388
+ ),
389
+ spawn(
390
+ x=1280.0,
391
+ y=768.0,
392
+ heading=0.0,
393
+ spawn_id=SpawnId.FORMATION_RING_ALIEN_8_12,
394
+ trigger_ms=18500,
395
+ count=1,
396
+ ),
397
+ spawn(
398
+ x=-256.0,
399
+ y=256.0,
400
+ heading=0.0,
401
+ spawn_id=SpawnId.FORMATION_RING_ALIEN_8_12,
402
+ trigger_ms=25000,
403
+ count=1,
404
+ ),
405
+ spawn(
406
+ x=-256.0,
407
+ y=768.0,
408
+ heading=0.0,
409
+ spawn_id=SpawnId.FORMATION_RING_ALIEN_8_12,
410
+ trigger_ms=30000,
411
+ count=1,
412
+ ),
413
+ ]
414
+ trigger = 36200
415
+ while trigger < 83000:
416
+ entries.append(
417
+ spawn(
418
+ x=-64.0,
419
+ y=-64.0,
420
+ heading=0.0,
421
+ spawn_id=SpawnId.ALIEN_CONST_PALE_GREEN_26,
422
+ trigger_ms=trigger - 400,
423
+ count=1,
424
+ )
425
+ )
426
+ entries.append(
427
+ spawn(
428
+ x=ctx.width + 64.0,
429
+ y=ctx.height + 64.0,
430
+ heading=0.0,
431
+ spawn_id=SpawnId.ALIEN_CONST_PALE_GREEN_26,
432
+ trigger_ms=trigger,
433
+ count=1,
434
+ )
435
+ )
436
+ trigger += 1800
437
+ return entries
438
+
439
+
440
+ @register_quest(
441
+ level="1.9",
442
+ title="Nesting Grounds",
443
+ time_limit_ms=240000,
444
+ start_weapon_id=1,
445
+ unlock_perk_id=PerkId.HOT_TEMPERED,
446
+ builder_address=0x004364A0,
447
+ )
448
+ def build_1_9_nesting_grounds(ctx: QuestContext) -> list[SpawnEntry]:
449
+ center_x, _center_y = center_point(ctx.width, ctx.height)
450
+ edges = edge_midpoints(ctx.width, ctx.height)
451
+ entries = [
452
+ spawn(
453
+ x=center_x,
454
+ y=edges.bottom[1],
455
+ heading=0.0,
456
+ spawn_id=SpawnId.ALIEN_RANDOM_1D,
457
+ trigger_ms=1500,
458
+ count=ctx.player_count * 2 + 6,
459
+ ),
460
+ spawn(x=256.0, y=256.0, heading=0.0, spawn_id=SpawnId.ALIEN_SPAWNER_CHILD_1D_LIMITED_09, trigger_ms=8000, count=1),
461
+ spawn(
462
+ x=512.0,
463
+ y=512.0,
464
+ heading=0.0,
465
+ spawn_id=SpawnId.ALIEN_SPAWNER_CHILD_1D_LIMITED_09,
466
+ trigger_ms=13000,
467
+ count=1,
468
+ ),
469
+ spawn(
470
+ x=768.0,
471
+ y=768.0,
472
+ heading=0.0,
473
+ spawn_id=SpawnId.ALIEN_SPAWNER_CHILD_1D_LIMITED_09,
474
+ trigger_ms=18000,
475
+ count=1,
476
+ ),
477
+ spawn(
478
+ x=center_x,
479
+ y=edges.bottom[1],
480
+ heading=0.0,
481
+ spawn_id=SpawnId.ALIEN_RANDOM_1D,
482
+ trigger_ms=25000,
483
+ count=ctx.player_count * 2 + 6,
484
+ ),
485
+ spawn(
486
+ x=center_x,
487
+ y=edges.bottom[1],
488
+ heading=0.0,
489
+ spawn_id=SpawnId.ALIEN_RANDOM_1D,
490
+ trigger_ms=39000,
491
+ count=ctx.player_count * 3 + 3,
492
+ ),
493
+ spawn(
494
+ x=384.0,
495
+ y=512.0,
496
+ heading=0.0,
497
+ spawn_id=SpawnId.ALIEN_SPAWNER_CHILD_1D_LIMITED_09,
498
+ trigger_ms=41100,
499
+ count=1,
500
+ ),
501
+ spawn(
502
+ x=640.0,
503
+ y=512.0,
504
+ heading=0.0,
505
+ spawn_id=SpawnId.ALIEN_SPAWNER_CHILD_1D_LIMITED_09,
506
+ trigger_ms=42100,
507
+ count=1,
508
+ ),
509
+ spawn(
510
+ x=512.0,
511
+ y=640.0,
512
+ heading=0.0,
513
+ spawn_id=SpawnId.ALIEN_SPAWNER_CHILD_1D_LIMITED_09,
514
+ trigger_ms=43100,
515
+ count=1,
516
+ ),
517
+ spawn(
518
+ x=512.0,
519
+ y=512.0,
520
+ heading=0.0,
521
+ spawn_id=SpawnId.ALIEN_SPAWNER_CHILD_1D_SLOW_08,
522
+ trigger_ms=44100,
523
+ count=1,
524
+ ),
525
+ spawn(
526
+ x=center_x,
527
+ y=edges.bottom[1],
528
+ heading=0.0,
529
+ spawn_id=SpawnId.ALIEN_RANDOM_1E,
530
+ trigger_ms=50000,
531
+ count=ctx.player_count * 2 + 5,
532
+ ),
533
+ spawn(
534
+ x=center_x,
535
+ y=edges.bottom[1],
536
+ heading=0.0,
537
+ spawn_id=SpawnId.ALIEN_RANDOM_1F,
538
+ trigger_ms=55000,
539
+ count=ctx.player_count * 2 + 2,
540
+ ),
541
+ ]
542
+ return entries
543
+
544
+
545
+ @register_quest(
546
+ level="1.10",
547
+ title="8-legged Terror",
548
+ time_limit_ms=240000,
549
+ start_weapon_id=1,
550
+ unlock_weapon_id=0x0C,
551
+ builder_address=0x00436120,
552
+ )
553
+ def build_1_10_8_legged_terror(ctx: QuestContext) -> list[SpawnEntry]:
554
+ entries = [
555
+ spawn(
556
+ x=float(ctx.width - 256),
557
+ y=float(ctx.width // 2),
558
+ heading=0.0,
559
+ spawn_id=SpawnId.SPIDER_SP1_CONST_SHOCK_BOSS_3A,
560
+ trigger_ms=1000,
561
+ count=1,
562
+ )
563
+ ]
564
+ top_left, top_right, bottom_left, bottom_right = corner_points(ctx.width, ctx.height, offset=25.0)
565
+ trigger = 6000
566
+ while trigger < 36800:
567
+ entries.append(
568
+ spawn_at(
569
+ top_left,
570
+ heading=0.0,
571
+ spawn_id=SpawnId.SPIDER_SP1_RANDOM_3D,
572
+ trigger_ms=trigger,
573
+ count=ctx.player_count,
574
+ )
575
+ )
576
+ entries.append(
577
+ spawn_at(
578
+ top_right,
579
+ heading=0.0,
580
+ spawn_id=SpawnId.SPIDER_SP1_RANDOM_3D,
581
+ trigger_ms=trigger,
582
+ count=1,
583
+ )
584
+ )
585
+ entries.append(
586
+ spawn_at(
587
+ bottom_left,
588
+ heading=0.0,
589
+ spawn_id=SpawnId.SPIDER_SP1_RANDOM_3D,
590
+ trigger_ms=trigger,
591
+ count=ctx.player_count,
592
+ )
593
+ )
594
+ entries.append(
595
+ spawn_at(
596
+ bottom_right,
597
+ heading=0.0,
598
+ spawn_id=SpawnId.SPIDER_SP1_RANDOM_3D,
599
+ trigger_ms=trigger,
600
+ count=1,
601
+ )
602
+ )
603
+ trigger += 2200
604
+ return entries
605
+
606
+
607
+ __all__ = [
608
+ "QuestContext",
609
+ "SpawnEntry",
610
+ "build_1_1_land_hostile",
611
+ "build_1_2_minor_alien_breach",
612
+ "build_1_3_target_practice",
613
+ "build_1_4_frontline_assault",
614
+ "build_1_5_alien_dens",
615
+ "build_1_6_the_random_factor",
616
+ "build_1_7_spider_wave_syndrome",
617
+ "build_1_8_alien_squads",
618
+ "build_1_9_nesting_grounds",
619
+ "build_1_10_8_legged_terror",
620
+ ]