Planned hero entry points: walls glow and pulse red, with a pulsing red light
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f113e1085c
commit
05ba88359e
3 files changed
+53
-1
No files matched your search
@@ -82,7 +82,7 @@ An original dungeon management game (genre: dungeon building & defence) that run
|
|||||||
- Each wave picks an **entry point** on the border of the realm facing the hero gate: few towers/creatures, no reinforced walls and a short way are attractive, entry points of recent waves are avoided, plus some randomness
|
- Each wave picks an **entry point** on the border of the realm facing the hero gate: few towers/creatures, no reinforced walls and a short way are attractive, entry points of recent waves are avoided, plus some randomness
|
||||||
- Waves of **6+ heroes split into two groups** with different entry points (the paladin goes with the bigger group)
|
- Waves of **6+ heroes split into two groups** with different entry points (the paladin goes with the bigger group)
|
||||||
- Heroes first tunnel to their entry point, then go for the core
|
- Heroes first tunnel to their entry point, then go for the core
|
||||||
- **Warning** 30 s before: scout message with the direction(s) and blinking markers on the minimap
|
- **Warning** 30 s before: scout message with the direction(s), blinking markers on the minimap and the **walls at the entry points glowing and pulsing red** (plus a pulsing red light) until the wave has broken in
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
- **Victory**: destroy the Hero Gate
|
- **Victory**: destroy the Hero Gate
|
||||||
|
|||||||
@@ -807,6 +807,10 @@ impl R3d {
|
|||||||
let (gx, gz) = g.gate_center();
|
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);
|
push(vec3(gx, 1.2, gz), 7.0, vec3(0.75, 0.85, 1.0), 1.0, 50.0);
|
||||||
}
|
}
|
||||||
|
let pulse = 0.5 + 0.5 * (t * 4.0).sin();
|
||||||
|
for &(ex, ey) in &g.planned_entries {
|
||||||
|
push(vec3(ex as f32 + 0.5, 1.2, ey as f32 + 0.5), 5.0, vec3(1.0, 0.12, 0.08), 0.6 + 1.0 * pulse, 30.0);
|
||||||
|
}
|
||||||
for tw in &g.towers {
|
for tw in &g.towers {
|
||||||
if tw.kind == TowerKind::Magic {
|
if tw.kind == TowerKind::Magic {
|
||||||
let (x, z) = tw.pos();
|
let (x, z) = tw.pos();
|
||||||
@@ -935,6 +939,7 @@ impl R3d {
|
|||||||
draw_flag(f, t);
|
draw_flag(f, t);
|
||||||
}
|
}
|
||||||
draw_overlay(&g.map, ov, self.wall_sub);
|
draw_overlay(&g.map, ov, self.wall_sub);
|
||||||
|
draw_entry_warnings(g, t, self.wall_sub);
|
||||||
// translucent glows and effects last (they write depth, see glow_material)
|
// translucent glows and effects last (they write depth, see glow_material)
|
||||||
draw_landmarks_glow(g, t);
|
draw_landmarks_glow(g, t);
|
||||||
draw_towers_glow(g, t);
|
draw_towers_glow(g, t);
|
||||||
@@ -1359,6 +1364,33 @@ fn outline(x0: f32, z0: f32, x1: f32, z1: f32, y: f32, c: Color) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Expected hero entry points: the walls around them glow red and pulse
|
||||||
|
fn draw_entry_warnings(g: &Game, t: f32, n: usize) {
|
||||||
|
if g.planned_entries.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let p = 0.5 + 0.5 * (t * 4.0).sin();
|
||||||
|
let fill = [255, 40, 30, (50.0 + 90.0 * p) as u8];
|
||||||
|
let line = [255, 90, 60, (120.0 + 120.0 * p) as u8];
|
||||||
|
let mut mb = MB::new();
|
||||||
|
for &(ex, ey) in &g.planned_entries {
|
||||||
|
for dy in -2..=2 {
|
||||||
|
for dx in -2..=2 {
|
||||||
|
let (x, y) = (ex + dx, ey + dy);
|
||||||
|
let Some(tile) = g.map.get(x, y) else { continue };
|
||||||
|
// walls of the realm's border near the entry point (not rock)
|
||||||
|
let border = DIR4.iter().any(|&(ax, ay)| g.map.get(x + ax, y + ay).map_or(false, |o| o.owner == Owner::Player && !o.solid()));
|
||||||
|
if tile.diggable() && border && dx.abs() + dy.abs() <= 3 && mb.v.len() < 30000 {
|
||||||
|
block_shell(&mut mb, &g.map, x, y, n, fill, line, 1.0, 0.04);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(m) = mb.into_plain_mesh() {
|
||||||
|
draw_mesh(&m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Hover feedback: wall blocks get a faint version of the dig-mark box (in the tool colour),
|
// Hover feedback: wall blocks get a faint version of the dig-mark box (in the tool colour),
|
||||||
// floor tiles an outline. While dragging a dig rectangle, every block inside is tinted.
|
// floor tiles an outline. While dragging a dig rectangle, every block inside is tinted.
|
||||||
fn draw_overlay(map: &Map, ov: &Overlay, n: usize) {
|
fn draw_overlay(map: &Map, ov: &Overlay, n: usize) {
|
||||||
|
|||||||
+20
@@ -111,4 +111,24 @@ mod tests {
|
|||||||
let l = from_bytes(json.as_bytes()).expect("load");
|
let l = from_bytes(json.as_bytes()).expect("load");
|
||||||
assert_eq!(l.game.map.t.len(), 256 * 256);
|
assert_eq!(l.game.map.t.len(), 256 * 256);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// writes a savegame shortly before a wave (with planned entry points) when DC_SAVE_OUT is set
|
||||||
|
#[test]
|
||||||
|
fn dump_entry_warning_save() {
|
||||||
|
let Ok(path) = std::env::var("DC_SAVE_OUT") else { return };
|
||||||
|
let mut g = Game::new(11, 64, 64);
|
||||||
|
for _ in 0..(60 * 20) {
|
||||||
|
g.update(0.05);
|
||||||
|
}
|
||||||
|
g.wave_timer = 31.0;
|
||||||
|
for _ in 0..30 {
|
||||||
|
g.update(0.05); // the scouts warn 30 s before the wave
|
||||||
|
}
|
||||||
|
assert!(!g.planned_entries.is_empty());
|
||||||
|
let (ex, ey) = g.planned_entries[0];
|
||||||
|
let mut cam = Cam::new(ex as f32 + 0.5, ey as f32 + 0.5);
|
||||||
|
cam.zoom = 12.0;
|
||||||
|
std::fs::write(path, to_json(&g, &cam, &Settings { language: "en".into(), ..Settings::default() })).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user