Defence towers: arrow (piercing), cannon (splash + knockback), magic (mana, slow, chain); 3 levels, repair by imps, heroes attack towers; torture/temple room tools prepared

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:47:50 +01:00
1 parent a1fe02ffa6
commit 903d6fb0f4
10 files changed
+708 -19

No files matched your search

+83
View File
@@ -531,6 +531,8 @@ fn build_chunk(map: &Map, amb: &[f32], cx: i32, cz: i32, gold_fill: f32, atlas:
}
Kind::Training if (x + z) % 2 == 0 => mb.cross(xf + 0.5, zf + 0.5, 0.7, 0.75, D_DUMMY, dc),
Kind::Library if z % 2 == 0 => mb.cross(xf + 0.5, zf + 0.5, 0.9, 0.85, D_SHELF, dc),
Kind::Torture if (x + z) % 2 == 1 => mb.cross(xf + 0.5, zf + 0.5, 0.8, 0.8, D_RACK, dc),
Kind::Temple if x % 3 == 1 && z % 3 == 1 => mb.cross(xf + 0.5, zf + 0.5, 0.8, 0.8, D_ALTAR, dc),
Kind::Treasury if gold_fill > 0.02 => {
let s = 0.35 + 0.55 * gold_fill;
mb.cross(xf + 0.5, zf + 0.5, s, s * 0.8, D_COINS, dc);
@@ -801,6 +803,12 @@ impl R3d {
let (gx, gz) = g.gate_center();
push(vec3(gx, 1.2, gz), 7.0, vec3(0.75, 0.85, 1.0), 1.0, 50.0);
}
for tw in &g.towers {
if tw.kind == TowerKind::Magic {
let (x, z) = tw.pos();
push(vec3(x, tower_height(tw) + 0.6, z), 4.5, vec3(0.75, 0.4, 1.0), 0.8 + tw.flash * 3.0, 10.0);
}
}
for f in &g.fx {
if f.kind == 1 {
push(vec3(f.x, 2.0, f.y), 8.0, vec3(1.0, 1.0, 0.85), 3.0 * (1.0 - f.t / f.max), 200.0);
@@ -874,6 +882,7 @@ impl R3d {
draw_cube(vec3(x, 0.55, z), vec3(0.07, 0.3, 0.07), None, Color::from_rgba(70, 45, 28, 255));
}
draw_landmarks_solid(g, t);
draw_towers_solid(g);
// ---- unlit glow / overlays
gl_use_material(&self.glow);
@@ -898,6 +907,7 @@ impl R3d {
}
draw_shadows(g);
draw_landmarks_glow(g, t);
draw_towers_glow(g, t);
if let Some(f) = g.flag {
draw_flag(f, t);
}
@@ -1007,6 +1017,16 @@ impl R3d {
draw_circle(p.x + w * 0.35, p.y, 3.0, Color::from_rgba(250, 210, 60, 255));
}
}
for tw in &g.towers {
if tw.hp < tw.max_hp() {
let (x, z) = tw.pos();
let p = Cam::project(m, vec3(x, tower_height(tw) + 0.9, z));
let w = 40.0;
let f = (tw.hp / tw.max_hp()).clamp(0.0, 1.0);
draw_rectangle(p.x - w * 0.5 - 1.0, p.y - 1.0, w + 2.0, 5.0, BLACK);
draw_rectangle(p.x - w * 0.5, p.y, w * f, 3.0, Color::from_rgba(255, 160, 60, 255));
}
}
if g.gate_hp > 0.0 && g.gate_hp < GATE_HP {
let (gx, gz) = g.gate_center();
let p = Cam::project(m, vec3(gx, 2.4, gz));
@@ -1017,6 +1037,68 @@ impl R3d {
}
}
// ------------------------------------------------------------------ towers
pub fn tower_height(t: &Tower) -> f32 {
match t.kind {
TowerKind::Arrow => 1.0 + 0.3 * (t.level - 1) as f32,
TowerKind::Cannon => 0.6 + 0.15 * (t.level - 1) as f32,
TowerKind::Magic => 1.2 + 0.3 * (t.level - 1) as f32,
}
}
fn shade_c(r: u8, g: u8, b: u8, f: f32) -> Color {
Color::new(r as f32 / 255.0 * f, g as f32 / 255.0 * f, b as f32 / 255.0 * f, 1.0)
}
fn draw_towers_solid(g: &Game) {
for tw in &g.towers {
let (x, z) = tw.pos();
let h = tower_height(tw);
let f = 0.75 + tw.flash * 1.5; // brightens briefly when firing
match tw.kind {
TowerKind::Arrow => {
draw_cube(vec3(x, h * 0.5, z), vec3(0.7, h, 0.7), None, shade_c(110, 75, 45, f));
draw_cube(vec3(x, h + 0.06, z), vec3(0.92, 0.12, 0.92), None, shade_c(130, 90, 55, f));
for (dx, dz) in [(-0.38, -0.38), (0.38, -0.38), (0.38, 0.38), (-0.38, 0.38)] {
draw_cube(vec3(x + dx, h + 0.2, z + dz), vec3(0.15, 0.18, 0.15), None, shade_c(130, 90, 55, f));
}
}
TowerKind::Cannon => {
draw_cube(vec3(x, h * 0.5, z), vec3(0.88, h, 0.88), None, shade_c(100, 100, 110, f));
draw_cube(vec3(x, h + 0.08, z), vec3(0.5, 0.16, 0.5), None, shade_c(70, 70, 78, f));
let (ax, az) = (tw.aim.cos(), tw.aim.sin());
for k in 0..4 {
let d = 0.1 + k as f32 * 0.14;
draw_cube(vec3(x + ax * d, h + 0.2, z + az * d), Vec3::splat(0.2 - k as f32 * 0.015), None, shade_c(40, 40, 46, f));
}
}
TowerKind::Magic => {
draw_cube(vec3(x, h * 0.5, z), vec3(0.42, h, 0.42), None, shade_c(84, 74, 104, f));
draw_cube(vec3(x, 0.1, z), vec3(0.75, 0.2, 0.75), None, shade_c(70, 62, 86, f));
draw_cube(vec3(x, h, z), vec3(0.6, 0.1, 0.6), None, shade_c(110, 96, 130, f));
}
}
// level pips
for k in 0..tw.level {
draw_cube(vec3(x - 0.2 + k as f32 * 0.2, 0.25, z + 0.46), Vec3::splat(0.09), None, Color::from_rgba(240, 200, 70, 255));
}
}
}
fn draw_towers_glow(g: &Game, t: f32) {
for (k, tw) in g.towers.iter().enumerate() {
if tw.kind != TowerKind::Magic {
continue;
}
let (x, z) = tw.pos();
let c = vec3(x, tower_height(tw) + 0.45 + (t * 2.0 + k as f32).sin() * 0.06, z);
let pulse = 1.0 + (t * 4.0 + k as f32).sin() * 0.1 + tw.flash * 2.0;
draw_sphere(c, 0.16 * pulse, None, Color::new(0.85, 0.5, 1.0, 0.95));
draw_sphere(c, 0.3 * pulse, None, Color::new(0.7, 0.3, 1.0, 0.25));
}
}
// ------------------------------------------------------------------ landmarks, fx, overlay
// Camera direction for camera-facing line quads (set once per frame)
@@ -1286,5 +1368,6 @@ pub fn minimap_color(tile: &Tile) -> [u8; 4] {
Kind::Gate => [230, 230, 255, 255],
Kind::Torture => [120, 40, 40, 255],
Kind::Tower => [255, 140, 60, 255],
Kind::Temple => [200, 110, 50, 255],
}
}