Aerie and flying creatures: bats, chain gargoyles, arcane owls, ember wyrms

- New room: aerie (key Y, rooms category, campaign from mission 7); flyers sleep there
- Arrivals: aerie 4+ bats; + torture chamber gargoyles; + library owls; big aerie and treasury
  (16+ each) a rare ember wyrm; portal checks free places in lairs and aerie separately
- Flyers cross water and lava (path finding, flag, attacks), are not burnt by lava, patrol far
  when idle, attack single enemies, flee to the aerie below 25% health and rest there up to 75%
- Owls shoot arcane bolts, the wyrm breathes fire with splash damage; shots from the air
- Hovering sprites with flapping, aerie floor, perches, roosts, plinths, twig and ember nests
- Room counts are recounted on load (no longer stored); tests for flying and arrivals

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-03 13:01:26 +01:00
1 parent 729dd4fe4c
commit b7d7fc2b52
10 files changed
+454 -56

No files matched your search

+13 -1
View File
@@ -57,6 +57,7 @@ pub enum Kind {
Silver, // silver vein: common, little value
Ruby, // ruby vein: rare, valuable
Diamond, // diamond vein: very rare, very valuable
Aerie, // room for flying creatures (their beds)
}
// options for the map generator (campaign missions)
@@ -85,7 +86,7 @@ pub struct River {
}
// order matters for the packed savegame codec: only append new kinds
const KINDS: [Kind; 23] = [
const KINDS: [Kind; 24] = [
Kind::Rock,
Kind::Earth,
Kind::Gold,
@@ -109,6 +110,7 @@ const KINDS: [Kind; 23] = [
Kind::Silver,
Kind::Ruby,
Kind::Diamond,
Kind::Aerie,
];
// treasures (veins, treasury content, imp loads): 0 gold, 1 silver, 2 ruby, 3 diamond
@@ -188,6 +190,7 @@ impl Tile {
| Kind::Bridge
| Kind::LavaBridge
| Kind::Shard
| Kind::Aerie
)
}
// river tiles (open, but nobody can walk there)
@@ -620,6 +623,15 @@ impl Map {
move |i| if self.t[i].walkable() { Some(1) } else { None }
}
// flying creatures also cross water and lava
pub fn fly_cost(&self) -> impl Fn(usize) -> Option<u32> + '_ {
move |i| if self.t[i].walkable() || self.t[i].liquid() { Some(1) } else { None }
}
pub fn fly_path_to(&self, start: usize, target: usize) -> Option<Vec<usize>> {
self.search(start, self.fly_cost(), |i| i == target, true)
}
pub fn hero_cost(&self) -> impl Fn(usize) -> Option<u32> + '_ {
move |i| {
let tl = &self.t[i];