Torture chamber with prisoners and defectors, Jailer; temple with prayer, Flame Priestess

- defeated heroes are knocked out if the torture chamber has room; imps carry them in
- torture drains HP over ~100 s; ~40% defect (paladins ~25%) and become own creatures
- Jailer (6+ torture tiles): tanky melee that pulls enemies in with a chain
- temple: creatures pray for mana (more than studying) and mood
- Flame Priestess (6+ temple tiles): fireballs with splash, heals creatures and the Soul Core
- tests: prisoner chain + defect rate, temple prayer + core healing

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-03 07:53:58 +01:00
1 parent 903d6fb0f4
commit a1ad5ad141
7 files changed
+545 -25

No files matched your search

+28 -10
View File
@@ -935,18 +935,28 @@ impl R3d {
}
};
let mut mb = MB::new();
let sw = 120.0;
let sh = 24.0;
let sw = SPRITE_TEX_W;
let sh = SPRITE_TEX_H;
for e in &g.ents {
if !e.alive || e.held {
continue;
}
let big = matches!(e.kind, EK::Ogre | EK::Paladin);
let big = matches!(e.kind, EK::Ogre | EK::Paladin | EK::Jailer);
let w = if big { 0.8 } else { 0.62 };
let h = w;
let sleeping = matches!(e.job, Job::Sleep(_)) && !e.moving;
let bob = if e.moving { (e.anim * 12.0).sin().abs() * 0.06 } else { 0.0 };
let rot = if e.working && !sleeping { (t * 14.0 + e.anim).sin() * 0.15 } else { 0.0 };
let mut bob = if e.moving { (e.anim * 12.0).sin().abs() * 0.06 } else { 0.0 };
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 {
1 => rot = std::f32::consts::FRAC_PI_2,
2 => {
rot = std::f32::consts::FRAC_PI_2;
bob = 0.4;
}
3 => rot = (t * 25.0 + e.anim).sin() * 0.08,
_ => {}
}
let white = e.flash > 0.07;
let src = Gfx::sprite_rect(e.kind, white);
let (mut u0, v0) = (src.x / sw, src.y / sh);
@@ -954,8 +964,14 @@ impl R3d {
if e.face < 0.0 {
std::mem::swap(&mut u0, &mut u1);
}
let a = amb(e.x, e.y) * if sleeping { 0.6 } else { 1.0 };
let c = if white { [255, 255, 255, 255] } else { col(Vec3::splat(a), 1.0) };
let a = amb(e.x, e.y) * if sleeping || e.captive == 1 { 0.6 } else { 1.0 };
let c = if white {
[255, 255, 255, 255]
} else if e.captive == 3 {
col(vec3(a * 1.2, a * 0.55, a * 0.55), 1.0)
} else {
col(Vec3::splat(a), 1.0)
};
// pulled towards the camera: unchanged on screen (orthographic), but walls behind
// the unit no longer cut into the sprite
let base = vec3(e.x, bob, e.y) + toward * 0.45;
@@ -985,7 +1001,7 @@ impl R3d {
if !e.alive || e.held {
continue;
}
let big = matches!(e.kind, EK::Ogre | EK::Paladin);
let big = matches!(e.kind, EK::Ogre | EK::Paladin | EK::Jailer);
let head = Cam::project(m, vec3(e.x, if big { 0.9 } else { 0.72 }, e.y));
let w = (px_per_tile * 0.6).clamp(12.0, 40.0);
if e.hp < e.max_hp || e.hero {
@@ -1206,9 +1222,11 @@ fn draw_shadows(g: &Game) {
if !e.alive || e.held {
continue;
}
let r = if matches!(e.kind, EK::Ogre | EK::Paladin) { 0.32 } else { 0.24 };
let r = if matches!(e.kind, EK::Ogre | EK::Paladin | EK::Jailer) { 0.32 } else { 0.24 };
disc(vec3(e.x, 0.012, e.y), r, Color::new(0.0, 0.0, 0.0, 0.4), 12);
let rc = if e.guard {
let rc = if e.captive != 0 {
Color::new(0.6, 0.6, 0.6, 0.6)
} else if e.guard {
Color::new(1.0, 0.85, 0.3, 0.9)
} else if e.hero {
Color::new(0.5, 0.8, 1.0, 0.8)