Imps reinforce walls next to claimed ground (heroes avoid them, ~10x slower to break)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c508e232b0
commit
a1fe02ffa6
8 files changed
+197
-13
No files matched your search
+75
-2
@@ -42,13 +42,19 @@ pub enum Sfx {
|
||||
Defeat,
|
||||
Click,
|
||||
Error,
|
||||
Reinforce,
|
||||
Cannon,
|
||||
Magic,
|
||||
Capture,
|
||||
Convert,
|
||||
}
|
||||
|
||||
pub const SFX_ALL: [Sfx; 29] = [
|
||||
pub const SFX_ALL: [Sfx; 34] = [
|
||||
Sfx::Dig, Sfx::GoldDig, Sfx::DigDone, Sfx::Claim, Sfx::Deposit, Sfx::Build, Sfx::Sell, Sfx::MeleeHit,
|
||||
Sfx::Shoot, Sfx::Death, Sfx::HeroDeath, Sfx::Lightning, Sfx::Heal, Sfx::Summon, Sfx::PortalArrive,
|
||||
Sfx::WaveAlarm, Sfx::WaveStart, Sfx::CoreHit, Sfx::GateHit, Sfx::GateDefenders, Sfx::LevelUp,
|
||||
Sfx::Pickup, Sfx::Drop, Sfx::Payday, Sfx::FlagSet, Sfx::Victory, Sfx::Defeat, Sfx::Click, Sfx::Error,
|
||||
Sfx::Reinforce, Sfx::Cannon, Sfx::Magic, Sfx::Capture, Sfx::Convert,
|
||||
];
|
||||
|
||||
impl Sfx {
|
||||
@@ -128,6 +134,7 @@ pub enum Job {
|
||||
AttackCore,
|
||||
Leave,
|
||||
Rally,
|
||||
Reinforce(usize), // wall tile
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
@@ -840,7 +847,7 @@ impl Game {
|
||||
EK::Dwarf => 3.0,
|
||||
EK::Paladin => 2.0,
|
||||
_ => 1.0,
|
||||
};
|
||||
} * if tile.reinforced { 0.2 } else { 1.0 };
|
||||
self.fx(6, tx as f32 + 0.5, ty as f32 + 0.5, 0.0, 0.0, 0.4, 0xff3a5a7a);
|
||||
self.sfx(Sfx::Dig, tx as f32 + 0.5, ty as f32 + 0.5);
|
||||
let t = &mut self.map.t[next];
|
||||
@@ -884,6 +891,7 @@ impl Game {
|
||||
t.kind = Kind::Floor;
|
||||
t.owner = Owner::None;
|
||||
t.marked = false;
|
||||
t.reinforced = false;
|
||||
t.reserved = 0;
|
||||
t.hp = 0.0;
|
||||
t.gold = 0;
|
||||
@@ -1054,6 +1062,22 @@ impl Game {
|
||||
found
|
||||
}
|
||||
|
||||
// an earth wall next to own floor that can be reinforced from tile i
|
||||
fn reinforce_neighbor(&self, i: usize, me: u32) -> Option<usize> {
|
||||
if self.map.t[i].owner != Owner::Player {
|
||||
return None;
|
||||
}
|
||||
let (x, y) = xy(i);
|
||||
for &(dx, dy) in &DIR4 {
|
||||
if let Some(t) = self.map.get(x + dx, y + dy) {
|
||||
if t.kind == Kind::Earth && !t.reinforced && !t.marked && (t.reserved == 0 || t.reserved == me) {
|
||||
return Some(idx(x + dx, y + dy));
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn claimable(&self, i: usize, me: u32) -> bool {
|
||||
let t = &self.map.t[i];
|
||||
if t.owner != Owner::None || !matches!(t.kind, Kind::Floor | Kind::Portal) {
|
||||
@@ -1147,6 +1171,27 @@ impl Game {
|
||||
}
|
||||
}
|
||||
}
|
||||
Job::Reinforce(w) => {
|
||||
let t = self.map.t[w];
|
||||
if !adj4(cur, w) || t.kind != Kind::Earth || t.reinforced || t.marked {
|
||||
self.unreserve(me);
|
||||
e.job = Job::None;
|
||||
return;
|
||||
}
|
||||
let (wx, wy) = xy(w);
|
||||
e.face = sgn(wx as f32 + 0.5 - e.x);
|
||||
e.working = true;
|
||||
e.timer += dt;
|
||||
if e.timer >= 2.5 {
|
||||
self.unreserve(me);
|
||||
e.job = Job::None;
|
||||
let tl = &mut self.map.t[w];
|
||||
tl.reinforced = true;
|
||||
tl.hp = 12.0; // the player's imps need twice as long to dig it out again
|
||||
self.fx(8, wx as f32 + 0.5, wy as f32 + 0.5, 0.0, 0.0, 0.5, 0xff4040e0);
|
||||
self.sfx(Sfx::Reinforce, wx as f32 + 0.5, wy as f32 + 0.5);
|
||||
}
|
||||
}
|
||||
Job::Claim(t) => {
|
||||
if cur != t || !self.claimable(t, me) {
|
||||
self.unreserve(me);
|
||||
@@ -1229,6 +1274,16 @@ impl Game {
|
||||
e.job = Job::Claim(end);
|
||||
return;
|
||||
}
|
||||
if let Some(p) = self.map.search(cur, self.map.walk_cost(), |i| self.reinforce_neighbor(i, me).is_some(), true) {
|
||||
let end = p.last().copied().unwrap_or(cur);
|
||||
if let Some(w) = self.reinforce_neighbor(end, me) {
|
||||
self.map.t[w].reserved = me;
|
||||
e.path = p;
|
||||
e.job = Job::Reinforce(w);
|
||||
e.timer = 0.0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
e.think = 1.0;
|
||||
self.wander(e, 3);
|
||||
}
|
||||
@@ -1875,6 +1930,7 @@ pub fn job_name(e: &Ent) -> &'static str {
|
||||
}
|
||||
}
|
||||
Job::Leave => "job.leave",
|
||||
Job::Reinforce(_) => "job.reinforce",
|
||||
Job::Rally => {
|
||||
if e.working {
|
||||
"job.gate_attack"
|
||||
@@ -1962,4 +2018,21 @@ mod tests {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn imps_reinforce_walls() {
|
||||
let mut g = Game::new(3, 64, 64);
|
||||
for _ in 0..(120 * 20) {
|
||||
g.update(0.05);
|
||||
}
|
||||
let n = g.map.t.iter().filter(|t| t.reinforced).count();
|
||||
println!("reinforced walls after 2 minutes: {}", n);
|
||||
assert!(n >= 10);
|
||||
// heroes avoid them: the hero path cost through reinforced earth is 10x
|
||||
let (cx, cy) = g.map.core;
|
||||
let w = (cx - 4, cy);
|
||||
if g.map.t[idx(w.0, w.1)].reinforced {
|
||||
assert_eq!(g.map.hero_cost()(idx(w.0, w.1)), Some(70));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user