diff --git a/src/game.rs b/src/game.rs index 76f5f08..3894962 100644 --- a/src/game.rs +++ b/src/game.rs @@ -4886,7 +4886,12 @@ impl Game { TowerKind::Arrow => { // the arrow pierces up to two more heroes behind the target let dir = norm(ex - px, ey - py); - let (endx, endy, wall) = self.arrow_end(px, py, dir.0, dir.1, t.range()); + // what the eye sees: past the target the spent arrow comes down at a random + // distance (not all on a circle at the end of the range); the damage below + // still reaches along the whole range + let to_target = ((ex - px).powi(2) + (ey - py).powi(2)).sqrt(); + let reach = to_target + 0.8 + self.vrng.f() * (t.range() + 1.5 - to_target - 0.8).max(0.5); + let (endx, endy, wall) = self.arrow_end(px, py, dir.0, dir.1, reach); self.shot(mx, my, mh, endx, endy, 0.45, 0.3, 0xffd0e0f0); self.style_last_fx(if wall { crate::particles::ST_ARROW_WALL } else { crate::particles::ST_ARROW_FALL }); self.sfx(Sfx::Shoot, px, py); diff --git a/src/particles.rs b/src/particles.rs index fc522fa..b8fe47d 100644 --- a/src/particles.rs +++ b/src/particles.rs @@ -332,12 +332,16 @@ impl Game { let spot = if f.style == ST_ARROW_FALL { // spent at the end of its range: it sails on a little and comes down there // (a wall in the way stops it in front of the wall) - let reach = 0.35 + f.h2.max(0.0) * 1.5; - let (fx, fy) = (x + dx * reach, y + dy * reach); + // where exactly varies: a little further or shorter, and off to the side + let reach = 0.2 + f.h2.max(0.0) * 1.5 + self.vrng.f() * 1.4; + let side = (self.vrng.f() - 0.5) * 0.9; + let (fx, fy) = (x + dx * reach - dy * side, y + dy * reach + dx * side); if self.map.get(fx as i32, fy as i32).map_or(true, |t| t.solid()) { (x, y) } else { (fx, fy) } } else if self.vrng.f() < 0.35 { // a hit that glanced off: it comes down next to the target - (x + self.vrng.f() * 0.7 - 0.35, y + self.vrng.f() * 0.7 - 0.35) + // (mostly on, a bit past the target) + let on = 0.1 + self.vrng.f() * 0.8; + (x + dx * on + self.vrng.f() * 1.0 - 0.5, y + dy * on + self.vrng.f() * 1.0 - 0.5) } else { return; // a hit: the arrow stays in the target }; @@ -493,10 +497,13 @@ mod tests { // a little lava and water east of the core fn river_spot(g: &mut Game, kind: Kind) -> (f32, f32) { let (cx, cy) = g.map.core; - let (x, y) = (cx + 3, cy - 3); - let t = &mut g.map.t[idx(x, y)]; - t.kind = kind; - t.owner = Owner::None; + let (x, y) = (cx + 4, cy - 4); + // a 3x3 patch around (x, y) + for (dx, dy) in [(-1, -1), (0, -1), (1, -1), (-1, 0), (0, 0), (1, 0), (-1, 1), (0, 1), (1, 1)] { + let t = &mut g.map.t[idx(x + dx, y + dy)]; + t.kind = kind; + t.owner = Owner::None; + } (x as f32 + 0.5, y as f32 + 0.5) } @@ -505,7 +512,7 @@ mod tests { let mut g = Game::new(3, 64, 64); let (lx, ly) = river_spot(&mut g, Kind::Lava); // a spent tower arrow comes down in the lava: it drifts there, burning, then is gone - g.shot(lx - 2.0, ly, 0.5, lx - 0.4, ly, 0.0, 0.3, 0xffffffff); + g.shot(lx - 2.0, ly, 0.5, lx - 1.2, ly, 0.0, 0.3, 0xffffffff); g.style_last_fx(ST_ARROW_FALL); for _ in 0..8 { g.update(0.05);