1
0

Implemented YoP and Monopoly

Lots of fixes

Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
This commit is contained in:
James Ketrenos 2022-03-04 17:49:58 -08:00
parent 83aafd981c
commit 96723e135c
5 changed files with 168 additions and 39 deletions

View File

@ -16,7 +16,7 @@ const Activity = ({ activity }) => {
}; };
if (display) { if (display) {
setTimeout(() => hide(10000), 0); setTimeout(() => { hide(10000) }, 0);
} }
let message; let message;

View File

@ -28,14 +28,17 @@
margin-bottom: 0.5em; margin-bottom: 0.5em;
} }
.ChooseCard .Stack { .ChooseCard .Stack {
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
.ChooseCard .Resource { .ChooseCard .Resource {
width: 8em; /* 5x7 aspect ratio */ /*
width: 8em;
height: 11.2em; height: 11.2em;
margin: 0; margin: 0;
padding: 0; padding: 0;
*/
} }

View File

@ -1,21 +1,50 @@
import React, { useState, useCallback } from "react"; import React, { useState, useCallback } from "react";
import "./ChooseCard.css"; import "./ChooseCard.css";
import Paper from '@material-ui/core/Paper'; import Paper from '@material-ui/core/Paper';
import Button from '@material-ui/core/Button';
import Resource from './Resource.js'; import Resource from './Resource.js';
const ChooseCard = ({table, type}) => { const ChooseCard = ({table, type}) => {
const [cards, setCards] = useState([]);
const count = (type === 'monopoly') ? 1 : 2;
const selectCard = useCallback((event) => {
event.target.classList.toggle('Selected');
const selected = document.querySelectorAll('.ChooseCard .Selected');
if (selected.length > count) {
for (let i = 0; i < selected.length; i++) {
selected[i].classList.remove('Selected');
}
setCards([]);
return;
}
let tmp = [];
for (let i = 0; i < selected.length; i++) {
tmp.push(selected[i].getAttribute('data-type'));
}
setCards(tmp);
}, [ setCards ]);
if (!table.game) { if (!table.game) {
return <></>; return <></>;
} }
const selectCard = (card) => { console.log(cards.length, count);
table.selectResource(card);
const submitCards = () => {
table.selectResources(cards);
} }
const resources = [ const resources = [
'wheat', 'brick', 'stone', 'sheep', 'wood' 'wheat', 'brick', 'stone', 'sheep', 'wood'
].map(type => { ].map(type => {
return <Resource type={type} key={type} count={1} select={() => selectCard(type)}/>; return <Resource
key={type}
type={type}
count={count}
onClick={selectCard}/>;
}); });
let title; let title;
@ -24,7 +53,7 @@ const ChooseCard = ({table, type}) => {
title = <><b>Monopoly</b>! Tap the resource type you want everyone to give you!</>; title = <><b>Monopoly</b>! Tap the resource type you want everyone to give you!</>;
break; break;
case 'year-of-plenty': case 'year-of-plenty':
title = <><b>Year of Plenty</b>! Tap the resource type and receive <b>2</b> from the bank!</>; title = <><b>Year of Plenty</b>! Tap the two resources you want to receive from the bank!</>;
break; break;
} }
@ -32,9 +61,10 @@ const ChooseCard = ({table, type}) => {
<div className="ChooseCard"> <div className="ChooseCard">
<Paper> <Paper>
<div className="Title">{ title }</div> <div className="Title">{ title }</div>
<div style={{display: 'flex', flexDirection: 'row'}}> <div style={{display: 'flex', flexDirection: 'row', justifyContent: 'center'}}>
{ resources } { resources }
</div> </div>
<div className="Actions"><Button disabled={cards.length !== count} onClick={submitCards}>submit</Button></div>
</Paper> </Paper>
</div> </div>
); );

View File

@ -430,7 +430,7 @@ class Table extends React.Component {
this.buildClicked = this.buildClicked.bind(this); this.buildClicked = this.buildClicked.bind(this);
this.closeCard = this.closeCard.bind(this); this.closeCard = this.closeCard.bind(this);
this.playCard = this.playCard.bind(this); this.playCard = this.playCard.bind(this);
this.selectResource = this.selectResource.bind(this); this.selectResources = this.selectResources.bind(this);
this.mouse = { x: 0, y: 0 }; this.mouse = { x: 0, y: 0 };
this.radius = 0.317; this.radius = 0.317;
@ -503,8 +503,8 @@ class Table extends React.Component {
return this.sendAction('chat', undefined, {message: message}); return this.sendAction('chat', undefined, {message: message});
} }
selectResource(card) { selectResources(cards) {
return this.sendAction('select-resource', card); return this.sendAction('select-resources', undefined, cards);
} }
playCard(card) { playCard(card) {
@ -569,7 +569,7 @@ class Table extends React.Component {
if (this.errorTimeout) { if (this.errorTimeout) {
clearTimeout(this.errorTimeout); clearTimeout(this.errorTimeout);
} }
setTimeout(() => this.setState({error: undefined}), 3000); setTimeout(() => { this.setState({error: undefined}) }, 3000);
if (this.state.error !== error) { if (this.state.error !== error) {
this.setState({ error }); this.setState({ error });
} }
@ -951,7 +951,7 @@ class Table extends React.Component {
const game = this.state.game, const game = this.state.game,
player = game ? game.player : undefined, player = game ? game.player : undefined,
isTurn = (game && game.turn && game.turn.color === game.color) ? true : false, isTurn = (game && game.turn && game.turn.color === game.color) ? true : false,
showMessage = (game && game.state === 'lobby'); showMessage = (game && (game.state === 'lobby' || !game.name));
let color; let color;
switch (game ? game.color : undefined) { switch (game ? game.color : undefined) {
@ -1057,7 +1057,7 @@ class Table extends React.Component {
{ game { game
&& isTurn && isTurn
&& game.turn.actions && game.turn.actions
&& game.turn.actions.indexOf('select-resource') !== -1 && && game.turn.actions.indexOf('select-resources') !== -1 &&
<ChooseCard table={this} type={game.turn.active}/> <ChooseCard table={this} type={game.turn.active}/>
} }

View File

@ -762,18 +762,26 @@ const setPlayerName = (game, session, name) => {
if (session.color) { if (session.color) {
return `You cannot change your name while you have a color selected.`; return `You cannot change your name while you have a color selected.`;
} }
let rejoin = false;
/* Check to ensure name is not already in use */ /* Check to ensure name is not already in use */
if (game && name) for (let key in game.sessions) { if (game && name) for (let key in game.sessions) {
const tmp = game.sessions[key]; const tmp = game.sessions[key];
if (tmp === session) {
continue;
}
if (tmp.name && tmp.name.toLowerCase() === name.toLowerCase()) { if (tmp.name && tmp.name.toLowerCase() === name.toLowerCase()) {
if (!tmp.player || (Date.now() - tmp.player.lastActive) > 60000) { if (!tmp.player || (Date.now() - tmp.player.lastActive) > 60000) {
rejoin = true;
Object.assign(session, tmp); Object.assign(session, tmp);
console.log(`${name} has been reallocated to a new session.`);
console.log({ old: game.sessions[key], new: session });
delete game.sessions[key]; delete game.sessions[key];
} else { } else {
return `${name} is already taken and has been active in the last minute.`; return `${name} is already taken and has been active in the last minute.`;
} }
} }
} else {
console.log(`Attempting to create new player for ${name}`);
} }
if (name.toLowerCase() === 'the bank') { if (name.toLowerCase() === 'the bank') {
@ -789,7 +797,11 @@ const setPlayerName = (game, session, name) => {
if (!old) { if (!old) {
message = `A new player has entered the lobby as ${name}.`; message = `A new player has entered the lobby as ${name}.`;
} else { } else {
message = `${old} has changed their name to ${name}.`; if (rejoin) {
message = `${name} has rejoined the game! Welcome back, ${name}.`;
} else {
message = `${old} has changed their name to ${name}.`;
}
} }
} else { } else {
return `You can not set your name to nothing!`; return `You can not set your name to nothing!`;
@ -1558,7 +1570,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
const name = session.name; const name = session.name;
let message, index; let message, index;
let corners, corner, card; let corners, corner, card, cards;
switch (action) { switch (action) {
case "trade": case "trade":
@ -1857,7 +1869,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
break; break;
} }
let victim = game.players[value]; let victim = game.players[value];
const cards = []; cards = [];
[ 'wheat', 'brick', 'sheep', 'stone', 'wood' ].forEach(field => { [ 'wheat', 'brick', 'sheep', 'stone', 'wood' ].forEach(field => {
for (let i = 0; i < victim[field]; i++) { for (let i = 0; i < victim[field]; i++) {
cards.push(field); cards.push(field);
@ -2000,12 +2012,12 @@ router.put("/:id/:action/:value?", async (req, res) => {
placeRoad(game, roads); placeRoad(game, roads);
break; break;
case 'monopoly': case 'monopoly':
game.turn.actions = [ 'select-resource' ]; game.turn.actions = [ 'select-resources' ];
game.turn.active = 'monopoly'; game.turn.active = 'monopoly';
addActivity(game, session, `${session.name} played the Monopoly card, and is selecting their resource type to claim.`); addActivity(game, session, `${session.name} played the Monopoly card, and is selecting their resource type to claim.`);
break; break;
case 'year-of-plenty': case 'year-of-plenty':
game.turn.actions = [ 'select-resource' ]; game.turn.actions = [ 'select-resources' ];
game.turn.active = 'year-of-plenty'; game.turn.active = 'year-of-plenty';
addActivity(game, session, `${session.name} played the Year of Plenty card.`); addActivity(game, session, `${session.name} played the Year of Plenty card.`);
break; break;
@ -2045,9 +2057,9 @@ router.put("/:id/:action/:value?", async (req, res) => {
break; break;
case 'select-resource': case 'select-resources':
if (!game || !game.turn || !game.turn.actions || if (!game || !game.turn || !game.turn.actions ||
game.turn.actions.indexOf('select-resource') === -1) { game.turn.actions.indexOf('select-resources') === -1) {
error = `Please, let's not cheat. Ok?`; error = `Please, let's not cheat. Ok?`;
console.log(game); console.log(game);
break; break;
@ -2058,26 +2070,53 @@ router.put("/:id/:action/:value?", async (req, res) => {
break; break;
} }
const type = value.trim(); const count = (game.turn.active === 'monopoly') ? 1 : 2;
switch (type) {
case 'wheat': cards = req.body;
case 'brick':
case 'sheep': if (!cards || cards.length > count || cards.length === 0) {
case 'stone': error = `You have chosen the wrong number of cards!`;
case 'wood':
break; break;
default: }
error = `That is not a valid resource type!`;
break; const isValidCard = (type) => {
}; switch (type.trim()) {
case 'wheat':
case 'brick':
case 'sheep':
case 'stone':
case 'wood':
return true;
default:
return false;
};
}
const selected = {};
cards.forEach(card => {
if (!isValidCard(card)) {
error = `Invalid resource type!`;
}
if (card in selected) {
selected[card]++;
} else {
selected[card] = 1;
}
});
const display = [];
for (let card in selected) {
display.push(`${selected[card]} ${card}`);
}
if (error) { if (error) {
break; break;
} }
addActivity(game, session, `${session.name} has chosen ${type}!`);
addActivity(game, session, `${session.name} has chosen ${display.join(', ')}!`);
switch (game.turn.active) { switch (game.turn.active) {
case 'monopoly': case 'monopoly':
const gave = []; const gave = [], type = cards[0];
let total = 0; let total = 0;
for (let color in game.players) { for (let color in game.players) {
const player = game.players[color]; const player = game.players[color];
@ -2103,8 +2142,10 @@ router.put("/:id/:action/:value?", async (req, res) => {
break; break;
case 'year-of-plenty': case 'year-of-plenty':
session.player[type] += 2; cards.forEach(type => {
addChatMessage(game, session, `${session.name} received 2 ${type} from the bank.`); session.player[type]++;
});
addChatMessage(game, session, `${session.name} received ${display.join(', ')} from the bank.`);
break; break;
} }
delete game.turn.active; delete game.turn.active;
@ -2620,6 +2661,11 @@ router.put("/:id/:action/:value?", async (req, res) => {
}) })
const ping = (session) => { const ping = (session) => {
if (!session.ws) {
console.log(`Not sending ping to ${session.name} -- connection does not exist.`);
return;
}
session.ping = Date.now(); session.ping = Date.now();
console.log(`Sending ping to ${session.name}`); console.log(`Sending ping to ${session.name}`);
session.ws.send(JSON.stringify({ type: 'ping', ping: session.ping })); session.ws.send(JSON.stringify({ type: 'ping', ping: session.ping }));
@ -2629,17 +2675,63 @@ const ping = (session) => {
session.keepAlive = setTimeout(() => { ping(session); }, 2500); session.keepAlive = setTimeout(() => { ping(session); }, 2500);
} }
const wsInactive = (game, req) => {
const session = getSession(game, req.session);
if (session && session.ws) {
console.log(`Closing WebSocket to ${session.name} due to inactivity.`);
session.ws.close();
session.ws = undefined;
}
/* Prevent future pings */
if (req.keepAlive) {
clearTimeout(req.keepAlive);
}
}
const resetDisconnectCheck = (game, req) => {
if (req.disconnectCheck) {
clearTimeout(req.disconnectCheck);
}
//req.disconnectCheck = setTimeout(() => { wsInactive(game, req) }, 20000);
}
router.ws("/ws/:id", async (ws, req) => { router.ws("/ws/:id", async (ws, req) => {
const { id } = req.params; const { id } = req.params;
/* Setup WebSocket event handlers prior to performing any async calls or /* Setup WebSocket event handlers prior to performing any async calls or
* we may miss the first messages from clients */ * we may miss the first messages from clients */
ws.on('error', (event) => { ws.on('error', async (event) => {
console.error(`WebSocket error: `, event.message); console.error(`WebSocket error: `, event.message);
const game = await loadGame(id);
if (game) {
const session = getSession(game, req.session);
if (session && session.ws) {
session.ws.close();
session.ws = undefined;
}
}
}); });
ws.on('open', (event) => { ws.on('open', async (event) => {
console.log(`WebSocket open: `, event.message); console.log(`WebSocket open: `, event.message);
const game = await loadGame(id);
if (game) {
resetDisconnectCheck(game, req);
}
});
ws.on('close', async (event) => {
const game = await loadGame(id);
if (game) {
const session = getSession(game, req.session);
console.log(`WebSocket closed for ${session.name}`);
if (session && session.ws) {
session.ws.close();
session.ws = undefined;
}
}
}); });
ws.on('message', async (message) => { ws.on('message', async (message) => {
@ -2656,9 +2748,11 @@ router.ws("/ws/:id", async (ws, req) => {
switch (data.type) { switch (data.type) {
case 'pong': case 'pong':
console.log(`Latency for ${session.name ? session.name : 'Unammed'} is ${Date.now() - data.timestamp}`); console.log(`Latency for ${session.name ? session.name : 'Unammed'} is ${Date.now() - data.timestamp}`);
resetDisconnectCheck(game, req);
break; break;
case 'game-update': case 'game-update':
console.log(`Player ${session.name ? session.name : 'Unnamed'} requested a game update.`); console.log(`Player ${session.name ? session.name : 'Unnamed'} requested a game update.`);
resetDisconnectCheck(game, req);
sendGame(req, undefined, game, undefined, ws); sendGame(req, undefined, game, undefined, ws);
break; break;
} }
@ -2678,6 +2772,8 @@ router.ws("/ws/:id", async (ws, req) => {
const session = getSession(game, req.session); const session = getSession(game, req.session);
resetDisconnectCheck(game, req);
console.log(`WebSocket connect from game ${id}:${session.name ? session.name : "Unnamed"}`); console.log(`WebSocket connect from game ${id}:${session.name ? session.name : "Unnamed"}`);
if (session) { if (session) {