Files

105 lines
3.9 KiB
Rust

// Creature equipment: when no trap or door is ordered, the forge makes armour and weapons in
// three tiers - iron, steel (once steel walls are known) and rune (once the magic door, the
// last discovery of the library, is known). Every finished piece goes to the strongest creature without anything that good yet:
// more health and harder blows. The tier shows as a little coloured mark at the health bar.
use crate::game::*;
// tier 1..3: forge work, gold, health and attack factor
pub const GEAR_WORK: [f32; 3] = [40.0, 70.0, 110.0];
pub const GEAR_GOLD: [f32; 3] = [60.0, 140.0, 280.0];
pub const GEAR_FACTOR: [f32; 4] = [1.0, 1.1, 1.22, 1.38];
pub fn gear_factor(gear: u8) -> f32 {
GEAR_FACTOR[(gear as usize).min(3)]
}
impl Game {
// the best tier the forge can make now (1..3)
pub fn gear_tier(&self) -> u8 {
if self.known(31) {
3
} else if self.known(19) {
2
} else {
1
}
}
// is a creature waiting for a piece of the best tier (and none in stock)?
pub fn gear_wanted(&self) -> bool {
let tier = self.gear_tier();
self.gear_stock.get(tier as usize - 1).copied().unwrap_or(0) == 0 && self.ents.iter().any(|e| e.alive && e.creature() && e.gear < tier)
}
// forge work without an order: the next piece of equipment
pub(crate) fn forge_gear(&mut self, work: f32) {
if !self.gear_wanted() {
return;
}
let tier = self.gear_tier();
let k = tier as usize - 1;
self.gear_work += work;
if self.gear_work >= GEAR_WORK[k] && self.gold >= GEAR_GOLD[k] {
self.gear_work -= GEAR_WORK[k];
self.gold -= GEAR_GOLD[k];
if self.gear_stock.len() < 3 {
self.gear_stock.resize(3, 0);
}
self.gear_stock[k] += 1;
}
self.equip_from_stock();
}
// finished pieces go to the strongest creatures that have nothing that good
pub(crate) fn equip_from_stock(&mut self) {
for k in (0..self.gear_stock.len().min(3)).rev() {
while self.gear_stock[k] > 0 {
let tier = k as u8 + 1;
let best = (0..self.ents.len())
.filter(|&j| {
let e = &self.ents[j];
e.alive && e.creature() && e.gear < tier
})
.max_by(|&a, &b| {
let (ea, eb) = (&self.ents[a], &self.ents[b]);
(ea.level, ea.max_hp as i32).cmp(&(eb.level, eb.max_hp as i32))
});
let Some(j) = best else { break };
self.gear_stock[k] -= 1;
let e = &mut self.ents[j];
let f = gear_factor(tier) / gear_factor(e.gear);
e.max_hp *= f;
e.hp *= f;
e.gear = tier;
let (x, y, kind) = (e.x, e.y, e.kind);
self.fx(7, x, y, 0.0, 0.0, 0.6, 0xff40c0ff);
self.msg("msg.gear_given", vec![format!("@gear.{}", tier), format!("@{}", st(kind).name)]);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_forge_equips_the_strongest_creature() {
let mut g = Game::new(4, 64, 64);
let (cx, cy) = g.map.core;
let weak = g.spawn(EK::Kobold, false, cx as f32 + 4.5, cy as f32 + 1.5, 1);
let strong = g.spawn(EK::Ogre, false, cx as f32 + 5.5, cy as f32 + 1.5, 5);
g.gold = 1000.0;
assert!(g.gear_wanted());
let hp0 = g.ents.iter().find(|e| e.id == strong).unwrap().max_hp;
g.forge_gear(GEAR_WORK[0] + 1.0);
let s = g.ents.iter().find(|e| e.id == strong).unwrap();
let w = g.ents.iter().find(|e| e.id == weak).unwrap();
assert_eq!(s.gear, 1, "the ogre got the first piece");
assert_eq!(w.gear, 0);
assert!(s.max_hp > hp0 && s.atk() > st(EK::Ogre).atk * (1.0 + 0.12 * 4.0));
assert!(g.gold < 1000.0);
}
}