powergrid-engine 1.10.0 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/available-moves.d.ts +2 -0
- package/dist/src/available-moves.js +110 -9
- package/dist/src/engine.js +290 -57
- package/dist/src/gamestate.d.ts +13 -1
- package/dist/src/maps/europe.d.ts +62 -0
- package/dist/src/maps/europe.js +356 -0
- package/dist/src/maps/korea.js +107 -0
- package/dist/src/maps/northamerica.d.ts +62 -0
- package/dist/src/maps/northamerica.js +330 -0
- package/dist/src/maps/northerneurope.js +75 -0
- package/dist/src/maps/southafrica.d.ts +26 -26
- package/dist/src/maps/southafrica.js +239 -116
- package/dist/src/maps/ukireland.js +163 -40
- package/dist/src/maps.d.ts +16 -0
- package/dist/src/maps.js +19 -8
- package/dist/src/move.d.ts +2 -0
- package/package.json +1 -1
- package/src/available-moves.ts +158 -10
- package/src/engine.spec.ts +17 -0
- package/src/engine.ts +305 -52
- package/src/gamestate.ts +33 -6
- package/src/maps/europe.ts +391 -0
- package/src/maps/korea.ts +109 -0
- package/src/maps/northamerica.ts +360 -0
- package/src/maps/northerneurope.ts +76 -0
- package/src/maps/southafrica.ts +247 -116
- package/src/maps/ukireland.ts +170 -40
- package/src/maps.ts +53 -13
- package/src/move.ts +7 -0
package/dist/src/engine.js
CHANGED
|
@@ -18,6 +18,7 @@ const utils_1 = require("./utils");
|
|
|
18
18
|
exports.playerColors = ['limegreen', 'mediumorchid', 'red', 'dodgerblue', 'yellow', 'brown'];
|
|
19
19
|
const citiesToStep2 = [10, 7, 7, 7, 6];
|
|
20
20
|
const citiesToStep2BadenWurttemberg = [9, 6, 6, 6, 5];
|
|
21
|
+
const citiesToStep2UKIreland = [7, 7, 7, 7, 6];
|
|
21
22
|
const citiesToEndGame = [21, 17, 17, 15, 14];
|
|
22
23
|
const cityIncome = [10, 22, 33, 44, 54, 64, 73, 82, 90, 98, 105, 112, 118, 124, 129, 134, 138, 142, 145, 148, 150, 150];
|
|
23
24
|
const regionsInPlay = [3, 3, 4, 5, 5];
|
|
@@ -70,7 +71,7 @@ function defaultSetupDeck(numPlayers, variant, rng, useNewRechargedSetup) {
|
|
|
70
71
|
}
|
|
71
72
|
exports.defaultSetupDeck = defaultSetupDeck;
|
|
72
73
|
function setup(numPlayers, { fastBid = false, map = 'USA', variant = 'original', showMoney = false, useNewRechargedSetup = true, trackTotalSpent = true, randomizeMap = false, }, seed, forceDeck, forceMap) {
|
|
73
|
-
var _a, _b, _c, _d;
|
|
74
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
74
75
|
seed = seed !== null && seed !== void 0 ? seed : Math.random().toString();
|
|
75
76
|
const rng = seedrandom_1.default(seed);
|
|
76
77
|
const chosenMap = lodash_1.cloneDeep(variant == 'original' ? maps_1.maps.find((m) => m.name == map) : maps_1.mapsRecharged.find((m) => m.name == map));
|
|
@@ -129,6 +130,15 @@ function setup(numPlayers, { fastBid = false, map = 'USA', variant = 'original',
|
|
|
129
130
|
let oilResupply;
|
|
130
131
|
let garbageResupply;
|
|
131
132
|
let uraniumResupply;
|
|
133
|
+
// Korea: parallel North-side resupply tables (no uranium row).
|
|
134
|
+
let coalResupplyNorth;
|
|
135
|
+
let oilResupplyNorth;
|
|
136
|
+
let garbageResupplyNorth;
|
|
137
|
+
if (chosenMap.resupplyNorth) {
|
|
138
|
+
coalResupplyNorth = chosenMap.resupplyNorth[0];
|
|
139
|
+
oilResupplyNorth = chosenMap.resupplyNorth[1];
|
|
140
|
+
garbageResupplyNorth = chosenMap.resupplyNorth[2];
|
|
141
|
+
}
|
|
132
142
|
if (chosenMap.resupply) {
|
|
133
143
|
coalResupply = chosenMap.resupply[0];
|
|
134
144
|
oilResupply = chosenMap.resupply[1];
|
|
@@ -211,7 +221,14 @@ function setup(numPlayers, { fastBid = false, map = 'USA', variant = 'original',
|
|
|
211
221
|
while (playRegions.size != Math.min(regionsInPlay[p], regions.length)) {
|
|
212
222
|
const region = regions[Math.floor(rng() * regions.length)];
|
|
213
223
|
if (playRegions.size == 0 ||
|
|
214
|
-
regionConnections[regions.indexOf(region)].some((con) => playRegions.has(con))
|
|
224
|
+
regionConnections[regions.indexOf(region)].some((con) => playRegions.has(con)) ||
|
|
225
|
+
// UK & Ireland: regions on the two islands have no edges between
|
|
226
|
+
// them (no sea connection). Skipping the connectivity check lets
|
|
227
|
+
// the random selection span both islands; the cross-island
|
|
228
|
+
// surcharge handles the disconnect at build time. Without this,
|
|
229
|
+
// requiring 5-of-6 regions for 5p would loop forever (GB has 4
|
|
230
|
+
// regions, IE has 2).
|
|
231
|
+
chosenMap.name === 'UK & Ireland') {
|
|
215
232
|
playRegions.add(region);
|
|
216
233
|
// Avoid italy Red Green Blue
|
|
217
234
|
if (chosenMap.name === 'Italy') {
|
|
@@ -227,6 +244,23 @@ function setup(numPlayers, { fastBid = false, map = 'USA', variant = 'original',
|
|
|
227
244
|
.map((n) => chosenMap.cities.find((city) => city.name == n).region)
|
|
228
245
|
.every((r) => playRegions.has(r)));
|
|
229
246
|
finalMap = filteredMap;
|
|
247
|
+
if (chosenMap.regionalPowerPlants) {
|
|
248
|
+
for (const region of playRegions) {
|
|
249
|
+
const replacements = chosenMap.regionalPowerPlants[region];
|
|
250
|
+
if (replacements) {
|
|
251
|
+
for (const newPlant of replacements) {
|
|
252
|
+
const swapIn = (arr) => {
|
|
253
|
+
const idx = arr.findIndex((p) => p.number === newPlant.number);
|
|
254
|
+
if (idx !== -1)
|
|
255
|
+
arr[idx] = { ...newPlant };
|
|
256
|
+
};
|
|
257
|
+
swapIn(actualMarket);
|
|
258
|
+
swapIn(futureMarket);
|
|
259
|
+
swapIn(powerPlantsDeck);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
230
264
|
}
|
|
231
265
|
const coalMarket = chosenMap.startingResources ? chosenMap.startingResources[0] : 24;
|
|
232
266
|
const oilMarket = chosenMap.startingResources ? chosenMap.startingResources[1] : 18;
|
|
@@ -236,14 +270,25 @@ function setup(numPlayers, { fastBid = false, map = 'USA', variant = 'original',
|
|
|
236
270
|
const totalOil = chosenMap.startingSupply ? chosenMap.startingSupply[1] : 24;
|
|
237
271
|
const totalGarbage = chosenMap.startingSupply ? chosenMap.startingSupply[2] : 24;
|
|
238
272
|
const totalUranium = chosenMap.startingSupply ? chosenMap.startingSupply[3] : 12;
|
|
239
|
-
|
|
240
|
-
const
|
|
241
|
-
const
|
|
273
|
+
// Korea: parallel North-side market and prices. Supply is shared — see below.
|
|
274
|
+
const coalMarketNorth = (_a = chosenMap.startingResourcesNorth) === null || _a === void 0 ? void 0 : _a[0];
|
|
275
|
+
const oilMarketNorth = (_b = chosenMap.startingResourcesNorth) === null || _b === void 0 ? void 0 : _b[1];
|
|
276
|
+
const garbageMarketNorth = (_c = chosenMap.startingResourcesNorth) === null || _c === void 0 ? void 0 : _c[2];
|
|
277
|
+
// Supply pools are shared between both sides for Korea. `startingSupply`
|
|
278
|
+
// represents the TOTAL cubes in the game; the supply pool is whatever is
|
|
279
|
+
// left after both markets are filled.
|
|
280
|
+
const coalSupply = totalCoal - coalMarket - (coalMarketNorth !== null && coalMarketNorth !== void 0 ? coalMarketNorth : 0);
|
|
281
|
+
const oilSupply = totalOil - oilMarket - (oilMarketNorth !== null && oilMarketNorth !== void 0 ? oilMarketNorth : 0);
|
|
282
|
+
const garbageSupply = totalGarbage - garbageMarket - (garbageMarketNorth !== null && garbageMarketNorth !== void 0 ? garbageMarketNorth : 0);
|
|
242
283
|
const uraniumSupply = totalUranium - uraniumMarket;
|
|
243
|
-
const coalPrices = lodash_1.cloneDeep((
|
|
244
|
-
const oilPrices = lodash_1.cloneDeep((
|
|
245
|
-
const garbagePrices = lodash_1.cloneDeep((
|
|
246
|
-
const uraniumPrices = lodash_1.cloneDeep((
|
|
284
|
+
const coalPrices = lodash_1.cloneDeep((_d = chosenMap.coalPrices) !== null && _d !== void 0 ? _d : prices_1.default.coal);
|
|
285
|
+
const oilPrices = lodash_1.cloneDeep((_e = chosenMap.oilPrices) !== null && _e !== void 0 ? _e : prices_1.default.oil);
|
|
286
|
+
const garbagePrices = lodash_1.cloneDeep((_f = chosenMap.garbagePrices) !== null && _f !== void 0 ? _f : prices_1.default.garbage);
|
|
287
|
+
const uraniumPrices = lodash_1.cloneDeep((_g = chosenMap.uraniumPrices) !== null && _g !== void 0 ? _g : prices_1.default.uranium);
|
|
288
|
+
const coalPricesNorth = chosenMap.coalPricesNorth ? lodash_1.cloneDeep(chosenMap.coalPricesNorth) : undefined;
|
|
289
|
+
const oilPricesNorth = chosenMap.oilPricesNorth ? lodash_1.cloneDeep(chosenMap.oilPricesNorth) : undefined;
|
|
290
|
+
const garbagePricesNorth = chosenMap.garbagePricesNorth ? lodash_1.cloneDeep(chosenMap.garbagePricesNorth) : undefined;
|
|
291
|
+
const isSouthAfrica = (forceMap || finalMap).name == 'South Africa';
|
|
247
292
|
const G = {
|
|
248
293
|
map: forceMap || finalMap,
|
|
249
294
|
players,
|
|
@@ -254,6 +299,9 @@ function setup(numPlayers, { fastBid = false, map = 'USA', variant = 'original',
|
|
|
254
299
|
oilSupply,
|
|
255
300
|
garbageSupply,
|
|
256
301
|
uraniumSupply,
|
|
302
|
+
// South Africa: separate coal pool below the market. Starts empty;
|
|
303
|
+
// used coal returns here; refill draws from here first.
|
|
304
|
+
coalStorage: isSouthAfrica ? 0 : undefined,
|
|
257
305
|
coalResupply,
|
|
258
306
|
oilResupply,
|
|
259
307
|
garbageResupply,
|
|
@@ -266,6 +314,17 @@ function setup(numPlayers, { fastBid = false, map = 'USA', variant = 'original',
|
|
|
266
314
|
oilPrices,
|
|
267
315
|
garbagePrices,
|
|
268
316
|
uraniumPrices,
|
|
317
|
+
// Korea: parallel North-side fields. Undefined for non-Korea maps.
|
|
318
|
+
// Supply is shared with the primary `*Supply` fields above.
|
|
319
|
+
coalMarketNorth,
|
|
320
|
+
oilMarketNorth,
|
|
321
|
+
garbageMarketNorth,
|
|
322
|
+
coalResupplyNorth,
|
|
323
|
+
oilResupplyNorth,
|
|
324
|
+
garbageResupplyNorth,
|
|
325
|
+
coalPricesNorth,
|
|
326
|
+
oilPricesNorth,
|
|
327
|
+
garbagePricesNorth,
|
|
269
328
|
actualMarket,
|
|
270
329
|
futureMarket,
|
|
271
330
|
chosenPowerPlant: undefined,
|
|
@@ -282,13 +341,22 @@ function setup(numPlayers, { fastBid = false, map = 'USA', variant = 'original',
|
|
|
282
341
|
auctionSkips: 0,
|
|
283
342
|
citiesToStep2: (forceMap || finalMap).name == 'Baden-Württemberg'
|
|
284
343
|
? citiesToStep2BadenWurttemberg[numPlayers - 2]
|
|
285
|
-
:
|
|
344
|
+
: (forceMap || finalMap).name == 'UK & Ireland'
|
|
345
|
+
? citiesToStep2UKIreland[numPlayers - 2]
|
|
346
|
+
: citiesToStep2[numPlayers - 2],
|
|
286
347
|
citiesToEndGame: citiesToEndGame[numPlayers - 2],
|
|
287
348
|
resourceResupply: [
|
|
288
349
|
`[${coalResupply[p][0]}, ${oilResupply[p][0]}, ${garbageResupply[p][0]}, ${uraniumResupply[p][0]}]`,
|
|
289
350
|
`[${coalResupply[p][1]}, ${oilResupply[p][1]}, ${garbageResupply[p][1]}, ${uraniumResupply[p][1]}]`,
|
|
290
351
|
`[${coalResupply[p][2]}, ${oilResupply[p][2]}, ${garbageResupply[p][2]}, ${uraniumResupply[p][2]}]`,
|
|
291
352
|
],
|
|
353
|
+
resourceResupplyNorth: coalResupplyNorth && oilResupplyNorth && garbageResupplyNorth
|
|
354
|
+
? [
|
|
355
|
+
`[${coalResupplyNorth[p][0]}, ${oilResupplyNorth[p][0]}, ${garbageResupplyNorth[p][0]}]`,
|
|
356
|
+
`[${coalResupplyNorth[p][1]}, ${oilResupplyNorth[p][1]}, ${garbageResupplyNorth[p][1]}]`,
|
|
357
|
+
`[${coalResupplyNorth[p][2]}, ${oilResupplyNorth[p][2]}, ${garbageResupplyNorth[p][2]}]`,
|
|
358
|
+
]
|
|
359
|
+
: undefined,
|
|
292
360
|
paymentTable: cityIncome,
|
|
293
361
|
variant,
|
|
294
362
|
minimunBid: 0,
|
|
@@ -340,7 +408,7 @@ function currentPlayers(G) {
|
|
|
340
408
|
}
|
|
341
409
|
exports.currentPlayers = currentPlayers;
|
|
342
410
|
function move(G, move, playerNumber, isUndo = false) {
|
|
343
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
411
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
|
|
344
412
|
const player = G.players[playerNumber];
|
|
345
413
|
const available = (_a = player.availableMoves) === null || _a === void 0 ? void 0 : _a[move.name];
|
|
346
414
|
updateGameState(G);
|
|
@@ -545,6 +613,11 @@ function move(G, move, playerNumber, isUndo = false) {
|
|
|
545
613
|
else {
|
|
546
614
|
player.passed = true;
|
|
547
615
|
}
|
|
616
|
+
// Korea: end of this player's buying turn — clear the side lock
|
|
617
|
+
// so the next player can pick freely.
|
|
618
|
+
if (G.map.name == 'Korea') {
|
|
619
|
+
G.chosenSide = undefined;
|
|
620
|
+
}
|
|
548
621
|
if (G.players.filter((p) => !p.passed && !p.isDropped).length == 0) {
|
|
549
622
|
G.players.forEach((p) => {
|
|
550
623
|
p.passed = p.isDropped;
|
|
@@ -589,7 +662,18 @@ function move(G, move, playerNumber, isUndo = false) {
|
|
|
589
662
|
G.powerPlantsDeck.unshift(getPowerPlant(18));
|
|
590
663
|
}
|
|
591
664
|
}
|
|
592
|
-
|
|
665
|
+
if (G.map.name == 'Europe') {
|
|
666
|
+
// Europe: do NOT draw a replacement from the deck.
|
|
667
|
+
// The future market shrinks from 5 to 4; reorganize
|
|
668
|
+
// the remaining 8 plants so actual stays at 4.
|
|
669
|
+
const market = [...G.actualMarket, ...G.futureMarket];
|
|
670
|
+
market.sort((a, b) => a.number - b.number);
|
|
671
|
+
G.actualMarket = market.slice(0, 4);
|
|
672
|
+
G.futureMarket = market.slice(4);
|
|
673
|
+
}
|
|
674
|
+
else {
|
|
675
|
+
addPowerPlant(G);
|
|
676
|
+
}
|
|
593
677
|
}
|
|
594
678
|
}
|
|
595
679
|
if (maxCities >= G.citiesToEndGame) {
|
|
@@ -656,9 +740,50 @@ function move(G, move, playerNumber, isUndo = false) {
|
|
|
656
740
|
player.targetCitiesPowered = 0;
|
|
657
741
|
}
|
|
658
742
|
if (G.players.filter((p) => !p.passed && !p.isDropped).length == 0) {
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
743
|
+
// Resupply is also capped by remaining market capacity (the
|
|
744
|
+
// prices array length minus current market size). Without
|
|
745
|
+
// this, smaller markets like Korea's can overflow past the
|
|
746
|
+
// number of slots and break price lookups.
|
|
747
|
+
const coalCapSouth = ((_d = (_c = G.coalPrices) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : prices_1.default[gamestate_1.ResourceType.Coal].length) - G.coalMarket;
|
|
748
|
+
const oilCapSouth = ((_f = (_e = G.oilPrices) === null || _e === void 0 ? void 0 : _e.length) !== null && _f !== void 0 ? _f : prices_1.default[gamestate_1.ResourceType.Oil].length) - G.oilMarket;
|
|
749
|
+
const garbageCapSouth = ((_h = (_g = G.garbagePrices) === null || _g === void 0 ? void 0 : _g.length) !== null && _h !== void 0 ? _h : prices_1.default[gamestate_1.ResourceType.Garbage].length) - G.garbageMarket;
|
|
750
|
+
const uraniumCapSouth = ((_k = (_j = G.uraniumPrices) === null || _j === void 0 ? void 0 : _j.length) !== null && _k !== void 0 ? _k : prices_1.default[gamestate_1.ResourceType.Uranium].length) - G.uraniumMarket;
|
|
751
|
+
// Korea: North restocks FIRST from the shared supply pool, then
|
|
752
|
+
// South takes whatever remains. If supply runs short, South gets less.
|
|
753
|
+
let coalResupplyNorthValue = 0;
|
|
754
|
+
let oilResupplyNorthValue = 0;
|
|
755
|
+
let garbageResupplyNorthValue = 0;
|
|
756
|
+
if (G.coalResupplyNorth) {
|
|
757
|
+
const coalCapNorth = G.coalPricesNorth.length - G.coalMarketNorth;
|
|
758
|
+
const oilCapNorth = G.oilPricesNorth.length - G.oilMarketNorth;
|
|
759
|
+
const garbageCapNorth = G.garbagePricesNorth.length - G.garbageMarketNorth;
|
|
760
|
+
coalResupplyNorthValue = Math.min(G.coalSupply, G.coalResupplyNorth[G.players.length - 2][G.step - 1], coalCapNorth);
|
|
761
|
+
G.coalMarketNorth += coalResupplyNorthValue;
|
|
762
|
+
G.coalSupply -= coalResupplyNorthValue;
|
|
763
|
+
oilResupplyNorthValue = Math.min(G.oilSupply, G.oilResupplyNorth[G.players.length - 2][G.step - 1], oilCapNorth);
|
|
764
|
+
G.oilMarketNorth += oilResupplyNorthValue;
|
|
765
|
+
G.oilSupply -= oilResupplyNorthValue;
|
|
766
|
+
garbageResupplyNorthValue = Math.min(G.garbageSupply, G.garbageResupplyNorth[G.players.length - 2][G.step - 1], garbageCapNorth);
|
|
767
|
+
G.garbageMarketNorth += garbageResupplyNorthValue;
|
|
768
|
+
G.garbageSupply -= garbageResupplyNorthValue;
|
|
769
|
+
}
|
|
770
|
+
// South Africa pulls from coalStorage first, then coalSupply.
|
|
771
|
+
// Other maps just pull from coalSupply.
|
|
772
|
+
let coalResupplyValue;
|
|
773
|
+
if (G.coalStorage !== undefined) {
|
|
774
|
+
const wantCoal = Math.min(G.coalResupply[G.players.length - 2][G.step - 1], coalCapSouth);
|
|
775
|
+
const fromStorage = Math.min(G.coalStorage, wantCoal);
|
|
776
|
+
const fromSupply = Math.min(G.coalSupply, wantCoal - fromStorage);
|
|
777
|
+
coalResupplyValue = fromStorage + fromSupply;
|
|
778
|
+
G.coalMarket += coalResupplyValue;
|
|
779
|
+
G.coalStorage -= fromStorage;
|
|
780
|
+
G.coalSupply -= fromSupply;
|
|
781
|
+
}
|
|
782
|
+
else {
|
|
783
|
+
coalResupplyValue = Math.min(G.coalSupply, G.coalResupply[G.players.length - 2][G.step - 1], coalCapSouth);
|
|
784
|
+
G.coalMarket += coalResupplyValue;
|
|
785
|
+
G.coalSupply -= coalResupplyValue;
|
|
786
|
+
}
|
|
662
787
|
let oilResupplyValue;
|
|
663
788
|
if (G.map.name == 'Middle East') {
|
|
664
789
|
if (G.oilMarket == 0) {
|
|
@@ -678,25 +803,33 @@ function move(G, move, playerNumber, isUndo = false) {
|
|
|
678
803
|
}
|
|
679
804
|
}
|
|
680
805
|
else {
|
|
681
|
-
oilResupplyValue = Math.min(G.oilSupply, G.oilResupply[G.players.length - 2][G.step - 1]);
|
|
806
|
+
oilResupplyValue = Math.min(G.oilSupply, G.oilResupply[G.players.length - 2][G.step - 1], oilCapSouth);
|
|
682
807
|
G.oilMarket += oilResupplyValue;
|
|
683
808
|
G.oilSupply -= oilResupplyValue;
|
|
684
809
|
}
|
|
685
|
-
const garbageResupplyValue = Math.min(G.garbageSupply, G.garbageResupply[G.players.length - 2][G.step - 1]);
|
|
810
|
+
const garbageResupplyValue = Math.min(G.garbageSupply, G.garbageResupply[G.players.length - 2][G.step - 1], garbageCapSouth);
|
|
686
811
|
G.garbageMarket += garbageResupplyValue;
|
|
687
812
|
G.garbageSupply -= garbageResupplyValue;
|
|
688
813
|
let uraniumResupplyValue = 0;
|
|
689
814
|
if (G.options.variant != 'recharged' ||
|
|
690
815
|
(G.options.map != 'Germany' && G.options.map != 'Italy') ||
|
|
691
816
|
!G.card39Bought) {
|
|
692
|
-
uraniumResupplyValue = Math.min(G.uraniumSupply, G.uraniumResupply[G.players.length - 2][G.step - 1]);
|
|
817
|
+
uraniumResupplyValue = Math.min(G.uraniumSupply, G.uraniumResupply[G.players.length - 2][G.step - 1], uraniumCapSouth);
|
|
693
818
|
G.uraniumMarket += uraniumResupplyValue;
|
|
694
819
|
G.uraniumSupply -= uraniumResupplyValue;
|
|
695
820
|
}
|
|
696
|
-
G.
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
821
|
+
if (G.coalResupplyNorth) {
|
|
822
|
+
G.log.push({
|
|
823
|
+
type: 'event',
|
|
824
|
+
event: `Resupplying resources — North: [${coalResupplyNorthValue}, ${oilResupplyNorthValue}, ${garbageResupplyNorthValue}], South: [${coalResupplyValue}, ${oilResupplyValue}, ${garbageResupplyValue}, ${uraniumResupplyValue}].`,
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
else {
|
|
828
|
+
G.log.push({
|
|
829
|
+
type: 'event',
|
|
830
|
+
event: `Resupplying resources: [${coalResupplyValue}, ${oilResupplyValue}, ${garbageResupplyValue}, ${uraniumResupplyValue}].`,
|
|
831
|
+
});
|
|
832
|
+
}
|
|
700
833
|
if (G.map.name == 'Middle East' && G.step == 2 && G.futureMarket.length > 0) {
|
|
701
834
|
// If we aren't about to enter step 3, discard top two plants instead of one.
|
|
702
835
|
let powerPlantToPush = G.futureMarket.pop();
|
|
@@ -968,17 +1101,35 @@ function move(G, move, playerNumber, isUndo = false) {
|
|
|
968
1101
|
case move_1.MoveName.BuyResource: {
|
|
969
1102
|
utils_1.asserts(move);
|
|
970
1103
|
G.chosenResource = move.data.resource;
|
|
1104
|
+
// Korea: lock the player to the side of their first buy this turn.
|
|
1105
|
+
// Subsequent buys must come from the same side until they pass.
|
|
1106
|
+
if (move.data.side) {
|
|
1107
|
+
G.chosenSide = move.data.side;
|
|
1108
|
+
}
|
|
1109
|
+
const isNorth = move.data.side === 'north';
|
|
971
1110
|
let price;
|
|
972
1111
|
switch (move.data.resource) {
|
|
973
1112
|
case gamestate_1.ResourceType.Coal: {
|
|
974
|
-
if (
|
|
1113
|
+
if (isNorth) {
|
|
1114
|
+
const coalPrices = G.coalPricesNorth;
|
|
1115
|
+
price = coalPrices[coalPrices.length - G.coalMarketNorth];
|
|
1116
|
+
player.coalLeft++;
|
|
1117
|
+
G.coalMarketNorth--;
|
|
1118
|
+
}
|
|
1119
|
+
else if (move.data.fromStorage) {
|
|
1120
|
+
// South Africa: $8 flat from the storage pool below the market.
|
|
1121
|
+
price = 8;
|
|
1122
|
+
player.coalLeft++;
|
|
1123
|
+
G.coalStorage--;
|
|
1124
|
+
}
|
|
1125
|
+
else if (G.coalMarket == 0) {
|
|
975
1126
|
price = 8;
|
|
976
1127
|
player.coalLeft++;
|
|
977
1128
|
G.coalSupply--;
|
|
978
1129
|
move.fromSupply = true;
|
|
979
1130
|
}
|
|
980
1131
|
else {
|
|
981
|
-
const coalPrices = (
|
|
1132
|
+
const coalPrices = (_l = G.coalPrices) !== null && _l !== void 0 ? _l : prices_1.default[gamestate_1.ResourceType.Coal];
|
|
982
1133
|
price = coalPrices[coalPrices.length - G.coalMarket];
|
|
983
1134
|
player.coalLeft++;
|
|
984
1135
|
G.coalMarket--;
|
|
@@ -986,28 +1137,45 @@ function move(G, move, playerNumber, isUndo = false) {
|
|
|
986
1137
|
break;
|
|
987
1138
|
}
|
|
988
1139
|
case gamestate_1.ResourceType.Oil: {
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
1140
|
+
if (isNorth) {
|
|
1141
|
+
const oilPrices = G.oilPricesNorth;
|
|
1142
|
+
price = oilPrices[oilPrices.length - G.oilMarketNorth];
|
|
1143
|
+
player.oilLeft++;
|
|
1144
|
+
G.oilMarketNorth--;
|
|
1145
|
+
}
|
|
1146
|
+
else {
|
|
1147
|
+
const oilPrices = (_m = G.oilPrices) !== null && _m !== void 0 ? _m : prices_1.default[gamestate_1.ResourceType.Oil];
|
|
1148
|
+
price = oilPrices[oilPrices.length - G.oilMarket];
|
|
1149
|
+
player.oilLeft++;
|
|
1150
|
+
G.oilMarket--;
|
|
1151
|
+
}
|
|
993
1152
|
break;
|
|
994
1153
|
}
|
|
995
1154
|
case gamestate_1.ResourceType.Garbage: {
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1155
|
+
if (isNorth) {
|
|
1156
|
+
const garbagePrices = G.garbagePricesNorth;
|
|
1157
|
+
price = garbagePrices[garbagePrices.length - G.garbageMarketNorth];
|
|
1158
|
+
player.garbageLeft++;
|
|
1159
|
+
G.garbageMarketNorth--;
|
|
1160
|
+
}
|
|
1161
|
+
else {
|
|
1162
|
+
const garbagePrices = (_o = G.garbagePrices) !== null && _o !== void 0 ? _o : prices_1.default[gamestate_1.ResourceType.Garbage];
|
|
1163
|
+
price = garbagePrices[garbagePrices.length - G.garbageMarket];
|
|
1164
|
+
// $1 cheaper for players in Wien in Central Europe
|
|
1165
|
+
if (G.map.name == 'Central Europe') {
|
|
1166
|
+
const wienCity = player.cities.filter((c) => c.name == 'Wien');
|
|
1167
|
+
if ((wienCity === null || wienCity === void 0 ? void 0 : wienCity.length) > 0) {
|
|
1168
|
+
price--;
|
|
1169
|
+
}
|
|
1003
1170
|
}
|
|
1171
|
+
player.garbageLeft++;
|
|
1172
|
+
G.garbageMarket--;
|
|
1004
1173
|
}
|
|
1005
|
-
player.garbageLeft++;
|
|
1006
|
-
G.garbageMarket--;
|
|
1007
1174
|
break;
|
|
1008
1175
|
}
|
|
1009
1176
|
case gamestate_1.ResourceType.Uranium: {
|
|
1010
|
-
|
|
1177
|
+
// Uranium is only available from the South market (or non-Korea maps).
|
|
1178
|
+
const uraniumPrices = (_p = G.uraniumPrices) !== null && _p !== void 0 ? _p : prices_1.default[gamestate_1.ResourceType.Uranium];
|
|
1011
1179
|
price = uraniumPrices[uraniumPrices.length - G.uraniumMarket];
|
|
1012
1180
|
player.uraniumLeft++;
|
|
1013
1181
|
G.uraniumMarket--;
|
|
@@ -1033,8 +1201,15 @@ function move(G, move, playerNumber, isUndo = false) {
|
|
|
1033
1201
|
player.cities.push({ name: move.data.name, position });
|
|
1034
1202
|
player.money -= move.data.price;
|
|
1035
1203
|
if (G.options.trackTotalSpent) {
|
|
1036
|
-
|
|
1037
|
-
|
|
1204
|
+
const cityData = G.map.cities.find((c) => c.name == move.data.name);
|
|
1205
|
+
if (cityData.singleOccupancy) {
|
|
1206
|
+
// SA cross-border: no house base — full price is "connection".
|
|
1207
|
+
player.totalSpentConnections += move.data.price;
|
|
1208
|
+
}
|
|
1209
|
+
else {
|
|
1210
|
+
player.totalSpentCities += 10 + position * 5;
|
|
1211
|
+
player.totalSpentConnections += move.data.price - (10 + position * 5);
|
|
1212
|
+
}
|
|
1038
1213
|
}
|
|
1039
1214
|
G.log.push({
|
|
1040
1215
|
type: 'move',
|
|
@@ -1065,7 +1240,13 @@ function move(G, move, playerNumber, isUndo = false) {
|
|
|
1065
1240
|
switch (resourceType) {
|
|
1066
1241
|
case gamestate_1.ResourceType.Coal:
|
|
1067
1242
|
player.coalLeft--;
|
|
1068
|
-
|
|
1243
|
+
// SA: used coal returns to the separate storage pool below the market.
|
|
1244
|
+
if (G.coalStorage !== undefined) {
|
|
1245
|
+
G.coalStorage++;
|
|
1246
|
+
}
|
|
1247
|
+
else {
|
|
1248
|
+
G.coalSupply++;
|
|
1249
|
+
}
|
|
1069
1250
|
break;
|
|
1070
1251
|
case gamestate_1.ResourceType.Oil:
|
|
1071
1252
|
player.oilLeft--;
|
|
@@ -1109,10 +1290,22 @@ function move(G, move, playerNumber, isUndo = false) {
|
|
|
1109
1290
|
break;
|
|
1110
1291
|
}
|
|
1111
1292
|
case move_1.MoveName.BuyResource: {
|
|
1293
|
+
const undoIsNorth = lastMove.data.side === 'north';
|
|
1112
1294
|
let price;
|
|
1113
1295
|
switch (lastMove.data.resource) {
|
|
1114
1296
|
case gamestate_1.ResourceType.Coal:
|
|
1115
|
-
if (
|
|
1297
|
+
if (undoIsNorth) {
|
|
1298
|
+
player.coalLeft--;
|
|
1299
|
+
G.coalMarketNorth++;
|
|
1300
|
+
const coalPrices = G.coalPricesNorth;
|
|
1301
|
+
price = coalPrices[coalPrices.length - G.coalMarketNorth];
|
|
1302
|
+
}
|
|
1303
|
+
else if (lastMove.data.fromStorage) {
|
|
1304
|
+
price = 8;
|
|
1305
|
+
player.coalLeft--;
|
|
1306
|
+
G.coalStorage++;
|
|
1307
|
+
}
|
|
1308
|
+
else if (lastMove.fromSupply) {
|
|
1116
1309
|
price = 8;
|
|
1117
1310
|
player.coalLeft--;
|
|
1118
1311
|
G.coalSupply++;
|
|
@@ -1120,35 +1313,52 @@ function move(G, move, playerNumber, isUndo = false) {
|
|
|
1120
1313
|
else {
|
|
1121
1314
|
player.coalLeft--;
|
|
1122
1315
|
G.coalMarket++;
|
|
1123
|
-
const coalPrices = (
|
|
1316
|
+
const coalPrices = (_q = G.coalPrices) !== null && _q !== void 0 ? _q : prices_1.default[gamestate_1.ResourceType.Coal];
|
|
1124
1317
|
price = coalPrices[coalPrices.length - G.coalMarket];
|
|
1125
1318
|
}
|
|
1126
1319
|
break;
|
|
1127
1320
|
case gamestate_1.ResourceType.Oil: {
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1321
|
+
if (undoIsNorth) {
|
|
1322
|
+
player.oilLeft--;
|
|
1323
|
+
G.oilMarketNorth++;
|
|
1324
|
+
const oilPrices = G.oilPricesNorth;
|
|
1325
|
+
price = oilPrices[oilPrices.length - G.oilMarketNorth];
|
|
1326
|
+
}
|
|
1327
|
+
else {
|
|
1328
|
+
player.oilLeft--;
|
|
1329
|
+
G.oilMarket++;
|
|
1330
|
+
const oilPrices = (_r = G.oilPrices) !== null && _r !== void 0 ? _r : prices_1.default[gamestate_1.ResourceType.Oil];
|
|
1331
|
+
price = oilPrices[oilPrices.length - G.oilMarket];
|
|
1332
|
+
}
|
|
1132
1333
|
break;
|
|
1133
1334
|
}
|
|
1134
1335
|
case gamestate_1.ResourceType.Garbage: {
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1336
|
+
if (undoIsNorth) {
|
|
1337
|
+
player.garbageLeft--;
|
|
1338
|
+
G.garbageMarketNorth++;
|
|
1339
|
+
const garbagePrices = G.garbagePricesNorth;
|
|
1340
|
+
price = garbagePrices[garbagePrices.length - G.garbageMarketNorth];
|
|
1341
|
+
}
|
|
1342
|
+
else {
|
|
1343
|
+
player.garbageLeft--;
|
|
1344
|
+
G.garbageMarket++;
|
|
1345
|
+
const garbagePrices = (_s = G.garbagePrices) !== null && _s !== void 0 ? _s : prices_1.default[gamestate_1.ResourceType.Garbage];
|
|
1346
|
+
price = garbagePrices[garbagePrices.length - G.garbageMarket];
|
|
1347
|
+
// $1 cheaper for players in Wien in Central Europe
|
|
1348
|
+
if (G.map.name == 'Central Europe') {
|
|
1349
|
+
const wienCity = player.cities.filter((c) => c.name == 'Wien');
|
|
1350
|
+
if ((wienCity === null || wienCity === void 0 ? void 0 : wienCity.length) > 0) {
|
|
1351
|
+
price--;
|
|
1352
|
+
}
|
|
1144
1353
|
}
|
|
1145
1354
|
}
|
|
1146
1355
|
break;
|
|
1147
1356
|
}
|
|
1148
1357
|
case gamestate_1.ResourceType.Uranium: {
|
|
1358
|
+
// Uranium is only available from the South market (or non-Korea maps).
|
|
1149
1359
|
player.uraniumLeft--;
|
|
1150
1360
|
G.uraniumMarket++;
|
|
1151
|
-
const uraniumPrices = (
|
|
1361
|
+
const uraniumPrices = (_t = G.uraniumPrices) !== null && _t !== void 0 ? _t : prices_1.default[gamestate_1.ResourceType.Uranium];
|
|
1152
1362
|
price = uraniumPrices[uraniumPrices.length - G.uraniumMarket];
|
|
1153
1363
|
break;
|
|
1154
1364
|
}
|
|
@@ -1161,6 +1371,22 @@ function move(G, move, playerNumber, isUndo = false) {
|
|
|
1161
1371
|
G.chosenResource = undefined;
|
|
1162
1372
|
}
|
|
1163
1373
|
G.log.pop();
|
|
1374
|
+
// Korea: keep chosenSide locked while the player still has
|
|
1375
|
+
// outstanding BuyResource moves this phase, but clear it once
|
|
1376
|
+
// the last one is undone so they can switch sides again.
|
|
1377
|
+
if (G.map.name == 'Korea' && G.chosenSide) {
|
|
1378
|
+
let stillCommitted = false;
|
|
1379
|
+
for (let i = G.log.length - 1; i >= 0; i--) {
|
|
1380
|
+
const entry = G.log[i];
|
|
1381
|
+
if (entry.type !== 'move')
|
|
1382
|
+
continue;
|
|
1383
|
+
stillCommitted = entry.player === playerNumber && entry.move.name === move_1.MoveName.BuyResource;
|
|
1384
|
+
break;
|
|
1385
|
+
}
|
|
1386
|
+
if (!stillCommitted) {
|
|
1387
|
+
G.chosenSide = undefined;
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1164
1390
|
break;
|
|
1165
1391
|
}
|
|
1166
1392
|
case move_1.MoveName.Build: {
|
|
@@ -1905,6 +2131,13 @@ function updateGameState(G) {
|
|
|
1905
2131
|
`[${G.coalResupply[p][1]}, ${G.oilResupply[p][1]}, ${G.garbageResupply[p][1]}, ${G.uraniumResupply[p][1]}]`,
|
|
1906
2132
|
`[${G.coalResupply[p][2]}, ${G.oilResupply[p][2]}, ${G.garbageResupply[p][2]}, ${G.uraniumResupply[p][2]}]`,
|
|
1907
2133
|
];
|
|
2134
|
+
if (G.coalResupplyNorth && G.oilResupplyNorth && G.garbageResupplyNorth) {
|
|
2135
|
+
G.resourceResupplyNorth = [
|
|
2136
|
+
`[${G.coalResupplyNorth[p][0]}, ${G.oilResupplyNorth[p][0]}, ${G.garbageResupplyNorth[p][0]}]`,
|
|
2137
|
+
`[${G.coalResupplyNorth[p][1]}, ${G.oilResupplyNorth[p][1]}, ${G.garbageResupplyNorth[p][1]}]`,
|
|
2138
|
+
`[${G.coalResupplyNorth[p][2]}, ${G.oilResupplyNorth[p][2]}, ${G.garbageResupplyNorth[p][2]}]`,
|
|
2139
|
+
];
|
|
2140
|
+
}
|
|
1908
2141
|
}
|
|
1909
2142
|
}
|
|
1910
2143
|
function fastAuction(G, player, bid) {
|
package/dist/src/gamestate.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { AvailableMoves } from './available-moves';
|
|
|
2
2
|
import { LogItem } from './log';
|
|
3
3
|
import { GameMap } from './maps';
|
|
4
4
|
import { Move } from './move';
|
|
5
|
-
export declare type MapName = 'USA' | 'Germany' | 'Brazil' | 'Spain & Portugal' | 'France' | 'Italy' | 'Quebec' | 'Middle East' | 'India' | 'China' | 'Benelux' | 'Russia' | 'Central Europe';
|
|
5
|
+
export declare type MapName = 'USA' | 'Germany' | 'Brazil' | 'Spain & Portugal' | 'France' | 'Italy' | 'Quebec' | 'Middle East' | 'India' | 'China' | 'Benelux' | 'Russia' | 'Central Europe' | 'Baden-Württemberg' | 'Northern Europe' | 'Korea' | 'Europe' | 'North America' | 'South Africa' | 'UK & Ireland';
|
|
6
6
|
export declare type Variant = 'original' | 'recharged';
|
|
7
7
|
export interface GameOptions {
|
|
8
8
|
fastBid?: boolean;
|
|
@@ -92,6 +92,7 @@ export interface GameState {
|
|
|
92
92
|
oilSupply: number;
|
|
93
93
|
garbageSupply: number;
|
|
94
94
|
uraniumSupply: number;
|
|
95
|
+
coalStorage?: number;
|
|
95
96
|
coalMarket: number;
|
|
96
97
|
oilMarket: number;
|
|
97
98
|
garbageMarket: number;
|
|
@@ -100,6 +101,15 @@ export interface GameState {
|
|
|
100
101
|
oilResupply?: number[][];
|
|
101
102
|
garbageResupply?: number[][];
|
|
102
103
|
uraniumResupply?: number[][];
|
|
104
|
+
coalMarketNorth?: number;
|
|
105
|
+
oilMarketNorth?: number;
|
|
106
|
+
garbageMarketNorth?: number;
|
|
107
|
+
coalResupplyNorth?: number[][];
|
|
108
|
+
oilResupplyNorth?: number[][];
|
|
109
|
+
garbageResupplyNorth?: number[][];
|
|
110
|
+
coalPricesNorth?: number[];
|
|
111
|
+
oilPricesNorth?: number[];
|
|
112
|
+
garbagePricesNorth?: number[];
|
|
103
113
|
coalPrices?: number[];
|
|
104
114
|
oilPrices?: number[];
|
|
105
115
|
garbagePrices?: number[];
|
|
@@ -108,6 +118,7 @@ export interface GameState {
|
|
|
108
118
|
futureMarket: PowerPlant[];
|
|
109
119
|
chosenPowerPlant: PowerPlant | undefined;
|
|
110
120
|
chosenResource?: ResourceType | undefined;
|
|
121
|
+
chosenSide?: 'north' | 'south';
|
|
111
122
|
currentBid: number | undefined;
|
|
112
123
|
auctioningPlayer: number | undefined;
|
|
113
124
|
step: number;
|
|
@@ -122,6 +133,7 @@ export interface GameState {
|
|
|
122
133
|
citiesToEndGame: number;
|
|
123
134
|
citiesBuiltInCurrentRound?: number;
|
|
124
135
|
resourceResupply: string[];
|
|
136
|
+
resourceResupplyNorth?: string[];
|
|
125
137
|
paymentTable: number[];
|
|
126
138
|
minimunBid: number;
|
|
127
139
|
plantDiscountActive: boolean;
|