2024-07-19 18:00:43 +02:00
|
|
|
|
"use client"
|
|
|
|
|
|
|
|
|
|
import React, {
|
2024-08-31 11:56:27 +02:00
|
|
|
|
Reducer,
|
2024-07-19 18:00:43 +02:00
|
|
|
|
useEffect,
|
2024-08-31 11:56:27 +02:00
|
|
|
|
useReducer
|
2024-07-19 18:00:43 +02:00
|
|
|
|
} from "react";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import Maze from "./maze";
|
|
|
|
|
import ZMQReceiver from "./zmqreceiver";
|
|
|
|
|
import TypewriterText from "./typewritertext";
|
|
|
|
|
import { GameState } from "./zmqreceiver";
|
2024-08-31 11:56:27 +02:00
|
|
|
|
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;
|
|
|
|
|
};
|
2024-07-19 18:00:43 +02:00
|
|
|
|
|
2024-08-31 11:56:27 +02:00
|
|
|
|
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>
|
2024-07-19 18:00:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-31 11:56:27 +02:00
|
|
|
|
|
2024-07-19 18:00:43 +02:00
|
|
|
|
function Pelita() {
|
2024-08-31 11:56:27 +02:00
|
|
|
|
const initialState: PelitaState = "initial";
|
|
|
|
|
const [state, dispatch] = useReducer(reducer, initialState);
|
|
|
|
|
|
2024-07-19 18:00:43 +02:00
|
|
|
|
const [showPre, setShowPre] = React.useState(true);
|
|
|
|
|
const [showMain, setShowMain] = React.useState(true);
|
2024-08-31 11:56:27 +02:00
|
|
|
|
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 "";
|
|
|
|
|
}
|
2024-07-19 18:00:43 +02:00
|
|
|
|
|
2024-08-31 11:56:27 +02:00
|
|
|
|
})(state);
|
2024-07-19 18:00:43 +02:00
|
|
|
|
|
|
|
|
|
|
2024-08-31 11:56:27 +02:00
|
|
|
|
useEffect(() => {
|
|
|
|
|
anime.timeline()
|
|
|
|
|
.add({
|
|
|
|
|
targets: 'body',
|
|
|
|
|
background: bg_color,
|
|
|
|
|
easing: 'linear',
|
|
|
|
|
duration: 2000,
|
|
|
|
|
}, 3000)
|
|
|
|
|
}, [bg_color]);
|
2024-07-19 18:00:43 +02:00
|
|
|
|
|
|
|
|
|
const flip = () => {
|
|
|
|
|
//setShowMain(!showMain);
|
|
|
|
|
//setShowPre(!showPre);
|
|
|
|
|
};
|
|
|
|
|
|
2024-08-31 11:56:27 +02:00
|
|
|
|
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;
|
|
|
|
|
});
|
2024-07-19 18:00:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const updateMessage = (msg: string) => {
|
2024-08-31 11:56:27 +02:00
|
|
|
|
let split_str = msg.split(/\r?\n/);
|
|
|
|
|
setTypewriterText(oldText => [...oldText, ...split_str]);
|
2024-07-19 18:00:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const clearPage = () => {
|
2024-08-31 11:56:27 +02:00
|
|
|
|
dispatch("clear-page");
|
|
|
|
|
setTypewriterText([]);
|
2024-07-19 18:00:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-31 11:56:27 +02:00
|
|
|
|
const handleClick = async () => {
|
|
|
|
|
switch (state) {
|
|
|
|
|
case "initial":
|
|
|
|
|
dispatch("start-movie");
|
|
|
|
|
break;
|
|
|
|
|
case "movie":
|
|
|
|
|
dispatch("start-intro");
|
|
|
|
|
break
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
};
|
2024-07-19 18:00:43 +02:00
|
|
|
|
|
2024-08-31 11:56:27 +02:00
|
|
|
|
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") {
|
2024-07-19 18:00:43 +02:00
|
|
|
|
|
2024-08-31 11:56:27 +02:00
|
|
|
|
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}
|
|
|
|
|
|
2024-08-31 13:28:30 +02:00
|
|
|
|
{state === "match" && gameState ?
|
2024-08-31 11:56:27 +02:00
|
|
|
|
<PelitaMain gameState={gameState}></PelitaMain>
|
|
|
|
|
: null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
<ZMQReceiver url='ws://localhost:5556' sendGameState={updateGameState} sendMessage={updateMessage} sendClearPage={clearPage}></ZMQReceiver>
|
2024-07-19 18:00:43 +02:00
|
|
|
|
</div>
|
2024-08-31 11:56:27 +02:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
};
|
2024-07-19 18:00:43 +02:00
|
|
|
|
|
2024-08-31 11:56:27 +02:00
|
|
|
|
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">
|
2024-07-19 18:00:43 +02:00
|
|
|
|
|
2024-08-31 11:56:27 +02:00
|
|
|
|
{ inner() }
|
2024-07-19 18:00:43 +02:00
|
|
|
|
|
|
|
|
|
</div>
|
2024-08-31 11:56:27 +02:00
|
|
|
|
</main>
|
2024-07-19 18:00:43 +02:00
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
export default Pelita;
|