From 163c020137c325577d59d46aa6afbdbded2184fc Mon Sep 17 00:00:00 2001 From: Jeff Heiges Date: Tue, 11 Mar 2025 09:55:13 +0000 Subject: Fixed all remaining hasOwnProperty errors --- diplomacy/web/src/diplomacy/client/channel.js | 2 +- diplomacy/web/src/diplomacy/client/connection.js | 8 ++--- .../web/src/diplomacy/client/game_instance_set.js | 14 ++++----- diplomacy/web/src/diplomacy/client/network_game.js | 6 ++-- .../src/diplomacy/client/notification_managers.js | 8 ++--- .../src/diplomacy/client/request_future_context.js | 4 +-- .../web/src/diplomacy/client/response_managers.js | 2 +- .../src/diplomacy/communication/notifications.js | 2 +- .../web/src/diplomacy/communication/requests.js | 8 ++--- diplomacy/web/src/diplomacy/engine/game.js | 34 +++++++++++----------- diplomacy/web/src/diplomacy/utils/utils.js | 8 ++--- diplomacy/web/src/gui/components/forms.jsx | 2 +- diplomacy/web/src/gui/components/tabs.jsx | 2 +- diplomacy/web/src/gui/maps/ancmed/SvgAncMed.js | 2 +- diplomacy/web/src/gui/maps/standard/SvgStandard.js | 2 +- diplomacy/web/src/gui/pages/content_connection.jsx | 2 +- 16 files changed, 53 insertions(+), 53 deletions(-) (limited to 'diplomacy') diff --git a/diplomacy/web/src/diplomacy/client/channel.js b/diplomacy/web/src/diplomacy/client/channel.js index eb8692a..6a70635 100644 --- a/diplomacy/web/src/diplomacy/client/channel.js +++ b/diplomacy/web/src/diplomacy/client/channel.js @@ -29,7 +29,7 @@ export class Channel { localJoinGame(joinParameters) { // Game ID must be known. - if (this.game_id_to_instances.hasOwnProperty(joinParameters.game_id)) { + if (Object.prototype.hasOwnProperty.call(this.game_id_to_instances, joinParameters.game_id)) { // If there is a power name, we return associated power game. if (joinParameters.power_name) return this.game_id_to_instances[joinParameters.game_id].get(joinParameters.power_name); diff --git a/diplomacy/web/src/diplomacy/client/connection.js b/diplomacy/web/src/diplomacy/client/connection.js index 1e40ed8..179f090 100644 --- a/diplomacy/web/src/diplomacy/client/connection.js +++ b/diplomacy/web/src/diplomacy/client/connection.js @@ -70,7 +70,7 @@ class Reconnection { for (let game of gis.getGames()) { const game_id = game.local.game_id; const game_role = game.local.role; - if (!this.games_phases.hasOwnProperty(game_id)) + if (!Object.prototype.hasOwnProperty.call(this.games_phases, game_id)) this.games_phases[game_id] = {}; this.games_phases[game_id][game_role] = null; ++this.n_expected_games; @@ -251,7 +251,7 @@ export class Connection { } if (jsonMessage.request_id) { const requestID = jsonMessage.request_id; - if (!this.requestsWaitingResponses.hasOwnProperty(requestID)) { + if (!Object.prototype.hasOwnProperty.call(this.requestsWaitingResponses, requestID)) { Diplog.error('Unknown request ' + requestID + '.'); return; } @@ -310,13 +310,13 @@ export class Connection { const onConnected = () => { connection.socket.send(JSON.stringify(request)); connection.requestsWaitingResponses[requestID] = requestContext; - if (connection.requestsToSend.hasOwnProperty(requestID)) { + if (Object.prototype.hasOwnProperty.call(connection.requestsToSend, requestID)) { delete connection.requestsToSend[requestID]; } writeFuture.setResult(null); }; const onAnyError = (error) => { - if (!connection.requestsToSend.hasOwnProperty(requestID)) { + if (!Object.prototype.hasOwnProperty.call(connection.requestsToSend, requestID)) { connection.requestsToSend[requestID] = requestContext; } Diplog.info('Error occurred while sending a request ' + requestID); diff --git a/diplomacy/web/src/diplomacy/client/game_instance_set.js b/diplomacy/web/src/diplomacy/client/game_instance_set.js index ca92e48..b03b027 100644 --- a/diplomacy/web/src/diplomacy/client/game_instance_set.js +++ b/diplomacy/web/src/diplomacy/client/game_instance_set.js @@ -28,7 +28,7 @@ export class GameInstanceSet { } has(role) { - return this.__games.hasOwnProperty(role); + return Object.prototype.hasOwnProperty.call(this.__games, role); } get(role) { @@ -36,9 +36,9 @@ export class GameInstanceSet { } getSpecial() { - if (this.__games.hasOwnProperty(STRINGS.OBSERVER_TYPE)) + if (Object.prototype.hasOwnProperty.call(this.__games, STRINGS.OBSERVER_TYPE)) return this.__games[STRINGS.OBSERVER_TYPE]; - if (this.__games.hasOwnProperty(STRINGS.OMNISCIENT_TYPE)) + if (Object.prototype.hasOwnProperty.call(this.__games, STRINGS.OMNISCIENT_TYPE)) return this.__games[STRINGS.OMNISCIENT_TYPE]; return null; } @@ -53,19 +53,19 @@ export class GameInstanceSet { } removeSpecial() { - if (this.__games.hasOwnProperty(STRINGS.OBSERVER_TYPE)) + if (Object.prototype.hasOwnProperty.call(this.__games, STRINGS.OBSERVER_TYPE)) delete this.__games[STRINGS.OBSERVER_TYPE]; - if (this.__games.hasOwnProperty(STRINGS.OMNISCIENT_TYPE)) + if (Object.prototype.hasOwnProperty.call(this.__games, STRINGS.OMNISCIENT_TYPE)) delete this.__games[STRINGS.OMNISCIENT_TYPE]; } add(game) { if (game.local.game_id !== this.__game_id) throw new Error('game ID to add does not match game instance set ID.'); - if (this.__games.hasOwnProperty(game.local.role)) + if (Object.prototype.hasOwnProperty.call(this.__games, game.local.role)) throw new Error('Role already in game instance set.'); if (!game.local.isPlayerGame() && ( - this.__games.hasOwnProperty(STRINGS.OBSERVER_TYPE) || this.__games.hasOwnProperty(STRINGS.OMNISCIENT_TYPE))) + Object.prototype.hasOwnProperty.call(this.__games, STRINGS.OBSERVER_TYPE) || Object.prototype.hasOwnProperty.call(this.__games, STRINGS.OMNISCIENT_TYPE))) throw new Error('Previous special game must be removed before adding new one.'); this.__games[game.local.role] = game; } diff --git a/diplomacy/web/src/diplomacy/client/network_game.js b/diplomacy/web/src/diplomacy/client/network_game.js index 9999093..85571e2 100644 --- a/diplomacy/web/src/diplomacy/client/network_game.js +++ b/diplomacy/web/src/diplomacy/client/network_game.js @@ -32,14 +32,14 @@ export class NetworkGame { } addCallback(notificationName, notificationCallback) { - if (!this.notificationCallbacks.hasOwnProperty(notificationName)) + if (!Object.prototype.hasOwnProperty.call(this.notificationCallbacks, notificationName)) this.notificationCallbacks[notificationName] = [notificationCallback]; else if (!this.notificationCallbacks[notificationName].includes(notificationCallback)) this.notificationCallbacks[notificationName].push(notificationCallback); } clearCallbacks(notificationName) { - if (this.notificationCallbacks.hasOwnProperty(notificationName)) + if (Object.prototype.hasOwnProperty.call(this.notificationCallbacks, notificationName)) delete this.notificationCallbacks[notificationName]; } @@ -48,7 +48,7 @@ export class NetworkGame { } notify(notification) { - if (this.notificationCallbacks.hasOwnProperty(notification.name)) { + if (Object.prototype.hasOwnProperty.call(this.notificationCallbacks, notification.name)) { for (let callback of this.notificationCallbacks[notification.name]) setTimeout(() => callback(this, notification), 0); } diff --git a/diplomacy/web/src/diplomacy/client/notification_managers.js b/diplomacy/web/src/diplomacy/client/notification_managers.js index bbfe862..5241316 100644 --- a/diplomacy/web/src/diplomacy/client/notification_managers.js +++ b/diplomacy/web/src/diplomacy/client/notification_managers.js @@ -23,7 +23,7 @@ import {Game} from "../engine/game"; export const NOTIFICATION_MANAGERS = { account_deleted: function (channel, notification) { const connection = channel.connection; - if (connection.channels.hasOwnProperty(channel.token)) + if (Object.prototype.hasOwnProperty.call(connection.channels, channel.token)) delete channel.connection.channels[channel.token]; }, cleared_centers: function (game, notification) { @@ -105,15 +105,15 @@ export const NOTIFICATION_MANAGERS = { } }, handleNotification: function (connection, notification) { - if (!NOTIFICATION_MANAGERS.hasOwnProperty(notification.name)) + if (!Object.prototype.hasOwnProperty.call(NOTIFICATION_MANAGERS, notification.name)) throw new Error('No notification handler available for notification ' + notification.name); const handler = NOTIFICATION_MANAGERS[notification.name]; const level = NOTIFICATIONS.levels[notification.name]; - if (!connection.channels.hasOwnProperty(notification.token)) + if (!Object.prototype.hasOwnProperty.call(connection.channels, notification.token)) throw new Error('Unable to find channel related to notification ' + notification.name); let objectToNotify = connection.channels[notification.token]; if (level === STRINGS.GAME) { - if (objectToNotify.game_id_to_instances.hasOwnProperty(notification.game_id) + if (Object.prototype.hasOwnProperty.call(objectToNotify.game_id_to_instances, notification.game_id) && objectToNotify.game_id_to_instances[notification.game_id].has(notification.game_role)) objectToNotify = objectToNotify.game_id_to_instances[notification.game_id].get(notification.game_role); else diff --git a/diplomacy/web/src/diplomacy/client/request_future_context.js b/diplomacy/web/src/diplomacy/client/request_future_context.js index 16103fb..febd75f 100644 --- a/diplomacy/web/src/diplomacy/client/request_future_context.js +++ b/diplomacy/web/src/diplomacy/client/request_future_context.js @@ -45,7 +45,7 @@ export class RequestFutureContext { newGame(received_game) { const channel = this.getChannel(); const game = new NetworkGame(channel, received_game); - if (!channel.game_id_to_instances.hasOwnProperty(game.local.game_id)) + if (!Object.prototype.hasOwnProperty.call(channel.game_id_to_instances, game.local.game_id)) channel.game_id_to_instances[game.local.game_id] = new GameInstanceSet(game.local.game_id); channel.game_id_to_instances[game.local.game_id].add(game); return game; @@ -57,7 +57,7 @@ export class RequestFutureContext { deleteGame() { const channel = this.getChannel(); - if (channel.game_id_to_instances.hasOwnProperty(this.request.game_id)) + if (Object.prototype.hasOwnProperty.call(channel.game_id_to_instances, this.request.game_id)) delete channel.game_id_to_instances[this.request.game_id]; } } diff --git a/diplomacy/web/src/diplomacy/client/response_managers.js b/diplomacy/web/src/diplomacy/client/response_managers.js index ba45938..125c3a9 100644 --- a/diplomacy/web/src/diplomacy/client/response_managers.js +++ b/diplomacy/web/src/diplomacy/client/response_managers.js @@ -110,7 +110,7 @@ export const RESPONSE_MANAGERS = { return context.newChannel(context.request.username, response.data); }, handleResponse: function (context, response) { - if (!RESPONSE_MANAGERS.hasOwnProperty(context.request.name)) + if (!Object.prototype.hasOwnProperty.call(RESPONSE_MANAGERS, context.request.name)) throw new Error('No response handler available for request ' + context.request.name); const handler = RESPONSE_MANAGERS[context.request.name]; return handler(context, response); diff --git a/diplomacy/web/src/diplomacy/communication/notifications.js b/diplomacy/web/src/diplomacy/communication/notifications.js index 5b66783..9cf06a8 100644 --- a/diplomacy/web/src/diplomacy/communication/notifications.js +++ b/diplomacy/web/src/diplomacy/communication/notifications.js @@ -43,7 +43,7 @@ export const NOTIFICATIONS = { throw new Error('No name field in expected notification object.'); if (!Object.prototype.hasOwnProperty.call(jsonObject, 'token')) throw new Error('No token field in expected notification object.'); - if (!NOTIFICATIONS.levels.hasOwnProperty(jsonObject.name)) + if (!Object.prototype.hasOwnProperty.call(NOTIFICATIONS.levels, jsonObject.name)) throw new Error('Invalid notification name ' + jsonObject.name); if (NOTIFICATIONS.levels[jsonObject.name] === STRINGS.GAME) { if (!Object.prototype.hasOwnProperty.call(jsonObject, 'game_id')) diff --git a/diplomacy/web/src/diplomacy/communication/requests.js b/diplomacy/web/src/diplomacy/communication/requests.js index 5963827..5d58fbc 100644 --- a/diplomacy/web/src/diplomacy/communication/requests.js +++ b/diplomacy/web/src/diplomacy/communication/requests.js @@ -79,7 +79,7 @@ export const REQUESTS = { }, isPhaseDependent: function (name) { - if (!REQUESTS.models.hasOwnProperty(name)) + if (!Object.prototype.hasOwnProperty.call(REQUESTS.models, name)) throw new Error('Unknown request name ' + name); const model = REQUESTS.models[name]; return (model.level === STRINGS.GAME && (!Object.prototype.hasOwnProperty.call(model, 'phase_dependent') || model.phase_dependent)); @@ -87,7 +87,7 @@ export const REQUESTS = { /** Return request level for given request name. Either null, 'channel' or 'game'. **/ getLevel: function (name) { - if (!REQUESTS.models.hasOwnProperty(name)) + if (!Object.prototype.hasOwnProperty.call(REQUESTS.models, name)) throw new Error('Unknown request name ' + name); return REQUESTS.models[name].level; }, @@ -98,7 +98,7 @@ export const REQUESTS = { * diplomacy.communication.requests about requests definitions, required and optional fields. * **/ create: function (name, parameters) { - if (!REQUESTS.models.hasOwnProperty(name)) + if (!Object.prototype.hasOwnProperty.call(REQUESTS.models, name)) throw new Error('Unknown request name ' + name); let models = null; const definition = REQUESTS.models[name]; @@ -111,7 +111,7 @@ export const REQUESTS = { models.push(REQUESTS.abstract.basic); models.push({name: name}); const request = Object.assign.apply(null, models); - if (parameters) for (let parameter of Object.keys(parameters)) if (request.hasOwnProperty(parameter)) + if (parameters) for (let parameter of Object.keys(parameters)) if (Object.prototype.hasOwnProperty.call(request, parameter)) request[parameter] = parameters[parameter]; if (!request.request_id) request.request_id = UTILS.createID(); diff --git a/diplomacy/web/src/diplomacy/engine/game.js b/diplomacy/web/src/diplomacy/engine/game.js index e86ae85..c5c23f7 100644 --- a/diplomacy/web/src/diplomacy/engine/game.js +++ b/diplomacy/web/src/diplomacy/engine/game.js @@ -40,9 +40,9 @@ export function comparablePhase(shortPhaseName) { const phaseStep = shortPhaseName[5]; if (isNaN(phaseYear)) throw new Error(`Unable to parse phase year from ${shortPhaseName}`); - if (!seasonOrder.hasOwnProperty(phaseSeason)) + if (!Object.prototype.hasOwnProperty.call(seasonOrder, phaseSeason)) throw new Error(`Unable to parse phase season from ${shortPhaseName}`); - if (!stepOrder.hasOwnProperty(phaseStep)) + if (!Object.prototype.hasOwnProperty.call(stepOrder, phaseStep)) throw new Error(`Unable to parse phase step from ${shortPhaseName}`); return (phaseYear * 100) + (seasonOrder[phaseSeason] * 10) + stepOrder[phaseStep]; } @@ -62,10 +62,10 @@ export class Game { const nullFields = ['n_controls', 'registration_password']; // All fields are required. for (let field of nonNullFields) - if (!gameData.hasOwnProperty(field) || gameData[field] == null) + if (!Object.prototype.hasOwnProperty.call(gameData, field) || gameData[field] == null) throw new Error('Game: given state must have field `' + field + '` with non-null value.'); for (let field of nullFields) - if (!gameData.hasOwnProperty(field)) + if (!Object.prototype.hasOwnProperty.call(gameData, field)) throw new Error('Game: given state must have field `' + field + '`.'); this.game_id = gameData.game_id; @@ -211,7 +211,7 @@ export class Game { message = new Message(message); if (!message.time_sent) throw new Error('No time sent for given message.'); - if (this.messages.hasOwnProperty(message.time_sent)) + if (Object.prototype.hasOwnProperty.call(this.messages, message.time_sent)) throw new Error('There is already a message with time sent ' + message.time_sent + ' in message history.'); if (this.isPlayerGame() && !message.isGlobal() && this.role !== message.sender && this.role !== message.recipient) throw new Error('Given message is not related to current player ' + this.role); @@ -280,7 +280,7 @@ export class Game { } getPower(name) { - return this.powers.hasOwnProperty(name) ? this.powers[name] : null; + return Object.prototype.hasOwnProperty.call(this.powers, name) ? this.powers[name] : null; } getRelatedPower() { @@ -288,7 +288,7 @@ export class Game { } hasPower(powerName) { - return this.powers.hasOwnProperty(powerName); + return Object.prototype.hasOwnProperty.call(this.powers, powerName); } isPlayerGame(powerName) { @@ -327,7 +327,7 @@ export class Game { this.phase = state.name; if (state.units) { for (let power_name of Object.keys(state.units)) { - if (this.powers.hasOwnProperty(power_name)) { + if (Object.prototype.hasOwnProperty.call(this.powers, power_name)) { const units = state.units[power_name]; const power = this.powers[power_name]; power.retreats = {}; @@ -343,19 +343,19 @@ export class Game { } if (state.centers) for (let power_name of Object.keys(state.centers)) - if (this.powers.hasOwnProperty(power_name)) + if (Object.prototype.hasOwnProperty.call(this.powers, power_name)) this.powers[power_name].centers = state.centers[power_name]; if (state.homes) for (let power_name of Object.keys(state.homes)) - if (this.powers.hasOwnProperty(power_name)) + if (Object.prototype.hasOwnProperty.call(this.powers, power_name)) this.powers[power_name].homes = state.homes[power_name]; if (state.influence) for (let power_name of Object.keys(state.influence)) - if (this.powers.hasOwnProperty(power_name)) + if (Object.prototype.hasOwnProperty.call(this.powers, power_name)) this.powers[power_name].influence = state.influence[power_name]; if (state.civil_disorder) for (let power_name of Object.keys(state.civil_disorder)) - if (this.powers.hasOwnProperty(power_name)) + if (Object.prototype.hasOwnProperty.call(this.powers, power_name)) this.powers[power_name].civil_disorder = state.civil_disorder[power_name]; if (state.builds) this.builds = state.builds; @@ -366,18 +366,18 @@ export class Game { } setOrders(powerName, orders) { - if (this.powers.hasOwnProperty(powerName) && (!this.isPlayerGame() || this.isPlayerGame(powerName))) + if (Object.prototype.hasOwnProperty.call(this.powers, powerName) && (!this.isPlayerGame() || this.isPlayerGame(powerName))) this.powers[powerName].setOrders(orders); } setWait(powerName, wait) { - if (this.powers.hasOwnProperty(powerName)) { + if (Object.prototype.hasOwnProperty.call(this.powers, powerName)) { this.powers[powerName].wait = wait; } } updateDummyPowers(dummyPowers) { - for (let dummyPowerName of dummyPowers) if (this.powers.hasOwnProperty(dummyPowerName)) + for (let dummyPowerName of dummyPowers) if (Object.prototype.hasOwnProperty.call(this.powers, dummyPowerName)) this.powers[dummyPowerName].setDummy(); } @@ -466,7 +466,7 @@ export class Game { protagonist = message.recipient; else if (message.recipient === role) protagonist = message.sender; - if (!messageChannels.hasOwnProperty(protagonist)) + if (!Object.prototype.hasOwnProperty.call(messageChannels, protagonist)) messageChannels[protagonist] = []; messageChannels[protagonist].push(message); } @@ -502,7 +502,7 @@ export class Game { for (let associatedLoc of associatedLocs) { const orderTypes = this.orderableLocToTypes[associatedLoc]; for (let orderType of orderTypes) { - if (!typeToLocs.hasOwnProperty(orderType)) + if (!Object.prototype.hasOwnProperty.call(typeToLocs, orderType)) typeToLocs[orderType] = [associatedLoc]; else typeToLocs[orderType].push(associatedLoc); diff --git a/diplomacy/web/src/diplomacy/utils/utils.js b/diplomacy/web/src/diplomacy/utils/utils.js index 8e54515..59d36a3 100644 --- a/diplomacy/web/src/diplomacy/utils/utils.js +++ b/diplomacy/web/src/diplomacy/utils/utils.js @@ -116,7 +116,7 @@ export const UTILS = { }, extendArrayWithUniqueValues(obj, key, value) { - if (!obj.hasOwnProperty(key)) + if (!Object.prototype.hasOwnProperty.call(obj, key)) obj[key] = [value]; else if (!obj[key].includes(value)) obj[key].push(value); @@ -128,12 +128,12 @@ export const UTILS = { const parentPathLength = pathLength - 1; for (let i = 0; i < parentPathLength; ++i) { const stepName = path[i]; - if (!current.hasOwnProperty(stepName)) + if (!Object.prototype.hasOwnProperty.call(current, stepName)) current[stepName] = new Dict(); current = current[stepName]; } const stepName = path[pathLength - 1]; - if (!current.hasOwnProperty(stepName)) + if (!Object.prototype.hasOwnProperty.call(current, stepName)) current[stepName] = []; if (allowMultipleValues || !current[stepName].includes(value)) current[stepName].push(value); @@ -142,7 +142,7 @@ export const UTILS = { getTreeValue: function (obj, path) { let current = obj; for (let stepName of path) { - if (!current.hasOwnProperty(stepName)) + if (!Object.prototype.hasOwnProperty.call(current, stepName)) return null; current = current[stepName]; } diff --git a/diplomacy/web/src/gui/components/forms.jsx b/diplomacy/web/src/gui/components/forms.jsx index da7250d..5c42b44 100644 --- a/diplomacy/web/src/gui/components/forms.jsx +++ b/diplomacy/web/src/gui/components/forms.jsx @@ -52,7 +52,7 @@ export class Forms { } static getValue(fieldValues, fieldName, defaultValue) { - return fieldValues.hasOwnProperty(fieldName) ? fieldValues[fieldName] : defaultValue; + return Object.prototype.hasOwnProperty.call(fieldValues, fieldName) ? fieldValues[fieldName] : defaultValue; } static createReset(title, large, onReset) { diff --git a/diplomacy/web/src/gui/components/tabs.jsx b/diplomacy/web/src/gui/components/tabs.jsx index a3f6b9b..d0112f2 100644 --- a/diplomacy/web/src/gui/components/tabs.jsx +++ b/diplomacy/web/src/gui/components/tabs.jsx @@ -46,7 +46,7 @@ export class Tabs extends React.Component { {this.props.children} diff --git a/diplomacy/web/src/gui/maps/ancmed/SvgAncMed.js b/diplomacy/web/src/gui/maps/ancmed/SvgAncMed.js index d726a67..c119ff1 100644 --- a/diplomacy/web/src/gui/maps/ancmed/SvgAncMed.js +++ b/diplomacy/web/src/gui/maps/ancmed/SvgAncMed.js @@ -17,4 +17,4 @@ Copyright (C) 2019 - Philip Paquette, Steven Bocco ============================================================================== **/ /** Generated with parameters: Namespace(input='src/diplomacy/maps/svg/ancmed.svg', name='SvgAncMed', output='src/gui/maps/ancmed/') **/ - import React from 'react'; import PropTypes from 'prop-types'; import './SvgAncMed.css'; import {Coordinates, SymbolSizes, Colors} from "./SvgAncMedMetadata"; import {getClickedID, parseLocation, setInfluence} from "../common/common"; import {Game} from "../../../diplomacy/engine/game"; import {MapData} from "../../utils/map_data"; import {UTILS} from "../../../diplomacy/utils/utils"; import {Diplog} from "../../../diplomacy/utils/diplog"; import {extendOrderBuilding} from "../../utils/order_building"; import {Unit} from "../common/unit"; import {Hold} from "../common/hold"; import {Move} from "../common/move"; import {SupportMove} from "../common/supportMove"; import {SupportHold} from "../common/supportHold"; import {Convoy} from "../common/convoy"; import {Build} from "../common/build"; import {Disband} from "../common/disband"; export class SvgAncMed extends React.Component { constructor(props) { super(props); this.onClick = this.onClick.bind(this); this.onHover = this.onHover.bind(this); } onClick(event) { if (this.props.orderBuilding) return this.handleClickedID(getClickedID(event)); } onHover(event) { return this.handleHoverID(getClickedID(event)); } handleClickedID(id) { const orderBuilding = this.props.orderBuilding; if (!orderBuilding.builder) return this.props.onError('No orderable locations.'); const province = this.props.mapData.getProvince(id); if (!province) throw new Error(`Cannot find a province named ${id}`); const stepLength = orderBuilding.builder.steps.length; if (orderBuilding.path.length >= stepLength) throw new Error(`Order building: current steps count (${orderBuilding.path.length}) should be less than expected steps count (${stepLength}) (${orderBuilding.path.join(', ')}).`); const lengthAfterClick = orderBuilding.path.length + 1; let validLocations = []; const testedPath = [orderBuilding.type].concat(orderBuilding.path); const value = UTILS.javascript.getTreeValue(this.props.game.ordersTree, testedPath); if (value !== null) { const checker = orderBuilding.builder.steps[lengthAfterClick - 1]; try { const possibleLocations = checker(province, orderBuilding.power); for (let possibleLocation of possibleLocations) { possibleLocation = possibleLocation.toUpperCase(); if (value.includes(possibleLocation)) validLocations.push(possibleLocation); } } catch (error) { return this.props.onError(error); } } if (!validLocations.length) return this.props.onError('Disallowed.'); if (validLocations.length > 1 && orderBuilding.type === 'S' && orderBuilding.path.length >= 2) { /* We are building a support order and we have a multiple choice for a location. */ /* Let's check if next location to choose is a coast. To have a coast: */ /* - all possible locations must start with same 3 characters. */ /* - we expect at least province name in possible locations (e.g. 'SPA' for 'SPA/NC'). */ /* If we have a coast, we will remove province name from possible locations. */ let isACoast = true; let validLocationsNoProvinceName = []; for (let i = 0; i < validLocations.length; ++i) { let location = validLocations[i]; if (i > 0) { /* Compare 3 first letters with previous location. */ if (validLocations[i - 1].substring(0, 3).toUpperCase() !== validLocations[i].substring(0, 3).toUpperCase()) { /* No same prefix with previous location. We does not have a coast. */ isACoast = false; break; } } if (location.length !== 3) validLocationsNoProvinceName.push(location); } if (validLocations.length === validLocationsNoProvinceName.length) { /* We have not found province name. */ isACoast = false; } if (isACoast) { /* We want to choose location in a coastal province. Let's remove province name. */ validLocations = validLocationsNoProvinceName; } } if (validLocations.length > 1) { if (this.props.onSelectLocation) { return this.props.onSelectLocation(validLocations, orderBuilding.power, orderBuilding.type, orderBuilding.path); } else { Diplog.warn(`Forced to select first valid location.`); validLocations = [validLocations[0]]; } } let orderBuildingType = orderBuilding.type; if (lengthAfterClick === stepLength && orderBuildingType === 'M') { const moveOrderPath = ['M'].concat(orderBuilding.path, validLocations[0]); const moveTypes = UTILS.javascript.getTreeValue(this.props.game.ordersTree, moveOrderPath); if (moveTypes !== null) { if (moveTypes.length === 2 && this.props.onSelectVia) { /* This move can be done either regularly or VIA a fleet. Let user choose. */ return this.props.onSelectVia(validLocations[0], orderBuilding.power, orderBuilding.path); } else { orderBuildingType = moveTypes[0]; } } } extendOrderBuilding( orderBuilding.power, orderBuildingType, orderBuilding.path, validLocations[0], this.props.onOrderBuilding, this.props.onOrderBuilt, this.props.onError ); } handleHoverID(id) { if (this.props.onHover) { const province = this.props.mapData.getProvince(id); if (province) { this.props.onHover(province.name, this.getRelatedOrders(province.name)); } } } getRelatedOrders(name) { const orders = []; if (this.props.orders) { for (let powerOrders of Object.values(this.props.orders)) { if (powerOrders) { for (let order of powerOrders) { const pieces = order.split(/ +/); if (pieces[1].slice(0, 3) === name.toUpperCase().slice(0, 3)) orders.push(order); } } } } return orders; } getNeighbors(extraLocation) { const selectedPath = [this.props.orderBuilding.type].concat(this.props.orderBuilding.path); if (extraLocation) selectedPath.push(extraLocation); const possibleNeighbors = UTILS.javascript.getTreeValue(this.props.game.ordersTree, selectedPath); const neighbors = possibleNeighbors ? possibleNeighbors.map(neighbor => parseLocation(neighbor)) : []; return neighbors.length ? neighbors: null; } render() { const classes = {"_adr":"water","_aeg":"water","_ale":"nopower","_ant":"nopower","_apu":"nopower","_ara":"nopower","_arm":"nopower","_ath":"nopower","_aus":"water","_bal":"nopower","_bay":"nopower","_ber":"water","_bit":"nopower","_bla":"water","_byz":"nopower","_cap":"nopower","_car":"nopower","_che":"nopower","_cil":"water","_cir":"nopower","_cor":"nopower","_cre":"nopower","_cyp":"nopower","_cyr":"nopower","_dac":"nopower","_dal":"nopower","_dam":"nopower","_egy":"water","_epi":"nopower","_etr":"nopower","_gal":"nopower","_gau":"nopower","_gop":"water","_gos":"water","_got":"water","_ibe":"water","_ill":"nopower","_ion":"water","_isa":"nopower","_jer":"nopower","_lep":"nopower","_lib":"water","_lig":"water","_lus":"nopower","_mac":"nopower","_mar":"nopower","_mas":"nopower","_mau":"nopower","_mem":"nopower","_mes":"water","_mil":"nopower","_min":"water","_nab":"nopower","_nea":"nopower","_num":"nopower","_pet":"nopower","_pha":"nopower","_pun":"water","_rav":"nopower","_ree":"water","_rha":"nopower","_rom":"nopower","_sag":"nopower","_sah":"nopower","_sad":"nopower","_sam":"nopower","_sic":"nopower","_sid":"nopower","_sin":"nopower","_sip":"nopower","_spa":"nopower","_syr":"water","_tar":"nopower","_tha":"nopower","_thb":"nopower","_tye":"nopower","_tyn":"water","_ven":"nopower","_vin":"nopower","water":"water","BriefLabelLayer":"smalllabeltext","CurrentNote":"currentnotetext","CurrentNote2":"currentnotetext","CurrentPhase":"currentphasetext","MouseLayer":"invisibleContent"}; const game = this.props.game; const mapData = this.props.mapData; const orders = this.props.orders; /* Current phase. */ const current_phase = (game.phase[0] === '?' || game.phase === 'COMPLETED') ? 'FINAL' : game.phase; /* Notes. */ const nb_centers = []; for (let power of Object.values(game.powers)) { if (!power.isEliminated()) nb_centers.push([power.name.substr(0, 3), power.centers.length]); } /* Sort nb_centers by descending number of centers. */ nb_centers.sort((a, b) => { return -(a[1] - b[1]) || a[0].localeCompare(b[0]); }); const nb_centers_per_power = nb_centers.map((couple) => (couple[0] + ': ' + couple[1])).join(' '); const note = game.note; /* Adding units, influence and orders. */ const renderedUnits = []; const renderedDislodgedUnits = []; const renderedOrders = []; const renderedOrders2 = []; const renderedHighestOrders = []; for (let power of Object.values(game.powers)) if (!power.isEliminated()) { for (let unit of power.units) { renderedUnits.push( ); } for (let unit of Object.keys(power.retreats)) { renderedDislodgedUnits.push( ); } for (let center of power.centers) { setInfluence(classes, mapData, center, power.name); } for (let loc of power.influence) { if (!mapData.supplyCenters.has(loc)) setInfluence(classes, mapData, loc, power.name); } if (orders) { const powerOrders = (orders && orders.hasOwnProperty(power.name) && orders[power.name]) || []; for (let order of powerOrders) { const tokens = order.split(/ +/); if (!tokens || tokens.length < 3) continue; const unit_loc = tokens[1]; if (tokens[2] === 'H') { renderedOrders.push( ); } else if (tokens[2] === '-') { const destLoc = tokens[tokens.length - (tokens[tokens.length - 1] === 'VIA' ? 2 : 1)]; renderedOrders.push( ); } else if (tokens[2] === 'S') { const destLoc = tokens[tokens.length - 1]; if (tokens.includes('-')) { const srcLoc = tokens[4]; renderedOrders2.push( ); } else { renderedOrders2.push( ); } } else if (tokens[2] === 'C') { const srcLoc = tokens[4]; const destLoc = tokens[tokens.length - 1]; if ((srcLoc !== destLoc) && (tokens.includes('-'))) { renderedOrders2.push( ); } } else if (tokens[2] === 'B') { renderedHighestOrders.push( ); } else if (tokens[2] === 'D') { renderedHighestOrders.push( ); } else if (tokens[2] === 'R') { const destLoc = tokens[3]; renderedOrders.push( ); } else { throw new Error(`Unknown error to render (${order}).`); } } } } if (this.props.orderBuilding && this.props.orderBuilding.path.length) { const clicked = parseLocation(this.props.orderBuilding.path[0]); const province = this.props.mapData.getProvince(clicked); if (!province) throw new Error(('Unknown clicked province ' + clicked)); const clickedID = province.getID(classes); if (!clicked) throw new Error(`Unknown path (${clickedID}) for province (${clicked}).`); classes[clickedID] = 'provinceRed'; const neighbors = this.getNeighbors(); if (neighbors) { for (let neighbor of neighbors) { const neighborProvince = this.props.mapData.getProvince(neighbor); if (!neighborProvince) throw new Error('Unknown neighbor province ' + neighbor); const neighborID = neighborProvince.getID(classes); if (!neighborID) throw new Error(`Unknown neoghbor path (${neighborID}) for province (${neighbor}).`); classes[neighborID] = neighborProvince.isWater() ? 'provinceBlue' : 'provinceGreen'; } } } if (this.props.showAbbreviations === false) { classes['BriefLabelLayer'] = 'visibilityHidden'; } return ( Ancient Med Map {renderedOrders2} {renderedOrders} {renderedUnits} {renderedDislodgedUnits} {renderedHighestOrders} adr aeg ale ant apu ara arm ath aus bal bay ber bit bla byz cap car che cil cir cor cre cyp cyr dac dal dam egy epi etr gal gau gop gos got ibe ill ion isa jer lep lib lig lus mac mar mas mau mem mes mil min nab nea num pet pha pun rav ree rha rom sag sah sad sam sic sid sin sip spa syr tar tha thb tye tyn ven vin {nb_centers_per_power ? nb_centers_per_power : ''} {note ? note : ''} {current_phase} ); } } SvgAncMed.propTypes = { game: PropTypes.instanceOf(Game).isRequired, mapData: PropTypes.instanceOf(MapData).isRequired, orders: PropTypes.object, onHover: PropTypes.func, onError: PropTypes.func.isRequired, onSelectLocation: PropTypes.func, onSelectVia: PropTypes.func, onOrderBuilding: PropTypes.func, onOrderBuilt: PropTypes.func, orderBuilding: PropTypes.object, showAbbreviations: PropTypes.bool }; // eslint-disable-line semi \ No newline at end of file + import React from 'react'; import PropTypes from 'prop-types'; import './SvgAncMed.css'; import {Coordinates, SymbolSizes, Colors} from "./SvgAncMedMetadata"; import {getClickedID, parseLocation, setInfluence} from "../common/common"; import {Game} from "../../../diplomacy/engine/game"; import {MapData} from "../../utils/map_data"; import {UTILS} from "../../../diplomacy/utils/utils"; import {Diplog} from "../../../diplomacy/utils/diplog"; import {extendOrderBuilding} from "../../utils/order_building"; import {Unit} from "../common/unit"; import {Hold} from "../common/hold"; import {Move} from "../common/move"; import {SupportMove} from "../common/supportMove"; import {SupportHold} from "../common/supportHold"; import {Convoy} from "../common/convoy"; import {Build} from "../common/build"; import {Disband} from "../common/disband"; export class SvgAncMed extends React.Component { constructor(props) { super(props); this.onClick = this.onClick.bind(this); this.onHover = this.onHover.bind(this); } onClick(event) { if (this.props.orderBuilding) return this.handleClickedID(getClickedID(event)); } onHover(event) { return this.handleHoverID(getClickedID(event)); } handleClickedID(id) { const orderBuilding = this.props.orderBuilding; if (!orderBuilding.builder) return this.props.onError('No orderable locations.'); const province = this.props.mapData.getProvince(id); if (!province) throw new Error(`Cannot find a province named ${id}`); const stepLength = orderBuilding.builder.steps.length; if (orderBuilding.path.length >= stepLength) throw new Error(`Order building: current steps count (${orderBuilding.path.length}) should be less than expected steps count (${stepLength}) (${orderBuilding.path.join(', ')}).`); const lengthAfterClick = orderBuilding.path.length + 1; let validLocations = []; const testedPath = [orderBuilding.type].concat(orderBuilding.path); const value = UTILS.javascript.getTreeValue(this.props.game.ordersTree, testedPath); if (value !== null) { const checker = orderBuilding.builder.steps[lengthAfterClick - 1]; try { const possibleLocations = checker(province, orderBuilding.power); for (let possibleLocation of possibleLocations) { possibleLocation = possibleLocation.toUpperCase(); if (value.includes(possibleLocation)) validLocations.push(possibleLocation); } } catch (error) { return this.props.onError(error); } } if (!validLocations.length) return this.props.onError('Disallowed.'); if (validLocations.length > 1 && orderBuilding.type === 'S' && orderBuilding.path.length >= 2) { /* We are building a support order and we have a multiple choice for a location. */ /* Let's check if next location to choose is a coast. To have a coast: */ /* - all possible locations must start with same 3 characters. */ /* - we expect at least province name in possible locations (e.g. 'SPA' for 'SPA/NC'). */ /* If we have a coast, we will remove province name from possible locations. */ let isACoast = true; let validLocationsNoProvinceName = []; for (let i = 0; i < validLocations.length; ++i) { let location = validLocations[i]; if (i > 0) { /* Compare 3 first letters with previous location. */ if (validLocations[i - 1].substring(0, 3).toUpperCase() !== validLocations[i].substring(0, 3).toUpperCase()) { /* No same prefix with previous location. We does not have a coast. */ isACoast = false; break; } } if (location.length !== 3) validLocationsNoProvinceName.push(location); } if (validLocations.length === validLocationsNoProvinceName.length) { /* We have not found province name. */ isACoast = false; } if (isACoast) { /* We want to choose location in a coastal province. Let's remove province name. */ validLocations = validLocationsNoProvinceName; } } if (validLocations.length > 1) { if (this.props.onSelectLocation) { return this.props.onSelectLocation(validLocations, orderBuilding.power, orderBuilding.type, orderBuilding.path); } else { Diplog.warn(`Forced to select first valid location.`); validLocations = [validLocations[0]]; } } let orderBuildingType = orderBuilding.type; if (lengthAfterClick === stepLength && orderBuildingType === 'M') { const moveOrderPath = ['M'].concat(orderBuilding.path, validLocations[0]); const moveTypes = UTILS.javascript.getTreeValue(this.props.game.ordersTree, moveOrderPath); if (moveTypes !== null) { if (moveTypes.length === 2 && this.props.onSelectVia) { /* This move can be done either regularly or VIA a fleet. Let user choose. */ return this.props.onSelectVia(validLocations[0], orderBuilding.power, orderBuilding.path); } else { orderBuildingType = moveTypes[0]; } } } extendOrderBuilding( orderBuilding.power, orderBuildingType, orderBuilding.path, validLocations[0], this.props.onOrderBuilding, this.props.onOrderBuilt, this.props.onError ); } handleHoverID(id) { if (this.props.onHover) { const province = this.props.mapData.getProvince(id); if (province) { this.props.onHover(province.name, this.getRelatedOrders(province.name)); } } } getRelatedOrders(name) { const orders = []; if (this.props.orders) { for (let powerOrders of Object.values(this.props.orders)) { if (powerOrders) { for (let order of powerOrders) { const pieces = order.split(/ +/); if (pieces[1].slice(0, 3) === name.toUpperCase().slice(0, 3)) orders.push(order); } } } } return orders; } getNeighbors(extraLocation) { const selectedPath = [this.props.orderBuilding.type].concat(this.props.orderBuilding.path); if (extraLocation) selectedPath.push(extraLocation); const possibleNeighbors = UTILS.javascript.getTreeValue(this.props.game.ordersTree, selectedPath); const neighbors = possibleNeighbors ? possibleNeighbors.map(neighbor => parseLocation(neighbor)) : []; return neighbors.length ? neighbors: null; } render() { const classes = {"_adr":"water","_aeg":"water","_ale":"nopower","_ant":"nopower","_apu":"nopower","_ara":"nopower","_arm":"nopower","_ath":"nopower","_aus":"water","_bal":"nopower","_bay":"nopower","_ber":"water","_bit":"nopower","_bla":"water","_byz":"nopower","_cap":"nopower","_car":"nopower","_che":"nopower","_cil":"water","_cir":"nopower","_cor":"nopower","_cre":"nopower","_cyp":"nopower","_cyr":"nopower","_dac":"nopower","_dal":"nopower","_dam":"nopower","_egy":"water","_epi":"nopower","_etr":"nopower","_gal":"nopower","_gau":"nopower","_gop":"water","_gos":"water","_got":"water","_ibe":"water","_ill":"nopower","_ion":"water","_isa":"nopower","_jer":"nopower","_lep":"nopower","_lib":"water","_lig":"water","_lus":"nopower","_mac":"nopower","_mar":"nopower","_mas":"nopower","_mau":"nopower","_mem":"nopower","_mes":"water","_mil":"nopower","_min":"water","_nab":"nopower","_nea":"nopower","_num":"nopower","_pet":"nopower","_pha":"nopower","_pun":"water","_rav":"nopower","_ree":"water","_rha":"nopower","_rom":"nopower","_sag":"nopower","_sah":"nopower","_sad":"nopower","_sam":"nopower","_sic":"nopower","_sid":"nopower","_sin":"nopower","_sip":"nopower","_spa":"nopower","_syr":"water","_tar":"nopower","_tha":"nopower","_thb":"nopower","_tye":"nopower","_tyn":"water","_ven":"nopower","_vin":"nopower","water":"water","BriefLabelLayer":"smalllabeltext","CurrentNote":"currentnotetext","CurrentNote2":"currentnotetext","CurrentPhase":"currentphasetext","MouseLayer":"invisibleContent"}; const game = this.props.game; const mapData = this.props.mapData; const orders = this.props.orders; /* Current phase. */ const current_phase = (game.phase[0] === '?' || game.phase === 'COMPLETED') ? 'FINAL' : game.phase; /* Notes. */ const nb_centers = []; for (let power of Object.values(game.powers)) { if (!power.isEliminated()) nb_centers.push([power.name.substr(0, 3), power.centers.length]); } /* Sort nb_centers by descending number of centers. */ nb_centers.sort((a, b) => { return -(a[1] - b[1]) || a[0].localeCompare(b[0]); }); const nb_centers_per_power = nb_centers.map((couple) => (couple[0] + ': ' + couple[1])).join(' '); const note = game.note; /* Adding units, influence and orders. */ const renderedUnits = []; const renderedDislodgedUnits = []; const renderedOrders = []; const renderedOrders2 = []; const renderedHighestOrders = []; for (let power of Object.values(game.powers)) if (!power.isEliminated()) { for (let unit of power.units) { renderedUnits.push( ); } for (let unit of Object.keys(power.retreats)) { renderedDislodgedUnits.push( ); } for (let center of power.centers) { setInfluence(classes, mapData, center, power.name); } for (let loc of power.influence) { if (!mapData.supplyCenters.has(loc)) setInfluence(classes, mapData, loc, power.name); } if (orders) { const powerOrders = (orders && Object.prototype.hasOwnProperty.call(orders, power.name) && orders[power.name]) || []; for (let order of powerOrders) { const tokens = order.split(/ +/); if (!tokens || tokens.length < 3) continue; const unit_loc = tokens[1]; if (tokens[2] === 'H') { renderedOrders.push( ); } else if (tokens[2] === '-') { const destLoc = tokens[tokens.length - (tokens[tokens.length - 1] === 'VIA' ? 2 : 1)]; renderedOrders.push( ); } else if (tokens[2] === 'S') { const destLoc = tokens[tokens.length - 1]; if (tokens.includes('-')) { const srcLoc = tokens[4]; renderedOrders2.push( ); } else { renderedOrders2.push( ); } } else if (tokens[2] === 'C') { const srcLoc = tokens[4]; const destLoc = tokens[tokens.length - 1]; if ((srcLoc !== destLoc) && (tokens.includes('-'))) { renderedOrders2.push( ); } } else if (tokens[2] === 'B') { renderedHighestOrders.push( ); } else if (tokens[2] === 'D') { renderedHighestOrders.push( ); } else if (tokens[2] === 'R') { const destLoc = tokens[3]; renderedOrders.push( ); } else { throw new Error(`Unknown error to render (${order}).`); } } } } if (this.props.orderBuilding && this.props.orderBuilding.path.length) { const clicked = parseLocation(this.props.orderBuilding.path[0]); const province = this.props.mapData.getProvince(clicked); if (!province) throw new Error(('Unknown clicked province ' + clicked)); const clickedID = province.getID(classes); if (!clicked) throw new Error(`Unknown path (${clickedID}) for province (${clicked}).`); classes[clickedID] = 'provinceRed'; const neighbors = this.getNeighbors(); if (neighbors) { for (let neighbor of neighbors) { const neighborProvince = this.props.mapData.getProvince(neighbor); if (!neighborProvince) throw new Error('Unknown neighbor province ' + neighbor); const neighborID = neighborProvince.getID(classes); if (!neighborID) throw new Error(`Unknown neoghbor path (${neighborID}) for province (${neighbor}).`); classes[neighborID] = neighborProvince.isWater() ? 'provinceBlue' : 'provinceGreen'; } } } if (this.props.showAbbreviations === false) { classes['BriefLabelLayer'] = 'visibilityHidden'; } return ( Ancient Med Map {renderedOrders2} {renderedOrders} {renderedUnits} {renderedDislodgedUnits} {renderedHighestOrders} adr aeg ale ant apu ara arm ath aus bal bay ber bit bla byz cap car che cil cir cor cre cyp cyr dac dal dam egy epi etr gal gau gop gos got ibe ill ion isa jer lep lib lig lus mac mar mas mau mem mes mil min nab nea num pet pha pun rav ree rha rom sag sah sad sam sic sid sin sip spa syr tar tha thb tye tyn ven vin {nb_centers_per_power ? nb_centers_per_power : ''} {note ? note : ''} {current_phase} ); } } SvgAncMed.propTypes = { game: PropTypes.instanceOf(Game).isRequired, mapData: PropTypes.instanceOf(MapData).isRequired, orders: PropTypes.object, onHover: PropTypes.func, onError: PropTypes.func.isRequired, onSelectLocation: PropTypes.func, onSelectVia: PropTypes.func, onOrderBuilding: PropTypes.func, onOrderBuilt: PropTypes.func, orderBuilding: PropTypes.object, showAbbreviations: PropTypes.bool }; // eslint-disable-line semi diff --git a/diplomacy/web/src/gui/maps/standard/SvgStandard.js b/diplomacy/web/src/gui/maps/standard/SvgStandard.js index 5428bdb..3b11d2d 100644 --- a/diplomacy/web/src/gui/maps/standard/SvgStandard.js +++ b/diplomacy/web/src/gui/maps/standard/SvgStandard.js @@ -17,4 +17,4 @@ Copyright (C) 2019 - Philip Paquette, Steven Bocco ============================================================================== **/ /** Generated with parameters: Namespace(input='src/diplomacy/maps/svg/standard.svg', name='SvgStandard', output='src/gui/maps/standard/') **/ - import React from 'react'; import PropTypes from 'prop-types'; import './SvgStandard.css'; import {Coordinates, SymbolSizes, Colors} from "./SvgStandardMetadata"; import {getClickedID, parseLocation, setInfluence} from "../common/common"; import {Game} from "../../../diplomacy/engine/game"; import {MapData} from "../../utils/map_data"; import {UTILS} from "../../../diplomacy/utils/utils"; import {Diplog} from "../../../diplomacy/utils/diplog"; import {extendOrderBuilding} from "../../utils/order_building"; import {Unit} from "../common/unit"; import {Hold} from "../common/hold"; import {Move} from "../common/move"; import {SupportMove} from "../common/supportMove"; import {SupportHold} from "../common/supportHold"; import {Convoy} from "../common/convoy"; import {Build} from "../common/build"; import {Disband} from "../common/disband"; export class SvgStandard extends React.Component { constructor(props) { super(props); this.onClick = this.onClick.bind(this); this.onHover = this.onHover.bind(this); } onClick(event) { if (this.props.orderBuilding) return this.handleClickedID(getClickedID(event)); } onHover(event) { return this.handleHoverID(getClickedID(event)); } handleClickedID(id) { const orderBuilding = this.props.orderBuilding; if (!orderBuilding.builder) return this.props.onError('No orderable locations.'); const province = this.props.mapData.getProvince(id); if (!province) throw new Error(`Cannot find a province named ${id}`); const stepLength = orderBuilding.builder.steps.length; if (orderBuilding.path.length >= stepLength) throw new Error(`Order building: current steps count (${orderBuilding.path.length}) should be less than expected steps count (${stepLength}) (${orderBuilding.path.join(', ')}).`); const lengthAfterClick = orderBuilding.path.length + 1; let validLocations = []; const testedPath = [orderBuilding.type].concat(orderBuilding.path); const value = UTILS.javascript.getTreeValue(this.props.game.ordersTree, testedPath); if (value !== null) { const checker = orderBuilding.builder.steps[lengthAfterClick - 1]; try { const possibleLocations = checker(province, orderBuilding.power); for (let possibleLocation of possibleLocations) { possibleLocation = possibleLocation.toUpperCase(); if (value.includes(possibleLocation)) validLocations.push(possibleLocation); } } catch (error) { return this.props.onError(error); } } if (!validLocations.length) return this.props.onError('Disallowed.'); if (validLocations.length > 1 && orderBuilding.type === 'S' && orderBuilding.path.length >= 2) { /* We are building a support order and we have a multiple choice for a location. */ /* Let's check if next location to choose is a coast. To have a coast: */ /* - all possible locations must start with same 3 characters. */ /* - we expect at least province name in possible locations (e.g. 'SPA' for 'SPA/NC'). */ /* If we have a coast, we will remove province name from possible locations. */ let isACoast = true; let validLocationsNoProvinceName = []; for (let i = 0; i < validLocations.length; ++i) { let location = validLocations[i]; if (i > 0) { /* Compare 3 first letters with previous location. */ if (validLocations[i - 1].substring(0, 3).toUpperCase() !== validLocations[i].substring(0, 3).toUpperCase()) { /* No same prefix with previous location. We does not have a coast. */ isACoast = false; break; } } if (location.length !== 3) validLocationsNoProvinceName.push(location); } if (validLocations.length === validLocationsNoProvinceName.length) { /* We have not found province name. */ isACoast = false; } if (isACoast) { /* We want to choose location in a coastal province. Let's remove province name. */ validLocations = validLocationsNoProvinceName; } } if (validLocations.length > 1) { if (this.props.onSelectLocation) { return this.props.onSelectLocation(validLocations, orderBuilding.power, orderBuilding.type, orderBuilding.path); } else { Diplog.warn(`Forced to select first valid location.`); validLocations = [validLocations[0]]; } } let orderBuildingType = orderBuilding.type; if (lengthAfterClick === stepLength && orderBuildingType === 'M') { const moveOrderPath = ['M'].concat(orderBuilding.path, validLocations[0]); const moveTypes = UTILS.javascript.getTreeValue(this.props.game.ordersTree, moveOrderPath); if (moveTypes !== null) { if (moveTypes.length === 2 && this.props.onSelectVia) { /* This move can be done either regularly or VIA a fleet. Let user choose. */ return this.props.onSelectVia(validLocations[0], orderBuilding.power, orderBuilding.path); } else { orderBuildingType = moveTypes[0]; } } } extendOrderBuilding( orderBuilding.power, orderBuildingType, orderBuilding.path, validLocations[0], this.props.onOrderBuilding, this.props.onOrderBuilt, this.props.onError ); } handleHoverID(id) { if (this.props.onHover) { const province = this.props.mapData.getProvince(id); if (province) { this.props.onHover(province.name, this.getRelatedOrders(province.name)); } } } getRelatedOrders(name) { const orders = []; if (this.props.orders) { for (let powerOrders of Object.values(this.props.orders)) { if (powerOrders) { for (let order of powerOrders) { const pieces = order.split(/ +/); if (pieces[1].slice(0, 3) === name.toUpperCase().slice(0, 3)) orders.push(order); } } } } return orders; } getNeighbors(extraLocation) { const selectedPath = [this.props.orderBuilding.type].concat(this.props.orderBuilding.path); if (extraLocation) selectedPath.push(extraLocation); const possibleNeighbors = UTILS.javascript.getTreeValue(this.props.game.ordersTree, selectedPath); const neighbors = possibleNeighbors ? possibleNeighbors.map(neighbor => parseLocation(neighbor)) : []; return neighbors.length ? neighbors: null; } render() { const classes = {"_ank":"nopower","_arm":"nopower","_con":"nopower","_mos":"nopower","_sev":"nopower","_stp":"nopower","_syr":"nopower","_ukr":"nopower","_lvn":"nopower","_war":"nopower","_pru":"nopower","_sil":"nopower","_ber":"nopower","_kie":"nopower","_ruh":"nopower","_mun":"nopower","_rum":"nopower","_bul":"nopower","_gre":"nopower","_smy":"nopower","_alb":"nopower","_ser":"nopower","_bud":"nopower","_gal":"nopower","_vie":"nopower","_boh":"nopower","_tyr":"nopower","_tri":"nopower","_fin":"nopower","_swe":"nopower","_nwy":"nopower","_den":"nopower","_hol":"nopower","_bel":"nopower","_swi":"impassable","_ven":"nopower","_pie":"nopower","_tus":"nopower","_rom":"nopower","_apu":"nopower","_nap":"nopower","_bur":"nopower","_mar":"nopower","_gas":"nopower","_pic":"nopower","_par":"nopower","_bre":"nopower","_spa":"nopower","_por":"nopower","_naf":"nopower","_tun":"nopower","_lon":"nopower","_wal":"nopower","_lvp":"nopower","_yor":"nopower","_edi":"nopower","_cly":"nopower","unplayable":"neutral","unplayable_water":"water","_nat":"water","_nrg":"water","_bar":"water","_bot":"water","_bal":"water","denmark_water":"water","_ska":"water","_hel":"water","_nth":"water","_eng":"water","_iri":"water","_mid":"water","_wes":"water","_gol":"water","_tyn":"water","_adr":"water","_ion":"water","_aeg":"water","_eas":"water","constantinople_water":"water","_bla":"water","BriefLabelLayer":"labeltext24","CurrentNote":"currentnotetext","CurrentNote2":"currentnotetext","CurrentPhase":"currentphasetext","MouseLayer":"invisibleContent"}; const game = this.props.game; const mapData = this.props.mapData; const orders = this.props.orders; /* Current phase. */ const current_phase = (game.phase[0] === '?' || game.phase === 'COMPLETED') ? 'FINAL' : game.phase; /* Notes. */ const nb_centers = []; for (let power of Object.values(game.powers)) { if (!power.isEliminated()) nb_centers.push([power.name.substr(0, 3), power.centers.length]); } /* Sort nb_centers by descending number of centers. */ nb_centers.sort((a, b) => { return -(a[1] - b[1]) || a[0].localeCompare(b[0]); }); const nb_centers_per_power = nb_centers.map((couple) => (couple[0] + ': ' + couple[1])).join(' '); const note = game.note; /* Adding units, influence and orders. */ const renderedUnits = []; const renderedDislodgedUnits = []; const renderedOrders = []; const renderedOrders2 = []; const renderedHighestOrders = []; for (let power of Object.values(game.powers)) if (!power.isEliminated()) { for (let unit of power.units) { renderedUnits.push( ); } for (let unit of Object.keys(power.retreats)) { renderedDislodgedUnits.push( ); } for (let center of power.centers) { setInfluence(classes, mapData, center, power.name); } for (let loc of power.influence) { if (!mapData.supplyCenters.has(loc)) setInfluence(classes, mapData, loc, power.name); } if (orders) { const powerOrders = (orders && Object.prototype.hasOwnProperty(orders, power.name) && orders[power.name]) || []; for (let order of powerOrders) { const tokens = order.split(/ +/); if (!tokens || tokens.length < 3) continue; const unit_loc = tokens[1]; if (tokens[2] === 'H') { renderedOrders.push( ); } else if (tokens[2] === '-') { const destLoc = tokens[tokens.length - (tokens[tokens.length - 1] === 'VIA' ? 2 : 1)]; renderedOrders.push( ); } else if (tokens[2] === 'S') { const destLoc = tokens[tokens.length - 1]; if (tokens.includes('-')) { const srcLoc = tokens[4]; renderedOrders2.push( ); } else { renderedOrders2.push( ); } } else if (tokens[2] === 'C') { const srcLoc = tokens[4]; const destLoc = tokens[tokens.length - 1]; if ((srcLoc !== destLoc) && (tokens.includes('-'))) { renderedOrders2.push( ); } } else if (tokens[2] === 'B') { renderedHighestOrders.push( ); } else if (tokens[2] === 'D') { renderedHighestOrders.push( ); } else if (tokens[2] === 'R') { const destLoc = tokens[3]; renderedOrders.push( ); } else { throw new Error(`Unknown error to render (${order}).`); } } } } if (this.props.orderBuilding && this.props.orderBuilding.path.length) { const clicked = parseLocation(this.props.orderBuilding.path[0]); const province = this.props.mapData.getProvince(clicked); if (!province) throw new Error(('Unknown clicked province ' + clicked)); const clickedID = province.getID(classes); if (!clicked) throw new Error(`Unknown path (${clickedID}) for province (${clicked}).`); classes[clickedID] = 'provinceRed'; const neighbors = this.getNeighbors(); if (neighbors) { for (let neighbor of neighbors) { const neighborProvince = this.props.mapData.getProvince(neighbor); if (!neighborProvince) throw new Error('Unknown neighbor province ' + neighbor); const neighborID = neighborProvince.getID(classes); if (!neighborID) throw new Error(`Unknown neoghbor path (${neighborID}) for province (${neighbor}).`); classes[neighborID] = neighborProvince.isWater() ? 'provinceBlue' : 'provinceGreen'; } } } if (this.props.showAbbreviations === false) { classes['BriefLabelLayer'] = 'visibilityHidden'; } return ( {renderedOrders2} {renderedOrders} {renderedUnits} {renderedDislodgedUnits} {renderedHighestOrders} SWI ADR AEG ALB ANK APU ARM BAL BAR BEL BER BLA BOH BRE BUD BUL BUR CLY CON DEN EAS EDI ENG FIN GAL GAS GRE BOT LYO HEL HOL ION IRI KIE LON LVN LVP MAR MAO MOS MUN NAF NAP NAO NTH NWY NWG PAR PIC PIE POR PRU ROM RUH RUM SER SEV SIL SKA SMY SPA STP SWE SYR TRI TUN TUS TYR TYS UKR VEN VIE WAL WAR WES YOR {nb_centers_per_power ? nb_centers_per_power : ''} {note ? note : ''} {current_phase} ); } } SvgStandard.propTypes = { game: PropTypes.instanceOf(Game).isRequired, mapData: PropTypes.instanceOf(MapData).isRequired, orders: PropTypes.object, onHover: PropTypes.func, onError: PropTypes.func.isRequired, onSelectLocation: PropTypes.func, onSelectVia: PropTypes.func, onOrderBuilding: PropTypes.func, onOrderBuilt: PropTypes.func, orderBuilding: PropTypes.object, showAbbreviations: PropTypes.bool }; // eslint-disable-line semi + import React from 'react'; import PropTypes from 'prop-types'; import './SvgStandard.css'; import {Coordinates, SymbolSizes, Colors} from "./SvgStandardMetadata"; import {getClickedID, parseLocation, setInfluence} from "../common/common"; import {Game} from "../../../diplomacy/engine/game"; import {MapData} from "../../utils/map_data"; import {UTILS} from "../../../diplomacy/utils/utils"; import {Diplog} from "../../../diplomacy/utils/diplog"; import {extendOrderBuilding} from "../../utils/order_building"; import {Unit} from "../common/unit"; import {Hold} from "../common/hold"; import {Move} from "../common/move"; import {SupportMove} from "../common/supportMove"; import {SupportHold} from "../common/supportHold"; import {Convoy} from "../common/convoy"; import {Build} from "../common/build"; import {Disband} from "../common/disband"; export class SvgStandard extends React.Component { constructor(props) { super(props); this.onClick = this.onClick.bind(this); this.onHover = this.onHover.bind(this); } onClick(event) { if (this.props.orderBuilding) return this.handleClickedID(getClickedID(event)); } onHover(event) { return this.handleHoverID(getClickedID(event)); } handleClickedID(id) { const orderBuilding = this.props.orderBuilding; if (!orderBuilding.builder) return this.props.onError('No orderable locations.'); const province = this.props.mapData.getProvince(id); if (!province) throw new Error(`Cannot find a province named ${id}`); const stepLength = orderBuilding.builder.steps.length; if (orderBuilding.path.length >= stepLength) throw new Error(`Order building: current steps count (${orderBuilding.path.length}) should be less than expected steps count (${stepLength}) (${orderBuilding.path.join(', ')}).`); const lengthAfterClick = orderBuilding.path.length + 1; let validLocations = []; const testedPath = [orderBuilding.type].concat(orderBuilding.path); const value = UTILS.javascript.getTreeValue(this.props.game.ordersTree, testedPath); if (value !== null) { const checker = orderBuilding.builder.steps[lengthAfterClick - 1]; try { const possibleLocations = checker(province, orderBuilding.power); for (let possibleLocation of possibleLocations) { possibleLocation = possibleLocation.toUpperCase(); if (value.includes(possibleLocation)) validLocations.push(possibleLocation); } } catch (error) { return this.props.onError(error); } } if (!validLocations.length) return this.props.onError('Disallowed.'); if (validLocations.length > 1 && orderBuilding.type === 'S' && orderBuilding.path.length >= 2) { /* We are building a support order and we have a multiple choice for a location. */ /* Let's check if next location to choose is a coast. To have a coast: */ /* - all possible locations must start with same 3 characters. */ /* - we expect at least province name in possible locations (e.g. 'SPA' for 'SPA/NC'). */ /* If we have a coast, we will remove province name from possible locations. */ let isACoast = true; let validLocationsNoProvinceName = []; for (let i = 0; i < validLocations.length; ++i) { let location = validLocations[i]; if (i > 0) { /* Compare 3 first letters with previous location. */ if (validLocations[i - 1].substring(0, 3).toUpperCase() !== validLocations[i].substring(0, 3).toUpperCase()) { /* No same prefix with previous location. We does not have a coast. */ isACoast = false; break; } } if (location.length !== 3) validLocationsNoProvinceName.push(location); } if (validLocations.length === validLocationsNoProvinceName.length) { /* We have not found province name. */ isACoast = false; } if (isACoast) { /* We want to choose location in a coastal province. Let's remove province name. */ validLocations = validLocationsNoProvinceName; } } if (validLocations.length > 1) { if (this.props.onSelectLocation) { return this.props.onSelectLocation(validLocations, orderBuilding.power, orderBuilding.type, orderBuilding.path); } else { Diplog.warn(`Forced to select first valid location.`); validLocations = [validLocations[0]]; } } let orderBuildingType = orderBuilding.type; if (lengthAfterClick === stepLength && orderBuildingType === 'M') { const moveOrderPath = ['M'].concat(orderBuilding.path, validLocations[0]); const moveTypes = UTILS.javascript.getTreeValue(this.props.game.ordersTree, moveOrderPath); if (moveTypes !== null) { if (moveTypes.length === 2 && this.props.onSelectVia) { /* This move can be done either regularly or VIA a fleet. Let user choose. */ return this.props.onSelectVia(validLocations[0], orderBuilding.power, orderBuilding.path); } else { orderBuildingType = moveTypes[0]; } } } extendOrderBuilding( orderBuilding.power, orderBuildingType, orderBuilding.path, validLocations[0], this.props.onOrderBuilding, this.props.onOrderBuilt, this.props.onError ); } handleHoverID(id) { if (this.props.onHover) { const province = this.props.mapData.getProvince(id); if (province) { this.props.onHover(province.name, this.getRelatedOrders(province.name)); } } } getRelatedOrders(name) { const orders = []; if (this.props.orders) { for (let powerOrders of Object.values(this.props.orders)) { if (powerOrders) { for (let order of powerOrders) { const pieces = order.split(/ +/); if (pieces[1].slice(0, 3) === name.toUpperCase().slice(0, 3)) orders.push(order); } } } } return orders; } getNeighbors(extraLocation) { const selectedPath = [this.props.orderBuilding.type].concat(this.props.orderBuilding.path); if (extraLocation) selectedPath.push(extraLocation); const possibleNeighbors = UTILS.javascript.getTreeValue(this.props.game.ordersTree, selectedPath); const neighbors = possibleNeighbors ? possibleNeighbors.map(neighbor => parseLocation(neighbor)) : []; return neighbors.length ? neighbors: null; } render() { const classes = {"_ank":"nopower","_arm":"nopower","_con":"nopower","_mos":"nopower","_sev":"nopower","_stp":"nopower","_syr":"nopower","_ukr":"nopower","_lvn":"nopower","_war":"nopower","_pru":"nopower","_sil":"nopower","_ber":"nopower","_kie":"nopower","_ruh":"nopower","_mun":"nopower","_rum":"nopower","_bul":"nopower","_gre":"nopower","_smy":"nopower","_alb":"nopower","_ser":"nopower","_bud":"nopower","_gal":"nopower","_vie":"nopower","_boh":"nopower","_tyr":"nopower","_tri":"nopower","_fin":"nopower","_swe":"nopower","_nwy":"nopower","_den":"nopower","_hol":"nopower","_bel":"nopower","_swi":"impassable","_ven":"nopower","_pie":"nopower","_tus":"nopower","_rom":"nopower","_apu":"nopower","_nap":"nopower","_bur":"nopower","_mar":"nopower","_gas":"nopower","_pic":"nopower","_par":"nopower","_bre":"nopower","_spa":"nopower","_por":"nopower","_naf":"nopower","_tun":"nopower","_lon":"nopower","_wal":"nopower","_lvp":"nopower","_yor":"nopower","_edi":"nopower","_cly":"nopower","unplayable":"neutral","unplayable_water":"water","_nat":"water","_nrg":"water","_bar":"water","_bot":"water","_bal":"water","denmark_water":"water","_ska":"water","_hel":"water","_nth":"water","_eng":"water","_iri":"water","_mid":"water","_wes":"water","_gol":"water","_tyn":"water","_adr":"water","_ion":"water","_aeg":"water","_eas":"water","constantinople_water":"water","_bla":"water","BriefLabelLayer":"labeltext24","CurrentNote":"currentnotetext","CurrentNote2":"currentnotetext","CurrentPhase":"currentphasetext","MouseLayer":"invisibleContent"}; const game = this.props.game; const mapData = this.props.mapData; const orders = this.props.orders; /* Current phase. */ const current_phase = (game.phase[0] === '?' || game.phase === 'COMPLETED') ? 'FINAL' : game.phase; /* Notes. */ const nb_centers = []; for (let power of Object.values(game.powers)) { if (!power.isEliminated()) nb_centers.push([power.name.substr(0, 3), power.centers.length]); } /* Sort nb_centers by descending number of centers. */ nb_centers.sort((a, b) => { return -(a[1] - b[1]) || a[0].localeCompare(b[0]); }); const nb_centers_per_power = nb_centers.map((couple) => (couple[0] + ': ' + couple[1])).join(' '); const note = game.note; /* Adding units, influence and orders. */ const renderedUnits = []; const renderedDislodgedUnits = []; const renderedOrders = []; const renderedOrders2 = []; const renderedHighestOrders = []; for (let power of Object.values(game.powers)) if (!power.isEliminated()) { for (let unit of power.units) { renderedUnits.push( ); } for (let unit of Object.keys(power.retreats)) { renderedDislodgedUnits.push( ); } for (let center of power.centers) { setInfluence(classes, mapData, center, power.name); } for (let loc of power.influence) { if (!mapData.supplyCenters.has(loc)) setInfluence(classes, mapData, loc, power.name); } if (orders) { const powerOrders = (orders && Object.prototype.hasOwnProperty.call(orders, power.name) && orders[power.name]) || []; for (let order of powerOrders) { const tokens = order.split(/ +/); if (!tokens || tokens.length < 3) continue; const unit_loc = tokens[1]; if (tokens[2] === 'H') { renderedOrders.push( ); } else if (tokens[2] === '-') { const destLoc = tokens[tokens.length - (tokens[tokens.length - 1] === 'VIA' ? 2 : 1)]; renderedOrders.push( ); } else if (tokens[2] === 'S') { const destLoc = tokens[tokens.length - 1]; if (tokens.includes('-')) { const srcLoc = tokens[4]; renderedOrders2.push( ); } else { renderedOrders2.push( ); } } else if (tokens[2] === 'C') { const srcLoc = tokens[4]; const destLoc = tokens[tokens.length - 1]; if ((srcLoc !== destLoc) && (tokens.includes('-'))) { renderedOrders2.push( ); } } else if (tokens[2] === 'B') { renderedHighestOrders.push( ); } else if (tokens[2] === 'D') { renderedHighestOrders.push( ); } else if (tokens[2] === 'R') { const destLoc = tokens[3]; renderedOrders.push( ); } else { throw new Error(`Unknown error to render (${order}).`); } } } } if (this.props.orderBuilding && this.props.orderBuilding.path.length) { const clicked = parseLocation(this.props.orderBuilding.path[0]); const province = this.props.mapData.getProvince(clicked); if (!province) throw new Error(('Unknown clicked province ' + clicked)); const clickedID = province.getID(classes); if (!clicked) throw new Error(`Unknown path (${clickedID}) for province (${clicked}).`); classes[clickedID] = 'provinceRed'; const neighbors = this.getNeighbors(); if (neighbors) { for (let neighbor of neighbors) { const neighborProvince = this.props.mapData.getProvince(neighbor); if (!neighborProvince) throw new Error('Unknown neighbor province ' + neighbor); const neighborID = neighborProvince.getID(classes); if (!neighborID) throw new Error(`Unknown neoghbor path (${neighborID}) for province (${neighbor}).`); classes[neighborID] = neighborProvince.isWater() ? 'provinceBlue' : 'provinceGreen'; } } } if (this.props.showAbbreviations === false) { classes['BriefLabelLayer'] = 'visibilityHidden'; } return ( {renderedOrders2} {renderedOrders} {renderedUnits} {renderedDislodgedUnits} {renderedHighestOrders} SWI ADR AEG ALB ANK APU ARM BAL BAR BEL BER BLA BOH BRE BUD BUL BUR CLY CON DEN EAS EDI ENG FIN GAL GAS GRE BOT LYO HEL HOL ION IRI KIE LON LVN LVP MAR MAO MOS MUN NAF NAP NAO NTH NWY NWG PAR PIC PIE POR PRU ROM RUH RUM SER SEV SIL SKA SMY SPA STP SWE SYR TRI TUN TUS TYR TYS UKR VEN VIE WAL WAR WES YOR {nb_centers_per_power ? nb_centers_per_power : ''} {note ? note : ''} {current_phase} ); } } SvgStandard.propTypes = { game: PropTypes.instanceOf(Game).isRequired, mapData: PropTypes.instanceOf(MapData).isRequired, orders: PropTypes.object, onHover: PropTypes.func, onError: PropTypes.func.isRequired, onSelectLocation: PropTypes.func, onSelectVia: PropTypes.func, onOrderBuilding: PropTypes.func, onOrderBuilt: PropTypes.func, orderBuilding: PropTypes.object, showAbbreviations: PropTypes.bool }; // eslint-disable-line semi diff --git a/diplomacy/web/src/gui/pages/content_connection.jsx b/diplomacy/web/src/gui/pages/content_connection.jsx index a7a151f..aea7f39 100644 --- a/diplomacy/web/src/gui/pages/content_connection.jsx +++ b/diplomacy/web/src/gui/pages/content_connection.jsx @@ -32,7 +32,7 @@ export class ContentConnection extends React.Component { onSubmit(data) { const page = this.context; for (let fieldName of ['hostname', 'port', 'username', 'password', 'showServerFields']) - if (!data.hasOwnProperty(fieldName)) + if (!Object.prototype.hasOwnProperty.call(data, fieldName)) return page.error(`Missing ${fieldName}, got ${JSON.stringify(data)}`); page.info('Connecting ...'); if (this.connection) { -- cgit v1.2.3