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
+139
-3
@@ -6,7 +6,7 @@ use macroquad::prelude::*;
|
||||
|
||||
pub const CELL: f32 = 16.0;
|
||||
const ATLAS_COLS: u32 = 16;
|
||||
const ATLAS_ROWS: u32 = 9;
|
||||
pub const ATLAS_ROWS: u32 = 14;
|
||||
|
||||
// atlas indices (4 variants each)
|
||||
pub const T_ROCK: u32 = 0;
|
||||
@@ -70,6 +70,8 @@ pub const I_STEEL: u32 = 134;
|
||||
pub const T_RIVAL1: u32 = 135; // 4 variants: floor of the green master
|
||||
pub const T_RIVAL2: u32 = 139; // 4 variants: floor of the blue master
|
||||
pub const I_RUNE: u32 = 143; // rune forge tower
|
||||
pub const T_FORGE: u32 = 144; // 4 variants: sooty flagstones with glowing cracks
|
||||
pub const I_TRAPS: u32 = 148; // 10 icons in TRAP_KINDS order
|
||||
|
||||
pub struct Gfx {
|
||||
pub atlas: Texture2D,
|
||||
@@ -749,6 +751,118 @@ fn gen_atlas() -> Image {
|
||||
let h = hash(cu, cv, seed) % 3;
|
||||
Some(if e { lo } else if h == 0 || (u % 4 == 1 && v % 4 == 1) { hi } else if d > 0.65 { lo } else { mid })
|
||||
};
|
||||
// forge: sooty dark flagstones, iron filings and glowing cracks
|
||||
for v in 0..4u32 {
|
||||
cv.cell(T_FORGE + v, |x, y| {
|
||||
let base = stones(x, y, v + 300, (52, 46, 46), (22, 18, 18), 8);
|
||||
if (x * 7 + y * 3 + v as i32 * 11) % 23 == 0 || ((x + y * 2 + v as i32) % 19 == 0 && y % 8 != 0) {
|
||||
Some(c(255, 120, 40))
|
||||
} else if hash(x, y, v + 301) % 13 == 0 {
|
||||
Some(c(120, 120, 130))
|
||||
} else {
|
||||
Some(base)
|
||||
}
|
||||
});
|
||||
}
|
||||
// trap and door icons
|
||||
let icons: [fn(i32, i32) -> Option<Color>; 10] = [
|
||||
// spikes
|
||||
|x, y| {
|
||||
if y >= 12 {
|
||||
Some(c(90, 90, 100))
|
||||
} else if y >= 3 && (x % 4 - 2).abs() <= (y - 3) / 4 && (2..14).contains(&x) {
|
||||
Some(if x % 4 == 2 { c(230, 230, 240) } else { c(160, 160, 175) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
// poison cloud
|
||||
|x, y| {
|
||||
let d = |cx: i32, cy: i32, r: i32| (x - cx).pow(2) + (y - cy).pow(2) <= r * r;
|
||||
if d(5, 9, 4) || d(10, 8, 4) || d(8, 5, 3) {
|
||||
Some(if (x + y) % 5 == 0 { c(200, 255, 140) } else { c(110, 200, 70) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
// fire jet
|
||||
|x, y| {
|
||||
let w = (y - 1).max(0) / 3;
|
||||
if (x - 8).abs() <= w && y <= 14 && y >= 1 {
|
||||
Some(if (x - 8).abs() <= w / 2 && y > 6 { c(255, 230, 120) } else { c(255, 120, 30) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
// stone roller
|
||||
|x, y| {
|
||||
let d = (x - 8).pow(2) + (y - 8).pow(2);
|
||||
if d <= 36 {
|
||||
Some(if (x + y) % 6 == 0 || d > 28 { c(80, 76, 72) } else { c(140, 132, 124) })
|
||||
} else if y == 14 && x < 15 {
|
||||
Some(c(90, 70, 50))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
// alarm bell
|
||||
|x, y| {
|
||||
let w = 2 + y / 3;
|
||||
if (2..=11).contains(&y) && (x - 8).abs() <= w.min(6) {
|
||||
Some(if x < 8 { c(255, 220, 90) } else { c(200, 160, 50) })
|
||||
} else if (12..=13).contains(&y) && (x - 8).abs() <= 1 {
|
||||
Some(c(140, 100, 40))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
// rune mine
|
||||
|x, y| {
|
||||
let d = (((x - 8).pow(2) + (y - 8).pow(2)) as f32).sqrt();
|
||||
if (5.0..6.5).contains(&d) || ((x - 8).abs() <= 1 && (3..=12).contains(&y)) || (y == 8 && (5..=11).contains(&x)) {
|
||||
Some(c(90, 200, 255))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
// frost glow
|
||||
|x, y| {
|
||||
let (dx, dy) = (x - 8, y - 8);
|
||||
if (dx == 0 || dy == 0 || dx == dy || dx == -dy) && dx.abs() <= 6 && dy.abs() <= 6 {
|
||||
Some(if dx.abs() + dy.abs() <= 2 { c(255, 255, 255) } else { c(150, 220, 255) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
// wooden door
|
||||
|x, y| {
|
||||
if (3..=12).contains(&x) && y >= 2 {
|
||||
Some(if x % 3 == 0 { c(80, 50, 28) } else if y == 5 || y == 11 { c(70, 70, 76) } else { c(130, 86, 48) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
// iron door
|
||||
|x, y| {
|
||||
if (3..=12).contains(&x) && y >= 2 {
|
||||
Some(if (x == 4 || x == 11) && y % 3 == 0 { c(200, 200, 210) } else if y == 7 { c(60, 60, 66) } else { c(110, 112, 122) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
// magic door
|
||||
|x, y| {
|
||||
if (3..=12).contains(&x) && y >= 2 {
|
||||
let rune = (x == 8 && (5..=11).contains(&y)) || (y == 8 && (6..=10).contains(&x));
|
||||
Some(if rune { c(240, 160, 255) } else if x == 3 || x == 12 || y == 2 { c(70, 40, 100) } else { c(110, 60, 160) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
];
|
||||
for (k, f) in icons.iter().enumerate() {
|
||||
cv.cell(I_TRAPS + k as u32, |x, y| f(x, y));
|
||||
}
|
||||
// aerie: straw and twigs on stone, a few feathers
|
||||
for v in 0..4u32 {
|
||||
cv.cell(T_AERIE + v, |x, y| {
|
||||
@@ -1005,6 +1119,19 @@ fn sprite_rows(k: EK) -> [&'static str; 10] {
|
||||
".kubbbbuk.",
|
||||
"..ky..yk..",
|
||||
],
|
||||
// cogling: a sooty little tinkerer with brass goggles and a hammer
|
||||
EK::Cogling => [
|
||||
"........SS",
|
||||
"...kkkk.SS",
|
||||
"..kOOOOk.b",
|
||||
".kyekkeykb",
|
||||
"..kOooOk.b",
|
||||
"...kCCk..b",
|
||||
"..kOCCOkbb",
|
||||
"..kOCCOk..",
|
||||
"...kO.Ok..",
|
||||
"...kk.kk..",
|
||||
],
|
||||
EK::Wyrm => [
|
||||
"R.......kw",
|
||||
"RR....krrk",
|
||||
@@ -1074,7 +1201,7 @@ fn pal(ch: char) -> Option<Color> {
|
||||
})
|
||||
}
|
||||
|
||||
pub const SPRITE_KINDS: [EK; 17] = [
|
||||
pub const SPRITE_KINDS: [EK; 18] = [
|
||||
EK::Worker,
|
||||
EK::Kobold,
|
||||
EK::Spider,
|
||||
@@ -1092,9 +1219,10 @@ pub const SPRITE_KINDS: [EK; 17] = [
|
||||
EK::Gargoyle,
|
||||
EK::Owl,
|
||||
EK::Wyrm,
|
||||
EK::Cogling,
|
||||
];
|
||||
// width of the sprite texture in pixels
|
||||
pub const SPRITE_TEX_W: f32 = (17 * 12) as f32;
|
||||
pub const SPRITE_TEX_W: f32 = (SPRITE_KINDS.len() * 12) as f32;
|
||||
pub const SPRITE_TEX_H: f32 = (2 * VIEWS * GEAR_TIERS * SPR_CELL) as f32;
|
||||
|
||||
pub fn sprite_index(k: EK) -> u32 {
|
||||
@@ -1504,6 +1632,14 @@ impl Gfx {
|
||||
Kind::Steel => T_STEEL + v,
|
||||
Kind::ManaSpring => T_PORTALFLOOR + v,
|
||||
Kind::RuneChest => T_FLOOR + v,
|
||||
Kind::Forge => T_FORGE + v,
|
||||
Kind::Door => {
|
||||
if claimed {
|
||||
T_CLAIM + v
|
||||
} else {
|
||||
T_FLOOR + v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user