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:
1 parent
729dd4fe4c
commit
b7d7fc2b52
10 files changed
+454
-56
No files matched your search
+15
-7
@@ -1088,11 +1088,14 @@ impl R3d {
|
||||
if !e.alive || e.held {
|
||||
continue;
|
||||
}
|
||||
let big = matches!(e.kind, EK::Ogre | EK::Paladin | EK::Jailer | EK::Chainbreaker);
|
||||
let w = if e.kind == EK::Chainbreaker { 1.0 } else if big { 0.8 } else { 0.62 };
|
||||
let w = sprite_size(e.kind);
|
||||
let h = w;
|
||||
let sleeping = matches!(e.job, Job::Sleep(_)) && !e.moving;
|
||||
let mut bob = if e.moving { (e.anim * 12.0).sin().abs() * 0.06 } else { 0.0 };
|
||||
// flying creatures hover and flap (on their perch while sleeping)
|
||||
if flies(e.kind) && !sleeping {
|
||||
bob = 0.45 + (t * 7.0 + e.anim * 3.0).sin() * 0.06;
|
||||
}
|
||||
let mut rot = if e.working && !sleeping { (t * 14.0 + e.anim).sin() * 0.15 } else { 0.0 };
|
||||
// prisoners: lying unconscious, carried above an imp, or shaking in the torture chamber
|
||||
match e.captive {
|
||||
@@ -1157,8 +1160,9 @@ impl R3d {
|
||||
if !e.alive || e.held {
|
||||
continue;
|
||||
}
|
||||
let big = matches!(e.kind, EK::Ogre | EK::Paladin | EK::Jailer | EK::Chainbreaker);
|
||||
let head = proj(vec3(e.x, if big { 0.9 } else { 0.72 }, e.y));
|
||||
let big = matches!(e.kind, EK::Ogre | EK::Paladin | EK::Jailer | EK::Chainbreaker | EK::Wyrm | EK::Gargoyle);
|
||||
let lift = if flies(e.kind) && !(matches!(e.job, Job::Sleep(_)) && !e.moving) { 0.45 } else { 0.0 };
|
||||
let head = proj(vec3(e.x, lift + if big { 0.9 } else { 0.72 }, e.y));
|
||||
// bar width in block characters, depending on the zoom
|
||||
let cols = ((px_per_tile * 0.6 / cw) as usize).clamp(3, 8);
|
||||
if (e.hp < e.max_hp || e.hero) && e.captive == 0 {
|
||||
@@ -1222,9 +1226,9 @@ fn shade_c(r: u8, g: u8, b: u8, f: f32) -> Color {
|
||||
|
||||
// size of a unit's sprite (same as in the billboards)
|
||||
fn sprite_size(k: EK) -> f32 {
|
||||
if k == EK::Chainbreaker {
|
||||
if matches!(k, EK::Chainbreaker | EK::Wyrm) {
|
||||
1.0
|
||||
} else if matches!(k, EK::Ogre | EK::Paladin | EK::Jailer) {
|
||||
} else if matches!(k, EK::Ogre | EK::Paladin | EK::Jailer | EK::Gargoyle) {
|
||||
0.8
|
||||
} else {
|
||||
0.62
|
||||
@@ -1242,7 +1246,10 @@ fn draw_gear(g: &Game, cam: &Cam) {
|
||||
let toward = cam.eye_dir();
|
||||
for e in g.ents.iter().filter(|e| gear_shown(e)) {
|
||||
let w = sprite_size(e.kind);
|
||||
let bob = if e.moving { (e.anim * 12.0).sin().abs() * 0.06 } else { 0.0 };
|
||||
let mut bob = if e.moving { (e.anim * 12.0).sin().abs() * 0.06 } else { 0.0 };
|
||||
if flies(e.kind) {
|
||||
bob = 0.45;
|
||||
}
|
||||
let base = vec3(e.x, bob, e.y) + toward * 0.5;
|
||||
let at = |dx: f32, dy: f32| base + r * (dx * w) + Vec3::Y * (dy * w);
|
||||
let metal = if e.level >= 8 {
|
||||
@@ -1709,6 +1716,7 @@ pub fn minimap_color(tile: &Tile) -> [u8; 4] {
|
||||
Kind::Bridge => [150, 110, 60, 255],
|
||||
Kind::LavaBridge => [130, 120, 115, 255],
|
||||
Kind::Shard => [255, 60, 120, 255],
|
||||
Kind::Aerie => [170, 140, 90, 255],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user