Badly hurt creatures may flee to their lair or the core and heal
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5701124c4f
commit
535800c7dc
1 file changed
+43
-13
+43
-13
@@ -3132,14 +3132,20 @@ impl Game {
|
||||
e.timer = 2.0 + self.rng.f() * 3.0;
|
||||
}
|
||||
|
||||
// badly hurt flyers flee to the aerie and rest until they are healed to 75%
|
||||
// badly hurt creatures flee to their bed (lair, flyers: aerie), or else next to the soul
|
||||
// core, and rest there until they are healed to 75%
|
||||
fn start_rest(&mut self, e: &mut Ent) -> bool {
|
||||
let cur = e.tile();
|
||||
let target = e.bed.filter(|&b| self.map.t[b].kind == Kind::Aerie).or_else(|| {
|
||||
self.map.search(cur, self.map.fly_cost(), |i| self.map.t[i].kind == Kind::Aerie, true).map(|p| p.last().copied().unwrap_or(cur))
|
||||
});
|
||||
let fly = flies(e.kind);
|
||||
let bed_kind = if fly { Kind::Aerie } else { Kind::Lair };
|
||||
let me = self.me;
|
||||
let target = e
|
||||
.bed
|
||||
.filter(|&b| self.map.t[b].kind == bed_kind)
|
||||
.or_else(|| self.map.search(cur, self.map.creature_cost(fly), |i| self.map.t[i].kind == bed_kind && self.map.t[i].owner == me, true).map(|p| p.last().copied().unwrap_or(cur)))
|
||||
.or_else(|| self.map.search(cur, self.map.creature_cost(fly), |i| self.map.adj_core_of(i, me), true).map(|p| p.last().copied().unwrap_or(cur)));
|
||||
let Some(b) = target else { return false };
|
||||
e.path = self.map.fly_path_to(cur, b).unwrap_or_default();
|
||||
e.path = self.map.creature_path(fly, cur, b).unwrap_or_default();
|
||||
e.job = Job::Rest(b);
|
||||
true
|
||||
}
|
||||
@@ -3511,8 +3517,9 @@ impl Game {
|
||||
self.fx(8, bx as f32 + 0.5, by as f32 + 0.5, 0.0, 0.0, 0.6, 0xff40d0ff);
|
||||
}
|
||||
}
|
||||
// flyers flee when badly hurt and come back at 75%
|
||||
if flies(e.kind) && e.hp < e.max_hp * 0.25 && !matches!(e.job, Job::Rest(_) | Job::Leave) {
|
||||
// badly hurt creatures may flee before they die (not all of them, and not at once)
|
||||
// and come back at 75%
|
||||
if e.hp < e.max_hp * 0.25 && !matches!(e.job, Job::Rest(_) | Job::Leave) && self.rng.f() < 0.3 {
|
||||
self.unreserve(me);
|
||||
if self.start_rest(e) {
|
||||
return;
|
||||
@@ -3570,17 +3577,18 @@ impl Game {
|
||||
return;
|
||||
}
|
||||
let (bx, by) = xy(b);
|
||||
let at_aerie = (e.x - bx as f32 - 0.5).abs() < 1.5 && (e.y - by as f32 - 0.5).abs() < 1.5;
|
||||
if !at_aerie {
|
||||
// pushed away on the way: fly on, or give up if there is no way
|
||||
match self.map.fly_path_to(e.tile(), b) {
|
||||
let there = (e.x - bx as f32 - 0.5).abs() < 1.5 && (e.y - by as f32 - 0.5).abs() < 1.5;
|
||||
if !there {
|
||||
// pushed away on the way: go on, or give up if there is no way
|
||||
match self.map.creature_path(flies(e.kind), e.tile(), b) {
|
||||
Some(p) if !p.is_empty() => e.path = p,
|
||||
_ => e.job = Job::None,
|
||||
}
|
||||
return;
|
||||
}
|
||||
// resting in the aerie heals quickly, back to work at 75%
|
||||
e.hp = (e.hp + e.max_hp * dt / 12.0).min(e.max_hp);
|
||||
// resting heals: quickly in a bed room, slower next to the core; back to work at 75%
|
||||
let bed_room = matches!(self.map.t[b].kind, Kind::Lair | Kind::Aerie);
|
||||
e.hp = (e.hp + e.max_hp * dt / if bed_room { 12.0 } else { 24.0 }).min(e.max_hp);
|
||||
e.energy = (e.energy + dt / 14.0).min(1.0);
|
||||
if e.hp >= e.max_hp * 0.75 {
|
||||
e.job = Job::None;
|
||||
@@ -6045,6 +6053,28 @@ mod tests {
|
||||
assert!(!g.torches.iter().any(|t| t.stand && t.wall == s0), "a stand on lost ground is removed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn badly_hurt_creatures_flee_to_the_lair_and_heal() {
|
||||
let mut g = Game::new(5, 64, 64);
|
||||
let (cx, cy) = g.map.core;
|
||||
g.gold = 5000.0;
|
||||
g.build_rect(1, cx - 3, cy - 3, cx - 2, cy + 2);
|
||||
assert!(g.counts[1] >= 8, "a lair");
|
||||
let id = g.spawn(EK::Kobold, false, cx as f32 + 5.5, cy as f32 + 0.5, 2);
|
||||
let j = g.ents.iter().position(|e| e.id == id).unwrap();
|
||||
g.ents[j].hp = g.ents[j].max_hp * 0.2;
|
||||
let mut fled = false;
|
||||
for _ in 0..(20 * 6) {
|
||||
g.update(0.05);
|
||||
fled |= matches!(g.ents[j].job, Job::Rest(_));
|
||||
}
|
||||
assert!(fled, "it fled to rest");
|
||||
for _ in 0..(20 * 20) {
|
||||
g.update(0.05);
|
||||
}
|
||||
assert!(g.ents[j].hp > g.ents[j].max_hp * 0.5, "and healed: {} of {}", g.ents[j].hp, g.ents[j].max_hp);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn flyers_take_every_way_across_rivers() {
|
||||
let (mut g, rx) = river_game(false);
|
||||
|
||||
Reference in new issue
Block a user