docs: ticket 11 (ui-geruest) aufloesen, nachtrag an 01, command ins glossar
This commit is contained in:
@@ -100,6 +100,22 @@ Questketten beim Betreten des Kellers bereits erfüllt wären.
|
|||||||
Das hier angeforderte Bedingungsvokabular steht ebenfalls in 08, zusammen mit dem **Trigger** als
|
Das hier angeforderte Bedingungsvokabular steht ebenfalls in 08, zusammen mit dem **Trigger** als
|
||||||
vierter Wirkungsform.
|
vierter Wirkungsform.
|
||||||
|
|
||||||
|
### Nachtrag aus Ticket 11: `symbol` trägt das Zeichen, nicht einen Schlüssel
|
||||||
|
|
||||||
|
Oben steht, `symbol` sei ein Schlüssel und die Zuordnung mache `ui/theme.rs`. Darin steckt eine Lücke:
|
||||||
|
**`ui/theme.rs` ist Code.** Ein Modder, der `meinmod:frostbite` anlegt, kann dort nichts eintragen —
|
||||||
|
sein Statuseffekt hätte weder Zeichen noch Farbe.
|
||||||
|
|
||||||
|
Stattdessen trägt die TOML beides selbst, die Farbe als Name aus fester Liste:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
symbol = "†"
|
||||||
|
color = "cyan"
|
||||||
|
```
|
||||||
|
|
||||||
|
`data/` kennt nur `char` und ein Farbnamen-Enum, `ui/theme.rs` übersetzt in `ratatui::Color` — `game/`
|
||||||
|
und `data/` bleiben damit weiterhin ratatui-frei.
|
||||||
|
|
||||||
### Bewusst nicht entschieden
|
### Bewusst nicht entschieden
|
||||||
|
|
||||||
Das **Bedingungsvokabular** für `condition`. Es kommt aus Ticket 08, damit Quests und Modifikatoren
|
Das **Bedingungsvokabular** für `condition`. Es kommt aus Ticket 08, damit Quests und Modifikatoren
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# 11 — UI-Gerüst und Screen-Modell
|
# 11 — UI-Gerüst und Screen-Modell
|
||||||
|
|
||||||
Type: grilling
|
Type: grilling
|
||||||
Status: open
|
Status: resolved
|
||||||
Blocked by: —
|
Blocked by: —
|
||||||
|
|
||||||
## Question
|
## Question
|
||||||
@@ -32,3 +32,150 @@ Ergebnis: Screen-Enum, Stack-Modell, Action-Liste und die Regel, was `game/` nic
|
|||||||
- **04**: Der Startbildschirm trägt eine Zeile mit Warnungsanzahl und Logdateiname
|
- **04**: Der Startbildschirm trägt eine Zeile mit Warnungsanzahl und Logdateiname
|
||||||
(„12 Ladewarnungen — `logs/load-20260812-112305.log`"). **Eine Zeile, kein Screen** — der Inhalt
|
(„12 Ladewarnungen — `logs/load-20260812-112305.log`"). **Eine Zeile, kein Screen** — der Inhalt
|
||||||
gehört in einen Texteditor, nicht in ein TUI mit Scrolling und Navigation.
|
gehört in einen Texteditor, nicht in ein TUI mit Scrolling und Navigation.
|
||||||
|
|
||||||
|
## Answer
|
||||||
|
|
||||||
|
Begriffe im [Glossar](../../../CONTEXT.md).
|
||||||
|
|
||||||
|
### Zwei Vokabulare, zwei Namen
|
||||||
|
|
||||||
|
Der Bericht aus 06 empfahl „genau einen Eintrittspunkt `Game::apply(Action)`" — Ticket 07 hat
|
||||||
|
`Game::apply` inzwischen aber für die Aktionen aus 01 vergeben. „Geh nach Norden" ist keine der sieben
|
||||||
|
Aktionen und wird nie eine.
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **Action** | TOML-Effektvokabular aus 01 — `Game::apply(action, source, target, reg)` |
|
||||||
|
| **Command** | Kommando der UI ans Spiel — `Game::execute(cmd, reg)` |
|
||||||
|
|
||||||
|
`Game::execute` ist die eine Stelle, an der ein **Zug endet**: Zähler hoch, befristete Modifikatoren
|
||||||
|
ticken, `turn_started` feuern, Event-Warteschlange aus 08 leerarbeiten. Direkte Methoden auf `Game`
|
||||||
|
(`game.move_player(dir)`) wären lazier gewesen und hätten dasselbe zwölfmal gebraucht — eine Methode
|
||||||
|
hätte es vergessen.
|
||||||
|
|
||||||
|
### Zwölf Commands, alle kosten einen Zug
|
||||||
|
|
||||||
|
`Move(Direction)` · `UseAbility(AbilityId, CreatureRef)` · `UseItem(usize)` · `Equip(usize)` ·
|
||||||
|
`Unequip(SlotId)` · `Drop(usize, u32)` · `PickUp(usize)` · `Descend` · `Talk(NpcId)` ·
|
||||||
|
`Buy(ItemId, u32)` · `Sell(usize, u32)` · `Wait`
|
||||||
|
|
||||||
|
Weder Angriff noch Flucht sind **eigene Varianten** — beides sind Fähigkeiten:
|
||||||
|
`UseAbility("core:attack", ziel)` und `UseAbility("core:flee", …)`. Ticket 02 hat Fähigkeiten als
|
||||||
|
Registry festgelegt, also gehören sie dorthin, und ein Mod kann beide ersetzen: eine Klasse, die
|
||||||
|
besser flieht, ist damit eine Datenänderung statt eines Engine-Sonderfalls.
|
||||||
|
|
||||||
|
Auch Handel kostet einen Zug. Ein `fn costs_turn(&self) -> bool` wäre eine Ausnahmeliste, die mit
|
||||||
|
jeder neuen Variante gepflegt werden muss und bei der irgendwann jemand falsch rät. Zehn Züge beim
|
||||||
|
Einkauf stören nur, wenn im Laden gekämpft wird; dagegen hilft, dass `Buy(item, 10)` bereits *ein*
|
||||||
|
Command ist.
|
||||||
|
|
||||||
|
**Screen-Navigation ist reine UI und fasst `Game` nie an** — Inventar öffnen ist
|
||||||
|
`push(Screen::Inventory)`, kein Command. Speichern und Laden sind ebenfalls keine Commands: Sie kosten
|
||||||
|
keinen Zug und bekommen ihren Weg von Ticket 09.
|
||||||
|
|
||||||
|
### Ein Stack, eine Antwort
|
||||||
|
|
||||||
|
```rust
|
||||||
|
enum Response { None, Pop, Push(Screen), Command(Command), Quit }
|
||||||
|
fn handle_key(&mut self, key: KeyEvent) -> Response
|
||||||
|
```
|
||||||
|
|
||||||
|
`Vec<Screen>` für Screens und Popups gemeinsam. Popup über Popup ist real und kommt früher als
|
||||||
|
gedacht — Inventar → Gegenstandsdetail → „wirklich wegwerfen?"; getrennte Felder (`current` plus
|
||||||
|
`Option<Popup>` wie chess-tui) bräuchten für den dritten Layer eine zweite Mechanik. Der
|
||||||
|
Rendering-Befund aus 06 bleibt unberührt: `Clear` auf ein zentriertes Sub-`Rect` ist eine Eigenschaft
|
||||||
|
des Screens, nicht des Stacks. Gerendert wird vom letzten Vollbild-Screen aufwärts.
|
||||||
|
|
||||||
|
Der Screen **gibt zurück, statt selbst zu schieben** — sonst hielte er ein `&mut` auf genau die `Vec`,
|
||||||
|
in der er liegt, und die Schleife müsste ihn vorher herausnehmen und danach zurücklegen. Dasselbe
|
||||||
|
Muster wie die Event-Warteschlange in 08: nicht mitten in der Iteration mutieren, sondern zurückgeben
|
||||||
|
und danach ausführen. Nebeneffekt: `Response::Command` ist der einzige Weg nach `game/`, ein Screen
|
||||||
|
ohne Command hat den Spielzustand also nachweislich nicht angefasst.
|
||||||
|
|
||||||
|
**Ein `Response::Command` schließt alle Overlay-Screens.** Das Flag existiert bereits fürs Rendern und
|
||||||
|
beantwortet damit auch „schließt sich nach einer Rückfrage von selbst" — eine Zeile in der Schleife,
|
||||||
|
keine zusätzliche `Response`-Variante und keine Antwortliste. `Confirm { text, on_yes: Command }` wird
|
||||||
|
dadurch für jede Rückfrage wiederverwendbar, ohne eigene Variante je Anlass. Dass `Inventory` als
|
||||||
|
Vollbild-Screen nach `UseItem` offen bleibt, fällt aus derselben Regel — man trinkt selten genau einen
|
||||||
|
Trank.
|
||||||
|
|
||||||
|
### Zehn Screens
|
||||||
|
|
||||||
|
`MainMenu` (trägt die Ladewarnungs-Zeile aus 04) · `CharacterCreation` (Registry-Schleife aus 02) ·
|
||||||
|
`Explore` · `Combat` · `Inventory` · `CharacterSheet` · `QuestLog` · `Shop` · `Dialog` · `Confirm`
|
||||||
|
|
||||||
|
Kein `ItemDetail`-Popup: Die Inventarliste zeigt Details in einer Seitenspalte, das ist ein Layout und
|
||||||
|
kein Screen. `Shop` bleibt getrennt von `Dialog`, weil Handel zwei Listen nebeneinander braucht und
|
||||||
|
der Dialog eine Textfläche mit Antwortoptionen.
|
||||||
|
|
||||||
|
`ListState` lebt in der Screen-Variante und wird beim `pop()` mitverworfen. Der Stack macht den
|
||||||
|
wichtigen Fall gratis richtig: Solange ein Screen im Stack *liegt*, existiert sein Zustand weiter —
|
||||||
|
Inventar → Detail → zurück landet wieder auf demselben Eintrag. Zurückgesetzt wird nur beim echten
|
||||||
|
Schließen und Neuöffnen, und das hat noch nie jemanden gestört. Eine Map `ScreenKind → ListState`
|
||||||
|
wäre eine Zustandsverwaltung neben dem Stack für genau diesen Randfall.
|
||||||
|
|
||||||
|
### Eingabe
|
||||||
|
|
||||||
|
**Nur `KeyEventKind::Press`.** Der Filter ist unter Windows ohnehin Pflicht (06), aber der Grund gegen
|
||||||
|
`Repeat` ist schwerer als die UX: Ein Schritt ist ein Zug, also bestimmte die Tastaturwiederholrate des
|
||||||
|
Betriebssystems die Spielzeit — ein gedrückt gehaltener Pfeil verbrennte ein Gift-Debuff mit dreißig
|
||||||
|
Zügen pro Sekunde und feuerte `turn_started` ebenso oft.
|
||||||
|
|
||||||
|
Die Decke, falls sich Laufen zäh anfühlt: ein Renn-Kommando („laufe, bis etwas passiert"), das *ein*
|
||||||
|
Tastendruck ist und in `game/` viele Züge auflöst — dort kann es an Gegnern und Abzweigungen anhalten.
|
||||||
|
Das ist die Lösung, die Roguelikes seit Jahrzehnten nehmen, und sie gehört nicht in die
|
||||||
|
Eingabeschleife.
|
||||||
|
|
||||||
|
Tastenbelegung fest im Code, Pfeiltasten **und** `hjkl` — drei zusätzliche `match`-Arme sind die
|
||||||
|
billige Höflichkeit gegenüber Vim-Fingern. Eine `keybindings.toml` bräuchte Parser, Konfliktprüfung
|
||||||
|
(„zwei Commands auf `i`") und einen Einstellungs-Screen, damit sie überhaupt auffindbar ist. Kommt sie
|
||||||
|
doch, wird der `match` zu einem `HashMap<KeyCode, Command>`-Lookup und sonst ändert sich nichts.
|
||||||
|
|
||||||
|
### Modulstruktur
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
main.rs # Laden, Fehlerpfad aus 04, dann ui::run
|
||||||
|
game/ # kennt ratatui nicht — Test prueft das
|
||||||
|
creature.rs floor.rs command.rs action.rs event.rs condition.rs
|
||||||
|
data/ # Definitionen, Registries, Mod-Lader aus 03/04
|
||||||
|
loader.rs registries.rs item.rs affix.rs quest.rs
|
||||||
|
ui/
|
||||||
|
app.rs # App { game, registries, screens: Vec<Screen> } + Schleife
|
||||||
|
input.rs theme.rs
|
||||||
|
screens/ widgets/grid.rs
|
||||||
|
```
|
||||||
|
|
||||||
|
`App` hält `game` und `registries` als **getrennte Felder**, damit die disjunkten Borrows aus 07
|
||||||
|
funktionieren. `Command` liegt in `game/`, obwohl er von der UI kommt — er ist Vokabular des Spiels,
|
||||||
|
nicht der Darstellung, und `game/` muss ihn ausführen können. Andersherum wäre `ui/` die Heimat eines
|
||||||
|
Typs, den `game/` importieren muss, und die Abhängigkeit zeigte in die falsche Richtung.
|
||||||
|
|
||||||
|
Die ratatui-Freiheit prüft ein `#[test]`, der `src/game/**/*.rs` liest und auf `ratatui` sucht. Fünf
|
||||||
|
Zeilen; ein Cargo-Workspace mit `game` als eigener Crate wäre echte Compiler-Durchsetzung und ist die
|
||||||
|
Decke, falls es je ernst wird.
|
||||||
|
|
||||||
|
### Nachtrag an Ticket 01: Darstellung muss moddbar sein
|
||||||
|
|
||||||
|
01 hat `symbol` als *Schlüssel* definiert, dessen Zuordnung `ui/theme.rs` macht. Darin steckt eine
|
||||||
|
Lücke: **`ui/theme.rs` ist Code.** Ein Modder, der `meinmod:frostbite` anlegt, kann dort nichts
|
||||||
|
eintragen — sein Statuseffekt hätte weder Zeichen noch Farbe. Das widerspricht dem Grundsatz aus 02
|
||||||
|
und 03, dass Inhalt moddbar ist.
|
||||||
|
|
||||||
|
Stattdessen trägt die TOML das Zeichen selbst und einen Farbnamen aus fester Liste:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
symbol = "†"
|
||||||
|
color = "cyan"
|
||||||
|
```
|
||||||
|
|
||||||
|
`data/` kennt nur `char` und ein Farbnamen-Enum, `ui/theme.rs` übersetzt in `ratatui::Color`. `game/`
|
||||||
|
und `data/` bleiben ratatui-frei, weil ein Farbname eine Zeichenkette ist.
|
||||||
|
|
||||||
|
### Auflagen an andere Tickets
|
||||||
|
|
||||||
|
- **09 Save-Schema**: Speichern und Laden sind keine Commands und brauchen einen eigenen Weg.
|
||||||
|
- **12 Prototyp**: Der Durchstich baut `MainMenu`, `Explore` und das Grid-Widget; alles andere ist
|
||||||
|
Kulisse.
|
||||||
|
- **14 Kampfformeln**: `core:attack` und `core:flee` müssen als Fähigkeiten im Kernspiel existieren —
|
||||||
|
ohne sie hat `UseAbility` weder Basisangriff noch Flucht.
|
||||||
|
|||||||
@@ -67,13 +67,14 @@ auch über Ticket 13.
|
|||||||
- [06 — Research: ratatui-App-Architektur](issues/06-research-ratatui-architektur.md) ([#7](https://gitlab.hive-brain.de/MDietermann/rustkeep/issues/7)) — Screen-Stack über zentralem `Game`-State statt Elm oder Component-Trait; `game/` bleibt ratatui-frei; Popups per `Clear` auf Sub-`Rect` statt Widget-Stack; blockierendes `event::read()` ohne Tick; Dungeon-Grid ist Eigenbau, es gibt kein Widget dafür; ratatui 0.30.2 mit MSRV 1.88; `KeyEventKind::Press`-Filter unter Windows Pflicht. Voller Bericht in [research/06](research/06-ratatui-architektur.md).
|
- [06 — Research: ratatui-App-Architektur](issues/06-research-ratatui-architektur.md) ([#7](https://gitlab.hive-brain.de/MDietermann/rustkeep/issues/7)) — Screen-Stack über zentralem `Game`-State statt Elm oder Component-Trait; `game/` bleibt ratatui-frei; Popups per `Clear` auf Sub-`Rect` statt Widget-Stack; blockierendes `event::read()` ohne Tick; Dungeon-Grid ist Eigenbau, es gibt kein Widget dafür; ratatui 0.30.2 mit MSRV 1.88; `KeyEventKind::Press`-Filter unter Windows Pflicht. Voller Bericht in [research/06](research/06-ratatui-architektur.md).
|
||||||
- [07 — Game-State-Baum](issues/07-game-state-baum.md) ([#8](https://gitlab.hive-brain.de/MDietermann/rustkeep/issues/8)) — `Registries` lebt **neben** `Game`, nicht darin: als Feld kollidierte `&mut game.player` mit `&game.registries` bei jedem Methodenaufruf. Verweise per `String`-ID, keine Indizes (die hängen an der Ladereihenfolge). Ein `Creature` für Held und Gegner, aber **zwei Felder** `player` und `enemies` statt einer `Vec` — Solo-Held heißt, „Gegner greift Gegner an" existiert nicht, und zwei Felder sind ein disjunkter Borrow. Ein `Floor`, kein Backtracking; Händler müssen deshalb auf jeder Etage vorkommen können. **Instanzzustand kommt**: `ItemInstance { def, affixes }`, und **Affixe sind die sechste Registry** — dadurch bleibt der Save eine ID-Liste und der Preis `base_price × Π price_factor`. Stapeln bei gleicher `def` und gleicher `affixes`. `enum CreatureRef`, dazu je ein Eingang `Game::apply` und `Game::attribute` — Letzteres auf `Game`, weil Auren beim Träger wohnen und ein `Creature` seine Attribute allein gar nicht ausrechnen kann. Kein Attribut-Cache.
|
- [07 — Game-State-Baum](issues/07-game-state-baum.md) ([#8](https://gitlab.hive-brain.de/MDietermann/rustkeep/issues/8)) — `Registries` lebt **neben** `Game`, nicht darin: als Feld kollidierte `&mut game.player` mit `&game.registries` bei jedem Methodenaufruf. Verweise per `String`-ID, keine Indizes (die hängen an der Ladereihenfolge). Ein `Creature` für Held und Gegner, aber **zwei Felder** `player` und `enemies` statt einer `Vec` — Solo-Held heißt, „Gegner greift Gegner an" existiert nicht, und zwei Felder sind ein disjunkter Borrow. Ein `Floor`, kein Backtracking; Händler müssen deshalb auf jeder Etage vorkommen können. **Instanzzustand kommt**: `ItemInstance { def, affixes }`, und **Affixe sind die sechste Registry** — dadurch bleibt der Save eine ID-Liste und der Preis `base_price × Π price_factor`. Stapeln bei gleicher `def` und gleicher `affixes`. `enum CreatureRef`, dazu je ein Eingang `Game::apply` und `Game::attribute` — Letzteres auf `Game`, weil Auren beim Träger wohnen und ein `Creature` seine Attribute allein gar nicht ausrechnen kann. Kein Attribut-Cache.
|
||||||
- [08 — Event- und Trigger-System](issues/08-event-trigger-system.md) ([#9](https://gitlab.hive-brain.de/MDietermann/rustkeep/issues/9)) — **Der Trigger ist die vierte Wirkungsform** neben Modifikator, Aktion und Fähigkeit: `{ on, condition, actions }` darf überall stehen, wo `modifiers` und `actions` stehen — sonst entstünde dieselbe Maschine ein zweites Mal in 14 als `on_hit`. Eine Bedingungsgrammatik für Trigger *und* Modifikatoren: getaggtes Enum, Liste ist UND, `not` je Eintrag, **kein ODER** (zwei Einträge oder ein gemeinsames Tag). Neun feste Events ohne Namensraum, jedes mit `source`/`target`; `attack_hit` und `damage_taken` bleiben getrennt, weil der eine beim Angreifer und der andere beim Getroffenen hängt. Im Trigger ist `self` immer der Träger. **Warteschlange statt synchron** — synchrones Feuern wäre ein Borrow-Fehler (über `self.quests` iterieren, während `self.apply` läuft) — mit Zähler bei 100 Events pro Zug statt Zyklengraph. Trigger werden gesucht, nicht indiziert. **Quest = Trigger mit `count`**, siebte Registry, erledigte bleiben markiert stehen. Zwei Nachträge an geschlossene Tickets: `start_quest` als siebte Aktion in 01, und `against: Option<CreatureRef>` plus `events: Vec<Event>` in 07.
|
- [08 — Event- und Trigger-System](issues/08-event-trigger-system.md) ([#9](https://gitlab.hive-brain.de/MDietermann/rustkeep/issues/9)) — **Der Trigger ist die vierte Wirkungsform** neben Modifikator, Aktion und Fähigkeit: `{ on, condition, actions }` darf überall stehen, wo `modifiers` und `actions` stehen — sonst entstünde dieselbe Maschine ein zweites Mal in 14 als `on_hit`. Eine Bedingungsgrammatik für Trigger *und* Modifikatoren: getaggtes Enum, Liste ist UND, `not` je Eintrag, **kein ODER** (zwei Einträge oder ein gemeinsames Tag). Neun feste Events ohne Namensraum, jedes mit `source`/`target`; `attack_hit` und `damage_taken` bleiben getrennt, weil der eine beim Angreifer und der andere beim Getroffenen hängt. Im Trigger ist `self` immer der Träger. **Warteschlange statt synchron** — synchrones Feuern wäre ein Borrow-Fehler (über `self.quests` iterieren, während `self.apply` läuft) — mit Zähler bei 100 Events pro Zug statt Zyklengraph. Trigger werden gesucht, nicht indiziert. **Quest = Trigger mit `count`**, siebte Registry, erledigte bleiben markiert stehen. Zwei Nachträge an geschlossene Tickets: `start_quest` als siebte Aktion in 01, und `against: Option<CreatureRef>` plus `events: Vec<Event>` in 07.
|
||||||
|
- [11 — UI-Gerüst und Screen-Modell](issues/11-ui-geruest-screen-modell.md) ([#12](https://gitlab.hive-brain.de/MDietermann/rustkeep/issues/12)) — **„Aktion" hiess zwei Dinge**: `Action` bleibt das TOML-Effektvokabular aus 01, `Command` wird das UI-Kommando, Eingang `Game::execute(cmd, reg)` — die eine Stelle, an der ein Zug endet (Modifikatoren ticken, Event-Warteschlange leerarbeiten). Zwölf Commands, **alle kosten einen Zug** (ein `costs_turn`-Flag waere eine Ausnahmeliste); Angriff und Flucht sind keine Varianten, sondern `UseAbility("core:attack")` und `UseAbility("core:flee")` — damit moddbar. Ein gemeinsamer `Vec<Screen>` fuer Screens und Popups; Screens **geben `Response` zurueck statt selbst zu schieben**, sonst haelt ein Screen ein `&mut` auf die `Vec`, in der er liegt. Ein `Response::Command` schliesst alle Overlays — dasselbe Flag, das schon fuers Rendern existiert. Zehn Screens, `ListState` in der Variante (der Stack erhaelt den Cursor gratis, solange der Screen liegt). Nur `KeyEventKind::Press`: bei `Repeat` bestimmte die Tastaturwiederholrate die Spielzeit; gegen zaehes Laufen hilft ein Renn-Kommando in `game/`. Tastenbelegung fest, Pfeile und `hjkl`. ratatui-Freiheit von `game/` prueft ein `#[test]` statt eines Workspace. Nachtrag an 01: `symbol` traegt das Zeichen und einen Farbnamen selbst — `ui/theme.rs` ist Code und damit fuer Modder unerreichbar.
|
||||||
|
|
||||||
## Not yet specified
|
## Not yet specified
|
||||||
|
|
||||||
- **Balancing** — konkrete Zahlen für Attribute, Schaden, Preise und Erfahrung über fünf Etagen. Wartet auf Kampfformeln (14), Progression (15) und Loot (16); vorher gibt es nichts zu balancieren.
|
- **Balancing** — konkrete Zahlen für Attribute, Schaden, Preise und Erfahrung über fünf Etagen. Wartet auf Kampfformeln (14), Progression (15) und Loot (16); vorher gibt es nichts zu balancieren.
|
||||||
- **Boss-Design** — ob Bosse nur Gegner mit besseren Werten sind oder eigene Mechanik brauchen (Phasen, Skripte). Berührt Stufe (c) des Mod-Supports.
|
- **Boss-Design** — ob Bosse nur Gegner mit besseren Werten sind oder eigene Mechanik brauchen (Phasen, Skripte). Berührt Stufe (c) des Mod-Supports.
|
||||||
- **NPC- und Handelsmodell** — Warenbestand, Dialogdaten. Wartet auf das Event-System (08). Die Preisformel steht bereits in 07; weil 07 Backtracking ausgeschlossen hat, muss ein Händler auf **jeder** Etage erreichbar sein.
|
- **NPC- und Handelsmodell** — Warenbestand, Dialogdaten. Wartet auf das Event-System (08). Die Preisformel steht bereits in 07; weil 07 Backtracking ausgeschlossen hat, muss ein Händler auf **jeder** Etage erreichbar sein.
|
||||||
- **Inventar-UX** — Slots, Gewicht oder Kapazität, Sortierung, Vergleichsansicht. Wartet jetzt auf das Screen-Modell (11), nicht mehr auf 06.
|
- **Inventar-UX** — Gewicht oder Kapazität (`carry_capacity` ist seit 01 ein Attribut ohne Regel), Sortierung, Vergleichsansicht. 11 hat nur den Screen und die Commands festgelegt, nicht was darin steht.
|
||||||
- **Mod-Verteilung** — durch 03 auf „Ordner ins Profil entpacken" geschrumpft, ohne Versionsprüfung. Offen ist nur noch, ob 1.0 mehr braucht.
|
- **Mod-Verteilung** — durch 03 auf „Ordner ins Profil entpacken" geschrumpft, ohne Versionsprüfung. Offen ist nur noch, ob 1.0 mehr braucht.
|
||||||
|
|
||||||
## Out of scope
|
## Out of scope
|
||||||
|
|||||||
@@ -40,6 +40,15 @@ Beispiele: „12 Schaden zufügen", „20 Leben heilen", „50 Gold geben", „G
|
|||||||
Eine Aktion kann einen befristeten [Modifikator](#modifikator) erzeugen — so hängen die beiden
|
Eine Aktion kann einen befristeten [Modifikator](#modifikator) erzeugen — so hängen die beiden
|
||||||
Begriffe zusammen, ohne dasselbe zu sein.
|
Begriffe zusammen, ohne dasselbe zu sein.
|
||||||
|
|
||||||
|
## Command
|
||||||
|
|
||||||
|
Ein Kommando der Oberfläche an das Spiel — „geh nach Norden", „leg das an", „kauf drei Tränke".
|
||||||
|
**Nicht dasselbe wie eine [Aktion](#aktion)**, und der Unterschied ist der Grund für den englischen
|
||||||
|
Namen: Eine Aktion ist Effektvokabular aus einer TOML, ein Command kommt von einem Tastendruck.
|
||||||
|
|
||||||
|
Jeder Command kostet einen [Zug](#zug), auch Handel — es gibt keine Ausnahmeliste. Bildschirme zu
|
||||||
|
öffnen ist dagegen kein Command, sondern reine Oberfläche und fasst den Spielzustand nicht an.
|
||||||
|
|
||||||
## Fähigkeit
|
## Fähigkeit
|
||||||
|
|
||||||
Ein benanntes, wiederholt auslösbares Angebot an den Spieler, das [Aktionen](#aktion) ausführt.
|
Ein benanntes, wiederholt auslösbares Angebot an den Spieler, das [Aktionen](#aktion) ausführt.
|
||||||
|
|||||||
Reference in New Issue
Block a user