feat(handel): NPC-Registry, Dialog, Laden und Stapelregel
Vierzehnte Registry: NPCs sind keine Wesen — kein Kampfzustand, keine Initiative, keine Attribute. Ihre Antwortliste ist flach; was erst nach einer Antwort erscheint, ist eine Option mit einer Bedingung. - open_shop als elfte Aktion (game/ setzt eine Absicht, die UI schiebt) - Talk/Choose/Buy/Sell, Talk wirkt auf das eigene Feld wie PickUp - Preisspanne statt Goldkonto beim Haendler, Charisma in der Preisfunktion - Warenkorb einmal bei der Etagenerzeugung gezogen - Stapelregel aus Ticket 07 endlich gebaut: 50-120 Gold war 120 Eintraege - Dialog- und Shop-Screen, NPC-Symbol im Grid
This commit is contained in:
@@ -25,8 +25,20 @@ pub enum Screen {
|
||||
/// Meldungszeile im Hauptmenue: Ein Abstiegs-Roguelike lebt davon, dass der
|
||||
/// Lauf am Ende *erzaehlt* wird (Ticket 14).
|
||||
GameOver,
|
||||
// TODO(M3+): `CharacterCreation`, `Combat`, `Inventory`, `QuestLog`,
|
||||
// `Shop`, `Dialog`, `Confirm` — elf sind es am Ende (11/14).
|
||||
/// **Flache Optionsliste**, kein Knotengraph (M4): Was erst nach einer
|
||||
/// Antwort erscheint, ist eine Option mit einer Bedingung.
|
||||
Dialog {
|
||||
pick: usize,
|
||||
},
|
||||
/// Zwei Spalten: Angebot links, eigenes Inventar rechts. `Tab` wechselt.
|
||||
Shop {
|
||||
pick: usize,
|
||||
/// `false` = Angebot, `true` = Inventar. Ein `bool` statt eines Enums
|
||||
/// mit zwei Werten, die nie mehr werden.
|
||||
selling: bool,
|
||||
},
|
||||
// TODO(M5+): `CharacterCreation`, `QuestLog`, `Confirm` — elf sind es am
|
||||
// Ende (11/14).
|
||||
}
|
||||
|
||||
/// Der Screen **gibt zurueck, statt selbst zu schieben**: sonst haelt er ein
|
||||
@@ -78,6 +90,7 @@ impl Screen {
|
||||
KeyCode::Char('.') => Response::Command(Command::Wait),
|
||||
KeyCode::Char('>') => Response::Command(Command::Descend),
|
||||
KeyCode::Char('g') => Response::Command(Command::PickUp),
|
||||
KeyCode::Char('t') => Response::Command(Command::Talk),
|
||||
// Screen-Navigation ist reine UI und fasst `Game` nie an.
|
||||
KeyCode::Char('c') => Response::Push(Screen::CharacterSheet),
|
||||
KeyCode::Char('i') => Response::Push(Screen::Inventory { pick: 0 }),
|
||||
@@ -165,6 +178,65 @@ impl Screen {
|
||||
_ => Response::None,
|
||||
},
|
||||
|
||||
Screen::Dialog { pick } => {
|
||||
let options = game.dialog_options(reg);
|
||||
match key {
|
||||
KeyCode::Up | KeyCode::Char('k') => {
|
||||
*pick = pick.saturating_sub(1);
|
||||
Response::None
|
||||
}
|
||||
KeyCode::Down | KeyCode::Char('j') => {
|
||||
*pick = (*pick + 1).min(options.len().saturating_sub(1));
|
||||
Response::None
|
||||
}
|
||||
KeyCode::Enter | KeyCode::Char('1'..='9') => {
|
||||
let i = match key {
|
||||
KeyCode::Char(c @ '1'..='9') => (c as u8 - b'1') as usize,
|
||||
_ => *pick,
|
||||
};
|
||||
match options.get(i) {
|
||||
Some(_) => Response::Command(Command::Choose(i)),
|
||||
None => Response::None,
|
||||
}
|
||||
}
|
||||
KeyCode::Esc | KeyCode::Char('q') => Response::Pop,
|
||||
_ => Response::None,
|
||||
}
|
||||
}
|
||||
|
||||
Screen::Shop { pick, selling } => {
|
||||
let n = if *selling {
|
||||
game.player.inventory.len()
|
||||
} else {
|
||||
game.shop_stock().map_or(0, |s| s.len())
|
||||
};
|
||||
if n > 0 {
|
||||
*pick = (*pick).min(n - 1);
|
||||
}
|
||||
|
||||
match key {
|
||||
KeyCode::Tab | KeyCode::Left | KeyCode::Right => {
|
||||
*selling = !*selling;
|
||||
*pick = 0;
|
||||
Response::None
|
||||
}
|
||||
KeyCode::Up | KeyCode::Char('k') => {
|
||||
*pick = pick.saturating_sub(1);
|
||||
Response::None
|
||||
}
|
||||
KeyCode::Down | KeyCode::Char('j') => {
|
||||
*pick = (*pick + 1).min(n.saturating_sub(1));
|
||||
Response::None
|
||||
}
|
||||
KeyCode::Enter if n > 0 && *selling => {
|
||||
Response::Command(Command::Sell(*pick))
|
||||
}
|
||||
KeyCode::Enter if n > 0 => Response::Command(Command::Buy(*pick)),
|
||||
KeyCode::Esc | KeyCode::Char('q') => Response::Pop,
|
||||
_ => Response::None,
|
||||
}
|
||||
}
|
||||
|
||||
Screen::GameOver => Response::Quit,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user