pelita-webtournament/app/pelita.tsx
Rike-Benjamin Schuppner 42baea3403 Lots of changes
2024-08-31 12:56:27 +03:00

218 lines
6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client"
import React, {
Reducer,
useEffect,
useReducer
} from "react";
import Maze from "./maze";
import ZMQReceiver from "./zmqreceiver";
import TypewriterText from "./typewritertext";
import { GameState } from "./zmqreceiver";
import anime from "animejs";
type PelitaState = "initial" | "movie" | "intro" | "match" | "faulted";
type PelitaEvent = "start-movie" | "start-intro" | "game-playing" | "clear-page" | "fail";
const MAX_LINES = 20;
const reducer: Reducer<PelitaState, PelitaEvent> = (state, event) => {
switch (state) {
case "initial":
if (event === "start-movie") return "movie";
break;
case "movie":
if (event === "start-intro") return "intro";
break;
case "intro":
if (event === "game-playing") return "match";
if (event === "clear-page") return "intro";
break;
case "match":
if (event === "game-playing") return "match";
if (event === "clear-page") return "intro";
break;
}
return state;
};
function PelitaMain({ gameState }: { gameState: GameState }) {
const [team1, team2] = gameState.team_names;
return <div id="main">
<h2 className="flex flex-row text-lg p-2">
<span className="basis-1/2 text-right w-64 blue-bot"><b>{team1}</b> {gameState.game_stats.score[0]}</span>
<span className="basis-1 px-2">:</span>
<span className="basis-1/2 text-left w-64 red-bot">{gameState.game_stats.score[1]} <b>{team2}</b></span>
</h2>
<div className="flex flex-row text-xs">
<div className="basis-1/2 w-64 px-2">Errors: {gameState.game_stats.num_errors[0]}, Kills: {gameState.game_stats.kills[0] + gameState.game_stats.kills[2]}, Deaths: {gameState.game_stats.deaths[0] + gameState.game_stats.deaths[2]}, Time: {gameState.game_stats.team_time[0].toFixed(2)} </div>
<div className="basis-1/2 text-right w-64 px-2">Errors: {gameState.game_stats.num_errors[1]}, Kills: {gameState.game_stats.kills[1] + gameState.game_stats.kills[3]}, Deaths: {gameState.game_stats.deaths[1] + gameState.game_stats.deaths[3]}, Time: {gameState.game_stats.team_time[1].toFixed(2)} </div>
</div>
<Maze
key={gameState.game_uuid}
game_uuid={gameState.game_uuid}
shape={gameState.shape}
walls={gameState.walls}
food={gameState.food}
bots={gameState.bots}
team_names={gameState.team_names}
say={gameState.say}
whowins={gameState.whowins}
gameover={gameState.gameover}
round={gameState.round}
turn={gameState.turn}
>
</Maze>
<div className="flex flex-row text-xs text-slate-600">
<div className="basis-1/2 w-64 px-2"> Pelita Tournament, ASPP 2024 Ηράκλειο</div>
<div className="basis-1/2 text-right w-64 px-2">Round {gameState.round ?? "-"}/{gameState.max_rounds}</div>
</div>
</div>
}
function Pelita() {
const initialState: PelitaState = "initial";
const [state, dispatch] = useReducer(reducer, initialState);
const [showPre, setShowPre] = React.useState(true);
const [showMain, setShowMain] = React.useState(true);
const [typewriterText, setTypewriterText] = React.useState<string[]>([]);
const [gameState, setGameState] = React.useState<GameState>();
const bg_color = ((state) => {
switch (state) {
case "initial":
case "movie":
case "intro":
return "#000"
case "match":
default:
return "#fff";
}
})(state);
const crt = ((state) => {
switch (state) {
case "initial":
case "movie":
case "intro":
return "crt"
case "match":
default:
return "";
}
})(state);
useEffect(() => {
anime.timeline()
.add({
targets: 'body',
background: bg_color,
easing: 'linear',
duration: 2000,
}, 3000)
}, [bg_color]);
const flip = () => {
//setShowMain(!showMain);
//setShowPre(!showPre);
};
const updateGameState = (gameState: GameState) => {
dispatch("game-playing");
setGameState((oldState) => {
if (oldState?.game_uuid === gameState.game_uuid) {
// we keep the walls array so that the effects are not re-run
// TODO: Maybe the effect should depend on only the game_uuid having changed?
const newState = {
...gameState,
"walls": oldState.walls,
};
return newState;
}
return gameState;
});
}
const updateMessage = (msg: string) => {
let split_str = msg.split(/\r?\n/);
setTypewriterText(oldText => [...oldText, ...split_str]);
}
const clearPage = () => {
dispatch("clear-page");
setTypewriterText([]);
}
const handleClick = async () => {
switch (state) {
case "initial":
dispatch("start-movie");
break;
case "movie":
dispatch("start-intro");
break
default:
break;
}
};
function showIntro() {
return <TypewriterText text={typewriterText} lines={MAX_LINES}></TypewriterText>;
}
function inner() {
if (state == "initial") {
return <button onClick={handleClick}>Start Movie</button>;
} else if (state == "movie") {
return <video autoPlay controls onEnded={handleClick}>
<source src={"Pelita Supercut ASPP Heraklion 2024.mp4"} type="video/mp4" />
</video>;
} else if (state == "intro" || state == "match") {
return (
<div>
<h1 className="fixed top-0 left-0 z-20 w-full px-24 py-4 text-xl">
Pelita Tournament 2024
</h1>
{state === "intro" ? showIntro() : null}
{state === "match" ?
<PelitaMain gameState={gameState}></PelitaMain>
: null
}
<ZMQReceiver url='ws://localhost:5556' sendGameState={updateGameState} sendMessage={updateMessage} sendClearPage={clearPage}></ZMQReceiver>
</div>
);
}
};
return (
<main className={`min-h-screen flex-col items-center justify-between px-24 py-12 ${crt}`}>
<div className="z-10 w-full max-w-screen items-center justify-between font-mono text-sm">
{ inner() }
</div>
</main>
);
};
export default Pelita;