Traps and doors made in a new forge room, installed by imps; new creature: the cogling
- forge room: creatures work there (coglings fastest), the work goes into the oldest planned trap or door; finished pieces wait as crates, imps carry and install them - traps: spike pit, poison vent (cloud), fire jet, stone roller, alarm bell (calls creatures), rune mine (one big blast), frost glow (slows around it) - doors: wood, iron, magic (hurls attackers back); own creatures pass, enemies smash them on their way; clicking a door with a door tool locks it for everybody - new 'Traps' category in the toolbar, forge in the rooms; texts EN/DE, bestiary entries; atlas grown for new textures and icons - tests: forge to installed trap, spikes hurt, doors lock and get smashed Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1696297ac3
commit
4f20223c93
13 files changed
+1267
-24
No files matched your search
@@ -157,10 +157,11 @@ pub enum Tool {
|
||||
Tower(TowerKind),
|
||||
Bridge,
|
||||
Steel,
|
||||
Trap(crate::traps::TrapKind),
|
||||
}
|
||||
|
||||
// New tools are appended so that existing key bindings ("tool<i>") keep their meaning
|
||||
pub const TOOLS: [Tool; 21] = [
|
||||
pub const TOOLS: [Tool; 32] = [
|
||||
Tool::Dig,
|
||||
Tool::Hand,
|
||||
Tool::Room(0),
|
||||
@@ -182,6 +183,17 @@ pub const TOOLS: [Tool; 21] = [
|
||||
Tool::Room(7),
|
||||
Tool::Steel,
|
||||
Tool::Tower(TowerKind::Rune),
|
||||
Tool::Room(8),
|
||||
Tool::Trap(crate::traps::TrapKind::Spikes),
|
||||
Tool::Trap(crate::traps::TrapKind::Poison),
|
||||
Tool::Trap(crate::traps::TrapKind::Fire),
|
||||
Tool::Trap(crate::traps::TrapKind::Roller),
|
||||
Tool::Trap(crate::traps::TrapKind::Alarm),
|
||||
Tool::Trap(crate::traps::TrapKind::Mine),
|
||||
Tool::Trap(crate::traps::TrapKind::Frost),
|
||||
Tool::Trap(crate::traps::TrapKind::WoodDoor),
|
||||
Tool::Trap(crate::traps::TrapKind::IronDoor),
|
||||
Tool::Trap(crate::traps::TrapKind::MagicDoor),
|
||||
];
|
||||
|
||||
|
||||
@@ -203,7 +215,9 @@ pub fn tool_info(t: Tool) -> ToolInfo {
|
||||
Tool::Room(4) => ("library", T_LIBRARY, Some(4)),
|
||||
Tool::Room(5) => ("torture", T_TORTURE, Some(5)),
|
||||
Tool::Room(6) => ("temple", T_TEMPLE, Some(6)),
|
||||
Tool::Room(_) => ("aerie", T_AERIE, Some(7)),
|
||||
Tool::Room(7) => ("aerie", T_AERIE, Some(7)),
|
||||
Tool::Room(_) => ("forge", T_FORGE, Some(8)),
|
||||
Tool::Trap(k) => (k.id(), I_TRAPS + crate::traps::TRAP_KINDS.iter().position(|&t| t == k).unwrap_or(0) as u32, None),
|
||||
Tool::Tower(TowerKind::Arrow) => ("arrow", I_ARROW, None),
|
||||
Tool::Tower(TowerKind::Cannon) => ("cannon", I_CANNON, None),
|
||||
Tool::Tower(TowerKind::Magic) => ("magic", I_MAGIC, None),
|
||||
@@ -226,6 +240,7 @@ pub fn tool_info(t: Tool) -> ToolInfo {
|
||||
// costs that do not depend on the game (bestiary)
|
||||
pub fn tool_cost_static(t: Tool) -> String {
|
||||
match t {
|
||||
Tool::Trap(k) => trf("cost.work", &[(k.work() as i32).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(TowerKind::Rune) => {
|
||||
@@ -246,6 +261,7 @@ pub fn tool_cost_static(t: Tool) -> String {
|
||||
|
||||
pub fn tool_cost(t: Tool, g: &Game) -> String {
|
||||
match t {
|
||||
Tool::Trap(_) => tool_cost_static(t),
|
||||
Tool::Room(r) => trf("cost.gold_tile", &[ROOM_COST[r].to_string()]),
|
||||
Tool::Lightning => trf("cost.mana", &["50".into()]),
|
||||
Tool::Heal => trf("cost.mana", &["60".into()]),
|
||||
@@ -269,11 +285,12 @@ pub fn tool_cost(t: Tool, g: &Game) -> String {
|
||||
}
|
||||
|
||||
// Touch toolbar: tool categories (indices into TOOLS); categories with several tools open a row
|
||||
pub const CATS: [(&str, &[usize]); 6] = [
|
||||
pub const CATS: [(&str, &[usize]); 7] = [
|
||||
("cat.dig", &[0]),
|
||||
("cat.hand", &[1]),
|
||||
("cat.rooms", &[2, 3, 4, 5, 6, 12, 13, 18, 17]),
|
||||
("cat.rooms", &[2, 3, 4, 5, 6, 12, 13, 18, 21, 17]),
|
||||
("cat.towers", &[14, 15, 16, 20]),
|
||||
("cat.traps", &[22, 23, 24, 25, 26, 27, 28, 29, 30, 31]),
|
||||
("cat.spells", &[9, 10, 11]),
|
||||
("cat.orders", &[8, 7, 19]),
|
||||
];
|
||||
@@ -1107,6 +1124,22 @@ pub fn hover_info(g: &Game, ent: Option<usize>, tile: Option<(i32, i32)>) -> Vec
|
||||
return out;
|
||||
}
|
||||
let Some((x, y)) = tile else { return out };
|
||||
if let Some(tr) = g.trap_at(idx(x, y)) {
|
||||
use crate::traps::*;
|
||||
out.push((tr_name(tr.kind), FRAME_HI));
|
||||
let state = match tr.stage {
|
||||
ORDERED => trf("trap.ordered", &[((tr.progress / tr.kind.work() * 100.0) as i32).to_string()]),
|
||||
CRATED => tr_key("trap.crated"),
|
||||
CARRIED => tr_key("trap.carried"),
|
||||
_ if tr.kind.door() => trf("info.hp", &[(tr.hp.max(0.0) as i32).to_string(), (tr.kind.hp() as i32).to_string()]),
|
||||
_ => tr_key("trap.armed"),
|
||||
};
|
||||
out.push((state, if tr.stage == ARMED { GREEN } else { GOLD }));
|
||||
if tr.kind.door() && tr.stage == ARMED {
|
||||
out.push((tr_key(if tr.locked { "trap.locked" } else { "trap.unlocked" }), DIM));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
let Some(t) = g.map.get(x, y) else { return out };
|
||||
let owner = match t.owner {
|
||||
Owner::Player => "owner.player",
|
||||
@@ -1249,3 +1282,11 @@ mod clip_tests {
|
||||
assert!(clip_segment(vec2(-5.0, -1.0), vec2(-1.0, 20.0), 10.0, 10.0).is_none());
|
||||
}
|
||||
}
|
||||
|
||||
fn tr_name(k: crate::traps::TrapKind) -> String {
|
||||
tr(&format!("trap.{}", k.id()))
|
||||
}
|
||||
|
||||
fn tr_key(key: &str) -> String {
|
||||
tr(key)
|
||||
}
|
||||
Reference in new issue
Block a user