combat
This commit is contained in:
BIN
apps/web/public/assets/hud-elements/x.png
Normal file
BIN
apps/web/public/assets/hud-elements/x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
@@ -1,6 +1,6 @@
|
||||
<section class="combat" aria-label="Kampf">
|
||||
@if (combat(); as combat) {
|
||||
<div class="combat__stage" [class.combat__stage--shaken]="phase() === 'hit'">
|
||||
<div class="combat__stage" [class.combat__stage--shaken]="stageShake()">
|
||||
<header class="combat__status">
|
||||
<div class="fighter fighter--player">
|
||||
<img class="fighter__icon" [src]="playerIcon" alt="" />
|
||||
|
||||
@@ -20,7 +20,12 @@
|
||||
container-type: inline-size;
|
||||
grid-template-rows: auto minmax(0, 1fr) auto;
|
||||
gap: var(--ar-space-4);
|
||||
min-block-size: 26rem;
|
||||
// The sprites are sized as a share of the stage, so the stage has to carry a
|
||||
// height of its own. With only a min-block-size the tallest cut-out -- the
|
||||
// road bandit -- sized the battlefield row from its intrinsic height and
|
||||
// pushed the page into a scrollbar. The subtracted 12.5rem is the shell
|
||||
// chrome around the main column: top bar, footer and its own padding.
|
||||
block-size: max(24rem, calc(100dvh - 12.5rem));
|
||||
padding: var(--ar-space-4);
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--ar-border);
|
||||
@@ -182,7 +187,11 @@
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: grid;
|
||||
// The single row is spelled out rather than left implicit: only then is it a
|
||||
// definite height, and only then do the sprites' percentage heights resolve
|
||||
// against the battlefield instead of against their own artwork.
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-rows: minmax(0, 1fr);
|
||||
align-items: end;
|
||||
min-block-size: 0;
|
||||
}
|
||||
@@ -602,7 +611,7 @@
|
||||
}
|
||||
|
||||
.combat__stage {
|
||||
min-block-size: clamp(24rem, 55vh, 34rem);
|
||||
block-size: clamp(20rem, 55dvh, 34rem);
|
||||
}
|
||||
|
||||
.combat__log {
|
||||
|
||||
@@ -162,7 +162,8 @@ describe('CombatPageComponent', () => {
|
||||
expect(sprite?.classList.contains('sprite--hit')).toBe(true);
|
||||
expect(monster?.classList.contains('sprite--lunge')).toBe(true);
|
||||
expect(monster?.classList.contains('sprite--flinch')).toBe(false);
|
||||
expect(stage?.classList.contains('combat__stage--shaken')).toBe(true);
|
||||
// The stage jolt is wired up but no longer fires on an ordinary hit.
|
||||
expect(stage?.classList.contains('combat__stage--shaken')).toBe(false);
|
||||
expect(element.textContent).toContain('90 / 100');
|
||||
expect(countOccurrences(element.textContent, monsterHitLine)).toBe(2);
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ const SWING_MS = 540;
|
||||
const RECOIL_MS = 540;
|
||||
// Beat between the player's blow landing and the monster striking back.
|
||||
const RIPOSTE_DELAY_MS = 260;
|
||||
// Length of the stage jolt keyframes, see `stage-shake` in the stylesheet.
|
||||
const STAGE_SHAKE_MS = 200;
|
||||
|
||||
@Component({
|
||||
selector: 'app-combat-page',
|
||||
@@ -47,9 +49,15 @@ export class CombatPageComponent implements OnInit {
|
||||
private readonly displayed = signal<Combat | null>(null);
|
||||
private readonly replaying = signal(false);
|
||||
|
||||
// The stage jolt stays wired up but is no longer fired by an ordinary hit --
|
||||
// it was too much for every single round. Call `shakeStage()` to bring it
|
||||
// back for a specific ability.
|
||||
private readonly stageShaking = signal(false);
|
||||
|
||||
protected readonly combat = this.displayed.asReadonly();
|
||||
protected readonly phase = signal<CombatPhase>('idle');
|
||||
protected readonly monsterPhase = signal<MonsterPhase>('idle');
|
||||
protected readonly stageShake = this.stageShaking.asReadonly();
|
||||
protected readonly busy = computed(() => this.replaying() || this.combatStore.actionPending());
|
||||
protected readonly playerIcon = PLAYER_ICON;
|
||||
|
||||
@@ -125,6 +133,16 @@ export class CombatPageComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
/** Jolts the whole stage once. Reserved for abilities; no attack triggers it. */
|
||||
protected shakeStage(): void {
|
||||
this.stageShaking.set(true);
|
||||
setTimeout(() => {
|
||||
if (!this.destroyed) {
|
||||
this.stageShaking.set(false);
|
||||
}
|
||||
}, STAGE_SHAKE_MS);
|
||||
}
|
||||
|
||||
protected retry(): void {
|
||||
void this.loadFromRoute();
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
<div class="app-shell">
|
||||
<app-top-bar [character]="worldStore.character()" />
|
||||
|
||||
<div class="app-shell__content">
|
||||
<div class="app-shell__content" [class.app-shell__content--no-context]="inCombat()">
|
||||
<app-side-navigation />
|
||||
<main class="app-shell__main" aria-label="Spielinhalt">
|
||||
<router-outlet />
|
||||
</main>
|
||||
@if (!inCombat()) {
|
||||
<app-context-panel />
|
||||
}
|
||||
</div>
|
||||
|
||||
<app-game-footer />
|
||||
|
||||
@@ -16,6 +16,12 @@
|
||||
min-block-size: 0;
|
||||
}
|
||||
|
||||
// Without the context rail the main column takes its place. The narrow layouts
|
||||
// below re-declare the template, so they keep working either way.
|
||||
.app-shell__content--no-context {
|
||||
grid-template-columns: minmax(11rem, 13rem) minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.app-shell__main {
|
||||
min-inline-size: 0;
|
||||
min-block-size: 0;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
import { Router, RouterOutlet, isActive } from '@angular/router';
|
||||
import { WorldStore } from '../../features/world/world.store';
|
||||
import { ContextPanelComponent } from '../context-panel/context-panel.component';
|
||||
import { GameFooterComponent } from '../game-footer/game-footer.component';
|
||||
@@ -20,4 +20,8 @@ import { TopBarComponent } from '../top-bar/top-bar.component';
|
||||
})
|
||||
export class AppShellComponent {
|
||||
protected readonly worldStore = inject(WorldStore);
|
||||
|
||||
// The fight has its own log rail and wants the width, and the area info
|
||||
// belongs to the world view anyway, so the rail is dropped during combat.
|
||||
protected readonly inCombat = isActive('/combat', inject(Router));
|
||||
}
|
||||
|
||||
1916
docs/Ashen_Realms_Story_Narrative_Implementation_V1.md
Normal file
1916
docs/Ashen_Realms_Story_Narrative_Implementation_V1.md
Normal file
File diff suppressed because it is too large
Load Diff
BIN
docs/references/verbrannte_strasse_in_den_aschenfeldern.png
Normal file
BIN
docs/references/verbrannte_strasse_in_den_aschenfeldern.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 MiB |
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,921 @@
|
||||
# Ashen Realms – Local Location View Design Specification V1
|
||||
|
||||
## Zweck
|
||||
|
||||
Dieses Dokument definiert die dauerhaften Design- und Content-Regeln für die **lokale Ortsansicht** von Ashen Realms.
|
||||
|
||||
Die Ortsansicht bildet die fehlende Weltebene zwischen der globalen Karte und spezialisierten Aktivitäten wie Jagd, Kampf, Händler, Quests, Dungeons oder Bossen.
|
||||
|
||||
Sie beantwortet dem Spieler unmittelbar vier Fragen:
|
||||
|
||||
1. **Wo bin ich?**
|
||||
2. **Wie sieht dieser Ort aus und wie fühlt er sich an?**
|
||||
3. **Wer oder was befindet sich hier?**
|
||||
4. **Was kann ich hier tun?**
|
||||
|
||||
Diese Spezifikation soll auch für zukünftige Gebiete und Orte gültig bleiben. Einzelne Orte dürfen sich visuell und spielerisch deutlich unterscheiden, verwenden aber dieselbe grundlegende Struktur und dasselbe Interaktionsmodell.
|
||||
|
||||
---
|
||||
|
||||
# 1. Rolle im Kernloop
|
||||
|
||||
Die lokale Ortsansicht wird zum normalen Ankunfts- und Ausgangsscreen, solange sich der Charakter physisch an einem Ort befindet.
|
||||
|
||||
Empfohlener Ablauf:
|
||||
|
||||
```text
|
||||
Karte
|
||||
→ Reise
|
||||
→ Ortsansicht
|
||||
→ Aktivität
|
||||
→ Jagd
|
||||
→ NPC
|
||||
→ Untersuchung
|
||||
→ Händler
|
||||
→ Quest
|
||||
→ Boss / Dungeon
|
||||
→ zurück zur Ortsansicht
|
||||
```
|
||||
|
||||
Die Karte beantwortet:
|
||||
|
||||
**Wohin kann ich reisen?**
|
||||
|
||||
Die Ortsansicht beantwortet:
|
||||
|
||||
**Was gibt es hier?**
|
||||
|
||||
Die Jagd beantwortet:
|
||||
|
||||
**Was kann ich hier bekämpfen?**
|
||||
|
||||
Der Kampf beantwortet:
|
||||
|
||||
**Wie besiege ich diesen Gegner?**
|
||||
|
||||
Diese Verantwortlichkeiten sollen getrennt bleiben.
|
||||
|
||||
---
|
||||
|
||||
# 2. Position in der Navigation
|
||||
|
||||
Die persistente linke Navigation erhält einen eigenen Eintrag:
|
||||
|
||||
```text
|
||||
Ort
|
||||
Karte
|
||||
Jagd
|
||||
Quests
|
||||
Inventar
|
||||
Charakter
|
||||
Shop
|
||||
```
|
||||
|
||||
`Ort` ist aktiv hervorgehoben, solange der Spieler die lokale Ortsansicht betrachtet.
|
||||
|
||||
Der Spieler soll grundsätzlich jederzeit zu dieser Ansicht zurückkehren können, sofern kein blockierender Gameplay-Zustand aktiv ist, beispielsweise ein noch nicht abgeschlossener Kampf.
|
||||
|
||||
---
|
||||
|
||||
# 3. Ziel des Spielerlebnisses
|
||||
|
||||
Ein Ort muss sich wie ein **Ort** anfühlen und nicht wie ein Datensatz oder Menüpunkt.
|
||||
|
||||
Der Screen soll beim Spieler das Gefühl erzeugen:
|
||||
|
||||
> Ich befinde mich gerade hier. Das ist meine Umgebung. Diese Personen und interessanten Punkte befinden sich hier. Von hier aus entscheide ich, was ich als Nächstes tue.
|
||||
|
||||
Die Ortsansicht ist deshalb kein Dashboard aus vielen kleinen Karten.
|
||||
|
||||
Das zentrale Artwork ist die wichtigste Präsentationsebene.
|
||||
|
||||
UI liegt darum herum oder gezielt darüber.
|
||||
|
||||
---
|
||||
|
||||
# 4. Grundaufbau des Screens
|
||||
|
||||
Jede Ortsansicht verwendet den bestehenden Ashen-Realms-App-Shell:
|
||||
|
||||
- persistente Topbar
|
||||
- persistente linke Navigation
|
||||
- große zentrale Artwork-Fläche
|
||||
- kontextuelle rechte Sidebar
|
||||
- persistenter Footer / Weltstatus
|
||||
|
||||
Der eigentliche Ortsinhalt besteht aus fünf funktionalen Ebenen.
|
||||
|
||||
## 4.1 Ortskopf
|
||||
|
||||
Zeigt:
|
||||
|
||||
- Ortsname
|
||||
- Gebiet / Region als Breadcrumb
|
||||
- kurze atmosphärische Beschreibung
|
||||
|
||||
Beispiel:
|
||||
|
||||
```text
|
||||
Verbrannte Straße
|
||||
Gebiet 1 > Aschenfelder
|
||||
|
||||
Ein alter Handelsweg, der durch Feuer und Krieg in Asche gelegt wurde.
|
||||
```
|
||||
|
||||
Die Beschreibung sollte meist in 1–3 kurzen Zeilen auskommen.
|
||||
|
||||
Längere Lore gehört in Dialoge, Quests, Bücher oder eigene Lore-Inhalte.
|
||||
|
||||
---
|
||||
|
||||
## 4.2 Großes Orts-Artwork
|
||||
|
||||
Das Orts-Artwork ist das visuelle Zentrum des Screens.
|
||||
|
||||
Es soll vermitteln:
|
||||
|
||||
- Biom
|
||||
- lokale Gefahr
|
||||
- Wetter / Atmosphäre
|
||||
- Architektur
|
||||
- Spuren vergangener Ereignisse
|
||||
- wichtige Landmarken
|
||||
|
||||
Beispiele:
|
||||
|
||||
### Aschenfelder
|
||||
- verbrannte Straßen
|
||||
- Asche
|
||||
- Glut
|
||||
- tote Bäume
|
||||
- zerstörte Wagen
|
||||
- Rauch
|
||||
|
||||
### Dämmerwald
|
||||
- dichte Vegetation
|
||||
- Nebel
|
||||
- dunkles Blätterdach
|
||||
- überwucherte Ruinen
|
||||
- Spuren verdorbener Tiere
|
||||
|
||||
### Vergessene Ruinen
|
||||
- alter Stein
|
||||
- Gräber
|
||||
- eingestürzte Mauern
|
||||
- Banner
|
||||
- Krypteneingänge
|
||||
- kaltes magisches Licht
|
||||
|
||||
Interaktionsbeschriftungen dürfen **nicht fest in das Artwork eingebrannt** sein.
|
||||
|
||||
Marker und Labels werden durch die UI gerendert.
|
||||
|
||||
---
|
||||
|
||||
# 5. Points of Interest und Hotspots
|
||||
|
||||
Ein Ort kann direkt auf dem Artwork interaktive **Points of Interest (POIs)** besitzen.
|
||||
|
||||
Ein POI besteht aus:
|
||||
|
||||
- Icon
|
||||
- Titel
|
||||
- optionalem kurzen Aktionslabel
|
||||
- normalisierter X-/Y-Position im Artwork
|
||||
- Interaktionstyp
|
||||
- optionalem Verfügbarkeitszustand
|
||||
|
||||
Beispiel:
|
||||
|
||||
```text
|
||||
[Truhen-Icon]
|
||||
Verlassener Wagen
|
||||
Durchsuchen
|
||||
```
|
||||
|
||||
POIs sollen sich optisch in die Szene integrieren.
|
||||
|
||||
Der Screen darf dadurch nicht zu einem Hidden-Object-Spiel werden.
|
||||
|
||||
Empfohlene sichtbare Anzahl:
|
||||
|
||||
- einfacher Übergangsort: 1–3
|
||||
- normaler Ort: 2–5
|
||||
- großer Hub: 3–7
|
||||
|
||||
Wenn deutlich mehr Aktionen notwendig sind, müssen sie gruppiert oder in eigene Panels/Screens ausgelagert werden.
|
||||
|
||||
---
|
||||
|
||||
# 6. Wiederverwendbare Interaktionstypen
|
||||
|
||||
Die erste gemeinsame Interaktionssprache lautet:
|
||||
|
||||
```text
|
||||
HUNT
|
||||
INVESTIGATE
|
||||
SEARCH
|
||||
NPC
|
||||
MAP
|
||||
TRAVEL
|
||||
SHOP
|
||||
QUEST
|
||||
BOSS
|
||||
DUNGEON
|
||||
```
|
||||
|
||||
Nicht jeder Typ muss bereits im ersten Slice vollständig umgesetzt sein.
|
||||
|
||||
Wichtig ist, dass neue Orte aus wiederverwendbaren Interaktionstypen aufgebaut werden und nicht jeweils eigene Angular-Spezialkomponenten erhalten.
|
||||
|
||||
## 6.1 HUNT
|
||||
|
||||
Zweck:
|
||||
|
||||
Startet die normale Jagd-/Encounter-Schleife des aktuellen Ortes.
|
||||
|
||||
Ablauf:
|
||||
|
||||
```text
|
||||
Ortsansicht
|
||||
→ Jagd
|
||||
```
|
||||
|
||||
Die Ortsansicht würfelt oder rendert selbst keine Encounter-Auswahl.
|
||||
|
||||
---
|
||||
|
||||
## 6.2 INVESTIGATE
|
||||
|
||||
Zweck:
|
||||
|
||||
Untersucht Spuren, Ruinen, Symbole, Leichen, Zeichen oder andere Hinweise in der Umgebung.
|
||||
|
||||
Mögliche Ergebnisse:
|
||||
|
||||
- atmosphärischer Text
|
||||
- Lore-Hinweis
|
||||
- Hinweis auf einen Ort
|
||||
- später Questfortschritt
|
||||
- später versteckte Verbindung
|
||||
|
||||
Für die erste Umsetzung reicht ein serverseitig geliefertes Ergebnis-Panel.
|
||||
|
||||
---
|
||||
|
||||
## 6.3 SEARCH
|
||||
|
||||
Zweck:
|
||||
|
||||
Durchsucht ein konkretes Objekt oder einen kleinen Bereich.
|
||||
|
||||
Beispiele:
|
||||
|
||||
- verlassener Wagen
|
||||
- alte Vorratskiste
|
||||
- Lagerreste
|
||||
- Kryptennische
|
||||
|
||||
Später mögliche Ergebnisse:
|
||||
|
||||
- Item
|
||||
- Währung
|
||||
- Verbrauchsgegenstand
|
||||
- Hinweis
|
||||
- nichts
|
||||
|
||||
Sobald eine Interaktion echte Belohnungen vergibt, muss sie serverautoritativ sein.
|
||||
|
||||
Die erste Version darf reine Text-/Informationsresultate verwenden.
|
||||
|
||||
---
|
||||
|
||||
## 6.4 NPC
|
||||
|
||||
Zweck:
|
||||
|
||||
Interaktion mit einem sichtbar am Ort vorhandenen NPC.
|
||||
|
||||
Für V1 reicht ein einfaches Dialogpanel.
|
||||
|
||||
Spätere Erweiterungen können sein:
|
||||
|
||||
- Quests
|
||||
- Händler
|
||||
- Ruf-/Tauschsystem
|
||||
- Dienstleistungen
|
||||
- Fraktionsinteraktionen
|
||||
|
||||
NPCs sollen möglichst im Kontext der Szene sichtbar sein und nicht ausschließlich als Textliste in einem Panel erscheinen.
|
||||
|
||||
---
|
||||
|
||||
## 6.5 MAP
|
||||
|
||||
Zweck:
|
||||
|
||||
Öffnet die bestehende Karten-/Reiseansicht.
|
||||
|
||||
```text
|
||||
Ortsansicht
|
||||
→ Karte
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6.6 TRAVEL
|
||||
|
||||
Reisen bleibt Bestandteil des bestehenden Karten-/Reisesystems.
|
||||
|
||||
Die Ortsansicht darf visuell Ausgänge oder Ziele zeigen, soll aber im Normalfall in den vorhandenen Reiseflow weiterleiten statt eine zweite Reiselogik zu bauen.
|
||||
|
||||
---
|
||||
|
||||
## 6.7 SHOP, QUEST, BOSS, DUNGEON
|
||||
|
||||
Diese Typen sind Erweiterungspunkte für späteren Content.
|
||||
|
||||
Sie verwenden dieselben POI- und Aktionsregeln, öffnen aber jeweils einen eigenen Screen, ein Panel oder einen spezialisierten Flow.
|
||||
|
||||
---
|
||||
|
||||
# 7. Primäre Aktionsleiste
|
||||
|
||||
Die wichtigsten lokalen Aktionen werden zusätzlich in einer großen Aktionsleiste unterhalb des Artworks dargestellt.
|
||||
|
||||
Diese Dopplung ist beabsichtigt.
|
||||
|
||||
POIs erzeugen Atmosphäre und räumlichen Kontext.
|
||||
|
||||
Die Aktionsleiste sorgt für klare Bedienbarkeit.
|
||||
|
||||
Empfohlenes Maximum:
|
||||
|
||||
**4 primäre Ortsaktionen**
|
||||
|
||||
Beispiel:
|
||||
|
||||
```text
|
||||
[Jagd beginnen]
|
||||
[Spuren untersuchen]
|
||||
[Umgebung durchsuchen]
|
||||
[Zur Karte]
|
||||
```
|
||||
|
||||
Sekundäre Aktionen dürfen ausschließlich als POI oder in der rechten Sidebar erscheinen.
|
||||
|
||||
---
|
||||
|
||||
# 8. Rechte Kontext-Sidebar
|
||||
|
||||
Die rechte Sidebar fasst die spielerische Bedeutung des aktuellen Ortes zusammen.
|
||||
|
||||
Empfohlene Bereiche:
|
||||
|
||||
## Ortsidentität
|
||||
|
||||
- Gebiet / Region
|
||||
- Ortsname
|
||||
- Ortstyp
|
||||
|
||||
## Progressionskontext
|
||||
|
||||
- empfohlener Fortschrittsbereich oder Empfehlung
|
||||
- relative Gefahr
|
||||
|
||||
Diese Information darf keine harte Zugangssperre sein.
|
||||
|
||||
Der bestehende Ashen-Realms-Grundsatz bleibt:
|
||||
|
||||
> Die Welt kommuniziert Gefahr, ohne Experimente künstlich zu verbieten.
|
||||
|
||||
## Mögliche Begegnungen
|
||||
|
||||
Zeigt repräsentative Gegner oder Encounter-Kategorien.
|
||||
|
||||
Das ist nur Vorschauinformation.
|
||||
|
||||
Der tatsächliche Encounter-Wurf erfolgt weiterhin im Jagdsystem.
|
||||
|
||||
## Verfügbare Interaktionen
|
||||
|
||||
Beispiele:
|
||||
|
||||
- Jagd
|
||||
- Untersuchen
|
||||
- Durchsuchen
|
||||
- Sprechen
|
||||
|
||||
## Mögliche Belohnungen
|
||||
|
||||
Optionale Vorschau-Icons für:
|
||||
|
||||
- Ausrüstung
|
||||
- Materialien
|
||||
- Verbrauchsgegenstände
|
||||
- Handelswaren
|
||||
- regionsspezifische Belohnungen
|
||||
|
||||
Es dürfen keine exakten Belohnungen versprochen werden, wenn der zugrunde liegende Content diese nicht garantiert.
|
||||
|
||||
---
|
||||
|
||||
# 9. Ortstypen
|
||||
|
||||
Orte können über wiederverwendbare Typen ihre grundlegende Rolle ausdrücken.
|
||||
|
||||
Empfohlene Startwerte:
|
||||
|
||||
```text
|
||||
SAFE_HUB
|
||||
TRANSITION
|
||||
HUNTING_GROUND
|
||||
QUEST_LOCATION
|
||||
OUTPOST
|
||||
ELITE_ZONE
|
||||
BOSS_LOCATION
|
||||
DUNGEON_ENTRANCE
|
||||
```
|
||||
|
||||
Der Typ beeinflusst Präsentation und verfügbare Aktionen, benötigt aber keine eigene Page-Implementierung.
|
||||
|
||||
Beispiele:
|
||||
|
||||
### Südtor von Graufurt
|
||||
|
||||
```text
|
||||
TRANSITION
|
||||
```
|
||||
|
||||
Fokus:
|
||||
|
||||
- Wachposten
|
||||
- Reise
|
||||
- Gebietsinformation
|
||||
- wenig oder keine reguläre Jagd
|
||||
|
||||
### Verbrannte Straße
|
||||
|
||||
```text
|
||||
HUNTING_GROUND
|
||||
```
|
||||
|
||||
Fokus:
|
||||
|
||||
- Jagd
|
||||
- Umgebungsinformationen
|
||||
- Spuren
|
||||
- erste NPC-Begegnung
|
||||
|
||||
### Verlassener Wachtposten
|
||||
|
||||
```text
|
||||
OUTPOST / QUEST_LOCATION
|
||||
```
|
||||
|
||||
Fokus:
|
||||
|
||||
- NPC
|
||||
- stärkere Jagd
|
||||
- Untersuchung
|
||||
- Storyfortschritt
|
||||
|
||||
### Aschengrube
|
||||
|
||||
```text
|
||||
ELITE_ZONE / BOSS_LOCATION
|
||||
```
|
||||
|
||||
Fokus:
|
||||
|
||||
- Gefahr
|
||||
- Elite-/Bosszugang
|
||||
- kaum zivile Interaktionen
|
||||
|
||||
---
|
||||
|
||||
# 10. Wiederverwendbares Content-Modell
|
||||
|
||||
Die Ortsansicht soll datengetrieben sein.
|
||||
|
||||
Ein konzeptionelles View-Model sollte mindestens enthalten:
|
||||
|
||||
```ts
|
||||
interface LocalLocationView {
|
||||
locationId: string;
|
||||
locationKey: string;
|
||||
name: string;
|
||||
regionName: string;
|
||||
description: string;
|
||||
locationType: LocationType;
|
||||
artworkPath: string;
|
||||
dangerRating: DangerRating;
|
||||
recommendationLabel?: string;
|
||||
huntingEnabled: boolean;
|
||||
pointsOfInterest: LocationPointOfInterest[];
|
||||
primaryActions: LocationAction[];
|
||||
encounterPreview: EncounterPreview[];
|
||||
rewardPreview: RewardPreview[];
|
||||
}
|
||||
```
|
||||
|
||||
Konzeptionelles POI-Modell:
|
||||
|
||||
```ts
|
||||
interface LocationPointOfInterest {
|
||||
key: string;
|
||||
title: string;
|
||||
actionLabel?: string;
|
||||
type: LocationInteractionType;
|
||||
iconKey: string;
|
||||
xPercent: number;
|
||||
yPercent: number;
|
||||
enabled: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
Koordinaten werden als Prozentwerte gespeichert, damit Hotspots beim Skalieren des Artworks an derselben Stelle bleiben.
|
||||
|
||||
Beispiel:
|
||||
|
||||
```text
|
||||
xPercent: 42.5
|
||||
yPercent: 66.0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# 11. Interaktionsergebnisse
|
||||
|
||||
Lokale Interaktionen sollen ein vorhersehbares Ergebnisformat zurückgeben.
|
||||
|
||||
Konzeptionell:
|
||||
|
||||
```ts
|
||||
interface LocationInteractionResult {
|
||||
interactionKey: string;
|
||||
title: string;
|
||||
text: string;
|
||||
nextAction?: {
|
||||
type: string;
|
||||
target?: string;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Die erste Version bleibt bewusst klein.
|
||||
|
||||
Nicht nur für diesen Screen bauen:
|
||||
|
||||
- generische Visual-Novel-Engine
|
||||
- verzweigte Dialogengine
|
||||
- Event-Skriptsprache
|
||||
- komplexen Questgraph
|
||||
|
||||
---
|
||||
|
||||
# 12. Navigationsregeln
|
||||
|
||||
## Nach abgeschlossener Reise
|
||||
|
||||
Der Spieler landet in der lokalen Ortsansicht des neuen aktuellen Ortes.
|
||||
|
||||
```text
|
||||
Reise abgeschlossen
|
||||
→ current location aktualisiert
|
||||
→ Ortsansicht
|
||||
```
|
||||
|
||||
## Nach normalem Kampf
|
||||
|
||||
Empfohlener Standard:
|
||||
|
||||
```text
|
||||
Kampfergebnis / Loot
|
||||
→ Ortsansicht
|
||||
```
|
||||
|
||||
Von dort kann der Spieler erneut jagen.
|
||||
|
||||
## Beim Verlassen der Jagd
|
||||
|
||||
`Zurück` führt zur Ortsansicht.
|
||||
|
||||
## Karte
|
||||
|
||||
`Zur Karte` öffnet die Karte, verändert aber nicht den aktuellen Ort.
|
||||
|
||||
---
|
||||
|
||||
# 13. Screen-Zustände
|
||||
|
||||
Die Ortsansicht muss mindestens folgende Zustände definieren.
|
||||
|
||||
## Loading
|
||||
|
||||
- App-Shell bleibt sichtbar
|
||||
- zurückhaltender Ladezustand im Hauptbereich
|
||||
|
||||
## Loaded
|
||||
|
||||
- Artwork
|
||||
- POIs
|
||||
- Aktionen
|
||||
- Kontext-Sidebar
|
||||
|
||||
## Interaktion geöffnet
|
||||
|
||||
- Ort bleibt im Hintergrund sichtbar
|
||||
- kurze Untersuchungen und einfache NPC-Dialoge öffnen kein komplett neues Seitenlayout
|
||||
|
||||
## Aktion nicht verfügbar
|
||||
|
||||
- sichtbar deaktiviert
|
||||
- optional kurze Erklärung / Tooltip
|
||||
|
||||
## API-Fehler
|
||||
|
||||
- Navigation bleibt benutzbar
|
||||
- kompakter Retry-Zustand
|
||||
|
||||
## Aktiver Kampf
|
||||
|
||||
Wenn der Server einen noch nicht abgeschlossenen Kampf meldet, darf die Ortsansicht nicht zum Umgehen dieses Kampfes genutzt werden.
|
||||
|
||||
Der bestehende Combat-Resume-Flow hat Vorrang.
|
||||
|
||||
---
|
||||
|
||||
# 14. Visuelle Regeln
|
||||
|
||||
Die Ortsansicht folgt vollständig der bestehenden Ashen-Realms-UI-Spezifikation.
|
||||
|
||||
Wichtig:
|
||||
|
||||
- Artwork zuerst
|
||||
- dunkles Metall / Stein / Leder
|
||||
- dezente Goldverzierungen
|
||||
- keine weißen SaaS-Cards
|
||||
- kein Glassmorphism
|
||||
- keine Neon-Dashboard-Optik
|
||||
- Fantasy-Serif für große Überschriften
|
||||
- sehr gut lesbare UI-Schrift für normalen Text
|
||||
- zurückhaltender Glow
|
||||
- eindeutige Interaktionszustände
|
||||
- konsistente Icon-Sprache
|
||||
|
||||
POI-Marker müssen erkennbar sein, dürfen aber das Artwork nicht dominieren.
|
||||
|
||||
Bevorzugt werden kleine runde oder schildartige Fantasy-Marker statt moderner Map-Pins.
|
||||
|
||||
---
|
||||
|
||||
# 15. Responsive Verhalten
|
||||
|
||||
Desktop bleibt das primäre Ziel.
|
||||
|
||||
## Desktop
|
||||
|
||||
- volle linke Navigation
|
||||
- Artwork mit positionierten POIs
|
||||
- rechte Sidebar sichtbar
|
||||
- primäre Aktionsleiste sichtbar
|
||||
|
||||
## Tablet
|
||||
|
||||
- rechte Sidebar darf einklappbar werden
|
||||
- Hauptaktionen bleiben sichtbar
|
||||
- POIs bleiben durch Prozentkoordinaten korrekt verankert
|
||||
|
||||
## Mobile – später
|
||||
|
||||
Nicht V1-Priorität.
|
||||
|
||||
Mögliche spätere Anpassung:
|
||||
|
||||
- Artwork oben
|
||||
- POI-Liste unterhalb des Artworks
|
||||
- rechte Sidebar wird einklappbare Ortsinfo
|
||||
- Aktionen als zweispaltiges Grid
|
||||
|
||||
Das Desktop-Design soll jetzt nicht zugunsten von Mobile kompromittiert werden.
|
||||
|
||||
---
|
||||
|
||||
# 16. Content-Regeln für zukünftige Orte
|
||||
|
||||
Bei jedem neuen Ort werden in dieser Reihenfolge definiert:
|
||||
|
||||
1. **Zweck des Ortes**
|
||||
2. **Visuelle Szene**
|
||||
3. **Wichtigste Spielerentscheidung**
|
||||
4. **2–5 sinnvolle POIs**
|
||||
5. **Bis zu 4 primäre Aktionen**
|
||||
6. **Encounter-Vorschau, falls relevant**
|
||||
7. **Informationen für die rechte Sidebar**
|
||||
8. **Rückkehr- und Weiterreise-Flow**
|
||||
|
||||
Für jeden relevanten Ort muss beantwortet werden:
|
||||
|
||||
> Warum soll sich der Spieler an diesen Ort erinnern und ihn nicht nur als weiteren Menüpunkt wahrnehmen?
|
||||
|
||||
Mindestens ein identitätsstiftendes Element sollte vorhanden sein:
|
||||
|
||||
- markanter NPC
|
||||
- besondere Landmarke
|
||||
- Untersuchung
|
||||
- spezieller Service
|
||||
- Elitezugang
|
||||
- Bosszugang
|
||||
- ungewöhnlicher Encounter-Pool
|
||||
- Story-Hinweis
|
||||
- visuelles Ereignis
|
||||
|
||||
---
|
||||
|
||||
# 17. Was ausdrücklich nicht gebaut werden soll
|
||||
|
||||
Die Ortsansicht ist kein:
|
||||
|
||||
- frei begehbarer Screen
|
||||
- WASD-Bewegungssystem
|
||||
- Point-and-Click-Adventure
|
||||
- Hidden-Object-Spiel
|
||||
- zweiter Kartenscreen
|
||||
- Ersatz für die Jagd
|
||||
- Ersatz für Quests
|
||||
- universelles Modal für alle Spielsysteme
|
||||
|
||||
Vermeiden:
|
||||
|
||||
- dutzende Hotspots
|
||||
- individuelle Komponenten pro Ort
|
||||
- Kampflogik im Orts-Screen
|
||||
- clientseitige Loot-Rolls
|
||||
- clientseitiger Reiseabschluss
|
||||
- duplizierte Jagdlogik
|
||||
- lange Lore-Textwände direkt auf der Szene
|
||||
|
||||
---
|
||||
|
||||
# 18. V1-Referenzort – Verbrannte Straße
|
||||
|
||||
Die erste Referenzimplementierung ist die **Verbrannte Straße** in den **Aschenfeldern**.
|
||||
|
||||
## Zweck
|
||||
|
||||
Beweisen, dass die Ortsansicht Weltgefühl, Jagd, einfache Exploration und NPC-Präsenz verbinden kann, ohne ein neues komplexes Subsystem zu werden.
|
||||
|
||||
## Visuelle Identität
|
||||
|
||||
- verbrannte Handelsstraße
|
||||
- zerstörter Wagen
|
||||
- aschebedeckter Boden
|
||||
- glühende Risse / Glut
|
||||
- tote Bäume
|
||||
- Wachtstrukturen in der Ferne
|
||||
- Rauch
|
||||
- Spuren früherer Kämpfe
|
||||
|
||||
## POIs
|
||||
|
||||
### Jagdgebiet
|
||||
|
||||
Typ:
|
||||
|
||||
```text
|
||||
HUNT
|
||||
```
|
||||
|
||||
Aktion:
|
||||
|
||||
```text
|
||||
Jagd beginnen
|
||||
```
|
||||
|
||||
### Verdächtige Spuren
|
||||
|
||||
Typ:
|
||||
|
||||
```text
|
||||
INVESTIGATE
|
||||
```
|
||||
|
||||
Aktion:
|
||||
|
||||
```text
|
||||
Untersuchen
|
||||
```
|
||||
|
||||
Beispielresultat:
|
||||
|
||||
> Zwischen Asche und zerbrochenen Steinen erkennst du mehrere frische Stiefelabdrücke. Sie führen nach Osten, in Richtung des verlassenen Wachtpostens.
|
||||
|
||||
### Verlassener Wagen
|
||||
|
||||
Typ:
|
||||
|
||||
```text
|
||||
SEARCH
|
||||
```
|
||||
|
||||
Aktion:
|
||||
|
||||
```text
|
||||
Durchsuchen
|
||||
```
|
||||
|
||||
Beispielresultat für die erste Umsetzung:
|
||||
|
||||
> Der Wagen wurde gründlich geplündert. Zwischen verbrannten Brettern findest du nur leere Kisten und Spuren eines hastigen Aufbruchs.
|
||||
|
||||
In der ersten Implementierung muss diese Aktion noch keine Belohnung vergeben.
|
||||
|
||||
### Verwundeter Kundschafter
|
||||
|
||||
Typ:
|
||||
|
||||
```text
|
||||
NPC
|
||||
```
|
||||
|
||||
Aktion:
|
||||
|
||||
```text
|
||||
Sprechen
|
||||
```
|
||||
|
||||
Beispieldialog:
|
||||
|
||||
> „Die Straße ist nicht mehr sicher. Die Plünderer kommen aus Richtung des alten Wachtpostens. Wenn du weitergehst, halte die Augen offen.“
|
||||
|
||||
Für diese erste NPC-Interaktion ist noch kein Quest-System notwendig.
|
||||
|
||||
## Primäre Aktionen
|
||||
|
||||
```text
|
||||
Jagd beginnen
|
||||
Spuren untersuchen
|
||||
Umgebung durchsuchen
|
||||
Zur Karte
|
||||
```
|
||||
|
||||
## Encounter-Vorschau
|
||||
|
||||
Repräsentative Gegner:
|
||||
|
||||
- Aschenratte
|
||||
- Verwilderter Straßenhund
|
||||
- Straßenräuber
|
||||
- Verkohlter Plünderer
|
||||
|
||||
Die Vorschau ist rein informativ.
|
||||
|
||||
Sie ersetzt nicht den gewichteten Encounter-Pool der Jagd.
|
||||
|
||||
---
|
||||
|
||||
# 19. Visuelle Referenz
|
||||
|
||||
Für dieses Konzept wurde folgender Referenzscreen erzeugt:
|
||||
|
||||
```text
|
||||
verbrannte_strasse_in_den_aschenfeldern.png
|
||||
```
|
||||
|
||||
Der Screenshot definiert Komposition und Zielgefühl, aber keine pixelgenauen Maße.
|
||||
|
||||
Zukünftige Ortsansichten sollen insbesondere beibehalten:
|
||||
|
||||
- denselben App-Shell
|
||||
- dominantes Orts-Artwork
|
||||
- dieselbe POI-Markersprache
|
||||
- primäre Aktionsleiste unten
|
||||
- kontextuelle rechte Sidebar
|
||||
- klare Trennung zwischen Ort, Karte, Jagd und Kampf
|
||||
|
||||
---
|
||||
|
||||
# 20. Definition of Done für zukünftige Orte
|
||||
|
||||
Eine Ortsansicht ist fertig, wenn:
|
||||
|
||||
- aktueller Ort und Region sofort erkennbar sind
|
||||
- das Artwork den Ort eindeutig vermittelt
|
||||
- verfügbare Aktionen klar sind
|
||||
- wichtige NPCs / POIs im Kontext sichtbar sind
|
||||
- POIs beim Skalieren korrekt positioniert bleiben
|
||||
- Jagdaktionen den bestehenden Jagdflow verwenden
|
||||
- Reisen den bestehenden Karten-/Reiseflow verwenden
|
||||
- lokale Interaktionen keine fremden Systeme duplizieren
|
||||
- serverautoritative Aktionen serverautoritativ bleiben
|
||||
- derselbe Komponentenaufbau den nächsten Ort nur über andere Daten rendern kann
|
||||
- der Screen wie ein Bestandteil desselben Ashen-Realms-UI-Systems wirkt
|
||||
|
||||
---
|
||||
|
||||
# 21. Leitprinzip
|
||||
|
||||
> **Die Karte zeigt dem Spieler, wohin er gehen kann. Die Ortsansicht lässt ihn spüren, wo er gerade ist.**
|
||||
|
||||
Jede zukünftige Ortsansicht soll genau diese Trennung stärken.
|
||||
Reference in New Issue
Block a user