Eight new spells: seer's eye, cave-in, haste, stoneskin, gold rain, invisibility, plague, quake

- researched in the library (and unlocked in the campaign), in the spells menu with own icons and a radius under the pointer
- haste speeds up everything a creature does, stoneskin halves damage, invisible creatures are ignored by enemies and towers until they attack (drawn see-through), plague spreads among enemies, quake hurts and stuns enemies only, cave-in turns floor back into earth
- particles for every spell

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-04 07:07:52 +01:00
1 parent a54316c86e
commit 7f4d5ca7b4
11 files changed
+532 -12

No files matched your search

+30 -6
View File
@@ -234,6 +234,14 @@ pub struct Ent {
pub boost: f32, // seconds of "slapped" speed-up left
#[serde(default)]
pub stun: f32, // seconds of stun left (punched)
#[serde(default)]
pub haste: f32, // spell: seconds of haste left
#[serde(default)]
pub shield: f32, // spell: seconds of stoneskin left (half damage)
#[serde(default)]
pub invis: f32, // spell: seconds of invisibility left (until it attacks)
#[serde(default)]
pub plague: f32, // spell: seconds of plague left (poison that spreads)
pub guard: bool, // stays at its home (gate defenders, treasure guards)
#[serde(default)]
pub home: Option<(f32, f32)>, // guard post
@@ -299,6 +307,10 @@ impl Ent {
waypoint: None,
boost: 0.0,
stun: 0.0,
haste: 0.0,
shield: 0.0,
invis: 0.0,
plague: 0.0,
guard: false,
home: None,
patrol: Vec::new(),
@@ -468,6 +480,8 @@ pub struct Game {
pub researchable: Vec<bool>, // tools that can be researched in the library
#[serde(default)]
pub research: f32, // research points towards the current item
#[serde(default)]
pub reveals: Vec<(f32, f32, f32)>, // seer's eye: x, y, seconds left
#[serde(skip)]
pub forge_work: f32, // work done in the forge this frame
#[serde(skip)]
@@ -638,6 +652,7 @@ impl Game {
rollers: Vec::new(),
clouds: Vec::new(),
forge_work: 0.0,
reveals: Vec::new(),
known: Vec::new(),
researchable: Vec::new(),
research: 0.0,
@@ -1022,6 +1037,12 @@ impl Game {
self.turn(&mut e, x0, y0);
self.ents[i] = e;
}
// units that wasted away (plague)
for j in 0..self.ents.len() {
if self.ents[j].alive && !self.ents[j].held && self.ents[j].hp <= 0.0 {
self.kill(j);
}
}
self.ents.retain(|e| e.alive);
}
@@ -1083,6 +1104,7 @@ impl Game {
self.update_towers(dt);
self.update_forge(dt);
self.update_research();
self.update_reveals(dt);
if !self.rivals.is_empty() {
self.update_rivals(dt);
}
@@ -1633,8 +1655,9 @@ impl Game {
e.moving = false;
return;
}
// slapped units work and move faster
let dt = if e.boost > 0.0 { dt * 1.5 } else { dt };
self.tick_effects(e, dt);
// slapped units work and move faster, hasted ones even more
let dt = if e.boost > 0.0 { dt * 1.5 } else { dt } * if e.haste > 0.0 { 1.6 } else { 1.0 };
e.cd -= dt;
e.think -= dt;
e.repath -= dt;
@@ -1850,7 +1873,7 @@ impl Game {
let mut bd = radius * radius;
for o in &self.ents {
// every other side is an enemy
if !o.alive || o.held || o.side() == e.side() || o.captive != 0 || o.chained {
if !o.alive || o.held || o.side() == e.side() || o.captive != 0 || o.chained || o.invis > 0.0 {
continue;
}
let d = (o.x - e.x).powi(2) + (o.y - e.y).powi(2);
@@ -1996,8 +2019,9 @@ impl Game {
}
}
let my_id = e.id;
e.invis = 0.0; // attacking breaks invisibility
let t = &mut self.ents[j];
t.hp -= dmg;
t.hp -= if t.shield > 0.0 { dmg * 0.5 } else { dmg };
t.flash = 0.15;
if t.creature() && !matches!(t.job, Job::Attack(_)) {
t.job = Job::Attack(my_id);
@@ -4063,7 +4087,7 @@ impl Game {
// damage dealt to a unit by a tower (no attacker unit involved)
fn tower_damage(&mut self, j: usize, dmg: f32) {
let e = &mut self.ents[j];
e.hp -= dmg;
e.hp -= if e.shield > 0.0 { dmg * 0.5 } else { dmg };
e.flash = 0.15;
if e.hp <= 0.0 && e.alive {
self.kill(j);
@@ -4079,7 +4103,7 @@ impl Game {
for (j, e) in self.ents.iter().enumerate() {
// knight towers shoot the player's units, the player's towers shoot heroes
// knight towers shoot everybody but the humans, the player's towers everybody else
if !e.alive || e.held || !self.tower_enemy(t, e) {
if !e.alive || e.held || !self.tower_enemy(t, e) || e.invis > 0.0 {
continue;
}
let d = (e.x - px).powi(2) + (e.y - py).powi(2);