Imps reinforce walls next to claimed ground (heroes avoid them, ~10x slower to break)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-03 07:39:39 +01:00
1 parent c508e232b0
commit a1fe02ffa6
8 files changed
+197 -13

No files matched your search

+5
View File
@@ -272,3 +272,8 @@ newgame.width = Kartenbreite
newgame.height = Kartenhöhe newgame.height = Kartenhöhe
newgame.start = Starten newgame.start = Starten
newgame.info = {0} Portal(e), {1} bewachte Schatzhöhle(n) newgame.info = {0} Portal(e), {1} bewachte Schatzhöhle(n)
# ---- Wände, Türme, Folter
job.reinforce = Verstärkt eine Wand
tile.reinforced = Verstärkte Wand
tile.reinforced_info = Helden kommen kaum durch
+5
View File
@@ -273,3 +273,8 @@ newgame.width = Map width
newgame.height = Map height newgame.height = Map height
newgame.start = Start newgame.start = Start
newgame.info = {0} portal(s), {1} guarded treasure cave(s) newgame.info = {0} portal(s), {1} guarded treasure cave(s)
# ---- walls, towers, torture
job.reinforce = Reinforcing a wall
tile.reinforced = Reinforced wall
tile.reinforced_info = heroes can hardly break through
+75 -2
View File
@@ -42,13 +42,19 @@ pub enum Sfx {
Defeat, Defeat,
Click, Click,
Error, Error,
Reinforce,
Cannon,
Magic,
Capture,
Convert,
} }
pub const SFX_ALL: [Sfx; 29] = [ pub const SFX_ALL: [Sfx; 34] = [
Sfx::Dig, Sfx::GoldDig, Sfx::DigDone, Sfx::Claim, Sfx::Deposit, Sfx::Build, Sfx::Sell, Sfx::MeleeHit, Sfx::Dig, Sfx::GoldDig, Sfx::DigDone, Sfx::Claim, Sfx::Deposit, Sfx::Build, Sfx::Sell, Sfx::MeleeHit,
Sfx::Shoot, Sfx::Death, Sfx::HeroDeath, Sfx::Lightning, Sfx::Heal, Sfx::Summon, Sfx::PortalArrive, Sfx::Shoot, Sfx::Death, Sfx::HeroDeath, Sfx::Lightning, Sfx::Heal, Sfx::Summon, Sfx::PortalArrive,
Sfx::WaveAlarm, Sfx::WaveStart, Sfx::CoreHit, Sfx::GateHit, Sfx::GateDefenders, Sfx::LevelUp, Sfx::WaveAlarm, Sfx::WaveStart, Sfx::CoreHit, Sfx::GateHit, Sfx::GateDefenders, Sfx::LevelUp,
Sfx::Pickup, Sfx::Drop, Sfx::Payday, Sfx::FlagSet, Sfx::Victory, Sfx::Defeat, Sfx::Click, Sfx::Error, Sfx::Pickup, Sfx::Drop, Sfx::Payday, Sfx::FlagSet, Sfx::Victory, Sfx::Defeat, Sfx::Click, Sfx::Error,
Sfx::Reinforce, Sfx::Cannon, Sfx::Magic, Sfx::Capture, Sfx::Convert,
]; ];
impl Sfx { impl Sfx {
@@ -128,6 +134,7 @@ pub enum Job {
AttackCore, AttackCore,
Leave, Leave,
Rally, Rally,
Reinforce(usize), // wall tile
} }
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
@@ -840,7 +847,7 @@ 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 };
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];
@@ -884,6 +891,7 @@ impl Game {
t.kind = Kind::Floor; t.kind = Kind::Floor;
t.owner = Owner::None; t.owner = Owner::None;
t.marked = false; t.marked = false;
t.reinforced = false;
t.reserved = 0; t.reserved = 0;
t.hp = 0.0; t.hp = 0.0;
t.gold = 0; t.gold = 0;
@@ -1054,6 +1062,22 @@ impl Game {
found found
} }
// an earth wall next to own floor that can be reinforced from tile i
fn reinforce_neighbor(&self, i: usize, me: u32) -> Option<usize> {
if self.map.t[i].owner != Owner::Player {
return None;
}
let (x, y) = xy(i);
for &(dx, dy) in &DIR4 {
if let Some(t) = self.map.get(x + dx, y + dy) {
if t.kind == Kind::Earth && !t.reinforced && !t.marked && (t.reserved == 0 || t.reserved == me) {
return Some(idx(x + dx, y + dy));
}
}
}
None
}
fn claimable(&self, i: usize, me: u32) -> bool { fn claimable(&self, i: usize, me: u32) -> bool {
let t = &self.map.t[i]; let t = &self.map.t[i];
if t.owner != Owner::None || !matches!(t.kind, Kind::Floor | Kind::Portal) { if t.owner != Owner::None || !matches!(t.kind, Kind::Floor | Kind::Portal) {
@@ -1147,6 +1171,27 @@ impl Game {
} }
} }
} }
Job::Reinforce(w) => {
let t = self.map.t[w];
if !adj4(cur, w) || t.kind != Kind::Earth || t.reinforced || t.marked {
self.unreserve(me);
e.job = Job::None;
return;
}
let (wx, wy) = xy(w);
e.face = sgn(wx as f32 + 0.5 - e.x);
e.working = true;
e.timer += dt;
if e.timer >= 2.5 {
self.unreserve(me);
e.job = Job::None;
let tl = &mut self.map.t[w];
tl.reinforced = true;
tl.hp = 12.0; // the player's imps need twice as long to dig it out again
self.fx(8, wx as f32 + 0.5, wy as f32 + 0.5, 0.0, 0.0, 0.5, 0xff4040e0);
self.sfx(Sfx::Reinforce, wx as f32 + 0.5, wy as f32 + 0.5);
}
}
Job::Claim(t) => { Job::Claim(t) => {
if cur != t || !self.claimable(t, me) { if cur != t || !self.claimable(t, me) {
self.unreserve(me); self.unreserve(me);
@@ -1229,6 +1274,16 @@ impl Game {
e.job = Job::Claim(end); e.job = Job::Claim(end);
return; return;
} }
if let Some(p) = self.map.search(cur, self.map.walk_cost(), |i| self.reinforce_neighbor(i, me).is_some(), true) {
let end = p.last().copied().unwrap_or(cur);
if let Some(w) = self.reinforce_neighbor(end, me) {
self.map.t[w].reserved = me;
e.path = p;
e.job = Job::Reinforce(w);
e.timer = 0.0;
return;
}
}
e.think = 1.0; e.think = 1.0;
self.wander(e, 3); self.wander(e, 3);
} }
@@ -1875,6 +1930,7 @@ pub fn job_name(e: &Ent) -> &'static str {
} }
} }
Job::Leave => "job.leave", Job::Leave => "job.leave",
Job::Reinforce(_) => "job.reinforce",
Job::Rally => { Job::Rally => {
if e.working { if e.working {
"job.gate_attack" "job.gate_attack"
@@ -1962,4 +2018,21 @@ mod tests {
} }
} }
} }
#[test]
fn imps_reinforce_walls() {
let mut g = Game::new(3, 64, 64);
for _ in 0..(120 * 20) {
g.update(0.05);
}
let n = g.map.t.iter().filter(|t| t.reinforced).count();
println!("reinforced walls after 2 minutes: {}", n);
assert!(n >= 10);
// heroes avoid them: the hero path cost through reinforced earth is 10x
let (cx, cy) = g.map.core;
let w = (cx - 4, cy);
if g.map.t[idx(w.0, w.1)].reinforced {
assert_eq!(g.map.hero_cost()(idx(w.0, w.1)), Some(70));
}
}
} }
+78 -2
View File
@@ -6,7 +6,7 @@ use macroquad::prelude::*;
pub const CELL: f32 = 16.0; pub const CELL: f32 = 16.0;
const ATLAS_COLS: u32 = 16; const ATLAS_COLS: u32 = 16;
const ATLAS_ROWS: u32 = 5; const ATLAS_ROWS: u32 = 6;
// atlas indices (4 variants each) // atlas indices (4 variants each)
pub const T_ROCK: u32 = 0; pub const T_ROCK: u32 = 0;
@@ -40,6 +40,12 @@ pub const I_FLAG: u32 = 68;
pub const I_BOLT: u32 = 69; pub const I_BOLT: u32 = 69;
pub const I_HEAL: u32 = 70; pub const I_HEAL: u32 = 70;
pub const I_SUMMON: u32 = 71; pub const I_SUMMON: u32 = 71;
pub const T_REINF: u32 = 72; // 4 variants: reinforced wall masonry
pub const T_TORTURE: u32 = 76; // 4 variants: torture chamber floor
pub const D_RACK: u32 = 80;
pub const I_ARROW: u32 = 81;
pub const I_CANNON: u32 = 82;
pub const I_MAGIC: u32 = 83;
pub struct Gfx { pub struct Gfx {
pub atlas: Texture2D, pub atlas: Texture2D,
@@ -365,6 +371,40 @@ fn gen_atlas() -> Image {
_ => c(100, 60, 120), _ => c(100, 60, 120),
}) })
}); });
// reinforced walls: masonry in dark stone with the player's red mortar
for v in 0..4u32 {
cv.cell(T_REINF + v, |x, y| {
let row = y / 4;
let off = if row % 2 == 1 { 4 } else { 0 };
if y % 4 == 3 || (x + off) % 8 == 7 {
return Some(shade((70, 26, 30), (rnd(x, y, v + 90) * 8.0) as i32));
}
let brick = hash((x + off) / 8, row, v + 91) % 4;
Some(shade((84, 76, 74), (rnd(x, y, v + 92) * 14.0) as i32 - 7 + brick as i32 * 5 - 6 + if y % 4 == 0 { 10 } else { 0 }))
});
// torture chamber: dark stones with rusty iron grates
cv.cell(T_TORTURE + v, |x, y| {
let grate = (4..=11).contains(&x) && (4..=11).contains(&y) && (x % 3 == 1 || y % 3 == 1);
if grate {
return Some(shade((96, 44, 30), (rnd(x, y, v + 93) * 12.0) as i32));
}
Some(stones(x, y, v + 94, (52, 40, 44), (26, 16, 18), 10))
});
}
// torture wheel
cv.cell(D_RACK, |x, y| {
let (dx, dy) = (x as f32 - 7.5, y as f32 - 7.0);
let d = (dx * dx + dy * dy).sqrt();
let a = dy.atan2(dx);
if (5.5..7.0).contains(&d) || (d < 6.0 && (a * 4.0 / std::f32::consts::PI).fract().abs() < 0.12) {
Some(c(110, 76, 44))
} else if y >= 13 && (x == 7 || x == 8 || (4..=11).contains(&x) && y == 15) {
Some(c(70, 48, 30))
} else {
None
}
});
// tool icons // tool icons
cv.cell(I_PICK, |x, y| { cv.cell(I_PICK, |x, y| {
let handle = (x + y == 16 || x + y == 17) && x >= 3; let handle = (x + y == 16 || x + y == 17) && x >= 3;
@@ -423,6 +463,39 @@ fn gen_atlas() -> Image {
None None
} }
}); });
cv.cell(I_ARROW, |x, y| {
// a small wooden tower with an arrow
if (4..=11).contains(&x) && y >= 7 {
Some(if (x + y) % 4 == 0 { c(90, 60, 34) } else { c(130, 88, 50) })
} else if y == 6 && x % 2 == 0 && (4..=11).contains(&x) {
Some(c(130, 88, 50))
} else if y == 3 && (2..=13).contains(&x) || (x == 12 && (y == 2 || y == 4)) {
Some(c(220, 220, 220))
} else {
None
}
});
cv.cell(I_CANNON, |x, y| {
let barrel = y >= 4 && y <= 7 && x >= 5 && x <= 14 && (y - 4) as i32 <= 3;
let wheel = (x - 6) * (x - 6) + (y - 10) * (y - 10) <= 9;
if barrel {
Some(c(50, 50, 56))
} else if wheel {
Some(c(120, 80, 40))
} else {
None
}
});
cv.cell(I_MAGIC, |x, y| {
let crystal = (x - 8).abs() + (y - 5).abs() <= 3;
if crystal {
Some(c(190, 110, 255))
} else if (6..=9).contains(&x) && y >= 9 {
Some(c(110, 110, 124))
} else {
None
}
});
cv.cell(I_SUMMON, |x, y| { cv.cell(I_SUMMON, |x, y| {
let d = (((x - 8) * (x - 8) + (y - 8) * (y - 8)) as f32).sqrt(); let d = (((x - 8) * (x - 8) + (y - 8) * (y - 8)) as f32).sqrt();
let a = ((y - 8) as f32).atan2((x - 8) as f32); let a = ((y - 8) as f32).atan2((x - 8) as f32);
@@ -645,10 +718,11 @@ impl Gfx {
Rect::new((i * SPR_CELL + 1) as f32, (1 + if white { SPR_CELL } else { 0 }) as f32, SPR as f32, SPR as f32) Rect::new((i * SPR_CELL + 1) as f32, (1 + if white { SPR_CELL } else { 0 }) as f32, SPR as f32, SPR as f32)
} }
pub fn tile_tex(kind: Kind, claimed: bool, hero: bool, var: u8) -> u32 { pub fn tile_tex(kind: Kind, claimed: bool, hero: bool, var: u8, reinforced: bool) -> u32 {
let v = var as u32 & 3; let v = var as u32 & 3;
match kind { match kind {
Kind::Rock => T_ROCK + v, Kind::Rock => T_ROCK + v,
Kind::Earth if reinforced => T_REINF + v,
Kind::Earth => T_EARTH + v, Kind::Earth => T_EARTH + v,
Kind::Gold => T_GOLD + v, Kind::Gold => T_GOLD + v,
Kind::Floor => { Kind::Floor => {
@@ -668,6 +742,8 @@ impl Gfx {
Kind::Core => T_COREFLOOR + v, Kind::Core => T_COREFLOOR + v,
Kind::Portal => T_PORTALFLOOR + v, Kind::Portal => T_PORTALFLOOR + v,
Kind::Gate => T_GATEFLOOR + v, Kind::Gate => T_GATEFLOOR + v,
Kind::Torture => T_TORTURE + v,
Kind::Tower => T_CLAIM + v,
} }
} }
+15 -6
View File
@@ -46,9 +46,12 @@ pub enum Kind {
Core, Core,
Portal, Portal,
Gate, Gate,
Torture,
Tower, // floor tile occupied by a defence tower (not walkable)
} }
const KINDS: [Kind; 12] = [ // order matters for the packed savegame codec: only append new kinds
const KINDS: [Kind; 14] = [
Kind::Rock, Kind::Rock,
Kind::Earth, Kind::Earth,
Kind::Gold, Kind::Gold,
@@ -61,6 +64,8 @@ const KINDS: [Kind; 12] = [
Kind::Core, Kind::Core,
Kind::Portal, Kind::Portal,
Kind::Gate, Kind::Gate,
Kind::Torture,
Kind::Tower,
]; ];
#[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize)] #[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize)]
@@ -93,11 +98,13 @@ pub struct Tile {
pub bed: u32, // entity id + 1 sleeping here pub bed: u32, // entity id + 1 sleeping here
#[serde(rename = "v")] #[serde(rename = "v")]
pub var: u8, // texture variant pub var: u8, // texture variant
#[serde(rename = "rf", default)]
pub reinforced: bool, // wall reinforced by imps
} }
impl Tile { impl Tile {
pub fn new(kind: Kind) -> Tile { pub fn new(kind: Kind) -> Tile {
Tile { kind, owner: Owner::None, hp: 0.0, gold: 0, marked: false, reserved: 0, food: 0.0, bed: 0, var: 0 } Tile { kind, owner: Owner::None, hp: 0.0, gold: 0, marked: false, reserved: 0, food: 0.0, bed: 0, var: 0, reinforced: false }
} }
pub fn solid(&self) -> bool { pub fn solid(&self) -> bool {
matches!(self.kind, Kind::Rock | Kind::Earth | Kind::Gold) matches!(self.kind, Kind::Rock | Kind::Earth | Kind::Gold)
@@ -108,7 +115,7 @@ impl Tile {
pub fn walkable(&self) -> bool { pub fn walkable(&self) -> bool {
matches!( matches!(
self.kind, self.kind,
Kind::Floor | Kind::Treasury | Kind::Lair | Kind::Farm | Kind::Training | Kind::Library | Kind::Portal | Kind::Gate Kind::Floor | Kind::Treasury | Kind::Lair | Kind::Farm | Kind::Training | Kind::Library | Kind::Portal | Kind::Gate | Kind::Torture
) )
} }
} }
@@ -429,9 +436,10 @@ impl Map {
move |i| { move |i| {
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 => Some(7), Kind::Earth => Some(7),
Kind::Gold => Some(12), Kind::Gold => Some(12),
Kind::Rock | Kind::Core => None, Kind::Rock | Kind::Core | Kind::Tower => None,
_ => Some(1), _ => Some(1),
} }
} }
@@ -505,7 +513,7 @@ fn tile_record(t: &Tile) -> [u8; REC] {
let mut r = [0u8; REC]; let mut r = [0u8; REC];
r[0] = KINDS.iter().position(|&k| k == t.kind).unwrap_or(0) as u8; r[0] = KINDS.iter().position(|&k| k == t.kind).unwrap_or(0) as u8;
r[1] = OWNERS.iter().position(|&o| o == t.owner).unwrap_or(0) as u8; r[1] = OWNERS.iter().position(|&o| o == t.owner).unwrap_or(0) as u8;
r[2] = t.marked as u8; r[2] = t.marked as u8 | (t.reinforced as u8) << 1;
r[3..7].copy_from_slice(&t.hp.to_le_bytes()); r[3..7].copy_from_slice(&t.hp.to_le_bytes());
r[7..11].copy_from_slice(&t.gold.to_le_bytes()); r[7..11].copy_from_slice(&t.gold.to_le_bytes());
r[11..15].copy_from_slice(&t.food.to_le_bytes()); r[11..15].copy_from_slice(&t.food.to_le_bytes());
@@ -567,7 +575,8 @@ fn tiles_de<'de, D: Deserializer<'de>>(d: D) -> Result<Vec<Tile>, D::Error> {
let t = Tile { let t = Tile {
kind: *KINDS.get(r[0] as usize).unwrap_or(&Kind::Rock), kind: *KINDS.get(r[0] as usize).unwrap_or(&Kind::Rock),
owner: *OWNERS.get(r[1] as usize).unwrap_or(&Owner::None), owner: *OWNERS.get(r[1] as usize).unwrap_or(&Owner::None),
marked: r[2] != 0, marked: r[2] & 1 != 0,
reinforced: r[2] & 2 != 0,
hp: f32::from_le_bytes(f(3)), hp: f32::from_le_bytes(f(3)),
gold: i32::from_le_bytes(f(7)), gold: i32::from_le_bytes(f(7)),
food: f32::from_le_bytes(f(11)), food: f32::from_le_bytes(f(11)),
+6 -3
View File
@@ -14,7 +14,7 @@ pub const WALL_H: f32 = 0.95;
const CHUNK: i32 = 16; const CHUNK: i32 = 16;
pub const MAX_LIGHTS: usize = 24; pub const MAX_LIGHTS: usize = 24;
const ATLAS_W: f32 = 256.0; const ATLAS_W: f32 = 256.0;
const ATLAS_H: f32 = 80.0; const ATLAS_H: f32 = 96.0;
const DISP_AMP: f32 = 0.11; // wall surface irregularity const DISP_AMP: f32 = 0.11; // wall surface irregularity
// ------------------------------------------------------------------ camera // ------------------------------------------------------------------ camera
@@ -482,7 +482,7 @@ fn build_chunk(map: &Map, amb: &[f32], cx: i32, cz: i32, gold_fill: f32, atlas:
for z in cz * CHUNK..((cz + 1) * CHUNK).min(mh() as i32) { for z in cz * CHUNK..((cz + 1) * CHUNK).min(mh() as i32) {
for x in cx * CHUNK..((cx + 1) * CHUNK).min(mw() as i32) { for x in cx * CHUNK..((cx + 1) * CHUNK).min(mw() as i32) {
let t = map.t[idx(x, z)]; let t = map.t[idx(x, z)];
let tex = Gfx::tile_tex(t.kind, t.owner == Owner::Player, t.owner == Owner::Hero, t.var); let tex = Gfx::tile_tex(t.kind, t.owner == Owner::Player, t.owner == Owner::Hero, t.var, t.reinforced);
let (ua, ub) = cell_uv(tex); let (ua, ub) = cell_uv(tex);
let (xf, zf) = (x as f32, z as f32); let (xf, zf) = (x as f32, z as f32);
if !t.solid() { if !t.solid() {
@@ -694,7 +694,7 @@ fn chunk_sig(map: &Map, cx: i32, cz: i32, fill_bucket: u8) -> u64 {
Kind::Treasury => fill_bucket as u64, Kind::Treasury => fill_bucket as u64,
_ => 0, _ => 0,
}; };
(t.kind as u64) | (t.owner as u64) << 4 | (t.marked as u64) << 6 | extra << 8 (t.kind as u64) | (t.owner as u64) << 5 | (t.marked as u64) << 7 | (t.reinforced as u64) << 8 | extra << 9
} }
None => 0xff, None => 0xff,
}; };
@@ -1268,6 +1268,7 @@ fn draw_overlay(map: &Map, ov: &Overlay, n: usize) {
pub fn minimap_color(tile: &Tile) -> [u8; 4] { pub fn minimap_color(tile: &Tile) -> [u8; 4] {
match tile.kind { match tile.kind {
Kind::Rock => [40, 40, 48, 255], Kind::Rock => [40, 40, 48, 255],
Kind::Earth if tile.reinforced => [120, 70, 70, 255],
Kind::Earth => [86, 60, 40, 255], Kind::Earth => [86, 60, 40, 255],
Kind::Gold => [220, 180, 50, 255], Kind::Gold => [220, 180, 50, 255],
Kind::Floor => match tile.owner { Kind::Floor => match tile.owner {
@@ -1283,5 +1284,7 @@ pub fn minimap_color(tile: &Tile) -> [u8; 4] {
Kind::Core => [255, 60, 60, 255], Kind::Core => [255, 60, 60, 255],
Kind::Portal => [190, 90, 240, 255], Kind::Portal => [190, 90, 240, 255],
Kind::Gate => [230, 230, 255, 255], Kind::Gate => [230, 230, 255, 255],
Kind::Torture => [120, 40, 40, 255],
Kind::Tower => [255, 140, 60, 255],
} }
} }
+9
View File
@@ -146,6 +146,15 @@ fn def(s: Sfx, r: f32) -> Vec<f32> {
Sfx::Defeat => l(&[seg(Square(0.5), 220.0, 110.0, 0.6, 0.22, 2.0)], 38), Sfx::Defeat => l(&[seg(Square(0.5), 220.0, 110.0, 0.6, 0.22, 2.0)], 38),
Sfx::Click => l(&[seg(Square(0.5), 1000.0, 1000.0, 0.02, 0.12, 50.0)], 39), Sfx::Click => l(&[seg(Square(0.5), 1000.0, 1000.0, 0.02, 0.12, 50.0)], 39),
Sfx::Error => l(&[seg(Square(0.5), 110.0, 105.0, 0.16, 0.2, 4.0)], 40), Sfx::Error => l(&[seg(Square(0.5), 110.0, 105.0, 0.16, 0.2, 4.0)], 40),
Sfx::Reinforce => l(&[seg(Tri, 320.0, 200.0, 0.07, 0.5, 20.0), seg(Tri, 260.0, 170.0, 0.09, 0.5, 20.0)], 41),
Sfx::Cannon => mix(vec![l(&[seg(Noise, 1500.0, 150.0, 0.5, 0.6, 6.0)], 42), l(&[seg(Tri, 75.0, 32.0, 0.45, 0.9, 5.0)], 43)]),
Sfx::Magic => mix(vec![l(&[seg(Sine, 880.0, 1760.0, 0.16, 0.35, 8.0)], 44), l(&[vib(seg(Square(0.125), 1320.0, 1320.0, 0.16, 0.08, 10.0), 0.05)], 45)]),
Sfx::Capture => l(&[
seg(Square(0.25), 1400.0, 1400.0, 0.04, 0.16, 20.0),
seg(Square(0.25), 1100.0, 1100.0, 0.04, 0.16, 20.0),
seg(Square(0.25), 900.0, 900.0, 0.08, 0.16, 15.0),
], 46),
Sfx::Convert => l(&arp(Saw, &[220.0, 262.0, 330.0, 440.0], 0.1, 0.22), 47),
} }
} }
+4
View File
@@ -617,6 +617,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::Earth if t.reinforced => {
out.push((tr("tile.reinforced"), FRAME_HI));
out.push((tr("tile.reinforced_info"), DIM));
}
Kind::Earth => out.push((tr("tile.earth"), FRAME_HI)), Kind::Earth => out.push((tr("tile.earth"), FRAME_HI)),
Kind::Gold => { Kind::Gold => {
out.push((tr("tile.gold"), GOLD)); out.push((tr("tile.gold"), GOLD));