Traps and doors made in a new forge room, installed by imps; new creature: the cogling

- forge room: creatures work there (coglings fastest), the work goes into the oldest planned trap or door; finished pieces wait as crates, imps carry and install them
- traps: spike pit, poison vent (cloud), fire jet, stone roller, alarm bell (calls creatures), rune mine (one big blast), frost glow (slows around it)
- doors: wood, iron, magic (hurls attackers back); own creatures pass, enemies smash them on their way; clicking a door with a door tool locks it for everybody
- new 'Traps' category in the toolbar, forge in the rooms; texts EN/DE, bestiary entries; atlas grown for new textures and icons
- tests: forge to installed trap, spikes hurt, doors lock and get smashed

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-04 06:55:37 +01:00
1 parent 1696297ac3
commit 4f20223c93
13 files changed
+1267 -24

No files matched your search

+34 -1
View File
@@ -72,7 +72,7 @@ fn usage(g: &Game) -> Use {
continue;
}
match e.job {
Job::Train(t) | Job::Study(t) | Job::Pray(t) if e.working || e.path.is_empty() => {
Job::Train(t) | Job::Study(t) | Job::Pray(t) | Job::Forge(t) if e.working || e.path.is_empty() => {
u.busy.insert(t);
}
_ => {}
@@ -139,6 +139,8 @@ pub fn draw_props_solid(g: &Game, cam: &Cam, t: f32) {
Kind::Library if h % 3 == 0 => lectern(c, l),
Kind::ManaSpring => spring_basin(c, l),
Kind::RuneChest => rune_chest(c, l),
Kind::Forge if (x + z) % 2 == 0 => anvil(c, h, l),
Kind::Forge if h % 4 == 1 => furnace(c, l),
_ => {}
}
}
@@ -169,6 +171,22 @@ fn rune_chest(c: Vec3, l: f32) {
cube(c + vec3(0.0, 0.22, 0.18), vec3(0.08, 0.1, 0.03), rgb(200, 170, 80, l));
}
// forge: an anvil on a block, a hammer leaning against it
fn anvil(c: Vec3, h: u32, l: f32) {
let o = vec3(((h >> 3) % 3) as f32 * 0.08 - 0.08, 0.0, ((h >> 5) % 3) as f32 * 0.08 - 0.08);
cube(c + o + vec3(0.0, 0.12, 0.0), vec3(0.22, 0.24, 0.22), rgb(70, 50, 36, l));
cube(c + o + vec3(0.0, 0.28, 0.0), vec3(0.16, 0.08, 0.16), rgb(56, 56, 62, l));
cube(c + o + vec3(0.0, 0.35, 0.0), vec3(0.38, 0.06, 0.16), rgb(76, 76, 84, l));
cube(c + o + vec3(0.22, 0.35, 0.0), vec3(0.1, 0.04, 0.08), rgb(76, 76, 84, l));
}
// forge: a squat stone furnace (its fire glows in the glow pass)
fn furnace(c: Vec3, l: f32) {
cube(c + vec3(0.0, 0.25, 0.0), vec3(0.6, 0.5, 0.6), rgb(64, 52, 50, l));
cube(c + vec3(0.0, 0.55, 0.0), vec3(0.4, 0.1, 0.4), rgb(50, 42, 40, l));
cube(c + vec3(0.0, 0.75, 0.0), vec3(0.16, 0.32, 0.16), rgb(44, 38, 38, l));
}
// a stone basin around a mana spring
fn spring_basin(c: Vec3, l: f32) {
for (dx, dz, sx, sz) in [(0.0, -0.38, 0.8, 0.1), (0.0, 0.38, 0.8, 0.1), (-0.38, 0.0, 0.1, 0.8), (0.38, 0.0, 0.1, 0.8)] {
@@ -234,6 +252,21 @@ pub fn draw_props_glow(g: &Game, cam: &Cam, t: f32) {
}
}
}
Kind::Forge if h % 4 == 1 && (x + z) % 2 != 0 => {
// furnace fire
let f = 0.7 + 0.3 * (t * 9.0 + k).sin();
draw_cube(c + vec3(0.0, 0.2, 0.31), vec3(0.28, 0.2 * f, 0.02), None, Color::new(1.0, 0.5, 0.1, 0.95));
draw_sphere(c + vec3(0.0, 0.25, 0.35), 0.22 * f, None, Color::new(1.0, 0.35, 0.05, 0.25));
}
Kind::Forge if (x + z) % 2 == 0 && (u.busy.contains(&i) || u.busy.iter().any(|&b| adj8(b, i))) => {
// sparks fly from the anvil while somebody hammers
for n in 0..5 {
let ph = (t * 2.2 + n as f32 * 0.21 + k * 0.1).fract();
let a = n as f32 * 1.3 + k;
let p = c + vec3(a.cos() * ph * 0.5, 0.4 + ph * 0.4 - ph * ph * 0.9, a.sin() * ph * 0.5);
draw_cube(p, Vec3::splat(0.03), None, Color::new(1.0, 0.75, 0.3, 1.0 - ph));
}
}
Kind::RuneChest => {
let f = 0.6 + 0.4 * (t * 2.5 + k).sin();
draw_cube(c + vec3(0.0, 0.39, 0.0), vec3(0.14, 0.02, 0.14), None, Color::new(0.35, 0.8, 1.0, f));