Release 2.0.0

Updated display and host
This commit is contained in:
2026-01-03 00:38:52 +01:00
parent 48074f7603
commit b24e43e142
13 changed files with 357 additions and 388 deletions

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "jeopardy", "name": "jeopardy",
"version": "1.0.6", "version": "2.0.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "jeopardy", "name": "jeopardy",
"version": "1.0.6", "version": "2.0.0",
"dependencies": { "dependencies": {
"axios": "^1.12.2", "axios": "^1.12.2",
"cookie": "^1.0.2" "cookie": "^1.0.2"

View File

@@ -1,7 +1,7 @@
{ {
"name": "jeopardy", "name": "jeopardy",
"private": true, "private": true,
"version": "1.0.6", "version": "2.0.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite dev", "dev": "vite dev",

View File

@@ -1,4 +1,4 @@
import type { FullGame, FullWall } from "./games/games"; import type { Game, Wall } from "./Types";
interface Player { interface Player {
name: string; name: string;
@@ -8,10 +8,9 @@ interface Player {
const baseRoute = "/connected/display/running"; const baseRoute = "/connected/display/running";
let players: Player[] = $state([]); let players: Player[] = $state([]);
let currentPlayer: string = $state(""); let currentPlayer: string = $state("");
// eslint-disable-next-line prefer-const let game: Game | undefined = $state();
let game: FullGame | undefined = undefined;
let gameIndex: number = -1; let gameIndex: number = -1;
let wall: FullWall | undefined = undefined; let wall: Wall | undefined = $state();
let wallIndex: number = -1; let wallIndex: number = -1;
export default { export default {
@@ -29,7 +28,7 @@ export default {
currentPlayer = str; currentPlayer = str;
}, },
baseRoute, baseRoute,
get game(): FullGame | undefined { get game(): Game | undefined {
return game; return game;
}, },
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -42,7 +41,7 @@ export default {
set gameIndex(i: number) { set gameIndex(i: number) {
gameIndex = i; gameIndex = i;
}, },
get wall(): FullWall | undefined { get wall(): Wall | undefined {
return wall; return wall;
}, },
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any

View File

@@ -8,7 +8,7 @@ import type {
SimpleQuestion SimpleQuestion
} from "./games/games"; } from "./games/games";
export type VisitedQuestions = number[][]; export type VisitedQuestions = QuestionId[];
export type Directory = { export type Directory = {
name: string; name: string;

View File

@@ -24,10 +24,6 @@
isEditor?: boolean; isEditor?: boolean;
} }
function isVisited(catIndex: number, queIndex: number): boolean {
return visited[catIndex] && visited[catIndex].includes(queIndex);
}
let { wall, onclick, onclickIds, visited, isEditor = false }: Props = $props(); let { wall, onclick, onclickIds, visited, isEditor = false }: Props = $props();
let categories: Category[] = $state([]); let categories: Category[] = $state([]);
@@ -107,10 +103,10 @@
> >
{/if} {/if}
</div> </div>
{#each category.questions as question, queIndex} {#each category.questions as question}
<!-- svelte-ignore a11y_click_events_have_key_events --> <!-- svelte-ignore a11y_click_events_have_key_events -->
<div <div
class="card {isVisited(catIndex, queIndex) ? 'visited' : ''}" class="card {visited.includes(`${question._id}`) ? 'visited' : ''}"
role="button" role="button"
aria-pressed="false" aria-pressed="false"
tabindex="0" tabindex="0"
@@ -125,27 +121,7 @@
{/each} {/each}
{/each} {/each}
{:else} {:else}
{#each wall.categories as category, catIndex} Legacy Not Supported
<div class="flex items-center justify-center text-3xl font-semibold">
<div>{category.name}</div>
</div>
{#each category.questions as question, queIndex}
<!-- svelte-ignore a11y_click_events_have_key_events -->
<div
class="card {isVisited(catIndex, queIndex) ? 'visited' : ''}"
role="button"
aria-pressed="false"
tabindex="0"
onclick={() => {
if (onclick) onclick(catIndex, queIndex);
}}
>
<div class="text-6xl font-thin">
{question.points >= 0 ? question.points : "???"}
</div>
</div>
{/each}
{/each}
{/if} {/if}
</div> </div>
{:else} {:else}

View File

@@ -2,29 +2,17 @@
let { children } = $props(); let { children } = $props();
import { error } from "@sveltejs/kit"; import { error } from "@sveltejs/kit";
import games from "$lib/games/games"; // import games from "$lib/games/games";
import { page } from "$app/state"; import { page } from "$app/state";
import DisplayStateSvelte from "$lib/DisplayState.svelte"; import DisplayStateSvelte from "$lib/DisplayState.svelte";
import { onMount } from "svelte";
import { fetchGame } from "../../../../editor/fetchers";
console.log("game:", page.params.game); onMount(() => {
fetchGame(`${page.params.game}`).then((game) => {
let paramGame = page.params.game;
if (paramGame === undefined) {
error(404);
}
const gameIndex = parseInt(paramGame);
if (isNaN(gameIndex)) {
error(404);
}
if (DisplayStateSvelte.gameIndex !== gameIndex) {
const game = games[gameIndex];
if (game) {
DisplayStateSvelte.game = game; DisplayStateSvelte.game = game;
DisplayStateSvelte.gameIndex = gameIndex; });
} else { });
error(404);
}
}
</script> </script>
<div class="flex grow flex-col pr-4 pl-4"> <div class="flex grow flex-col pr-4 pl-4">

View File

@@ -6,27 +6,11 @@
import ws from "$lib/websocket.svelte"; import ws from "$lib/websocket.svelte";
import { MessageType } from "$lib/MessageType"; import { MessageType } from "$lib/MessageType";
import type { VisitedQuestions } from "$lib/Types"; import type { VisitedQuestions } from "$lib/Types";
import { onMount } from "svelte";
import { fetchWall } from "../../../../../editor/fetchers";
console.log("wall:", page.params.wall); console.log("wall:", page.params.wall);
let paramWall = page.params.wall;
if (paramWall === undefined) {
error(404);
}
const wallIndex = parseInt(paramWall);
if (isNaN(wallIndex)) {
error(404);
}
if (DisplayStateSvelte.wallIndex !== wallIndex) {
const wall = DisplayStateSvelte.game?.walls[wallIndex];
if (wall) {
DisplayStateSvelte.wall = wall;
DisplayStateSvelte.gameIndex = wallIndex;
} else {
error(404);
}
}
let visited: VisitedQuestions = $state([]); let visited: VisitedQuestions = $state([]);
$effect(() => { $effect(() => {
@@ -40,6 +24,12 @@
} }
} catch (e) {} } catch (e) {}
}); });
onMount(() => {
fetchWall(`${page.params.wall}`).then((wall) => {
DisplayStateSvelte.wall = wall;
});
});
</script> </script>
<Wall wall={DisplayStateSvelte.wall} {visited} /> <Wall wall={DisplayStateSvelte.wall} {visited} />

View File

@@ -9,65 +9,22 @@
isImageMultipleChoiceQuestion, isImageMultipleChoiceQuestion,
isImageQuestion, isImageQuestion,
isMultipleChoiceQuestion, isMultipleChoiceQuestion,
isSimpleQuestion isSimpleQuestion,
type Question
} from "$lib/games/games"; } from "$lib/games/games";
import ws from "$lib/websocket.svelte"; import ws from "$lib/websocket.svelte";
import { MessageType } from "$lib/MessageType"; import { MessageType } from "$lib/MessageType";
import { untrack } from "svelte"; import { onMount, untrack } from "svelte";
import MultipleChoiceQuestionComponent from "$lib/MultipleChoiceQuestionComponent.svelte"; import MultipleChoiceQuestionComponent from "$lib/MultipleChoiceQuestionComponent.svelte";
import ImageQuestionComponent from "$lib/ImageQuestionComponent.svelte"; import ImageQuestionComponent from "$lib/ImageQuestionComponent.svelte";
import AudioQuestionComponent from "$lib/AudioQuestionComponent.svelte"; import AudioQuestionComponent from "$lib/AudioQuestionComponent.svelte";
import AudioMultipleChoiceQuestionComponent from "$lib/AudioMultipleChoiceQuestionComponent.svelte"; import AudioMultipleChoiceQuestionComponent from "$lib/AudioMultipleChoiceQuestionComponent.svelte";
import ImageMultipleChoiceQuestionComponent from "$lib/ImageMultipleChoiceQuestionComponent.svelte"; import ImageMultipleChoiceQuestionComponent from "$lib/ImageMultipleChoiceQuestionComponent.svelte";
import { fetchCategory, fetchQuestion } from "../../../../../../../editor/fetchers";
import type { Category, GeneralQuestion } from "$lib/Types";
console.log("wall:", page.params.wall); let category: Category | undefined = $state();
let question: GeneralQuestion | undefined = $state();
let paramWall = page.params.wall;
if (paramWall === undefined) {
error(404);
}
const wallIndex = parseInt(paramWall);
if (isNaN(wallIndex)) {
error(404);
}
if (DisplayStateSvelte.wallIndex !== wallIndex) {
const wall = DisplayStateSvelte.game?.walls[wallIndex];
if (wall) {
DisplayStateSvelte.wall = wall;
DisplayStateSvelte.gameIndex = wallIndex;
} else {
error(404);
}
}
if (page.params.category === undefined) {
error(404);
}
const categoryIndex = parseInt(page.params.category);
if (isNaN(categoryIndex)) {
error(404);
}
const category = DisplayStateSvelte.wall?.categories[categoryIndex];
if (category === undefined) {
error(404);
}
if (page.params.question === undefined) {
error(404);
}
const questionIndex = parseInt(page.params.question);
if (isNaN(questionIndex)) {
error(404);
}
const question = category.questions[questionIndex];
console.log(question);
if (question === undefined) {
error(404);
}
let showAnswer = $state(false); let showAnswer = $state(false);
let showQuestion = $state(false); let showQuestion = $state(false);
@@ -118,9 +75,21 @@
} }
} catch (e) {} } catch (e) {}
}); });
onMount(() => {
fetchCategory(`${page.params.category}`)
.then((cat) => {
category = cat;
return fetchQuestion(`${page.params.question}`);
})
.then((que) => {
question = que;
});
});
</script> </script>
<div class="mt-4 flex grow flex-col"> {#if category && question}
<div class="mt-4 flex grow flex-col">
<div class="mb-4 flex justify-between text-4xl"> <div class="mb-4 flex justify-between text-4xl">
<div>{category.name}</div> <div>{category.name}</div>
<div> <div>
@@ -135,25 +104,42 @@
{:else if isMultipleChoiceQuestion(question)} {:else if isMultipleChoiceQuestion(question)}
<MultipleChoiceQuestionComponent {question} {showAnswer} {showQuestion} /> <MultipleChoiceQuestionComponent {question} {showAnswer} {showQuestion} />
{:else if isImageQuestion(question)} {:else if isImageQuestion(question)}
<ImageQuestionComponent {question} {showAnswer} {showQuestion} {isBuzzed} /> <ImageQuestionComponent
{question}
{showAnswer}
{showQuestion}
{isBuzzed}
isLegacy={false}
/>
{:else if isImageMultipleChoiceQuestion(question)} {:else if isImageMultipleChoiceQuestion(question)}
<ImageMultipleChoiceQuestionComponent <ImageMultipleChoiceQuestionComponent
{question} {question}
{showAnswer} {showAnswer}
{showQuestion} {showQuestion}
{isBuzzed} {isBuzzed}
isLegacy={false}
/> />
{:else if isAudioQuestion(question)} {:else if isAudioQuestion(question)}
<AudioQuestionComponent {question} {showAnswer} {showQuestion} showPlayer={false} /> <AudioQuestionComponent
{question}
{showAnswer}
{showQuestion}
showPlayer={false}
isLegacy={false}
/>
{:else if isAudioMultipleChoiceQuestion(question)} {:else if isAudioMultipleChoiceQuestion(question)}
<AudioMultipleChoiceQuestionComponent <AudioMultipleChoiceQuestionComponent
{question} {question}
{showAnswer} {showAnswer}
{showQuestion} {showQuestion}
showPlayer={false} showPlayer={false}
isLegacy={false}
/> />
{:else} {:else}
<p>Type of question unknown</p> <p>Type of question unknown</p>
{/if} {/if}
</div> </div>
</div> </div>
{:else}
Loading...
{/if}

View File

@@ -1,7 +0,0 @@
import games from '$lib/games/games';
export function load() {
return {
games
};
}

View File

@@ -1,14 +1,39 @@
<script lang="ts"> <script lang="ts">
let { data } = $props(); import type { Game } from "$lib/Types";
import { url } from "$lib/util";
import axios from "axios";
import { onMount } from "svelte";
let games: Game[] = $state([]);
function fetchGames() {
axios
.get(url("/games"), { withCredentials: true })
.then((response) => {
if (response.status === 200) {
games = response.data;
games.sort((a, b) => a.name.localeCompare(b.name));
} else {
console.error("Could not fetch games: " + response.status);
}
})
.catch((err) => {
console.error(err);
});
}
onMount(() => {
fetchGames();
});
</script> </script>
<h1 class="m-4 mb-8 text-7xl font-bold">Games</h1> <h1 class="m-4 mb-8 text-7xl font-bold">Games</h1>
<div class="flex flex-col space-y-4"> <div class="flex flex-col space-y-4">
{#each data.games as game, i} {#each games as game}
<a <a
class="ms-4 me-4 rounded-xl border-2 p-4 hover:cursor-pointer hover:bg-emerald-200" class="ms-4 me-4 rounded-xl border-2 p-4 hover:cursor-pointer hover:bg-emerald-200"
href="/connected/games/{i}">{game.name}</a href="/connected/games/{game._id}">{game.name}</a
> >
{/each} {/each}
</div> </div>

View File

@@ -1,12 +0,0 @@
import { error } from '@sveltejs/kit';
import games from '$lib/games/games';
export function load({ params }) {
const index = parseInt(params.game);
if (isNaN(index)) {
error(404);
}
const game = games[index];
if (game === undefined) error(404);
else return game;
}

View File

@@ -9,7 +9,8 @@
isAudioQuestion, isAudioQuestion,
isAudioMultipleChoiceQuestion, isAudioMultipleChoiceQuestion,
isImageMultipleChoiceQuestion, isImageMultipleChoiceQuestion,
type FullGame type FullGame,
type Question
} from "$lib/games/games"; } from "$lib/games/games";
import ws from "$lib/websocket.svelte"; import ws from "$lib/websocket.svelte";
import { page } from "$app/state"; import { page } from "$app/state";
@@ -18,12 +19,14 @@
import Scoreboard from "$lib/Scoreboard.svelte"; import Scoreboard from "$lib/Scoreboard.svelte";
import SimpleQuestionComponent from "$lib/SimpleQuestionComponent.svelte"; import SimpleQuestionComponent from "$lib/SimpleQuestionComponent.svelte";
import PlusMinusButton from "$lib/PlusMinusButton.svelte"; import PlusMinusButton from "$lib/PlusMinusButton.svelte";
import type { VisitedQuestions } from "$lib/Types.js"; import type { _id, Category, Game, VisitedQuestions, Wall as WallType } from "$lib/Types.js";
import MultipleChoiceQuestionComponent from "$lib/MultipleChoiceQuestionComponent.svelte"; import MultipleChoiceQuestionComponent from "$lib/MultipleChoiceQuestionComponent.svelte";
import ImageQuestionComponent from "$lib/ImageQuestionComponent.svelte"; import ImageQuestionComponent from "$lib/ImageQuestionComponent.svelte";
import AudioQuestionComponent from "$lib/AudioQuestionComponent.svelte"; import AudioQuestionComponent from "$lib/AudioQuestionComponent.svelte";
import AudioMultipleChoiceQuestionComponent from "$lib/AudioMultipleChoiceQuestionComponent.svelte"; import AudioMultipleChoiceQuestionComponent from "$lib/AudioMultipleChoiceQuestionComponent.svelte";
import ImageMultipleChoiceQuestionComponent from "$lib/ImageMultipleChoiceQuestionComponent.svelte"; import ImageMultipleChoiceQuestionComponent from "$lib/ImageMultipleChoiceQuestionComponent.svelte";
import { fetchCategory, fetchGame, fetchQuestion, fetchWall } from "../../../editor/fetchers";
import { onMount } from "svelte";
interface SaveData { interface SaveData {
players: Player[]; players: Player[];
@@ -57,7 +60,7 @@
class GameManager { class GameManager {
public state: GameState = $state(GameState.INIT); public state: GameState = $state(GameState.INIT);
public game: FullGame; public game: Game | undefined = $state();
public players: Player[] = $state([ public players: Player[] = $state([
{ {
name: "Player 1", name: "Player 1",
@@ -74,37 +77,42 @@
]); ]);
public currentPlayer = $state(0); public currentPlayer = $state(0);
public currentWall = $state(0); public currentWallIndex = $state(0);
public currentWall: WallType | undefined = $state();
public visitedQuestions: VisitedQuestions = $state([]); public visitedQuestions: VisitedQuestions = $state([]);
public currentCategory = $state(0); public currentCategoryId = $state("");
public currentQuestion = $state(0); public currentCategory: Category | undefined = $state();
public currentQuestionId = $state("");
public currentQuestion: Question | undefined = $state();
public answerIsShowing = $state(false); public answerIsShowing = $state(false);
public questionIsShowing = $state(false); public questionIsShowing = $state(false);
public isBuzzed = $state(false); public isBuzzed = $state(false);
constructor(game: FullGame) { setGame(game: Game) {
this.game = game; this.game = game;
} }
save(): void { save(): void {
if (!this.game) return;
const saveData = { const saveData = {
players: this.players, players: this.players,
currentPlayer: this.currentPlayer, currentPlayer: this.currentPlayer,
currentWall: this.currentWall, currentWall: this.currentWallIndex,
visitedQuestions: this.visitedQuestions visitedQuestions: this.visitedQuestions
}; };
localStorage.setItem(`saveGame-${this.game.name}`, JSON.stringify(saveData)); localStorage.setItem(`saveGame-${this.game._id}`, JSON.stringify(saveData));
} }
load(): void { load(): void {
const saveDataString = localStorage.getItem(`saveGame-${this.game.name}`); if (!this.game) return;
const saveDataString = localStorage.getItem(`saveGame-${this.game._id}`);
if (saveDataString === null) return; if (saveDataString === null) return;
try { try {
const saveData: SaveData = JSON.parse(saveDataString); const saveData: SaveData = JSON.parse(saveDataString);
this.players = saveData.players; this.players = saveData.players;
this.currentPlayer = saveData.currentPlayer; this.currentPlayer = saveData.currentPlayer;
this.currentWall = saveData.currentWall; this.currentWallIndex = saveData.currentWall;
this.visitedQuestions = saveData.visitedQuestions; this.visitedQuestions = saveData.visitedQuestions;
console.log(saveData); console.log(saveData);
} catch (e) { } catch (e) {
@@ -113,10 +121,14 @@
} }
startGame(): void { startGame(): void {
if (!this.game) return;
this.currentPlayer = Math.floor(Math.random() * this.players.length); this.currentPlayer = Math.floor(Math.random() * this.players.length);
this.state = GameState.CHOOSING_QUESTION; this.state = GameState.CHOOSING_QUESTION;
fetchWall(this.game.walls[this.currentWallIndex]).then((wall) => {
this.currentWall = wall;
this.sendStart(); this.sendStart();
this.sendCurrentState(); this.sendCurrentState();
});
} }
sendStart(): void { sendStart(): void {
@@ -136,7 +148,7 @@
sendWall(): void { sendWall(): void {
ws.sendMessage({ ws.sendMessage({
type: MessageType.GOTO, type: MessageType.GOTO,
route: `/${page.params.game}/${this.currentWall}` route: `/${page.params.game}/${this.currentWall?._id}`
}); });
this.sendVisited(); this.sendVisited();
} }
@@ -154,30 +166,39 @@
} }
sendCurrentQuestion(): void { sendCurrentQuestion(): void {
if (!this.game) return;
ws.sendMessage({ ws.sendMessage({
type: MessageType.GOTO, type: MessageType.GOTO,
route: `/${page.params.game}/${this.currentWall}/${this.currentCategory}/${this.currentQuestion}` route: `/${this.game._id}/${this.currentWall?._id}/${this.currentCategoryId}/${this.currentQuestionId}`
}); });
} }
sendEnd(): void { sendEnd(): void {
ws.sendMessage({ ws.sendMessage({
type: MessageType.GOTO, type: MessageType.GOTO,
route: `/${page.params.game}/${this.currentWall}/end` route: `/${page.params.game}/${this.currentWall?._id}/end`
}); });
} }
tileClicked(categoryIndex: number, questionIndex: number) { tileClicked(catId: _id, queId: _id) {
console.log("Cat", categoryIndex, "Que", questionIndex); console.log("Cat", catId, "Que", queId);
console.log(gameManager.wall.categories[categoryIndex]?.questions[questionIndex]);
this.currentCategory = categoryIndex; this.currentCategoryId = catId;
this.currentQuestion = questionIndex; this.currentQuestionId = queId;
this.answerIsShowing = false; this.answerIsShowing = false;
this.sendCurrentQuestion(); fetchCategory(this.currentCategoryId)
.then((category) => {
this.currentCategory = category;
return fetchQuestion(this.currentQuestionId);
})
.then((question) => {
this.currentQuestion = question;
this.sendCurrentQuestion();
this.state = GameState.SHOW_QUESTION; this.state = GameState.SHOW_QUESTION;
});
} }
addPlayer() { addPlayer() {
@@ -236,20 +257,21 @@
} }
plus(player: Player) { plus(player: Player) {
if (!this.answerIsShowing) return; if (!this.answerIsShowing || !this.currentQuestion) return;
if (player.name === this.currentPlayerToName()) { if (player.name === this.currentPlayerToName()) {
player.points += this.question.points * 2; player.points += this.currentQuestion.points * 2;
} else { } else {
player.points += this.question.points; player.points += this.currentQuestion.points;
} }
this.sendPlayers(); this.sendPlayers();
} }
minus(player: Player) { minus(player: Player) {
if (!this.currentQuestion) return;
if (player.name === this.currentPlayerToName()) { if (player.name === this.currentPlayerToName()) {
player.points -= this.question.points * 2; player.points -= this.currentQuestion.points * 2;
} else { } else {
player.points -= this.question.points; player.points -= this.currentQuestion.points;
} }
this.sendPlayers(); this.sendPlayers();
} }
@@ -267,12 +289,8 @@
} }
finishQuestion(): void { finishQuestion(): void {
if (this.visitedQuestions[this.currentCategory] == undefined) { if (!this.visitedQuestions.includes(this.currentQuestionId)) {
this.visitedQuestions[this.currentCategory] = [this.currentQuestion]; this.visitedQuestions.push(this.currentQuestionId);
} else if (
!this.visitedQuestions[this.currentCategory].includes(this.currentQuestion)
) {
this.visitedQuestions[this.currentCategory].push(this.currentQuestion);
} }
this.setupGoingBack(); this.setupGoingBack();
this.nextPlayer(); this.nextPlayer();
@@ -286,28 +304,21 @@
} }
wallIsDone(): boolean { wallIsDone(): boolean {
let visitedNum = 0; return this.visitedQuestions.length >= 25;
for (const questions of this.visitedQuestions) {
if (questions != undefined) {
visitedNum += questions.length;
}
}
let totalNum = 0;
for (const category of this.wall.categories) {
totalNum += category.questions.length;
}
console.log(`${visitedNum} >= ${totalNum}`);
return visitedNum >= totalNum;
} }
goToNextWall(): void { goToNextWall(): void {
if (this.currentWall + 1 >= this.game.walls.length) { if (!this.game) return;
if (this.currentWallIndex + 1 >= this.game.walls.length) {
this.goToEndScreen(); this.goToEndScreen();
} else { } else {
this.currentWall += 1; this.currentWallIndex += 1;
this.visitedQuestions = []; this.visitedQuestions = [];
fetchWall(this.game.walls[this.currentWallIndex]).then((wall) => {
this.currentWall = wall;
this.sendWall(); this.sendWall();
this.state = GameState.CHOOSING_QUESTION; this.state = GameState.CHOOSING_QUESTION;
});
} }
} }
@@ -324,32 +335,27 @@
currentPlayerToName(): string { currentPlayerToName(): string {
return this.players[this.currentPlayer].name; return this.players[this.currentPlayer].name;
} }
get wall() {
return this.game.walls[this.currentWall];
} }
get category() { let gameManager = new GameManager();
return this.wall.categories[this.currentCategory];
}
get question() { onMount(() => {
return this.category.questions[this.currentQuestion]; fetchGame(`${page.params.game}`).then((game) => {
} gameManager.game = game;
} });
});
let { data } = $props();
let gameManager = new GameManager(data);
</script> </script>
<div class="flex h-full flex-col"> {#if gameManager.game}
<div class="flex h-full flex-col">
<h1 class="ms-4 text-7xl font-bold">{gameManager.game.name}</h1> <h1 class="ms-4 text-7xl font-bold">{gameManager.game.name}</h1>
{#if gameManager.state === GameState.INIT} {#if gameManager.state === GameState.INIT}
<div class="p-4"> <div class="p-4">
<div class="flex items-center"> <div class="flex items-center">
<h2 class="grow pb-4 text-5xl">Spieler</h2> <h2 class="grow pb-4 text-5xl">Spieler</h2>
<button class="btn me-4" onclick={() => gameManager.load()}>Load SaveGame</button> <button class="btn me-4" onclick={() => gameManager.load()}
>Load SaveGame</button
>
<button <button
class="btn" class="btn"
disabled={!startDisabled} disabled={!startDisabled}
@@ -366,7 +372,9 @@
</div> </div>
{/each} {/each}
</div> </div>
<button class="btn" onclick={() => gameManager.addPlayer()}>Spieler hinzufügen</button> <button class="btn" onclick={() => gameManager.addPlayer()}
>Spieler hinzufügen</button
>
</div> </div>
{:else} {:else}
<div class="flex grow"> <div class="flex grow">
@@ -379,53 +387,57 @@
{#if gameManager.state === GameState.SHOW_QUESTION} {#if gameManager.state === GameState.SHOW_QUESTION}
<div class="flex grow flex-col"> <div class="flex grow flex-col">
<div class="m-4 flex justify-between text-4xl"> <div class="m-4 flex justify-between text-4xl">
<div>{gameManager.category.name}</div> <div>{gameManager.currentCategory?.name}</div>
<div> <div>
{gameManager.question.points} Punkte {gameManager.currentQuestion?.points} Punkte
</div> </div>
</div> </div>
<div class="flex grow ps-4 pe-4"> <div class="flex grow ps-4 pe-4">
{#if gameManager.question === undefined} {#if gameManager.currentQuestion === undefined}
<p>Question is undefined</p> <p>Question is undefined</p>
{:else if isSimpleQuestion(gameManager.question)} {:else if isSimpleQuestion(gameManager.currentQuestion)}
<SimpleQuestionComponent <SimpleQuestionComponent
question={gameManager.question} question={gameManager.currentQuestion}
showAnswer={true} showAnswer={true}
showQuestion={true} showQuestion={true}
/> />
{:else if isMultipleChoiceQuestion(gameManager.question)} {:else if isMultipleChoiceQuestion(gameManager.currentQuestion)}
<MultipleChoiceQuestionComponent <MultipleChoiceQuestionComponent
question={gameManager.question} question={gameManager.currentQuestion}
showAnswer={true} showAnswer={true}
showQuestion={true} showQuestion={true}
/> />
{:else if isImageQuestion(gameManager.question)} {:else if isImageQuestion(gameManager.currentQuestion)}
<ImageQuestionComponent <ImageQuestionComponent
question={gameManager.question} question={gameManager.currentQuestion}
showAnswer={true} showAnswer={true}
showQuestion={true} showQuestion={true}
isBuzzed={false} isBuzzed={false}
isLegacy={false}
/> />
{:else if isImageMultipleChoiceQuestion(gameManager.question)} {:else if isImageMultipleChoiceQuestion(gameManager.currentQuestion)}
<ImageMultipleChoiceQuestionComponent <ImageMultipleChoiceQuestionComponent
question={gameManager.question} question={gameManager.currentQuestion}
showAnswer={true} showAnswer={true}
showQuestion={true} showQuestion={true}
isBuzzed={false} isBuzzed={false}
isLegacy={false}
/> />
{:else if isAudioQuestion(gameManager.question)} {:else if isAudioQuestion(gameManager.currentQuestion)}
<AudioQuestionComponent <AudioQuestionComponent
question={gameManager.question} question={gameManager.currentQuestion}
showAnswer={true} showAnswer={true}
showPlayer={true} showPlayer={true}
showQuestion={true} showQuestion={true}
isLegacy={false}
/> />
{:else if isAudioMultipleChoiceQuestion(gameManager.question)} {:else if isAudioMultipleChoiceQuestion(gameManager.currentQuestion)}
<AudioMultipleChoiceQuestionComponent <AudioMultipleChoiceQuestionComponent
question={gameManager.question} question={gameManager.currentQuestion}
showAnswer={true} showAnswer={true}
showPlayer={true} showPlayer={true}
showQuestion={true} showQuestion={true}
isLegacy={false}
/> />
{:else} {:else}
<p>Type of question unknown</p> <p>Type of question unknown</p>
@@ -477,16 +489,21 @@
</div> </div>
</div> </div>
{:else if gameManager.state === GameState.END} {:else if gameManager.state === GameState.END}
<div class="flex grow items-center justify-center text-7xl"><div>ENDE</div></div> <div class="flex grow items-center justify-center text-7xl">
<div>ENDE</div>
</div>
{:else} {:else}
<div class="grow ps-4 pe-4"> <div class="grow ps-4 pe-4">
<Wall <Wall
wall={gameManager.game.walls[gameManager.currentWall]} wall={gameManager.currentWall}
onclick={(cat, que) => gameManager.tileClicked(cat, que)} onclickIds={(cat, que) => gameManager.tileClicked(cat, que)}
visited={gameManager.visitedQuestions} visited={gameManager.visitedQuestions}
/> />
</div> </div>
{/if} {/if}
</div> </div>
{/if} {/if}
</div> </div>
{:else}
Loading Game...
{/if}

View File

@@ -218,8 +218,15 @@
<option value="AUDIO_MULTIPLE_CHOICE">AUDIO_MULTIPLE_CHOICE</option> <option value="AUDIO_MULTIPLE_CHOICE">AUDIO_MULTIPLE_CHOICE</option>
</select> </select>
<div class="ms-4 me-4"> <div class="ms-4 me-4">
<div class="flex items-center gap-2">
<Textfield type="number" bind:value={question.points} label="Punkte" <Textfield type="number" bind:value={question.points} label="Punkte"
></Textfield> ></Textfield>
<Button
onclick={() => {
if (question) question.points *= -1;
}}><i class="fa-solid fa-plus-minus"></i></Button
>
</div>
</div> </div>
<div class="ms-4 me-4 grow"> <div class="ms-4 me-4 grow">
{#if isSimpleQuestion(question)} {#if isSimpleQuestion(question)}