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) {
setTimeout(() => hide(10000), 0);
setTimeout(() => { hide(10000) }, 0);
}
let message;

View File

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

View File

@ -1,21 +1,50 @@
import React, { useState, useCallback } from "react";
import "./ChooseCard.css";
import Paper from '@material-ui/core/Paper';
import Button from '@material-ui/core/Button';
import Resource from './Resource.js';
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) {
return <></>;
}
const selectCard = (card) => {
table.selectResource(card);
console.log(cards.length, count);
const submitCards = () => {
table.selectResources(cards);
}
const resources = [
'wheat', 'brick', 'stone', 'sheep', 'wood'
].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;
@ -24,7 +53,7 @@ const ChooseCard = ({table, type}) => {
title = <><b>Monopoly</b>! Tap the resource type you want everyone to give you!</>;
break;
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;
}
@ -32,9 +61,10 @@ const ChooseCard = ({table, type}) => {
<div className="ChooseCard">
<Paper>
<div className="Title">{ title }</div>
<div style={{display: 'flex', flexDirection: 'row'}}>
<div style={{display: 'flex', flexDirection: 'row', justifyContent: 'center'}}>
{ resources }
</div>
<div className="Actions"><Button disabled={cards.length !== count} onClick={submitCards}>submit</Button></div>
</Paper>
</div>
);

View File

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

View File

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