149 lines
4.8 KiB
JavaScript
149 lines
4.8 KiB
JavaScript
import React, { useState, useEffect, useContext, useRef, useMemo, useCallback } from "react";
|
|
import equal from "fast-deep-equal";
|
|
|
|
import Paper from '@material-ui/core/Paper';
|
|
import Button from '@material-ui/core/Button';
|
|
|
|
import "./Winner.css";
|
|
|
|
import {Resource} from './Resource.js';
|
|
import {PlayerColor} from './PlayerColor.js';
|
|
import { GlobalContext } from "./GlobalContext.js";
|
|
|
|
const Winner = ({ winnerDismissed, setWinnerDismissed }) => {
|
|
const { ws } = useContext(GlobalContext);
|
|
const [winner, setWinner] = useState(undefined);
|
|
const [state, setState] = useState(undefined);
|
|
const fields = useMemo(() => [
|
|
'winner', 'state'
|
|
], []);
|
|
const onWsMessage = (event) => {
|
|
const data = JSON.parse(event.data);
|
|
switch (data.type) {
|
|
case 'game-update':
|
|
console.log(`winner - game update`, data.update);
|
|
if ('winner' in data.update && !equal(data.update.winner, winner)) {
|
|
setWinner(data.update.winner);
|
|
}
|
|
if ('state' in data.update && data.update.state !== state) {
|
|
if (data.update.state !== 'winner') {
|
|
setWinner(undefined);
|
|
}
|
|
setWinnerDismissed(false);
|
|
setState(data.update.state);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
};
|
|
const refWsMessage = useRef(onWsMessage);
|
|
useEffect(() => { refWsMessage.current = onWsMessage; });
|
|
useEffect(() => {
|
|
if (!ws) { return; }
|
|
const cbMessage = e => refWsMessage.current(e);
|
|
ws.addEventListener('message', cbMessage);
|
|
return () => {
|
|
ws.removeEventListener('message', cbMessage);
|
|
}
|
|
}, [ws, refWsMessage]);
|
|
useEffect(() => {
|
|
if (!ws) { return; }
|
|
ws.send(JSON.stringify({
|
|
type: 'get',
|
|
fields
|
|
}));
|
|
}, [ws, fields]);
|
|
|
|
const quitClicked = useCallback((event) => {
|
|
if (!winnerDismissed) {
|
|
setWinnerDismissed(true);
|
|
ws.send(JSON.stringify({
|
|
type: 'goto-lobby'
|
|
}));
|
|
}
|
|
}, [ws, winnerDismissed, setWinnerDismissed]);
|
|
|
|
if (!winner || winnerDismissed) {
|
|
return <></>;
|
|
}
|
|
|
|
let losers = [];
|
|
for (let key in winner.players) {
|
|
if (key === winner.color || winner.players[key].status === 'Not active') {
|
|
continue;
|
|
}
|
|
losers.push(winner.players[key]);
|
|
}
|
|
|
|
const turnCount = Math.floor(winner.turns / (losers.length + 1));
|
|
|
|
losers = losers.map(player => {
|
|
const averageSeconds = Math.floor(player.totalTime / turnCount / 1000),
|
|
average = `${Math.floor(averageSeconds / 60)}m:${averageSeconds % 60}s`;
|
|
return <div key={player.color}>
|
|
<PlayerColor color={player.color}/> {player.name} finished with {player.points} victory points.
|
|
{ Number(player.potential) !== 0 && <>They had <b>{player.potential}</b> unplayed Victory Point card(s).</> }
|
|
Their average turn time was {average}.
|
|
</div>;
|
|
});
|
|
|
|
let robber = <></>;
|
|
|
|
if (winner.robberStole) {
|
|
let stolen = <></>;
|
|
for (let type in winner.stolen) {
|
|
const resource = winner.stolen[type];
|
|
if (typeof resource === 'object') { /* player colors are also in 'game.stolen' */
|
|
continue;
|
|
}
|
|
stolen = <>{stolen}
|
|
<Resource label={true} type={type} count={resource}/>
|
|
</>;
|
|
}
|
|
robber = <div>
|
|
Throughout the game, the robber stole <b>{winner.robberStole}</b> resources:
|
|
<div>{stolen}</div>
|
|
</div>;
|
|
} else {
|
|
robber = <div>The robber never stole any resources from anyone!</div>;
|
|
}
|
|
|
|
const averageSeconds = Math.floor(winner.totalTime / turnCount / 1000),
|
|
average = `${Math.floor(averageSeconds / 60)}m:${averageSeconds % 60}s`;
|
|
|
|
const seconds = winner.elapsedTime / 1000,
|
|
h = Math.floor(seconds / (60 * 60)),
|
|
m = Math.floor((seconds % (60 * 60)) / 60),
|
|
s = Math.floor((seconds % (60 * 60)) % 60);
|
|
const totalTime = `${h}h:${m}m:${s}s`;
|
|
|
|
let vpType = ['market', 'university', 'library', 'palace'];
|
|
vpType = vpType[Math.floor(vpType.length * Math.random())];
|
|
|
|
return (
|
|
<div className="Winner">
|
|
<Paper>
|
|
<div className="Title">{winner.name} has won with {winner.points} victory points!</div>
|
|
<div style={{display: 'flex', flexDirection: 'row'}}>
|
|
<Resource type={`vp-${vpType}`} disabled count={1}/>
|
|
<div className="Description">
|
|
<div>Congratulations, <b>{winner.name}</b>!</div>
|
|
<div>
|
|
<PlayerColor color={winner.color}/> {winner.name} won the game
|
|
with <b>{winner.points}</b> Victory Points after {turnCount} game turns.
|
|
{ Number(winner.potential) !== 0 && <>They had <b>{winner.potential}</b> unplayed Victory Point card(s).</>}
|
|
Their average turn time was {average}.
|
|
</div>
|
|
{ losers }
|
|
<div>The game took {totalTime}.</div>
|
|
{ robber }
|
|
</div>
|
|
</div>
|
|
<Button onClick={quitClicked}>Go back to Lobby</Button>
|
|
</Paper>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export { Winner }; |