Steel walls: plate earth walls next to own ground with steel

- New tool Steel (key O, orders category; campaign from mission 11): 80 gold per earth wall,
  40 for a reinforced wall; riveted iron plate texture
- Heroes dig through steel 20 times slower than through earth and avoid it (path cost 300)
- Selling turns a steel wall back into a reinforced wall and refunds half the plating
- Texts EN/DE, test

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-03 13:10:04 +01:00
1 parent f298e13d6e
commit 8853d84564
10 files changed
+156 -16

No files matched your search

+10 -1
View File
@@ -145,7 +145,7 @@ help.k_slap = Shift+Links Hand: Rückhand für eigene, Faust für Helden au
help.k_pan = Rechts ziehen Karte verschieben (auch WASD/Pfeile, Bildrand) help.k_pan = Rechts ziehen Karte verschieben (auch WASD/Pfeile, Bildrand)
help.k_rot = Mitte ziehen Kamera drehen und neigen (auch Q/E, R/F) help.k_rot = Mitte ziehen Kamera drehen und neigen (auch Q/E, R/F)
help.k_zoom = Mausrad Zoomen help.k_zoom = Mausrad Zoomen
help.k_tools = 1-9,0,X,V,K,J,B,C,T,U,Y Werkzeug help.k_tools = 1-9,0,X,V,K,J,B,C,T,U,Y,O Werkzeug
help.k_misc = P / Leertaste Pause M Ton an/aus +/- Lautstärke help.k_misc = P / Leertaste Pause M Ton an/aus +/- Lautstärke
help.k_misc2 = G Kachel-Umrisse an/aus H Diese Hilfe help.k_misc2 = G Kachel-Umrisse an/aus H Diese Hilfe
help.s1 = 1. Grabe zum Portal und lass es von Grubenwichten erobern. help.s1 = 1. Grabe zum Portal und lass es von Grubenwichten erobern.
@@ -529,3 +529,12 @@ unit.wyrm = Glutwyrm
job.rest = Erholt sich im Horst job.rest = Erholt sich im Horst
job.torment = Bearbeitet einen Gefangenen job.torment = Bearbeitet einen Gefangenen
menu.license = DungeonCraft - MIT-Lizenz - (c) 2026 Richard Zink menu.license = DungeonCraft - MIT-Lizenz - (c) 2026 Richard Zink
# steel walls
tool.steel.label = Stahl
tool.steel.name = Stahlwände
tool.steel.desc = Beschlägt Erdwände an deinem Gebiet mit Stahl. Helden kommen kaum hindurch und nehmen lieber lange Umwege. Verkaufen macht wieder befestigte Wände daraus.
cost.steel = {0} Gold/Wand, {1} für befestigte Wände
hint.steel_where = Stahl lässt sich nur an Erdwände neben deinem Gebiet anbringen.
tile.steel = Stahlwand
tile.steel_info = Helden brauchen ewig, um hindurchzukommen.
+10 -1
View File
@@ -146,7 +146,7 @@ help.k_slap = Shift+Left Hand: backhand own units, punch heroes on your gro
help.k_pan = Right drag Move the map (also WASD/arrows, screen edge) help.k_pan = Right drag Move the map (also WASD/arrows, screen edge)
help.k_rot = Middle drag Rotate and tilt the camera (also Q/E, R/F) help.k_rot = Middle drag Rotate and tilt the camera (also Q/E, R/F)
help.k_zoom = Mouse wheel Zoom help.k_zoom = Mouse wheel Zoom
help.k_tools = 1-9,0,X,V,K,J,B,C,T,U,Y Select tool help.k_tools = 1-9,0,X,V,K,J,B,C,T,U,Y,O Select tool
help.k_misc = P / Space Pause M Sound on/off +/- Volume help.k_misc = P / Space Pause M Sound on/off +/- Volume
help.k_misc2 = G Tile outlines on/off H This help help.k_misc2 = G Tile outlines on/off H This help
help.s1 = 1. Dig to the portal and let your Pit Imps claim it. help.s1 = 1. Dig to the portal and let your Pit Imps claim it.
@@ -530,3 +530,12 @@ unit.wyrm = Ember Wyrm
job.rest = Recovering in the aerie job.rest = Recovering in the aerie
job.torment = Working on a prisoner job.torment = Working on a prisoner
menu.license = DungeonCraft - MIT License - (c) 2026 Richard Zink menu.license = DungeonCraft - MIT License - (c) 2026 Richard Zink
# steel walls
tool.steel.label = Steel
tool.steel.name = Steel Walls
tool.steel.desc = Plates earth walls next to your ground with steel. Heroes hardly get through and rather take long detours. Selling turns them back into reinforced walls.
cost.steel = {0} gold/wall, {1} for reinforced walls
hint.steel_where = Steel can only be put on earth walls next to your own ground.
tile.steel = Steel wall
tile.steel_info = Heroes need ages to get through.
+2 -2
View File
@@ -9,8 +9,8 @@ use serde::{Deserialize, Serialize};
// From which mission (0-based) on each tool is available (same order as ui::TOOLS): // From which mission (0-based) on each tool is available (same order as ui::TOOLS):
// dig, hand, treasury, lair, farm, training, library, sell, flag, lightning, heal, imp, // dig, hand, treasury, lair, farm, training, library, sell, flag, lightning, heal, imp,
// torture, temple, arrow tower, cannon tower, magic tower, bridge, aerie // torture, temple, arrow tower, cannon tower, magic tower, bridge, aerie, steel
pub const TOOL_UNLOCK: [usize; 19] = [0, 0, 0, 0, 0, 2, 4, 0, 0, 3, 4, 0, 6, 9, 3, 5, 9, 1, 6]; pub const TOOL_UNLOCK: [usize; 20] = [0, 0, 0, 0, 0, 2, 4, 0, 0, 3, 4, 0, 6, 9, 3, 5, 9, 1, 6, 10];
pub struct FortDef { pub struct FortDef {
pub at: (f32, f32), // centre as a fraction of the map size pub at: (f32, f32), // centre as a fraction of the map size
+81 -1
View File
@@ -418,6 +418,9 @@ pub const ROOM_NAMES: [&str; 8] = ["room.treasury", "room.lair", "room.farm", "r
// bridge cost per tile: over water, over lava // bridge cost per tile: over water, over lava
pub const BRIDGE_COST: [i32; 2] = [30, 75]; pub const BRIDGE_COST: [i32; 2] = [30, 75];
// steel wall cost per tile: from earth, from a reinforced wall
pub const STEEL_COST: [i32; 2] = [80, 40];
pub const STEEL_HP: f32 = 40.0;
pub fn room_index(k: Kind) -> Option<usize> { pub fn room_index(k: Kind) -> Option<usize> {
ROOM_KINDS.iter().position(|&r| r == k) ROOM_KINDS.iter().position(|&r| r == k)
@@ -1399,7 +1402,13 @@ impl Game {
EK::Dwarf => 3.0, EK::Dwarf => 3.0,
EK::Paladin => 2.0, EK::Paladin => 2.0,
_ => 1.0, _ => 1.0,
} * if tile.reinforced { 0.2 } else { 1.0 }; } * if tile.kind == Kind::Steel {
0.05
} else 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.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); self.sfx(Sfx::Dig, tx as f32 + 0.5, ty as f32 + 0.5);
let t = &mut self.map.t[next]; let t = &mut self.map.t[next];
@@ -1780,6 +1789,48 @@ impl Game {
// Bridges grow from own ground into the river: every pass adds the river tiles of the // Bridges grow from own ground into the river: every pass adds the river tiles of the
// rectangle that touch own walkable ground (including bridges built in the pass before) // rectangle that touch own walkable ground (including bridges built in the pass before)
// Earth walls next to own ground become steel walls
pub fn build_steel(&mut self, x0: i32, y0: i32, x1: i32, y1: i32) {
let (mut built, mut broke) = (0, false);
for y in y0.min(y1)..=y0.max(y1) {
for x in x0.min(x1)..=x0.max(x1) {
if !inb(x, y) {
continue;
}
let t = self.map.t[idx(x, y)];
if t.kind != Kind::Earth || t.owner == Owner::Hero {
continue;
}
let own = DIR4.iter().any(|&(dx, dy)| self.map.get(x + dx, y + dy).map_or(false, |n| n.owner == Owner::Player && n.walkable()));
if !own {
continue;
}
let cost = STEEL_COST[t.reinforced as usize] as f32;
if self.gold < cost {
broke = true;
continue;
}
self.gold -= cost;
let tl = &mut self.map.t[idx(x, y)];
tl.kind = Kind::Steel;
tl.reinforced = true;
tl.marked = false;
tl.hp = STEEL_HP;
built += 1;
self.fx(8, x as f32 + 0.5, y as f32 + 0.5, 0.0, 0.0, 0.5, 0xffd0d0d0);
if built == 1 {
self.sfx(Sfx::Reinforce, x as f32 + 0.5, y as f32 + 0.5);
}
}
}
if broke {
self.msg("msg.no_gold", vec![]);
self.sfx_ui(Sfx::Error);
} else if built == 0 {
self.hint(23, "hint.steel_where");
}
}
pub fn build_bridges(&mut self, x0: i32, y0: i32, x1: i32, y1: i32) { pub fn build_bridges(&mut self, x0: i32, y0: i32, x1: i32, y1: i32) {
let (mut built, mut broke, mut any_river) = (0, false, false); let (mut built, mut broke, mut any_river) = (0, false, false);
loop { loop {
@@ -3361,6 +3412,13 @@ impl Game {
continue; continue;
} }
let t = &mut self.map.t[i]; let t = &mut self.map.t[i];
if t.kind == Kind::Steel {
t.kind = Kind::Earth;
t.reinforced = true;
t.hp = 12.0;
refund += STEEL_COST[1] as f32 * 0.5;
continue;
}
if t.owner == Owner::Player && t.bridge() { if t.owner == Owner::Player && t.bridge() {
let lava = t.kind == Kind::LavaBridge; let lava = t.kind == Kind::LavaBridge;
t.kind = if lava { Kind::Lava } else { Kind::Water }; t.kind = if lava { Kind::Lava } else { Kind::Water };
@@ -4637,6 +4695,28 @@ mod tests {
assert!(seen.iter().all(|&k| flies(k)), "no lair: only flyers come ({:?})", seen); assert!(seen.iter().all(|&k| flies(k)), "no lair: only flyers come ({:?})", seen);
} }
#[test]
fn steel_walls_hold_heroes_back() {
let mut g = Game::new(3, 64, 64);
let (cx, cy) = g.map.core;
let (wx, wy) = (cx + 6, (cy - 3..=cy + 5).find(|&y| g.map.t[idx(cx + 6, y)].kind == Kind::Earth).unwrap());
g.gold = 1000.0;
g.build_steel(wx, wy, wx, wy);
assert_eq!(g.map.t[idx(wx, wy)].kind, Kind::Steel);
assert_eq!(g.gold, 1000.0 - STEEL_COST[0] as f32);
// far from own ground: nothing happens
g.build_steel(wx + 5, wy, wx + 5, wy);
assert_ne!(g.map.t[idx(wx + 5, wy)].kind, Kind::Steel);
// heroes avoid it and dig 20 times slower than through earth
assert_eq!(g.map.hero_cost()(idx(wx, wy)), Some(300));
// selling: a reinforced earth wall again, half of the plating back
let gold = g.gold;
g.sell_rect(wx, wy, wx, wy);
assert_eq!(g.map.t[idx(wx, wy)].kind, Kind::Earth);
assert!(g.map.t[idx(wx, wy)].reinforced);
assert!(g.gold > gold);
}
#[test] #[test]
fn imps_reinforce_walls() { fn imps_reinforce_walls() {
let mut g = Game::new(3, 64, 64); let mut g = Game::new(3, 64, 64);
+28
View File
@@ -65,6 +65,8 @@ pub const D_DIAMOND: u32 = 123;
pub const D_RUBBLE: u32 = 124; // floor decals: pebbles and fragments pub const D_RUBBLE: u32 = 124; // floor decals: pebbles and fragments
pub const D_CRACK: u32 = 125; // a long crack through several stones pub const D_CRACK: u32 = 125; // a long crack through several stones
pub const T_AERIE: u32 = 126; // 4 variants: straw, twigs and feathers pub const T_AERIE: u32 = 126; // 4 variants: straw, twigs and feathers
pub const T_STEEL: u32 = 130; // 4 variants: riveted iron plates
pub const I_STEEL: u32 = 134;
pub struct Gfx { pub struct Gfx {
pub atlas: Texture2D, pub atlas: Texture2D,
@@ -744,6 +746,31 @@ fn gen_atlas() -> Image {
} }
}); });
} }
// steel walls: riveted plates with a little rust
for v in 0..4u32 {
cv.cell(T_STEEL + v, |x, y| {
let seam = x % 8 == 0 || y % 8 == 0;
let rivet = (x % 8 == 2 || x % 8 == 6) && (y % 8 == 2 || y % 8 == 6);
let rust = rnd(x / 2, y / 2, v + 240) > 0.86;
if seam {
Some(c(44, 48, 58))
} else if rivet {
Some(c(170, 176, 190))
} else if rust {
Some(shade((120, 70, 40), (rnd(x, y, v + 241) * 16.0) as i32))
} else {
Some(shade((96, 102, 116), (rnd(x, y, v + 242) * 10.0) as i32 - 5 + if y % 8 == 1 { 10 } else { 0 }))
}
});
}
cv.cell(I_STEEL, |x, y| {
if (2..=13).contains(&x) && (3..=12).contains(&y) {
let rivet = (x == 4 || x == 11) && (y == 5 || y == 10);
Some(if rivet { c(220, 224, 235) } else if x == 2 || y == 3 || x == 13 || y == 12 { c(60, 64, 76) } else { c(130, 136, 150) })
} else {
None
}
});
// floor decals // floor decals
cv.cell(D_RUBBLE, |x, y| { cv.cell(D_RUBBLE, |x, y| {
for k in 0..9 { for k in 0..9 {
@@ -1229,6 +1256,7 @@ impl Gfx {
Kind::LavaBridge => T_STONEBRIDGE + (v & 1), Kind::LavaBridge => T_STONEBRIDGE + (v & 1),
Kind::Shard => T_HEROFLOOR + v, Kind::Shard => T_HEROFLOOR + v,
Kind::Aerie => T_AERIE + v, Kind::Aerie => T_AERIE + v,
Kind::Steel => T_STEEL + v,
} }
} }
+5 -3
View File
@@ -68,7 +68,7 @@ struct Input {
// Tile under the pointer for a tool: digging (and the hand) aim at walls too, // Tile under the pointer for a tool: digging (and the hand) aim at walls too,
// building and everything else only at the floor below the pointer // building and everything else only at the floor below the pointer
fn tool_tile(cam: &Cam, map: &map::Map, tool: Tool, mx: f32, my: f32) -> Option<(i32, i32)> { fn tool_tile(cam: &Cam, map: &map::Map, tool: Tool, mx: f32, my: f32) -> Option<(i32, i32)> {
if matches!(tool, Tool::Dig | Tool::Hand) { if matches!(tool, Tool::Dig | Tool::Hand | Tool::Steel) {
return cam.pick_tile(map, mx, my).map(|(x, z, _)| (x, z)); return cam.pick_tile(map, mx, my).map(|(x, z, _)| (x, z));
} }
let p = cam.ground_point(mx, my); let p = cam.ground_point(mx, my);
@@ -81,7 +81,7 @@ fn tool_tile(cam: &Cam, map: &map::Map, tool: Tool, mx: f32, my: f32) -> Option<
} }
fn area_tool(t: Tool) -> bool { fn area_tool(t: Tool) -> bool {
matches!(t, Tool::Dig | Tool::Room(_) | Tool::Sell | Tool::Bridge) matches!(t, Tool::Dig | Tool::Room(_) | Tool::Sell | Tool::Bridge | Tool::Steel)
} }
// Use the active tool on the world at (mx, my) (CSS pixels): a click, or a tap on touch screens // Use the active tool on the world at (mx, my) (CSS pixels): a click, or a tap on touch screens
@@ -94,7 +94,7 @@ fn world_action(app: &mut App, ui: &mut Ui, r3d: &R3d, inp: &mut Input, mx: f32,
let ground = app.cam.ground_point(mx, my); let ground = app.cam.ground_point(mx, my);
let (wx, wy) = (ground.x, ground.y); let (wx, wy) = (ground.x, ground.y);
match (ui.tool, tile) { match (ui.tool, tile) {
(Tool::Dig | Tool::Room(_) | Tool::Sell | Tool::Bridge, Some(t)) => inp.ldown = Some(t), (Tool::Dig | Tool::Room(_) | Tool::Sell | Tool::Bridge | Tool::Steel, Some(t)) => inp.ldown = Some(t),
(Tool::Hand, _) => { (Tool::Hand, _) => {
let j = r3d.pick_ent(&app.game, &app.cam, mx, my, false); let j = r3d.pick_ent(&app.game, &app.cam, mx, my, false);
if slap { if slap {
@@ -127,6 +127,7 @@ fn finish_rect(app: &mut App, tool: Tool, start: (i32, i32), mx: f32, my: f32) {
Tool::Room(r) => app.game.build_rect(r, sx, sy, ex, ey), Tool::Room(r) => app.game.build_rect(r, sx, sy, ex, ey),
Tool::Sell => app.game.sell_rect(sx, sy, ex, ey), Tool::Sell => app.game.sell_rect(sx, sy, ex, ey),
Tool::Bridge => app.game.build_bridges(sx, sy, ex, ey), Tool::Bridge => app.game.build_bridges(sx, sy, ex, ey),
Tool::Steel => app.game.build_steel(sx, sy, ex, ey),
_ => {} _ => {}
} }
} }
@@ -900,6 +901,7 @@ fn draw_frame(app: &mut App, gfx: &Gfx, r3d: &mut R3d, ui: &mut Ui, menu: &mut M
Tool::Heal => (Color::new(0.4, 1.0, 0.5, 1.0), Some((ground.x, ground.y, 2.55))), Tool::Heal => (Color::new(0.4, 1.0, 0.5, 1.0), Some((ground.x, ground.y, 2.55))),
Tool::Summon => (Color::new(0.8, 0.5, 1.0, 1.0), None), Tool::Summon => (Color::new(0.8, 0.5, 1.0, 1.0), None),
Tool::Bridge => (Color::new(0.9, 0.7, 0.4, 1.0), None), Tool::Bridge => (Color::new(0.9, 0.7, 0.4, 1.0), None),
Tool::Steel => (Color::new(0.75, 0.8, 0.9, 1.0), None),
Tool::Tower(_) => (Color::new(1.0, 0.6, 0.25, 1.0), None), Tool::Tower(_) => (Color::new(1.0, 0.6, 0.25, 1.0), None),
}; };
let ov = Overlay { let ov = Overlay {
+6 -3
View File
@@ -58,6 +58,7 @@ pub enum Kind {
Ruby, // ruby vein: rare, valuable Ruby, // ruby vein: rare, valuable
Diamond, // diamond vein: very rare, very valuable Diamond, // diamond vein: very rare, very valuable
Aerie, // room for flying creatures (their beds) Aerie, // room for flying creatures (their beds)
Steel, // steel wall: hardly anyone gets through
} }
// options for the map generator (campaign missions) // options for the map generator (campaign missions)
@@ -86,7 +87,7 @@ pub struct River {
} }
// order matters for the packed savegame codec: only append new kinds // order matters for the packed savegame codec: only append new kinds
const KINDS: [Kind; 24] = [ const KINDS: [Kind; 25] = [
Kind::Rock, Kind::Rock,
Kind::Earth, Kind::Earth,
Kind::Gold, Kind::Gold,
@@ -111,6 +112,7 @@ const KINDS: [Kind; 24] = [
Kind::Ruby, Kind::Ruby,
Kind::Diamond, Kind::Diamond,
Kind::Aerie, Kind::Aerie,
Kind::Steel,
]; ];
// treasures (veins, treasury content, imp loads): 0 gold, 1 silver, 2 ruby, 3 diamond // treasures (veins, treasury content, imp loads): 0 gold, 1 silver, 2 ruby, 3 diamond
@@ -159,10 +161,10 @@ impl Tile {
Tile { kind, owner: Owner::None, hp: 0.0, gold: 0, marked: false, reserved: 0, food: 0.0, bed: 0, var: 0, reinforced: false, res: 0 } Tile { kind, owner: Owner::None, hp: 0.0, gold: 0, marked: false, reserved: 0, food: 0.0, bed: 0, var: 0, reinforced: false, res: 0 }
} }
pub fn solid(&self) -> bool { pub fn solid(&self) -> bool {
matches!(self.kind, Kind::Rock | Kind::Earth | Kind::Gold | Kind::Silver | Kind::Ruby | Kind::Diamond) matches!(self.kind, Kind::Rock | Kind::Earth | Kind::Gold | Kind::Silver | Kind::Ruby | Kind::Diamond | Kind::Steel)
} }
pub fn diggable(&self) -> bool { pub fn diggable(&self) -> bool {
matches!(self.kind, Kind::Earth | Kind::Gold | Kind::Silver | Kind::Ruby | Kind::Diamond) matches!(self.kind, Kind::Earth | Kind::Gold | Kind::Silver | Kind::Ruby | Kind::Diamond | Kind::Steel)
} }
// the treasure of a vein (None for everything else) // the treasure of a vein (None for everything else)
pub fn vein(&self) -> Option<u8> { pub fn vein(&self) -> Option<u8> {
@@ -637,6 +639,7 @@ impl Map {
let tl = &self.t[i]; let tl = &self.t[i];
match tl.kind { match tl.kind {
Kind::Earth if tl.reinforced => Some(70), Kind::Earth if tl.reinforced => Some(70),
Kind::Steel => Some(300),
Kind::Earth => Some(7), Kind::Earth => Some(7),
Kind::Gold | Kind::Silver | Kind::Ruby | Kind::Diamond => Some(12), Kind::Gold | Kind::Silver | Kind::Ruby | Kind::Diamond => Some(12),
Kind::Rock | Kind::Core | Kind::Tower | Kind::Water | Kind::Lava => None, Kind::Rock | Kind::Core | Kind::Tower | Kind::Water | Kind::Lava => None,
+1
View File
@@ -1717,6 +1717,7 @@ pub fn minimap_color(tile: &Tile) -> [u8; 4] {
Kind::LavaBridge => [130, 120, 115, 255], Kind::LavaBridge => [130, 120, 115, 255],
Kind::Shard => [255, 60, 120, 255], Kind::Shard => [255, 60, 120, 255],
Kind::Aerie => [170, 140, 90, 255], Kind::Aerie => [170, 140, 90, 255],
Kind::Steel => [150, 160, 180, 255],
} }
} }
+3 -3
View File
@@ -7,7 +7,7 @@ use std::collections::BTreeMap;
// Rebindable keyboard actions. Esc (menu) and the arrow keys (camera) are fixed. // Rebindable keyboard actions. Esc (menu) and the arrow keys (camera) are fixed.
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Action { pub enum Action {
Tool(usize), // 0..19, same order as ui::TOOLS Tool(usize), // 0..20, same order as ui::TOOLS
CamForward, CamForward,
CamBack, CamBack,
CamLeft, CamLeft,
@@ -25,7 +25,7 @@ pub enum Action {
} }
pub fn all_actions() -> Vec<Action> { pub fn all_actions() -> Vec<Action> {
let mut v: Vec<Action> = (0..19).map(Action::Tool).collect(); let mut v: Vec<Action> = (0..20).map(Action::Tool).collect();
v.extend_from_slice(&[ v.extend_from_slice(&[
Action::CamForward, Action::CamForward,
Action::CamBack, Action::CamBack,
@@ -70,7 +70,7 @@ impl Action {
fn default_key(self) -> KeyCode { fn default_key(self) -> KeyCode {
use KeyCode::*; use KeyCode::*;
match self { match self {
Action::Tool(i) => [Key1, Key2, Key3, Key4, Key5, Key6, Key7, Key8, Key9, Key0, X, V, K, J, B, C, T, U, Y][i.min(18)], Action::Tool(i) => [Key1, Key2, Key3, Key4, Key5, Key6, Key7, Key8, Key9, Key0, X, V, K, J, B, C, T, U, Y, O][i.min(19)],
Action::CamForward => W, Action::CamForward => W,
Action::CamBack => S, Action::CamBack => S,
Action::CamLeft => A, Action::CamLeft => A,
+10 -2
View File
@@ -156,10 +156,11 @@ pub enum Tool {
Summon, Summon,
Tower(TowerKind), Tower(TowerKind),
Bridge, Bridge,
Steel,
} }
// New tools are appended so that existing key bindings ("tool<i>") keep their meaning // New tools are appended so that existing key bindings ("tool<i>") keep their meaning
pub const TOOLS: [Tool; 19] = [ pub const TOOLS: [Tool; 20] = [
Tool::Dig, Tool::Dig,
Tool::Hand, Tool::Hand,
Tool::Room(0), Tool::Room(0),
@@ -179,6 +180,7 @@ pub const TOOLS: [Tool; 19] = [
Tool::Tower(TowerKind::Magic), Tool::Tower(TowerKind::Magic),
Tool::Bridge, Tool::Bridge,
Tool::Room(7), Tool::Room(7),
Tool::Steel,
]; ];
@@ -210,6 +212,7 @@ pub fn tool_info(t: Tool) -> ToolInfo {
Tool::Heal => ("heal", I_HEAL, None), Tool::Heal => ("heal", I_HEAL, None),
Tool::Summon => ("summon", I_SUMMON, None), Tool::Summon => ("summon", I_SUMMON, None),
Tool::Bridge => ("bridge", I_BRIDGE, None), Tool::Bridge => ("bridge", I_BRIDGE, None),
Tool::Steel => ("steel", I_STEEL, None),
}; };
let name = match room { let name = match room {
Some(r) => tr(ROOM_NAMES[r]), Some(r) => tr(ROOM_NAMES[r]),
@@ -225,6 +228,7 @@ pub fn tool_cost(t: Tool, g: &Game) -> String {
Tool::Heal => trf("cost.mana", &["60".into()]), Tool::Heal => trf("cost.mana", &["60".into()]),
Tool::Summon => trf("cost.mana", &[(g.summon_cost() as i32).to_string()]), Tool::Summon => trf("cost.mana", &[(g.summon_cost() as i32).to_string()]),
Tool::Bridge => trf("cost.bridge", &[BRIDGE_COST[0].to_string(), BRIDGE_COST[1].to_string()]), Tool::Bridge => trf("cost.bridge", &[BRIDGE_COST[0].to_string(), BRIDGE_COST[1].to_string()]),
Tool::Steel => trf("cost.steel", &[STEEL_COST[0].to_string(), STEEL_COST[1].to_string()]),
Tool::Tower(k) => { Tool::Tower(k) => {
let s = tower_stats(k); let s = tower_stats(k);
let mut c = trf("cost.tower", &[s.cost[0].to_string(), s.cost[1].to_string(), s.cost[2].to_string()]); let mut c = trf("cost.tower", &[s.cost[0].to_string(), s.cost[1].to_string(), s.cost[2].to_string()]);
@@ -244,7 +248,7 @@ pub const CATS: [(&str, &[usize]); 6] = [
("cat.rooms", &[2, 3, 4, 5, 6, 12, 13, 18, 17]), ("cat.rooms", &[2, 3, 4, 5, 6, 12, 13, 18, 17]),
("cat.towers", &[14, 15, 16]), ("cat.towers", &[14, 15, 16]),
("cat.spells", &[9, 10, 11]), ("cat.spells", &[9, 10, 11]),
("cat.orders", &[8, 7]), ("cat.orders", &[8, 7, 19]),
]; ];
#[derive(Clone, Copy, PartialEq, Debug)] #[derive(Clone, Copy, PartialEq, Debug)]
@@ -1061,6 +1065,10 @@ pub fn hover_info(g: &Game, ent: Option<usize>, tile: Option<(i32, i32)>) -> Vec
}; };
match t.kind { match t.kind {
Kind::Rock => out.push((tr("tile.rock"), DIM)), Kind::Rock => out.push((tr("tile.rock"), DIM)),
Kind::Steel => {
out.push((tr("tile.steel"), FRAME_HI));
out.push((tr("tile.steel_info"), DIM));
}
Kind::Earth if t.reinforced => { Kind::Earth if t.reinforced => {
out.push((tr("tile.reinforced"), FRAME_HI)); out.push((tr("tile.reinforced"), FRAME_HI));
out.push((tr("tile.reinforced_info"), DIM)); out.push((tr("tile.reinforced_info"), DIM));