Make RustRaptor the repository root and track its playable bundle
This commit is contained in:
1 parent
4b1edefeec
commit
8f459796b1
9860 files changed
+21084
-61019
No files matched your search
@@ -0,0 +1,54 @@
|
||||
# Iron Crown boss
|
||||
|
||||
A standalone API 1 mod for the Iron Coast finale. It adds a new command
|
||||
Dreadnought with broad armored wings and three forward cannon pods, matching
|
||||
the industrial overhead style of the original game. The package has no mod
|
||||
dependencies and does not replace any original or Iron Coast enemy definition.
|
||||
|
||||
- Enemy: `iron_coast_boss_6:unit`; health 160, reward 1800, air boss, logical 96×64.
|
||||
- Weapon: `iron_coast_boss_6:projectile`; damage 3, speed 4, logical 8×8.
|
||||
- Objective: every actual boss death increments `iron_coast_boss_6:defeated`.
|
||||
- Entry: fly downward to y 24, then patrol between x 80 and x 144.
|
||||
- Attack: every 54 simulation ticks, alternate a three-shell fan with two
|
||||
straight cannon lanes. A rising charging sound begins nine ticks before
|
||||
each volley. At 70/3 Hz this gives 0.386 seconds warning before a 2.314-second
|
||||
volley cycle. Charging creates no explosion effects.
|
||||
- State: per-entity patrol direction, age and volley cursor; removed on death.
|
||||
Supports the finale's two staged bosses and simultaneous spawns. It never
|
||||
completes a mission directly or fires from retired entities.
|
||||
|
||||
Difficulty uses the engine's original boss health rule: definitions retain 160
|
||||
health, and the two lower difficulty levels spawn bosses with 80 health.
|
||||
|
||||
`art/unit-sd.png` and `art/unit-hd.png` share one centered 96×64 logical canvas.
|
||||
The HD texture is 768×512 (8×) and the SD version is derived from the same
|
||||
transparent generated master. The cannon shell likewise has matching 8×8 and
|
||||
64×64 versions. `art-qa.json` records bounds and source hashes. The supplied
|
||||
alpha is preserved; runtime colors with alpha below 128 remain transparent.
|
||||
|
||||
The built-in imagegen tool generated both masters. Exact prompts live in
|
||||
`prompts/`; `provenance.json` records their outputs. All authored images and
|
||||
sounds belong in Git. Original sprite references remain outside this package.
|
||||
|
||||
Reproduce the deterministic sounds and SD/HD reductions with:
|
||||
|
||||
```sh
|
||||
python3 RustRaptor/mods/iron_coast_boss_6/build_assets.py
|
||||
```
|
||||
|
||||
`--audio-only` needs only Python's standard library. `audio-recipe.json`
|
||||
records seeds, PCM properties and hashes. The sounds are non-silent PCM16
|
||||
mono 22050 Hz charging, firing and destruction cues; no recordings are used.
|
||||
|
||||
Validate activation and lifecycle behavior using the production simulation:
|
||||
|
||||
```sh
|
||||
CARGO_TARGET_DIR=RustRaptor/target cargo run --offline \
|
||||
--manifest-path RustRaptor/mods/iron_coast_boss_6/validation/Cargo.toml
|
||||
```
|
||||
|
||||
The validation checks alternating patterns, warning timing, independent
|
||||
entity state, serialized state restoration, death counter/reward behavior,
|
||||
dead-enemy firing guards and two staged encounters on all four difficulties.
|
||||
`validation-results.json` records the controlled outcomes. The complete
|
||||
mission 6 mod runs separate campaign and balance checks with its other enemies.
|
||||
@@ -0,0 +1,95 @@
|
||||
{
|
||||
"pipeline": "Full-canvas proportional RGBA resize, centered clear padding, BOX reduction to SD; no bitmap redraw",
|
||||
"logical_boss": [
|
||||
96,
|
||||
64
|
||||
],
|
||||
"logical_projectile": [
|
||||
8,
|
||||
8
|
||||
],
|
||||
"hd_scale": 8,
|
||||
"frames": 1,
|
||||
"origin": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"alpha": "Preserved RGBA; runtime alpha below128 is transparent",
|
||||
"sources": {
|
||||
"art/unit-generated-v1.png": {
|
||||
"size": [
|
||||
1536,
|
||||
1024
|
||||
],
|
||||
"visible_margin_crop": null,
|
||||
"sha256": "b5e1c404993e7b14b13dc0c2a9dde4dabbc1ab49936b62884af9b4f7c174c676"
|
||||
},
|
||||
"art/projectile-generated-v1.png": {
|
||||
"size": [
|
||||
1254,
|
||||
1254
|
||||
],
|
||||
"visible_margin_crop": [
|
||||
502,
|
||||
377,
|
||||
752,
|
||||
881
|
||||
],
|
||||
"sha256": "75c5c376ff44d785082d4f0a4c714d68191c88881397840267a9c1255343760f"
|
||||
}
|
||||
},
|
||||
"files": {
|
||||
"art/unit-hd.png": {
|
||||
"size": [
|
||||
768,
|
||||
512
|
||||
],
|
||||
"opaque_bounds": [
|
||||
45,
|
||||
59,
|
||||
724,
|
||||
457
|
||||
],
|
||||
"sha256": "048ce0e71464710826b3a4df83b6988f20a969b669577db20a866e70d134c730"
|
||||
},
|
||||
"art/unit-sd.png": {
|
||||
"size": [
|
||||
96,
|
||||
64
|
||||
],
|
||||
"opaque_bounds": [
|
||||
6,
|
||||
7,
|
||||
90,
|
||||
57
|
||||
],
|
||||
"sha256": "419095cf2e14abb5bdea945e95cc5fa2f22ce9e84980080b46150ec19f727e7e"
|
||||
},
|
||||
"art/projectile-hd.png": {
|
||||
"size": [
|
||||
64,
|
||||
64
|
||||
],
|
||||
"opaque_bounds": [
|
||||
21,
|
||||
9,
|
||||
43,
|
||||
55
|
||||
],
|
||||
"sha256": "7ed23b4124809260f1b44e5486b4093d2e4b746a8e997f0b15f567d5673b181c"
|
||||
},
|
||||
"art/projectile-sd.png": {
|
||||
"size": [
|
||||
8,
|
||||
8
|
||||
],
|
||||
"opaque_bounds": [
|
||||
3,
|
||||
1,
|
||||
5,
|
||||
6
|
||||
],
|
||||
"sha256": "84e820daff78e441512da0792243973e006ef3ff42c4299cb976d86936ddefe4"
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 213 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 201 B |
Binary file not shown.
|
After Width: | Height: | Size: 2.0 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 343 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.6 KiB |
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"generator": "build_assets.py deterministic standard-library chirp/noise synthesis",
|
||||
"recordings": false,
|
||||
"files": {
|
||||
"audio/warning.wav": {
|
||||
"duration": 0.22,
|
||||
"seed": 6609,
|
||||
"sample_rate": 22050,
|
||||
"channels": 1,
|
||||
"bits": 16,
|
||||
"samples": 4851,
|
||||
"peak": 25558,
|
||||
"rms": 13432.484979695546,
|
||||
"sha256": "1d49f31fac3d610875589369c1a04085a31c7d377796b275c3e88e4d2d1ed4d4"
|
||||
},
|
||||
"audio/shot.wav": {
|
||||
"duration": 0.2700226757369614,
|
||||
"seed": 6654,
|
||||
"sample_rate": 22050,
|
||||
"channels": 1,
|
||||
"bits": 16,
|
||||
"samples": 5954,
|
||||
"peak": 25558,
|
||||
"rms": 3752.013236853832,
|
||||
"sha256": "7ba7ae98bb62fdc3a3649849a03ac0333cd0bbf14a4c0bab6ff29bbd443ac844"
|
||||
},
|
||||
"audio/death.wav": {
|
||||
"duration": 1.0499773242630386,
|
||||
"seed": 6616,
|
||||
"sample_rate": 22050,
|
||||
"channels": 1,
|
||||
"bits": 16,
|
||||
"samples": 23152,
|
||||
"peak": 25558,
|
||||
"rms": 3615.7503574583607,
|
||||
"sha256": "0a08330ec974274d83f770df27c337e51ffbf97bff64dfccd0b86086ee47eeeb"
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Derive matching SD/HD canvases from imagegen masters and synthesize local PCM.
|
||||
|
||||
No artwork is painted or replaced: resizing preserves source RGBA. The supplied
|
||||
projectile's transparent margins are cropped before proportional fitting.
|
||||
Use --audio-only to reproduce just the deterministic sounds without Pillow.
|
||||
"""
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import math
|
||||
from pathlib import Path
|
||||
import random
|
||||
import struct
|
||||
import wave
|
||||
|
||||
ROOT = Path(__file__).resolve().parent
|
||||
RATE = 22050
|
||||
|
||||
|
||||
def hash_file(path):
|
||||
return hashlib.sha256(path.read_bytes()).hexdigest()
|
||||
|
||||
|
||||
def sounds():
|
||||
files = {}
|
||||
for name, duration, seed in [('warning', .22, 6609), ('shot', .27, 6654), ('death', 1.05, 6616)]:
|
||||
count = round(duration * RATE)
|
||||
rng = random.Random(seed)
|
||||
phase = low_noise = 0.0
|
||||
samples = []
|
||||
for i in range(count):
|
||||
t, p = i / RATE, i / (count - 1)
|
||||
noise = rng.uniform(-1, 1)
|
||||
low_noise = .89 * low_noise + .11 * noise
|
||||
if name == 'warning':
|
||||
frequency = [760, 1020, 1340][min(2, int(p * 3))]
|
||||
phase += 2 * math.pi * frequency / RATE
|
||||
value = .72 * math.sin(phase) + .16 * math.sin(phase * 2)
|
||||
segment = (p * 3) % 1
|
||||
envelope = math.sin(math.pi * segment) ** .55
|
||||
elif name == 'shot':
|
||||
frequency = 65 + 385 * (1 - p) ** 2
|
||||
phase += 2 * math.pi * frequency / RATE
|
||||
value = .52 * math.sin(phase) + .22 * noise + .26 * math.sin(2 * math.pi * 68 * t)
|
||||
envelope = min(1, t / .002) * math.exp(-p * 5.7)
|
||||
else:
|
||||
phase += 2 * math.pi * (62 - 35 * p) / RATE
|
||||
value = .58 * low_noise + .21 * noise + .26 * math.sin(phase)
|
||||
envelope = min(1, t / .003) * math.exp(-p * 4.3)
|
||||
envelope *= min(1, (count - 1 - i) / (RATE * .005))
|
||||
samples.append(value * max(0, envelope))
|
||||
peak = max(abs(v) for v in samples)
|
||||
pcm = [round(v / peak * .78 * 32767) for v in samples]
|
||||
path = ROOT / 'audio' / f'{name}.wav'
|
||||
with wave.open(str(path), 'wb') as out:
|
||||
out.setnchannels(1)
|
||||
out.setsampwidth(2)
|
||||
out.setframerate(RATE)
|
||||
out.writeframes(struct.pack('<' + 'h' * len(pcm), *pcm))
|
||||
files[str(path.relative_to(ROOT))] = {
|
||||
'duration': count / RATE, 'seed': seed, 'sample_rate': RATE,
|
||||
'channels': 1, 'bits': 16, 'samples': count,
|
||||
'peak': max(abs(v) for v in pcm),
|
||||
'rms': math.sqrt(sum(v * v for v in pcm) / count),
|
||||
'sha256': hash_file(path),
|
||||
}
|
||||
(ROOT / 'audio-recipe.json').write_text(json.dumps({
|
||||
'generator': 'build_assets.py deterministic standard-library chirp/noise synthesis',
|
||||
'recordings': False, 'files': files,
|
||||
}, indent=2) + '\n')
|
||||
|
||||
|
||||
def artwork():
|
||||
from PIL import Image
|
||||
sources, files = {}, {}
|
||||
for name, logical in [('unit', (96, 64)), ('projectile', (8, 8))]:
|
||||
path = ROOT / 'art' / f'{name}-generated-v1.png'
|
||||
source = Image.open(path).convert('RGBA')
|
||||
original_size = source.size
|
||||
source_box = None
|
||||
if name == 'projectile':
|
||||
# Only transparent margin is discarded; the complete indexed-visible
|
||||
# shell remains present, with its antialiased fringe preserved.
|
||||
bbox = source.getchannel('A').point(lambda a: 255 if a >= 128 else 0).getbbox()
|
||||
source_box = (max(0, bbox[0] - 8), max(0, bbox[1] - 8),
|
||||
min(source.width, bbox[2] + 8), min(source.height, bbox[3] + 8))
|
||||
source = source.crop(source_box)
|
||||
elif source.width * logical[1] != source.height * logical[0]:
|
||||
raise ValueError('Unit source does not have the 3:2 logical canvas aspect')
|
||||
hd_size = (logical[0] * 8, logical[1] * 8)
|
||||
padding = (32, 24) if name == 'unit' else (12, 8)
|
||||
maximum = (hd_size[0] - padding[0] * 2, hd_size[1] - padding[1] * 2)
|
||||
ratio = min(maximum[0] / source.width, maximum[1] / source.height)
|
||||
fitted = source.resize((round(source.width * ratio), round(source.height * ratio)), Image.Resampling.LANCZOS)
|
||||
hd = Image.new('RGBA', hd_size, (0, 0, 0, 0))
|
||||
hd.alpha_composite(fitted, ((hd.width - fitted.width) // 2, (hd.height - fitted.height) // 2))
|
||||
sd = hd.resize(logical, Image.Resampling.BOX)
|
||||
for mode, im in [('hd', hd), ('sd', sd)]:
|
||||
target = ROOT / 'art' / f'{name}-{mode}.png'
|
||||
bounds = im.getchannel('A').point(lambda a: 255 if a >= 128 else 0).getbbox()
|
||||
if bounds is None or bounds[0] == 0 or bounds[1] == 0 or bounds[2] == im.width or bounds[3] == im.height:
|
||||
raise ValueError(f'{name}-{mode} silhouette touches canvas edge')
|
||||
im.save(target)
|
||||
files[str(target.relative_to(ROOT))] = {'size': list(im.size), 'opaque_bounds': list(bounds), 'sha256': hash_file(target)}
|
||||
sources[str(path.relative_to(ROOT))] = {'size': list(original_size), 'visible_margin_crop': source_box, 'sha256': hash_file(path)}
|
||||
(ROOT / 'art-qa.json').write_text(json.dumps({
|
||||
'pipeline': 'Full-canvas proportional RGBA resize, centered clear padding, BOX reduction to SD; no bitmap redraw',
|
||||
'logical_boss': [96, 64], 'logical_projectile': [8, 8], 'hd_scale': 8,
|
||||
'frames': 1, 'origin': [0, 0], 'alpha': 'Preserved RGBA; runtime alpha below128 is transparent',
|
||||
'sources': sources, 'files': files,
|
||||
}, indent=2) + '\n')
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--audio-only', action='store_true')
|
||||
args = parser.parse_args()
|
||||
sounds()
|
||||
if not args.audio_only:
|
||||
artwork()
|
||||
print('Iron Crown SD/HD artwork and deterministic PCM assets ready')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"weapons": [
|
||||
{
|
||||
"id": "iron_coast_boss_6:projectile",
|
||||
"name": "Iron Crown cannon shell",
|
||||
"damage": 3,
|
||||
"speed": 4,
|
||||
"cooldown": 54,
|
||||
"behavior": "straight",
|
||||
"target": "all",
|
||||
"art": {
|
||||
"png": "art/projectile-sd.png",
|
||||
"hd_png": "art/projectile-hd.png",
|
||||
"logical_width": 8,
|
||||
"logical_height": 8
|
||||
}
|
||||
}
|
||||
],
|
||||
"enemies": [
|
||||
{
|
||||
"id": "iron_coast_boss_6:unit",
|
||||
"name": "Iron Crown Command Dreadnought",
|
||||
"health": 160,
|
||||
"speed": 0,
|
||||
"reward": 1800,
|
||||
"ground": false,
|
||||
"boss": true,
|
||||
"cooldown": 54,
|
||||
"art": {
|
||||
"png": "art/unit-sd.png",
|
||||
"hd_png": "art/unit-hd.png",
|
||||
"logical_width": 96,
|
||||
"logical_height": 64
|
||||
},
|
||||
"script": "scripts/ai.rhai"
|
||||
}
|
||||
],
|
||||
"sounds": [
|
||||
{
|
||||
"id": "iron_coast_boss_6:warning",
|
||||
"name": "Iron Crown charging warning",
|
||||
"file": "audio/warning.wav",
|
||||
"volume": 90,
|
||||
"pan": 127,
|
||||
"pitch": 128,
|
||||
"priority": 3
|
||||
},
|
||||
{
|
||||
"id": "iron_coast_boss_6:shot",
|
||||
"name": "Iron Crown heavy cannon",
|
||||
"file": "audio/shot.wav",
|
||||
"volume": 100,
|
||||
"pan": 127,
|
||||
"pitch": 128,
|
||||
"priority": 2
|
||||
},
|
||||
{
|
||||
"id": "iron_coast_boss_6:death",
|
||||
"name": "Iron Crown destruction",
|
||||
"file": "audio/death.wav",
|
||||
"volume": 120,
|
||||
"pan": 127,
|
||||
"pitch": 128,
|
||||
"priority": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
id = "iron_coast_boss_6"
|
||||
name = "Iron Coast: Iron Crown Boss"
|
||||
version = "1.0.0"
|
||||
api_version = 1
|
||||
description = "The Iron Crown command dreadnought: a persistent finale boss with telegraphed alternating cannon fans and twin lanes. Includes matching SD/HD artwork and synthesized sound."
|
||||
content = "content.json"
|
||||
scripts = ["scripts/ai.rhai"]
|
||||
@@ -0,0 +1,6 @@
|
||||
Use case: stylized-concept
|
||||
Asset type: a single transparent game projectile sprite, logical 8 by 8 pixels, HD source.
|
||||
Primary request: One compact Iron Crown heavy cannon shell in the industrial Raptor sprite style. A small dark steel rectangular shell core with a sharp warm amber tip pointing directly downward, subtle orange metal rim and one restrained amber highlight, clearly distinguishable from terrain at 8 pixels.
|
||||
Style/medium: crisp detailed top-down painted mechanical game sprite, gunmetal, brass and amber, polished but not shiny.
|
||||
Composition/framing: strict orthographic top-down, exactly one projectile centered on square transparent canvas with 20 percent clear margin all sides, downward orientation; complete and symmetric.
|
||||
Constraints: genuinely transparent RGBA background, no environmental background, no shadows, no text or labels, no sheet of multiple objects, no long trail, no fog, no luminous haze, no round explosion, no large bloom. Keep the silhouette compact and solid.
|
||||
@@ -0,0 +1,9 @@
|
||||
Use case: stylized-concept
|
||||
Asset type: transparent top-down game enemy sprite for RustRaptor, logical 96 by 64 pixels, detailed HD source.
|
||||
Primary request: Design the Iron Crown finale boss, an imposing coastal command dreadnought aircraft with very broad armored wings and three projecting forward cannon pods forming a crown-like silhouette, distinct from the reference bosses.
|
||||
Input images: The shown original Raptor broad gray boss and the existing Iron Coast command cruiser are style references only. Retain their overhead orientation, readable mechanical panels and grounded industrial palette, while making a new silhouette.
|
||||
Subject: one complete symmetrical heavy flying war machine; broad wings, central armored command hull, three forward pods on the bottom edge, rear engine pods on the top edge. Gunmetal gray, brushed dull steel, restrained dark red trim, tiny warm amber warning lights. No people.
|
||||
Style/medium: polished detailed hand-painted sprite illustration with crisp clean edges, mechanical panel shading like a modern remaster of the 1990s Raptor sprites, readable at small pixel size.
|
||||
Composition/framing: strict orthographic overhead view with no perspective and no side faces; front points straight down toward the bottom; full silhouette centered on a 3:2 landscape transparent canvas with at least 5 percent clear margin all sides; width much greater than height.
|
||||
Lighting/mood: restrained overhead upper-left light, opaque mechanical surfaces, no environmental cast shadow.
|
||||
Constraints: exactly one static idle sprite, genuinely transparent RGBA background; no terrain, no rectangle or checkerboard background, no text, no logos, no exhaust plume, no blurred bloom, no muzzle flash, no detached objects, no cut-off tips.
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"api_version": 1,
|
||||
"mod_version": "1.0.0",
|
||||
"generated_at": "2026-10-10",
|
||||
"tool": "built-in image_gen.imagegen via imagegen skill",
|
||||
"skill": "/home/quintine/.codex/skills/.system/imagegen/SKILL.md",
|
||||
"reference_role": "Inspected original SHIP10G1 boss and authored Iron Coast command cruiser for overhead mechanical Raptor style. New silhouette and generated pixels, no original catalog pixels packaged.",
|
||||
"assets": [
|
||||
{
|
||||
"file": "art/unit-generated-v1.png",
|
||||
"prompt": "prompts/unit-hd-v1.txt",
|
||||
"tool_output": "exec-5704a764-985a-426e-a30b-ea579fe6ff6d.png",
|
||||
"sha256": "b5e1c404993e7b14b13dc0c2a9dde4dabbc1ab49936b62884af9b4f7c174c676"
|
||||
},
|
||||
{
|
||||
"file": "art/projectile-generated-v1.png",
|
||||
"prompt": "prompts/projectile-hd-v1.txt",
|
||||
"tool_output": "exec-71e43e55-2cb7-47cf-a76c-a09492ded036.png",
|
||||
"sha256": "75c5c376ff44d785082d4f0a4c714d68191c88881397840267a9c1255343760f"
|
||||
}
|
||||
],
|
||||
"pipeline": "build_assets.py proportional RGBA resizing, clear padding and BOX SD reduction. Projectile transparent margins cropped. No artwork redraw.",
|
||||
"audio": "Deterministic standard-library synthesis in build_assets.py; three uncompressed 22050 Hz PCM16 mono WAVs. No recordings or external sound assets.",
|
||||
"version_control": "Generated masters, SD/HD artwork, prompt text, source recipe, metadata and WAV sounds intended for Git per user request."
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
fn is_alive(event) {
|
||||
for unit in event.entities {
|
||||
if unit.entity == event.entity && unit.health > 0 { return true; }
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
// State is shared by a script, so each staged or simultaneous boss has its own
|
||||
// patrol direction, charge timer and alternating attack cursor.
|
||||
fn on_spawn(event, state, random) {
|
||||
if state.contains("last_death") && state.last_death == event.entity { state.remove("last_death"); }
|
||||
if !is_alive(event) { return #{ commands: [], state: state }; }
|
||||
if !state.contains("units") { state.units = #{}; }
|
||||
state.units[event.entity.to_string()] = #{direction: 1, age: 0, volley: 0};
|
||||
#{ commands: [#{ op: "velocity", entity: event.entity, vx: 0, vy: 2 }], state: state }
|
||||
}
|
||||
|
||||
fn on_tick(event, state, random) {
|
||||
if event.health <= 0 || !is_alive(event) { return #{ commands: [], state: state }; }
|
||||
let key = event.entity.to_string();
|
||||
if !state.contains("units") { state.units = #{}; }
|
||||
let cursor = if state.units.contains(key) {
|
||||
state.units[key]
|
||||
} else { #{direction: 1, age: 0, volley: 0} };
|
||||
if event.y < 24 {
|
||||
state.units[key] = cursor;
|
||||
return #{ commands: [#{ op: "velocity", entity: event.entity, vx: 0, vy: 2 }], state: state };
|
||||
}
|
||||
if event.x >= 144 { cursor.direction = -1; }
|
||||
if event.x <= 80 { cursor.direction = 1; }
|
||||
cursor.age += 1;
|
||||
let commands = [
|
||||
#{ op: "move", entity: event.entity, x: event.x, y: 24 },
|
||||
#{ op: "velocity", entity: event.entity, vx: cursor.direction, vy: 0 }
|
||||
];
|
||||
// Nine simulation ticks (0.386 seconds) of audible warning precede each
|
||||
// volley. Charging does not create an explosion in front of the aircraft.
|
||||
if cursor.age % 54 == 45 {
|
||||
commands.push(#{ op: "play_sound", sound: "iron_coast_boss_6:warning" });
|
||||
}
|
||||
if cursor.age % 54 == 0 {
|
||||
if cursor.volley % 2 == 0 {
|
||||
commands.push(#{ op: "projectile", weapon: "iron_coast_boss_6:projectile", x: event.x + 28, y: event.y + 60, vx: -2, vy: 4, hostile: true });
|
||||
commands.push(#{ op: "projectile", weapon: "iron_coast_boss_6:projectile", x: event.x + 48, y: event.y + 60, vx: 0, vy: 4, hostile: true });
|
||||
commands.push(#{ op: "projectile", weapon: "iron_coast_boss_6:projectile", x: event.x + 68, y: event.y + 60, vx: 2, vy: 4, hostile: true });
|
||||
} else {
|
||||
commands.push(#{ op: "projectile", weapon: "iron_coast_boss_6:projectile", x: event.x + 28, y: event.y + 60, vx: 0, vy: 4, hostile: true });
|
||||
commands.push(#{ op: "projectile", weapon: "iron_coast_boss_6:projectile", x: event.x + 68, y: event.y + 60, vx: 0, vy: 4, hostile: true });
|
||||
}
|
||||
commands.push(#{ op: "play_sound", sound: "iron_coast_boss_6:shot" });
|
||||
cursor.volley += 1;
|
||||
}
|
||||
state.units[key] = cursor;
|
||||
#{ commands: commands, state: state }
|
||||
}
|
||||
|
||||
fn on_hit(event, state, random) {
|
||||
state.hits = if state.contains("hits") { state.hits + 1 } else { 1 };
|
||||
#{ commands: [], state: state }
|
||||
}
|
||||
|
||||
fn on_death(event, state, random) {
|
||||
let key = event.entity.to_string();
|
||||
// Retired entities cannot fire. Preserve other live bosses' cursors, and
|
||||
// still count an aircraft destroyed before its queued spawn hook runs.
|
||||
if state.contains("last_death") && state.last_death == event.entity {
|
||||
return #{ commands: [], state: state };
|
||||
}
|
||||
state.last_death = event.entity;
|
||||
if state.contains("units") { state.units.remove(key); }
|
||||
state.destroyed = if state.contains("destroyed") { state.destroyed + 1 } else { 1 };
|
||||
let defeated = if event.objectives.contains("iron_coast_boss_6:defeated") {
|
||||
event.objectives["iron_coast_boss_6:defeated"] + 1
|
||||
} else { 1 };
|
||||
#{ commands: [
|
||||
#{ op: "objective", key: "iron_coast_boss_6:defeated", value: defeated },
|
||||
#{ op: "effect", x: event.x + 28, y: event.y + 44 },
|
||||
#{ op: "effect", x: event.x + 68, y: event.y + 44 },
|
||||
#{ op: "play_sound", sound: "iron_coast_boss_6:death" }
|
||||
], state: state }
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"activation": true,
|
||||
"alternating_volleys_verified": true,
|
||||
"dead_entity_no_fire": true,
|
||||
"exact_death_counters_and_rewards": true,
|
||||
"immediate_kill_counted": true,
|
||||
"independent_dependency_free_package": true,
|
||||
"no_premature_mission_completion": true,
|
||||
"per_entity_patrol_and_timers": true,
|
||||
"runs": [
|
||||
{
|
||||
"dead_bosses_retired": true,
|
||||
"defeated": 2,
|
||||
"difficulty": 0,
|
||||
"remaining_shield": 99,
|
||||
"rewards": 3600,
|
||||
"tick": 330
|
||||
},
|
||||
{
|
||||
"dead_bosses_retired": true,
|
||||
"defeated": 2,
|
||||
"difficulty": 1,
|
||||
"remaining_shield": 97,
|
||||
"rewards": 3600,
|
||||
"tick": 330
|
||||
},
|
||||
{
|
||||
"dead_bosses_retired": true,
|
||||
"defeated": 2,
|
||||
"difficulty": 2,
|
||||
"remaining_shield": 91,
|
||||
"rewards": 3600,
|
||||
"tick": 650
|
||||
},
|
||||
{
|
||||
"dead_bosses_retired": true,
|
||||
"defeated": 2,
|
||||
"difficulty": 3,
|
||||
"remaining_shield": 91,
|
||||
"rewards": 3600,
|
||||
"tick": 650
|
||||
}
|
||||
],
|
||||
"state_roundtrip": true,
|
||||
"warning_lead_ticks": 9
|
||||
}
|
||||
+821
@@ -0,0 +1,821 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"const-random",
|
||||
"getrandom 0.3.4",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.25.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder-lite"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
|
||||
|
||||
[[package]]
|
||||
name = "const-random"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359"
|
||||
dependencies = [
|
||||
"const-random-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-random-macro"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
|
||||
dependencies = [
|
||||
"getrandom 0.2.17",
|
||||
"once_cell",
|
||||
"tiny-keccak",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01a7799fd6b852db0e61728dde9a204c423b44d689dbd432522543614b490e78"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dyn-clone"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "fdeflate"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
|
||||
dependencies = [
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide 0.9.1",
|
||||
"zlib-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"pin-project-lite",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasip2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.25.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder-lite",
|
||||
"moxcms",
|
||||
"num-traits",
|
||||
"png",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iron-crown-boss-validation"
|
||||
version = "1.0.0"
|
||||
dependencies = [
|
||||
"raptor-replica",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7883d941dae510fb2d978fc3fe018c71c9e2892fd38854de3e8b92c2e5ad9cc5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"futures-util",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.190"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "moxcms"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"pxfm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "no-std-compat"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c"
|
||||
dependencies = [
|
||||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
||||
dependencies = [
|
||||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crc32fast",
|
||||
"fdeflate",
|
||||
"flate2",
|
||||
"miniz_oxide 0.8.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pxfm"
|
||||
version = "0.1.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||
|
||||
[[package]]
|
||||
name = "raptor-replica"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"image",
|
||||
"rhai",
|
||||
"schemars",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rhai"
|
||||
version = "1.26.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0334639972c0ea5a3fd366aa36116754a11431b619fec3ed559b3f73bcbcebf5"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"bitflags",
|
||||
"no-std-compat",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"rhai_codegen",
|
||||
"serde",
|
||||
"smallvec",
|
||||
"smartstring",
|
||||
"thin-vec",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rhai_codegen"
|
||||
version = "3.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cd3a7535e50bf36857e7be7bec276d334e8c2dfa469c2201226fd01638ea5ca"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
|
||||
|
||||
[[package]]
|
||||
name = "schemars"
|
||||
version = "0.8.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615"
|
||||
dependencies = [
|
||||
"dyn-clone",
|
||||
"schemars_derive",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schemars_derive"
|
||||
version = "0.8.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_derive_internals",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive_internals"
|
||||
version = "0.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.151"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"serde",
|
||||
"serde_core",
|
||||
"zmij",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simd-adler32"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.16.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9395f0f0eee849a9b707b2f06bb92a6a422090e2123bb2ef8e87a0e61892a8e"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smartstring"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"static_assertions",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.119"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "3.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thin-vec"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6a4b9ba8738cb4a4f399d37e266becfd475e75eb73425b87a05a2f2039ba63e"
|
||||
|
||||
[[package]]
|
||||
name = "tiny-keccak"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
|
||||
dependencies = [
|
||||
"crunchy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_write",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_write"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.1+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||
|
||||
[[package]]
|
||||
name = "wasip2"
|
||||
version = "1.0.4+wasi-0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487"
|
||||
dependencies = [
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.129"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9bb54f33acc68fd454578d9820b0bde1a1a3d17aa17bb7b6595806d02886d409"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.129"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e29d0c35b16e224a7eeb5cd2d25e3e1968fbd65604117b44d3b789d00ee8535"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.129"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f501a8bc3719dba86ef8ae4728879c08001bea749eb1333ac5b91e040e2a6b7"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.6",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.129"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23f0c9c52aa7cd7d77769a4cfe2a9adb1b331f489a41d912ce14513d5ab995c6"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-time"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.57.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.62"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86502bf56ac7c77571a32e2647bb2a15894565e981fb2a48d7bde2d91c965a9d"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.62"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5457206954b06561e2608c7e19cf58b1926586d999c246eebe4502f7e2039d1a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zlib-rs"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b268e58e7c693d7c271f93ffc4ba3b380412554231c85bf61ca7af91042a4112"
|
||||
|
||||
[[package]]
|
||||
name = "zmij"
|
||||
version = "1.0.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
|
||||
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "iron-crown-boss-validation"
|
||||
version = "1.0.0"
|
||||
edition = "2024"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
raptor-replica = { path = "../../..", default-features = false }
|
||||
serde_json = "1"
|
||||
@@ -0,0 +1,188 @@
|
||||
use raptor_replica::{
|
||||
content::{ContentPack, Registry},
|
||||
modding::{self, ActiveMods, Command},
|
||||
persistence::Pilot,
|
||||
simulation::{Input, Outcome, World},
|
||||
};
|
||||
use serde_json::{Value, json};
|
||||
use std::{fs, path::PathBuf};
|
||||
|
||||
const OWNER: &str = "iron_coast_boss_6";
|
||||
const SCRIPT: &str = "scripts/ai.rhai";
|
||||
const STATE: &str = "iron_coast_boss_6/scripts/ai.rhai";
|
||||
const BOSS: &str = "iron_coast_boss_6:unit";
|
||||
const OBJECTIVE: &str = "iron_coast_boss_6:defeated";
|
||||
|
||||
fn active() -> ActiveMods {
|
||||
let mut registry = Registry::default();
|
||||
let pack: ContentPack = serde_json::from_value(json!({
|
||||
"weapons":[{"id":"base:projectile_forward_guns","name":"Forward guns","damage":1,"speed":8,"cooldown":2,"behavior":"straight","target":"all"}],
|
||||
"items":[{"id":"base:forward_guns","name":"Forward guns","price":0,"weapon":"base:projectile_forward_guns"},{"id":"base:energy","name":"Shield","price":0,"max_count":100}],
|
||||
"missions":[{"id":"base:sector_1_wave_1","name":"Boss test","duration":10000}]
|
||||
})).unwrap();
|
||||
registry.apply(pack, "base").unwrap();
|
||||
registry.validate().unwrap();
|
||||
let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..");
|
||||
ActiveMods::build(®istry, &modding::discover(&root), &[OWNER.into()], None).unwrap()
|
||||
}
|
||||
|
||||
fn event(entity: u64, x: i32, health: i32, defeated: i32) -> Value {
|
||||
json!({"entity":entity,"tick":1,"x":x,"y":24,"health":health,
|
||||
"entities":[{"entity":entity,"health":health}],
|
||||
"objectives":{OBJECTIVE:defeated}})
|
||||
}
|
||||
|
||||
fn invoke(active: &mut ActiveMods, hook: &str, event: &Value) -> Vec<Command> {
|
||||
active.scripts.begin_tick();
|
||||
active
|
||||
.scripts
|
||||
.invoke(OWNER, SCRIPT, hook, event, 6)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn callback_contract(active: &mut ActiveMods) {
|
||||
let first = event(1, 144, 160, 0);
|
||||
let second = event(2, 80, 160, 0);
|
||||
invoke(active, "on_spawn", &first);
|
||||
invoke(active, "on_spawn", &second);
|
||||
for age in 1..=108 {
|
||||
let commands = invoke(active, "on_tick", &first);
|
||||
let warnings = commands
|
||||
.iter()
|
||||
.filter(|c| matches!(c, Command::PlaySound {sound} if sound.ends_with(":warning")))
|
||||
.count();
|
||||
assert_eq!(warnings, usize::from(age % 54 == 45));
|
||||
let projectiles = commands
|
||||
.iter()
|
||||
.filter_map(|c| match c {
|
||||
Command::Projectile {
|
||||
vx, vy, hostile, ..
|
||||
} => Some((*vx, *vy, *hostile)),
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
match age {
|
||||
54 => assert_eq!(projectiles, vec![(-2, 4, true), (0, 4, true), (2, 4, true)]),
|
||||
108 => assert_eq!(projectiles, vec![(0, 4, true), (0, 4, true)]),
|
||||
_ => assert!(projectiles.is_empty()),
|
||||
}
|
||||
assert!(
|
||||
commands
|
||||
.iter()
|
||||
.all(|c| !matches!(c, Command::Effect { .. } | Command::Complete))
|
||||
);
|
||||
}
|
||||
assert_eq!(active.scripts.states[STATE]["units"]["1"]["volley"], 2);
|
||||
assert_eq!(active.scripts.states[STATE]["units"]["2"]["volley"], 0);
|
||||
invoke(active, "on_tick", &second);
|
||||
assert_eq!(active.scripts.states[STATE]["units"]["1"]["direction"], -1);
|
||||
assert_eq!(active.scripts.states[STATE]["units"]["2"]["direction"], 1);
|
||||
let commands = invoke(active, "on_death", &event(1, 120, 0, 0));
|
||||
assert!(
|
||||
commands
|
||||
.iter()
|
||||
.any(|c| matches!(c, Command::Objective {key,value:1} if key == OBJECTIVE))
|
||||
);
|
||||
assert!(commands.iter().all(|c| !matches!(c, Command::Complete)));
|
||||
assert!(active.scripts.states[STATE]["units"].get("1").is_none());
|
||||
assert!(active.scripts.states[STATE]["units"].get("2").is_some());
|
||||
assert!(invoke(active, "on_tick", &event(1, 120, 0, 1)).is_empty());
|
||||
assert!(invoke(active, "on_death", &event(1, 120, 0, 1)).is_empty());
|
||||
let commands = invoke(active, "on_death", &event(2, 120, 0, 1));
|
||||
assert!(
|
||||
commands
|
||||
.iter()
|
||||
.any(|c| matches!(c, Command::Objective {key,value:2} if key == OBJECTIVE))
|
||||
);
|
||||
assert!(
|
||||
active.scripts.states[STATE]["units"]
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.is_empty()
|
||||
);
|
||||
let checkpoint = active.scripts.checkpoints();
|
||||
let serialized = serde_json::to_vec(&checkpoint).unwrap();
|
||||
active
|
||||
.scripts
|
||||
.restore(serde_json::from_slice(&serialized).unwrap());
|
||||
assert_eq!(active.scripts.states[STATE]["destroyed"], 2);
|
||||
// An immediate kill can retire an enemy before on_spawn is dispatched.
|
||||
let commands = invoke(active, "on_death", &event(3, 120, 0, 2));
|
||||
assert!(
|
||||
commands
|
||||
.iter()
|
||||
.any(|c| matches!(c, Command::Objective {key,value:3} if key == OBJECTIVE))
|
||||
);
|
||||
}
|
||||
|
||||
fn staged_world(active: &mut ActiveMods, difficulty: u32) -> Value {
|
||||
active.scripts.restore(Default::default());
|
||||
let pilot = Pilot {
|
||||
difficulty,
|
||||
..Pilot::default()
|
||||
};
|
||||
let mut world = World::new(&"base:sector_1_wave_1".into(), &pilot, &active.registry).unwrap();
|
||||
world
|
||||
.spawn(&BOSS.into(), 110, -64, &active.registry)
|
||||
.unwrap();
|
||||
let mut second_spawned = false;
|
||||
for _ in 0..1600 {
|
||||
if world.objectives.get(OBJECTIVE) == Some(&1) && !second_spawned {
|
||||
world
|
||||
.spawn(&BOSS.into(), 110, -64, &active.registry)
|
||||
.unwrap();
|
||||
second_spawned = true;
|
||||
}
|
||||
let target = world.enemies.iter().find(|e| e.health > 0);
|
||||
let x = target.map(|e| e.x + 40).unwrap_or(150);
|
||||
let player_x = world.player.x + (x - world.player.x).clamp(-4, 4);
|
||||
world
|
||||
.step(
|
||||
Input {
|
||||
fire: true,
|
||||
absolute: Some([player_x, 160]),
|
||||
..Input::default()
|
||||
},
|
||||
&active.registry,
|
||||
&mut active.scripts,
|
||||
)
|
||||
.unwrap();
|
||||
if world.objectives.get(OBJECTIVE) == Some(&2) {
|
||||
break;
|
||||
}
|
||||
assert_eq!(world.outcome, Outcome::Playing);
|
||||
}
|
||||
assert_eq!(world.objectives[OBJECTIVE], 2);
|
||||
assert!(world.enemies.is_empty());
|
||||
assert_eq!(world.player.credits, pilot.credits + 3600);
|
||||
assert!(
|
||||
active.scripts.states[STATE]["units"]
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.is_empty()
|
||||
);
|
||||
let credit = world.player.credits;
|
||||
world
|
||||
.step(Input::default(), &active.registry, &mut active.scripts)
|
||||
.unwrap();
|
||||
assert_eq!(world.player.credits, credit);
|
||||
json!({"difficulty":difficulty,"tick":world.tick,"remaining_shield":world.player.shield,"defeated":2,"rewards":3600,"dead_bosses_retired":true})
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut active = active();
|
||||
callback_contract(&mut active);
|
||||
let runs = (0..=3)
|
||||
.map(|difficulty| staged_world(&mut active, difficulty))
|
||||
.collect::<Vec<_>>();
|
||||
let report = json!({"activation":true,"independent_dependency_free_package":true,"warning_lead_ticks":9,
|
||||
"alternating_volleys_verified":true,"per_entity_patrol_and_timers":true,"state_roundtrip":true,
|
||||
"exact_death_counters_and_rewards":true,"dead_entity_no_fire":true,"immediate_kill_counted":true,
|
||||
"no_premature_mission_completion":true,"runs":runs});
|
||||
fs::write(
|
||||
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../validation-results.json"),
|
||||
serde_json::to_string_pretty(&report).unwrap() + "\n",
|
||||
)
|
||||
.unwrap();
|
||||
println!("{}", serde_json::to_string_pretty(&report).unwrap());
|
||||
}
|
||||
Reference in new issue
Block a user