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:
1 parent
a1fe02ffa6
commit
903d6fb0f4
10 files changed
+708
-19
No files matched your search
@@ -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],
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user