feat: m3 kampf, events und trigger
Der Dungeon hat jetzt Gegner, und man kann sterben.
- game/action.rs: sieben Schadenstypen, fuenf der zehn Aktionen, Target
- game/condition.rs: Bedingungsgrammatik (Liste = UND, not je Eintrag)
- game/event.rs: zwoelf Events, Trigger als vierte Wirkungsform
- game/combat.rs: Treffer- und Schadensformel mit drei Klemmbereichen
- Game::apply, drain_events (FIFO), Initiative, Rundenablauf aus Ticket 14
- data/: abilities-, creatures- und modifiers-Registry, [balance] feldweise
- ui/: Combat-Screen mit Faehigkeitsmenue und Sperrgrund
Drei Befunde:
- Die Trefferformel war toter Code — jeder Angriff traf. Nur der Compiler
hat es gemeldet ('hit_chance is never used'). Test haelt sie am Leben.
- Die Warteschlange war ein Stack (pop statt pop_front), obwohl Ticket 08
ausdruecklich 'haengt es hinten an' sagt. Jetzt VecDeque.
- Benannte Modifikatoren (core:poisoned) hatten keine Registry — Ticket 01
laesst apply_modifier per ID referenzieren, aber keine der zwoelf
definierte sie. Das ist die dreizehnte.
43 Tests.
This commit is contained in:
@@ -2,7 +2,8 @@
|
||||
|
||||
use ratatui::crossterm::event::KeyCode;
|
||||
|
||||
use crate::game::{Command, Direction};
|
||||
use crate::data::Registries;
|
||||
use crate::game::{Command, CreatureRef, Direction, Game};
|
||||
|
||||
/// Popups sind gewoehnliche Screens, die sich beim Rendern als Overlay
|
||||
/// ausweisen — ein gemeinsamer `Vec<Screen>` statt `current` plus
|
||||
@@ -10,6 +11,11 @@ use crate::game::{Command, Direction};
|
||||
pub enum Screen {
|
||||
MainMenu,
|
||||
Explore,
|
||||
/// Menue-Kampf (Charter): Faehigkeitsliste, Zielwahl mit den Zifferntasten.
|
||||
Combat {
|
||||
/// Cursor in der Faehigkeitsliste.
|
||||
pick: usize,
|
||||
},
|
||||
CharacterSheet,
|
||||
/// Vollbild, kein Overlay. Bewusst nicht die lazy Variante mit einer
|
||||
/// Meldungszeile im Hauptmenue: Ein Abstiegs-Roguelike lebt davon, dass der
|
||||
@@ -37,7 +43,12 @@ impl Screen {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn handle_key(&mut self, key: KeyCode) -> Response {
|
||||
/// **Befund aus M3:** Ticket 11 hatte `handle_key(&mut self, key)` ohne
|
||||
/// Kontext festgelegt. Der Kampf-Screen muss aber wissen, wie viele
|
||||
/// Faehigkeiten es gibt, um den Cursor zu klemmen, und welche der Cursor
|
||||
/// meint. Lesender Zugriff genuegt — die Regel „ein Screen fasst `Game`
|
||||
/// nicht an" bleibt, weil nur `Response::Command` etwas aendert.
|
||||
pub fn handle_key(&mut self, key: KeyCode, game: &Game, reg: &Registries) -> Response {
|
||||
match self {
|
||||
Screen::MainMenu => match key {
|
||||
KeyCode::Enter => Response::Push(Screen::Explore),
|
||||
@@ -68,6 +79,45 @@ impl Screen {
|
||||
_ => Response::None,
|
||||
},
|
||||
|
||||
Screen::Combat { pick } => {
|
||||
let abilities = game.abilities_of(CreatureRef::Player, reg);
|
||||
if abilities.is_empty() {
|
||||
return Response::None;
|
||||
}
|
||||
*pick = (*pick).min(abilities.len() - 1);
|
||||
|
||||
match key {
|
||||
KeyCode::Up | KeyCode::Char('k') => {
|
||||
*pick = pick.saturating_sub(1);
|
||||
Response::None
|
||||
}
|
||||
KeyCode::Down | KeyCode::Char('j') => {
|
||||
*pick = (*pick + 1).min(abilities.len() - 1);
|
||||
Response::None
|
||||
}
|
||||
// Ziel ueber die Zifferntasten; ohne Gegner (Flucht,
|
||||
// Selbstheilung) zaehlt der Held selbst als Ziel.
|
||||
KeyCode::Enter | KeyCode::Char('1'..='9') => {
|
||||
let index = match key {
|
||||
KeyCode::Char(c @ '1'..='9') => (c as u8 - b'1') as usize,
|
||||
_ => 0,
|
||||
};
|
||||
let target = if game.enemies.is_empty() {
|
||||
CreatureRef::Player
|
||||
} else {
|
||||
CreatureRef::Enemy(index.min(game.enemies.len() - 1))
|
||||
};
|
||||
Response::Command(Command::UseAbility {
|
||||
ability: abilities[*pick].clone(),
|
||||
target,
|
||||
})
|
||||
}
|
||||
KeyCode::Char('.') => Response::Command(Command::Wait),
|
||||
KeyCode::Char('c') => Response::Push(Screen::CharacterSheet),
|
||||
_ => Response::None,
|
||||
}
|
||||
}
|
||||
|
||||
Screen::CharacterSheet => match key {
|
||||
KeyCode::Esc | KeyCode::Char('c') | KeyCode::Char('q') => Response::Pop,
|
||||
_ => Response::None,
|
||||
|
||||
Reference in New Issue
Block a user