Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions webapp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,27 @@ This service ports the Discord AdventureBot experience to a standalone web stack
- `GET /health` returns an immediate OK payload to verify the process is running.
- `GET /ready` performs a lightweight database ping against the configured MariaDB instance.

## Game session prototype
## In-browser lobby prototype
You can now try the lobby and session flows directly from the server without extra tooling. Start the dev server (`npm run dev` from `webapp/`) and open [http://localhost:3000](http://localhost:3000) to load a static UI that exercises the APIs:

- Create new lobbies with difficulty, join rules, optional passwords, and max player counts.
- Difficulty options are loaded from the database seed values (Easy, Medium, Hard, Crazy Catto) instead of hard-coded lists.
- View the list of active rooms, copy session IDs, and prefill the join inspector.
- Post lobby chat messages (optionally tagged to a session) and see the chat feed update.
- Join rooms, then load a session to inspect players, recent log entries, and grid size.

## Game session prototype APIs
Early web game APIs are exposed under `/api` and use in-memory state to start experimenting with browser gameplay flows:

- `POST /api/sessions` — create a new dungeon run with an owner name and optional difficulty (`easy`, `normal`, `hard`). Returns the session ID and owner player ID.
- `GET /api/difficulties` — surface the difficulty definitions mirrored from the database (Easy, Medium, Hard, Crazy Catto) with floor sizing, enemy chances, and basement tuning.
- `POST /api/sessions` — create a new dungeon run with an owner name and optional difficulty (`easy`, `medium`, `hard`, `crazy_catto`). Returns the session ID and owner player ID.
- `POST /api/sessions/:sessionId/join` — join an existing run by session ID and player name. Responds with the joining player ID plus the updated session state.
- `GET /api/sessions/:sessionId` — fetch the latest session state (players, turn order, log, and grid size).
- `POST /api/sessions/:sessionId/actions/move` — move the active player north/south/east/west. Enforces turn order and appends a descriptive log entry for the discovered room type.

Sessions now support lobby-style controls: optional passwords, configurable maximum party size, and a toggle that allows or blocks mid-dungeon joins once a run begins. Live sessions report their status (`waiting` or `in_progress`), whether a password is required, and how many seats remain.

## Lobby and cyber chat prototype
## Lobby and cyber chat prototype APIs
The lobby surfaces an in-memory chat feed alongside the list of joinable rooms to help players coordinate:

- `GET /api/lobby` — fetch the current lobby snapshot (chat messages annotated with session summaries and the live room list).
Expand Down
131 changes: 131 additions & 0 deletions webapp/public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>AdventureBot Web Lobby</title>
<link rel="stylesheet" href="/styles.css" />
</head>
<body>
<header>
<h1>AdventureBot Web Lobby</h1>
<p>Prototype web interface for creating and joining dungeon runs.</p>
<div id="status"></div>
</header>

<main>
<section class="panel">
<h2>Create a Lobby</h2>
<form id="create-room-form">
<div class="field">
<label for="ownerName">Owner name</label>
<input id="ownerName" name="ownerName" type="text" required />
</div>

<div class="field">
<label for="difficulty">Difficulty</label>
<select id="difficulty" name="difficulty">
<option disabled selected>Loading difficulties…</option>
</select>
</div>

<div class="field">
<label for="maxPlayers">Max players</label>
<input id="maxPlayers" name="maxPlayers" type="number" min="1" max="10" value="4" />
</div>

<div class="field checkbox">
<input id="allowJoinMidgame" name="allowJoinMidgame" type="checkbox" checked />
<label for="allowJoinMidgame">Allow join mid-dungeon</label>
</div>

<div class="field">
<label for="password">Password (optional)</label>
<input id="password" name="password" type="password" placeholder="min 4 characters" />
</div>

<button type="submit">Create lobby</button>
</form>
<div id="create-room-result" class="result"></div>
</section>

<section class="panel">
<h2>Dungeon settings (mirrors database)</h2>
<p class="muted">Difficulties and room types come from AdventureBot's database tables, not hard-coded defaults.</p>
<div id="difficulty-cards" class="grid"></div>
<div id="legend" class="legend"></div>
</section>

<section class="panel">
<h2>Lobby Rooms</h2>
<button id="refresh-lobby">Refresh lobby</button>
<div id="rooms"></div>
</section>

<section class="panel">
<h2>Lobby Chat</h2>
<div id="chat" class="scrollable"></div>
<form id="chat-form">
<div class="field">
<label for="chat-author">Name</label>
<input id="chat-author" name="chat-author" type="text" required />
</div>
<div class="field">
<label for="chat-body">Message</label>
<input id="chat-body" name="chat-body" type="text" required />
</div>
<div class="field">
<label for="chat-session">Session ID (optional)</label>
<input id="chat-session" name="chat-session" type="text" placeholder="Session to link" />
</div>
<button type="submit">Send message</button>
</form>
</section>

<section class="panel">
<h2>Join a Session</h2>
<form id="join-form">
<div class="field">
<label for="join-session-id">Session ID</label>
<input id="join-session-id" name="join-session-id" type="text" required />
</div>
<div class="field">
<label for="join-name">Player name</label>
<input id="join-name" name="join-name" type="text" required />
</div>
<div class="field">
<label for="join-password">Password (if required)</label>
<input id="join-password" name="join-password" type="password" />
</div>
<button type="submit">Join session</button>
</form>
<div id="join-result" class="result"></div>
</section>

<section class="panel">
<h2>Session State</h2>
<form id="load-session-form">
<div class="field">
<label for="session-id">Session ID</label>
<input id="session-id" name="session-id" type="text" required />
</div>
<button type="submit">Load session</button>
</form>
<div id="session"></div>
</section>
</main>

<template id="room-template">
<div class="room-card">
<div class="room-heading">
<strong class="room-owner"></strong>
<span class="room-meta"></span>
</div>
<div class="room-body"></div>
<button class="join-room">Copy Session ID</button>
</div>
</template>

<script src="/main.js" type="module"></script>
</body>
</html>
Loading
Loading