Implemented YoP and Monopoly
Lots of fixes Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
This commit is contained in:
parent
83aafd981c
commit
96723e135c
@ -16,7 +16,7 @@ const Activity = ({ activity }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (display) {
|
if (display) {
|
||||||
setTimeout(() => hide(10000), 0);
|
setTimeout(() => { hide(10000) }, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
let message;
|
let message;
|
||||||
|
@ -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;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
);
|
);
|
||||||
|
@ -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}/>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user