Let flyers path over water and lava everywhere

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-05 14:46:16 +01:00
1 parent 574660e173
commit 1ef2239fbf
7 files changed
+85 -23

No files matched your search

+47 -10
View File
@@ -1692,7 +1692,7 @@ impl Game {
}
let cur = e.tile();
let near = |i: usize| tasks.iter().copied().find(|&t| i != t && adj4(i, t) || (i == t && self.map.t[t].walkable()));
let Some(p) = self.map.search(cur, self.map.walk_cost(), |i| near(i).is_some(), true) else { return false };
let Some(p) = self.map.search(cur, self.map.creature_cost(flies(e.kind)), |i| near(i).is_some(), true) else { return false };
let end = p.last().copied().unwrap_or(cur);
let Some(t) = near(end) else { return false };
e.path = p;
@@ -3387,10 +3387,10 @@ impl Game {
// ---------------------------------------------------------------- creatures
fn find_room_tile(&self, cur: usize, kind: Kind, me: u32, need_food: bool) -> Option<Vec<usize>> {
fn find_room_tile(&self, e: &Ent, kind: Kind, me: u32, need_food: bool) -> Option<Vec<usize>> {
self.map.search(
cur,
self.map.walk_cost(),
e.tile(),
self.map.creature_cost(flies(e.kind)),
|i| {
let t = &self.map.t[i];
t.kind == kind && t.owner == self.me && (t.reserved == 0 || t.reserved == me) && (!need_food || t.food >= 1.0)
@@ -3905,7 +3905,7 @@ impl Game {
return;
}
if e.hunger > 1.0 && !(self.flag.is_some() && e.hunger < 1.5) {
if let Some(p) = self.find_room_tile(cur, Kind::Farm, me, true) {
if let Some(p) = self.find_room_tile(e, Kind::Farm, me, true) {
let t = p.last().copied().unwrap_or(cur);
self.map.t[t].reserved = me;
e.path = p;
@@ -3939,7 +3939,7 @@ impl Game {
if self.counts[6] > 0 {
let r2 = self.rng.f();
if r2 < 0.3 || (e.kind == EK::Priestess && r2 < 0.7) {
if let Some(p) = self.find_room_tile(cur, Kind::Temple, me, false) {
if let Some(p) = self.find_room_tile(e, Kind::Temple, me, false) {
let t = p.last().copied().unwrap_or(cur);
self.map.t[t].reserved = me;
e.path = p;
@@ -3974,7 +3974,7 @@ impl Game {
}
}
if self.counts[crate::rooms::ROOM_ARENA] > 0 && e.hp > e.max_hp * 0.8 && self.rng.f() < 0.25 {
if let Some(p) = self.find_room_tile(cur, Kind::Arena, me, false) {
if let Some(p) = self.find_room_tile(e, Kind::Arena, me, false) {
let t = p.last().copied().unwrap_or(cur);
self.map.t[t].reserved = me;
e.path = p;
@@ -3987,7 +3987,7 @@ impl Game {
if self.forge_orders() && self.counts[ROOM_FORGE] > 0 {
let r = self.rng.f();
if (e.kind == EK::Cogling && r < 0.9) || r < 0.25 {
if let Some(p) = self.find_room_tile(cur, Kind::Forge, me, false) {
if let Some(p) = self.find_room_tile(e, Kind::Forge, me, false) {
let t = p.last().copied().unwrap_or(cur);
self.map.t[t].reserved = me;
e.path = p;
@@ -3999,7 +3999,7 @@ impl Game {
}
let r = self.rng.f();
if (e.kind == EK::Mage && r < 0.8) || r < 0.2 {
if let Some(p) = self.find_room_tile(cur, Kind::Library, me, false) {
if let Some(p) = self.find_room_tile(e, Kind::Library, me, false) {
let t = p.last().copied().unwrap_or(cur);
self.map.t[t].reserved = me;
e.path = p;
@@ -4009,7 +4009,7 @@ impl Game {
}
}
if r < 0.8 && self.gold >= 5.0 {
if let Some(p) = self.find_room_tile(cur, Kind::Training, me, false) {
if let Some(p) = self.find_room_tile(e, Kind::Training, me, false) {
let t = p.last().copied().unwrap_or(cur);
self.map.t[t].reserved = me;
e.path = p;
@@ -5935,6 +5935,43 @@ mod tests {
assert!(best <= 2.0);
}
#[test]
fn flyers_take_every_way_across_rivers() {
let (mut g, rx) = river_game(false);
let (cx, cy) = g.map.core;
// open floor on the far bank with one training tile of the player
for y in cy - 2..=cy + 2 {
for x in rx + 3..rx + 7 {
let t = &mut g.map.t[idx(x, y)];
t.kind = Kind::Floor;
t.owner = Owner::None;
}
}
let room = idx(rx + 4, cy);
g.map.t[room].kind = Kind::Training;
g.map.t[room].owner = g.me;
let owl = g.spawn(EK::Owl, false, (cx + 4) as f32 + 0.5, cy as f32 + 0.5, 1);
let kobold = g.spawn(EK::Kobold, false, (cx + 4) as f32 + 0.5, cy as f32 + 0.5, 1);
let owl = g.ents.iter().find(|e| e.id == owl).unwrap().clone();
let kobold = g.ents.iter().find(|e| e.id == kobold).unwrap().clone();
// room searches: the owl flies over the river to the training room, the kobold cannot get there
let p = g.find_room_tile(&owl, Kind::Training, owl.id + 1, false).expect("the owl finds the room across the river");
assert_eq!(p.last().copied(), Some(room));
assert!(g.find_room_tile(&kobold, Kind::Training, kobold.id + 1, false).map_or(true, |p| p.last() != Some(&room)));
// flyers cut corners over water: a diagonal crossing is as short as on open ground
let (a, b) = (idx(rx - 1, cy - 1), idx(rx + 3, cy + 1));
let p = g.map.creature_path(true, a, b).expect("flight path");
assert!(p.len() <= 5, "diagonal flight over the river: {} steps", p.len());
assert!(p.iter().any(|&i| g.map.t[i].liquid()));
// attacking flyers (the fairy spy) also fly over rivers instead of searching for a bridge
assert!(g.map.hero_cost_as(true)(idx(rx + 1, cy)).is_some());
assert_eq!(g.map.hero_cost()(idx(rx + 1, cy)), None);
// a locked door stops flyers too
g.map.t[idx(rx + 5, cy)].kind = Kind::Door;
g.map.t[idx(rx + 5, cy)].res = 1;
assert_eq!(g.map.fly_cost()(idx(rx + 5, cy)), None);
}
#[test]
fn flyers_cross_rivers_flee_and_heal() {
let (mut g, rx) = river_game(true);