use crate::diagnostic::{Diagnostic, codes};
use crate::envelope::Campaign;
use crate::fight::{Fight, fights, unleashed_actors, wave_area};
pub fn on_kill_checks(c: &Campaign, d: &mut Vec<Diagnostic>) {
let unleashed = unleashed_actors(c);
for (path, fight) in fights(c) {
let Some(ok) = fight.on_kill() else {
continue;
};
if ok.effects.is_empty() {
d.push(Diagnostic::error(
codes::SCHEMA,
"quests",
format!("{path}/on_kill/effects"),
format!(
"`on_kill` on {} `{}` has no effects. The schema requires at least one \
(`minItems: 1`): a bundle that does nothing is not a bundle. Add the effect \
each kill should have, or remove `on_kill`.",
fight.word(),
fight.id()
),
));
}
let unreachable = match fight {
Fight::Wave(w) => wave_area(c, w.id.as_str()).is_none().then(|| {
format!(
"no beat spawns wave `{}` — no `spawn-wave` names it where the engine can \
seat it, so it has no bodies and no kill can be credited. Spawn it from a \
beat, or remove the bundle.",
w.id
)
}),
Fight::Actor(a) => (!a.vulnerable && !unleashed.contains(a.id.as_str())).then(|| {
format!(
"actor `{}` is never unleashed and is not `vulnerable`, so its body is \
`Invulnerable` for the whole delve and no player can be credited with \
killing it. Unleash it with an `unleash-actor` beat, mark it \
`vulnerable: true`, or remove the bundle.",
a.id
)
}),
};
if let Some(why) = unreachable {
d.push(Diagnostic::error(
codes::ON_KILL_UNREACHABLE,
"quests",
format!("{path}/on_kill"),
format!(
"`on_kill` on {} `{}` can never fire: {why}",
fight.word(),
fight.id()
),
));
}
}
}