202 lines
7.2 KiB
Rust
202 lines
7.2 KiB
Rust
//! Original-data integration coverage. Run explicitly with --ignored; no game data is tracked.
|
|
//! The assisted campaign fixture is described in tools/campaign_check.rs.
|
|
#[path = "../tools/campaign_check.rs"]
|
|
mod campaign_check;
|
|
use raptor_replica::{
|
|
assets::{Catalog, decode_demo},
|
|
content::ContentId,
|
|
modding::ScriptRuntime,
|
|
persistence::Pilot,
|
|
simulation::{Input, World},
|
|
};
|
|
use std::{collections::BTreeSet, path::PathBuf};
|
|
|
|
fn catalog_registry() -> (Catalog, raptor_replica::content::Registry) {
|
|
let root = std::env::var_os("RAPTOR_TEST_DATA")
|
|
.map(PathBuf::from)
|
|
.unwrap_or_else(|| PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("data"));
|
|
campaign_check::catalog_registry(&root).unwrap()
|
|
}
|
|
fn registry() -> raptor_replica::content::Registry {
|
|
catalog_registry().1
|
|
}
|
|
|
|
#[test]
|
|
#[ignore = "requires original untracked catalog; assisted inspection, not ordinary gameplay wins"]
|
|
fn every_original_wave_reaches_its_end_on_all_four_difficulties() {
|
|
let registry = registry();
|
|
assert_eq!(registry.missions.len(), 27);
|
|
let mut failures = vec![];
|
|
let mut reports = vec![];
|
|
for difficulty in 0..=3 {
|
|
for sector in 1..=3 {
|
|
for wave in 1..=9 {
|
|
let report =
|
|
campaign_check::run_wave(®istry, sector, wave, difficulty, 12000).unwrap();
|
|
eprintln!("{}", report.csv());
|
|
if !report.completed()
|
|
|| report.visited_spawns != report.total_spawns
|
|
|| report.bosses_seen != report.expected_bosses
|
|
{
|
|
failures.push(format!("{report:?}"));
|
|
}
|
|
reports.push(report.csv());
|
|
}
|
|
}
|
|
}
|
|
if let Some(path) = std::env::var_os("RAPTOR_CAMPAIGN_REPORT") {
|
|
std::fs::write(
|
|
path,
|
|
format!("{}\n{}\n", campaign_check::csv_header(), reports.join("\n")),
|
|
)
|
|
.unwrap();
|
|
}
|
|
assert!(
|
|
failures.is_empty(),
|
|
"Assisted fixture blockers:\n{}",
|
|
failures.join("\n")
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore = "requires original untracked catalog; progression fixture bypasses combat"]
|
|
fn all_original_campaign_and_training_progression_paths_are_available() {
|
|
let registry = registry();
|
|
for difficulty in 0..=3 {
|
|
let mut pilot = Pilot {
|
|
difficulty,
|
|
..Pilot::default()
|
|
};
|
|
let waves = if difficulty == 0 { 4 } else { 9 };
|
|
let sectors = if difficulty == 0 { 1 } else { 3 };
|
|
for sector in 1..=sectors {
|
|
for wave in 1..=waves {
|
|
let expected = ContentId::new(format!("base:sector_{sector}_wave_{wave}")).unwrap();
|
|
assert_eq!(pilot.mission, expected);
|
|
pilot.complete_mission(®istry).unwrap();
|
|
pilot.validate(®istry, &[]).unwrap();
|
|
}
|
|
}
|
|
assert_eq!(pilot.mission, ContentId::from("base:sector_1_wave_1"));
|
|
assert_eq!(pilot.difficulty, (difficulty + 1).min(3));
|
|
let progress = pilot.legacy_progress.as_ref().unwrap();
|
|
assert!(progress.waves.iter().all(|wave| *wave == 0));
|
|
if difficulty == 0 {
|
|
assert!(progress.training_completed);
|
|
assert_eq!(pilot.credits, 10000);
|
|
assert_eq!(pilot.inventory[&"base:energy".into()], 75);
|
|
} else {
|
|
assert_eq!(pilot.completed.len(), 27);
|
|
assert_eq!(&progress.difficulties[..3], &[(difficulty + 1).min(3); 3]);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[ignore = "requires original untracked catalog; assisted weapon exercise, no weapon parity claim"]
|
|
fn every_original_player_weapon_emits_with_live_mission_targets() {
|
|
let registry = registry();
|
|
let weapons: Vec<_> = registry
|
|
.items
|
|
.values()
|
|
.filter(|i| i.weapon.is_some() && i.legacy.is_some())
|
|
.collect();
|
|
assert_eq!(weapons.len(), 15);
|
|
let mut exercised = BTreeSet::new();
|
|
for item in weapons {
|
|
let id = item.weapon.clone().unwrap();
|
|
let mut pilot = Pilot {
|
|
difficulty: 3,
|
|
selected: Some(item.id.clone()),
|
|
..Pilot::default()
|
|
};
|
|
pilot.inventory = [
|
|
(item.id.clone(), item.max_count),
|
|
("base:energy".into(), 100),
|
|
]
|
|
.into_iter()
|
|
.collect();
|
|
let mut world = World::new(&pilot.mission, &pilot, ®istry).unwrap();
|
|
let mut scripts = ScriptRuntime::new();
|
|
for tick in 0..1500 {
|
|
world.player.shield = 100;
|
|
world.player.super_shield = 100;
|
|
world
|
|
.step(
|
|
Input {
|
|
fire: true,
|
|
absolute: Some([144, 160]),
|
|
bomb: tick % 180 == 0,
|
|
..Input::default()
|
|
},
|
|
®istry,
|
|
&mut scripts,
|
|
)
|
|
.unwrap();
|
|
if world.projectiles.iter().any(|p| p.weapon == id) {
|
|
exercised.insert(id.clone());
|
|
break;
|
|
}
|
|
}
|
|
assert!(
|
|
exercised.contains(&id),
|
|
"original weapon {id} produced no projectile with mission targets"
|
|
);
|
|
}
|
|
assert_eq!(exercised.len(), 15);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore = "requires original catalog and rebuilt C++ full-demo reference trace"]
|
|
fn complete_demo_1_matches_every_reference_gameplay_snapshot() {
|
|
let path = std::env::var_os("RAPTOR_REFERENCE_DEMO1")
|
|
.map(PathBuf::from)
|
|
.unwrap_or_else(|| {
|
|
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(".reference/cpp-demo1-full.jsonl")
|
|
});
|
|
let reference: Vec<serde_json::Value> = std::fs::read_to_string(&path)
|
|
.expect("produce the trace using the command in docs/campaign-validation.md")
|
|
.lines()
|
|
.map(|line| serde_json::from_str(line).unwrap())
|
|
.collect();
|
|
assert_eq!(
|
|
reference.len(),
|
|
1889,
|
|
"expected the entire available DEMO1G1 recording"
|
|
);
|
|
let (catalog, registry) = catalog_registry();
|
|
let (sector, wave, frames) = decode_demo(&catalog.named("DEMO1G1_REC").unwrap()).unwrap();
|
|
assert_eq!(frames.len(), reference.len());
|
|
let mut pilot = Pilot::demo(sector, ®istry).unwrap();
|
|
pilot.mission = format!("base:sector_{}_wave_{}", sector + 1, wave + 1)
|
|
.as_str()
|
|
.into();
|
|
let mut world = World::new(&pilot.mission, &pilot, ®istry).unwrap();
|
|
let mut scripts = ScriptRuntime::new();
|
|
for (frame, expected) in frames.into_iter().zip(reference) {
|
|
world
|
|
.step(
|
|
Input {
|
|
fire: frame.buttons[0],
|
|
cycle: frame.buttons[1],
|
|
bomb: frame.buttons[2],
|
|
absolute: Some([frame.x as i32, frame.y as i32]),
|
|
demo_bank: Some(frame.bank as i32),
|
|
..Input::default()
|
|
},
|
|
®istry,
|
|
&mut scripts,
|
|
)
|
|
.unwrap();
|
|
assert_eq!(
|
|
world.reference_state(®istry),
|
|
expected,
|
|
"reference mismatch at simulation step {}",
|
|
world.tick
|
|
);
|
|
}
|
|
assert_eq!(world.tick, 1889);
|
|
assert_eq!(world.player.shield, 3);
|
|
assert_eq!(world.player.credits, 60825);
|
|
}
|