1
0

Lots of fixes. Road mapping, longest army, monopoly, year of plenty (sort of), road building (sort of), etc.

Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
This commit is contained in:
James Ketrenos 2022-02-21 01:50:52 -08:00
parent 433eff8473
commit 2152f6b93a
4 changed files with 188 additions and 28 deletions

View File

@ -2,9 +2,9 @@ import React from "react";
import "./Resource.css";
import { assetsPath } from './Common.js';
const Resource = ({ type, disabled, count }) => {
const Resource = ({ type, select, disabled, count }) => {
const array = new Array(Number(count ? count : 0));
const select = (event) => {
const click = select ? select : (event) => {
if (!disabled) {
event.target.classList.toggle('Selected');
}
@ -16,7 +16,7 @@ const Resource = ({ type, disabled, count }) => {
{ React.Children.map(array, i => (
<div className="Resource"
data-type={type}
onClick={select}
onClick={click}
style={{backgroundImage:`url(${assetsPath}/gfx/card-${type}.png)`}}>
</div>
)) }

View File

@ -16,6 +16,7 @@ import Dice from './Dice.js';
import Resource from './Resource.js';
import ViewCard from './ViewCard.js';
import Winner from './Winner.js';
import ChooseCard from './ChooseCard.js';
/* Start of withRouter polyfill */
// https://reactrouter.com/docs/en/v6/faq#what-happened-to-withrouter-i-need-it
@ -549,6 +550,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.mouse = { x: 0, y: 0 };
this.radius = 0.317;
@ -615,6 +617,10 @@ class Table extends React.Component {
return this.sendAction('chat', undefined, {message: message});
}
selectResource(card) {
return this.sendAction('select-resource', card);
}
playCard(card) {
this.setState({ cardActive: undefined });
return this.sendAction('play-card', undefined, card);
@ -1005,7 +1011,9 @@ class Table extends React.Component {
render() {
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;
let color;
switch (game ? game.color : undefined) {
case "O": color = "orange"; break;
@ -1100,14 +1108,21 @@ class Table extends React.Component {
<Trade table={this}/>
}
{ game
&& isTurn
&& game.turn.actions
&& game.turn.actions.indexOf('select-resource') !== -1 &&
<ChooseCard table={this} type={game.turn.active}/>
}
{ game && game.state === 'normal' &&
game.turn &&
game.turn.color === game.color &&
isTurn &&
game.turn.actions && game.turn.actions.indexOf('steal-resource') !== -1 &&
<SelectPlayer table={this} players={game.turn.limits.players}/>
}
{ game && game.turn && game.turn.color !== game.color &&
{ game && game.turn && !isTurn &&
(game.state === 'initial-placement' || game.state === 'normal') &&
(!game.player || !game.player.mustDiscard) && <WaitingForPlayer table={this}/>
}

View File

@ -34,8 +34,20 @@ const ViewCard = ({table, card}) => {
knight or one progress card.</p></>,
vp: <><b>1</b> victory point.
<p>You only reveal your victory point cards when the game is over, either
when you or an opponent reaches <b>10+</b> victory points on their turn and declares
when you or an opponent
reaches <b>10+</b> victory points on their turn and declares
victory!</p></>,
'progress-road-1': <>
<p>Play <b>2</b> new roads as if you had just built them.</p>
<p>This is still limited by the number of roads you have (a maximum of 15.)</p>
<p><b>NOTE:</b> This card is not yet implemented. The server will give you <b>2</b> wood
and <b>2</b> brick and we trust you will use them to build <b>2</b> roads.</p>
<p>If
you do not have enough roads remaining, you may end up with extra resources...
but the game is in beta, so... be happy :)
</p>
<p>As an FYI, you currently have {15 - table.game.player.roads} roads remaining.</p>
</>,
'progress-road-2': <>
<p>Play <b>2</b> new roads as if you had just built them.</p>
<p>This is still limited by the number of roads you have (a maximum of 15.)</p>
@ -46,6 +58,16 @@ const ViewCard = ({table, card}) => {
but the game is in beta, so... be happy :)
</p>
<p>As an FYI, you currently have {15 - table.game.player.roads} roads remaining.</p>
</>,
'progress-monopoly': <>
When you play this card, you will select <b>1</b> type of resource.
All other players must give you all their resource cards of that type.
</>,
'progress-year-of-plenty': <>
Take any <b>2</b> resources from the bank. Add them to your hand. They can be
<b>2</b> of the same resource or <b>2</b> different resources.
<p><b>Unfortunately</b> the current implementation only lets you pick a single
resource and you will then get <b>2</b> of those.</p>
</>
};
@ -57,7 +79,7 @@ const ViewCard = ({table, card}) => {
}
if (description === undefined) {
console.log('No description for ', card);
console.log(`No description for ${card.type}-${card.card}`);
}
let canPlay = false;
@ -79,11 +101,15 @@ const ViewCard = ({table, card}) => {
}
if (canPlay) {
canPlay = table.game.player.playedCard !== table.game.turns;
if (!canPlay) {
description = <>{description}<p>You have already played a development card this turn.</p></>;
}
}
}
if (card.played) {
description = <>{description}<p>You have already played this card.</p></>;
canPlay = false;
}
return (

View File

@ -562,10 +562,12 @@ const adminActions = (game, action, value) => {
break;
case "give":
parts = value.match(/^([^-]+)-([0-9]+)$/);
parts = value.match(/^([^-]+)-(.*)$/);
if (!parts) {
return `Unable to parse give request.`;
}
const type = parts[1], card = parts[2];
for (let id in game.sessions) {
if (game.sessions[id].name === game.turn.name) {
session = game.sessions[id];
@ -574,12 +576,30 @@ const adminActions = (game, action, value) => {
if (!session) {
return `Unable to determine current player turn to give resources.`;
}
if (!(parts[1] in session.player)) {
return `Invalid resource request.`;
}
session.player[parts[1]] += parseInt(parts[2]);
addChatMessage(game, null, `Admin gave ${parseInt(parts[2])} ${parts[1]} to ${game.turn.name}.`);
if (type in session.player) {
const count = parseInt(card);
session.player[card] += count;
addChatMessage(game, null, `Admin gave ${count} ${type} to ${game.turn.name}.`);
break;
}
const index = game.developmentCards.findIndex(item =>
item.card === card && item.type === type);
if (index === -1) {
console.log({ card, type}, game.developmentCards);
return `Unable to find ${type}-${card} in the current deck of development cards.`;
}
let tmp = game.developmentCards.splice(index, 1)[0];
tmp.turn = game.turns ? game.turns - 1 : 0;
session.player.development.push(tmp);
addChatMessage(game, null, `Admin gave a ${card}-${type} to ${game.turn.name}.`);
break;
case "cards":
let results = game.developmentCards.map(card => `${card.type}-${card.card}`)
.join(', ');
return results;
case "roll":
parts = value.match(/^([1-6])(-([1-6]))?$/);
@ -1187,7 +1207,15 @@ const isCompatibleOffer = (player, offer) => {
return false;
}
console.log(player.gets, player.gives, offer);
console.log({
player: getPlayerName(player),
gets: player.gets,
gives: player.gives
}, {
name: offer.name,
gets: offer.gets,
gives: offer.gives
});
player.gets.forEach(get => {
if (!valid) {
@ -1242,6 +1270,17 @@ const isSameOffer = (player, offer) => {
const checkOffer = (player, offer) => {
let error = undefined;
console.log({
player: getPlayerName(player),
gets: player.gets,
gives: player.gives
}, {
name: offer.name,
gets: offer.gets,
gives: offer.gives
});
offer.gives.forEach(give => {
if (!error) {
return;
@ -1397,7 +1436,6 @@ router.put("/:id/:action/:value?", async (req, res) => {
/* Any player can reject an offer */
if (value === 'reject') {
const offer = req.body;
session.player.offerRejected = true;
addChatMessage(game, session, `${session.name} rejected ${game.turn.name}'s offer.`);
break;
@ -1469,7 +1507,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
});
addChatMessage(game, session, `${session.name} has accepted a trade ` +
`offer for ${offerToString(session.player)} ` +
`offer to give ${offerToString(session.player)} ` +
`from ${(offer.name === 'The bank') ? 'the bank' : offer.name}.`);
delete game.turn.offer;
@ -1709,17 +1747,35 @@ router.put("/:id/:action/:value?", async (req, res) => {
}
}
if (card.type === 'progress' && card.card === 'road-2') {
if (card.type === 'progress') {
switch (card.card) {
case 'road-1':
case 'road-2':
addChatMessage(game, session, `${session.name} played a Road Building card. The server is giving them 2 brick and 2 wood to build those roads!`);
player.brick += 2;
player.wood += 2;
break;
case 'monopoly':
game.turn.actions = [ 'select-resource' ];
game.turn.active = 'monopoly';
addChatMessage(game, session, `${session.name} played the Monopoly card.`);
break;
case 'year-of-plenty':
game.turn.actions = [ 'select-resource' ];
game.turn.active = 'year-of-plenty';
addChatMessage(game, session, `${session.name} played the Year of Plenty card.`);
break;
default:
addChatMessage(game, session, `Oh no! ${card.card} isn't impmented yet!`);
break;
}
}
card.played = true;
player.playedCard = game.turns;
addChatMessage(game, session, `${session.name} played a ${card.type}-${card.card} development card.`);
if (card.type === 'army') {
player.army++;
addChatMessage(game, session, `${session.name} played a Kaniget!`);
if (player.army > 2 &&
(!game.largestArmy || game.players[game.largestArmy].army < player.army)) {
@ -1736,6 +1792,72 @@ router.put("/:id/:action/:value?", async (req, res) => {
break;
case 'select-resource':
if (!game || !game.turn || !game.turn.actions ||
game.turn.actions.indexOf('select-resource') === -1) {
error = `Please, let's not cheat. Ok?`;
console.log(game);
break;
}
if (session.color !== game.turn.color) {
error = `It is not your turn! It is ${game.turn.name}'s turn.`;
break;
}
const type = value.trim();
switch (type) {
case 'wheat':
case 'brick':
case 'sheep':
case 'stone':
case 'wood':
break;
default:
error = `That is not a valid resource type!`;
break;
};
if (error) {
break;
}
addChatMessage(game, session, `${session.name} has chosen ${type}!`);
switch (game.turn.active) {
case 'monopoly':
const gave = [];
let total = 0;
for (let color in game.players) {
const player = game.players[color];
if (player.status === 'Not active') {
continue
}
if (color === session.color) {
continue;
}
if (player[type]) {
gave.push(`${playerNameFromColor(game, color)} gave ${player[type]} ${type}`);
session.player[type] += player[type];
total += player[type];
player[type] = 0;
}
}
if (gave.length) {
addChatMessage(game, session, `Players ${gave.join(', ')}. In total, ${session.name} received ${total} ${type}.`);
} else {
addChatMessage(game, session, 'No players had that resource. Wa-waaaa.');
}
break;
case 'year-of-plenty':
session.player[type] += 2;
addChatMessage(game, session, `${session.name} received 2 ${type} from the bank.`);
break;
}
delete game.turn.active;
game.turn.actions = [];
break;
case 'buy-settlement':
if (game.state !== 'normal') {
error = `You cannot purchase a settlement unless the game is active.`;
@ -2197,10 +2319,8 @@ const debugChat = (game, preamble) => {
}
playerInventory += ` ${playerNameFromColor(game, key)} has `;
const has = [ 'wheat', 'brick', 'sheep', 'stone', 'wood' ].map(resource => {
if (game.players[key][resource] > 0) {
return `${game.players[key][resource]} ${resource}`;
}
return '';
const count = game.players[key][resource] ? game.players[key][resource] : 0;
return `${count} ${resource}`;
}).filter(item => item !== '').join(', ');
if (has) {
playerInventory += `${has}, `;
@ -2276,7 +2396,6 @@ const sendGame = async (req, res, game, error) => {
lastTime = message.date;
});
/* Calculate points and determine if there is a winner */
for (let key in game.players) {
const player = game.players[key];