diff --git a/DESIGN.md b/DESIGN.md index 60bc58d..264f0f7 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -22,6 +22,14 @@ Eigenständiges Dungeon-Management-Spiel (Genre: Dungeon-Aufbau & Verteidigung), - Linksklick: aktives Werkzeug benutzen (Rechteck aufziehen für Graben/Räume) - Rechtsklick: Einheit aus der Hand absetzen - Kamera: WASD/Pfeiltasten, rechte Maus ziehen, Mausrad-Zoom, Bildschirmrand +- Drehen/Neigen: mittlere Maustaste ziehen, Q/E drehen, R/F neigen +- Zauber: 0 Blitz, X Heilung, V Wicht beschwören +- Fackeln: automatisch beim Erobern; fremde Gebiete schummrig sichtbar + +## Geplant (nach 3D) +- Repo komplett auf Englisch; Spieltexte in separaten Sprachdateien (EN + DE, erweiterbar), Sprache im Spiel umschaltbar +- Menü: Speichern (Download *.dcsave), Laden (Dateiauswahl + Drag & Drop), Autosave im Browser (localStorage) +- Einstellungen: Sprache + Ton, Kamera, Grafik, Spiel, Tastenbelegung – gespeichert im Browser **und** im Savegame ## Spielinhalt (volles Konzept) - **Graben**: Erde/Gold markieren → Grubenwichte graben, bringen Gold heim, erobern Boden diff --git a/src/game.rs b/src/game.rs index 27852af..aa8a62c 100644 --- a/src/game.rs +++ b/src/game.rs @@ -236,9 +236,26 @@ pub struct Game { pub flag: Option, pub events: Vec, pub last_wave_value: f32, + pub torches: Vec, hint_t: [f32; 16], } +// Fackel an einer Wandseite: Wandkachel + Richtung (Index in DIR4) zur offenen Seite +#[derive(Clone, Copy, PartialEq)] +pub struct Torch { + pub wall: usize, + pub dir: usize, +} + +impl Torch { + // Weltposition der Flamme (x, z) auf Bodenebene + pub fn pos(&self) -> (f32, f32) { + let (x, y) = xy(self.wall); + let (dx, dy) = DIR4[self.dir]; + (x as f32 + 0.5 + dx as f32 * 0.58, y as f32 + 0.5 + dy as f32 * 0.58) + } +} + pub const ROOM_KINDS: [Kind; 5] = [Kind::Treasury, Kind::Lair, Kind::Farm, Kind::Training, Kind::Library]; pub const ROOM_COST: [i32; 5] = [60, 80, 100, 140, 160]; pub const ROOM_NAMES: [&str; 5] = ["Schatzkammer", "Quartier", "Pilzgarten", "Trainingshalle", "Bibliothek"]; @@ -290,6 +307,7 @@ impl Game { flag: None, events: Vec::new(), last_wave_value: 0.0, + torches: Vec::new(), hint_t: [-1000.0; 16], }; let (cx, cy) = g.map.core; @@ -297,6 +315,11 @@ impl Game { g.spawn(EK::Worker, false, cx as f32 - 0.5, cy as f32 + k as f32 * 0.7 + 0.3, 1); } g.recount(); + for i in 0..N { + if g.map.t[i].owner == Owner::Player { + g.place_torches(i); + } + } g.msg("Willkommen, Herrscher des Unterreichs! Beschütze deinen Seelenkern und zerstöre das Heldentor.".into()); g.msg("Markiere Erde und Goldadern mit dem Werkzeug »Graben« (Taste 1). Deine Grubenwichte erledigen den Rest.".into()); g.msg("Grabe dich zum Portal durch und erobere es. Kreaturen brauchen ein Quartier und einen Pilzgarten.".into()); @@ -339,6 +362,27 @@ impl Game { (h * d).sqrt() } + // Wichte hängen Fackeln an Wände neben erobertem Boden (Mindestabstand 3,5 Felder) + pub fn place_torches(&mut self, i: usize) { + let (x, y) = xy(i); + for (d, &(dx, dy)) in DIR4.iter().enumerate() { + let (wx, wy) = (x + dx, y + dy); + if !inb(wx, wy) || !self.map.t[idx(wx, wy)].solid() { + continue; + } + // Richtung von der Wand zum Boden ist die Gegenrichtung + let t = Torch { wall: idx(wx, wy), dir: (d + 2) % 4 }; + let (px, pz) = t.pos(); + let near = self.torches.iter().any(|o| { + let (ox, oz) = o.pos(); + (ox - px).powi(2) + (oz - pz).powi(2) < 3.5 * 3.5 + }); + if !near { + self.torches.push(t); + } + } + } + fn hint(&mut self, key: usize, s: &str) { if self.time - self.hint_t[key] > 30.0 { self.hint_t[key] = self.time; @@ -782,6 +826,7 @@ impl Game { } pub fn dig_out(&mut self, i: usize) { + self.torches.retain(|t| t.wall != i); let t = &mut self.map.t[i]; t.kind = Kind::Floor; t.owner = Owner::None; @@ -1072,6 +1117,7 @@ impl Game { } else { self.map.t[t].owner = Owner::Player; } + self.place_torches(t); let (x, y) = xy(t); self.fx(8, x as f32 + 0.5, y as f32 + 0.5, 0.0, 0.0, 0.5, 0xff4040e0); self.sfx(Sfx::Claim, x as f32 + 0.5, y as f32 + 0.5); @@ -1653,12 +1699,12 @@ impl Game { best } - pub fn pickup(&mut self, wx: f32, wy: f32) -> bool { + pub fn pickup(&mut self, target: Option) -> bool { if self.hand.len() >= 8 { self.hint(8, "Deine Hand ist voll (max. 8). Rechtsklick lässt Einheiten fallen."); return false; } - if let Some(j) = self.ent_at(wx, wy, true) { + if let Some(j) = target.filter(|&j| j < self.ents.len() && self.ents[j].alive && !self.ents[j].held && !self.ents[j].hero) { let id = self.ents[j].id; let me = id + 1; self.unreserve(me);