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.
@@ -8,6 +8,8 @@ export interface AvailableMoves {
8
8
  [MoveName.BuyResource]?: {
9
9
  resource: ResourceType;
10
10
  price: number;
11
+ side?: 'north' | 'south';
12
+ fromStorage?: boolean;
11
13
  }[];
12
14
  [MoveName.Build]?: {
13
15
  name: string;
@@ -66,6 +66,15 @@ function availableMoves(G, player) {
66
66
  canBid = canBid.filter((p) => p.type != gamestate_1.PowerPlantType.Uranium);
67
67
  }
68
68
  }
69
+ // No nuclear plants for Republic of Ireland (Green region) on UK&I.
70
+ // The restriction lifts as soon as the player has any non-Green city
71
+ // (Scotland/Wales/England/Northern Ireland = Brown/Yellow/Red/Pink/Orange).
72
+ if (G.map.name == 'UK & Ireland') {
73
+ const playerCities = player.cities.map((c) => G.map.cities.find((c_) => c_.name == c.name));
74
+ if (playerCities.every((c) => c.region == 'green')) {
75
+ canBid = canBid.filter((p) => p.type != gamestate_1.PowerPlantType.Uranium);
76
+ }
77
+ }
69
78
  if (canBid.length > 0) {
70
79
  moves[move_1.MoveName.ChoosePowerPlant] = canBid.map((p) => p.number);
71
80
  }
@@ -107,6 +116,14 @@ function availableMoves(G, player) {
107
116
  moves[move_1.MoveName.Bid] = undefined;
108
117
  }
109
118
  }
119
+ // No nuclear plants for Republic of Ireland (Green region) on UK&I.
120
+ if (G.map.name == 'UK & Ireland') {
121
+ const playerCities = player.cities.map((c) => G.map.cities.find((c_) => c_.name == c.name));
122
+ if (playerCities.every((c) => c.region == 'green') &&
123
+ G.chosenPowerPlant.type == gamestate_1.PowerPlantType.Uranium) {
124
+ moves[move_1.MoveName.Bid] = undefined;
125
+ }
126
+ }
110
127
  if (G.options.fastBid) {
111
128
  if (player.id != G.auctioningPlayer) {
112
129
  moves[move_1.MoveName.Pass] = [true];
@@ -135,17 +152,22 @@ function availableMoves(G, player) {
135
152
  else {
136
153
  maxPriceAvailable = 16;
137
154
  }
138
- if (G.coalMarket > 0) {
155
+ // Korea: each side is offered separately, tagged with the side. The
156
+ // player's chosenSide locks them to one side once they make a buy.
157
+ const isKorea = G.coalResupplyNorth !== undefined;
158
+ const allowSouth = !isKorea || G.chosenSide !== 'north';
159
+ const allowNorth = isKorea && G.chosenSide !== 'south';
160
+ if (allowSouth && G.coalMarket > 0) {
139
161
  const hybridCapacityUsed = player.hybridCapacity > 0 ? Math.max(0, player.oilLeft - player.oilCapacity) : 0;
140
162
  const coalPrices = (_c = G.coalPrices) !== null && _c !== void 0 ? _c : prices_1.default[gamestate_1.ResourceType.Coal];
141
163
  const price = coalPrices[coalPrices.length - G.coalMarket];
142
164
  if (player.money >= price &&
143
165
  player.coalCapacity + player.hybridCapacity > hybridCapacityUsed + player.coalLeft &&
144
166
  price <= maxPriceAvailable) {
145
- toBuy.push({ resource: gamestate_1.ResourceType.Coal });
167
+ toBuy.push(isKorea ? { resource: gamestate_1.ResourceType.Coal, side: 'south' } : { resource: gamestate_1.ResourceType.Coal });
146
168
  }
147
169
  }
148
- else {
170
+ else if (allowSouth) {
149
171
  if (G.options.variant == 'recharged' && G.map.name == 'USA' && G.coalSupply > 0) {
150
172
  const hybridCapacityUsed = player.hybridCapacity > 0 ? Math.max(0, player.oilLeft - player.oilCapacity) : 0;
151
173
  if (player.money >= 8 &&
@@ -154,17 +176,48 @@ function availableMoves(G, player) {
154
176
  }
155
177
  }
156
178
  }
157
- if (G.oilMarket > 0) {
179
+ // South Africa: $8 flat coal from the storage pool below the market.
180
+ // Always available alongside the regular market option (not gated on
181
+ // market being empty), as long as there are cubes in storage.
182
+ if (allowSouth && G.coalStorage !== undefined && G.coalStorage > 0) {
183
+ const hybridCapacityUsed = player.hybridCapacity > 0 ? Math.max(0, player.oilLeft - player.oilCapacity) : 0;
184
+ if (player.money >= 8 &&
185
+ player.coalCapacity + player.hybridCapacity > hybridCapacityUsed + player.coalLeft &&
186
+ 8 <= maxPriceAvailable) {
187
+ toBuy.push({ resource: gamestate_1.ResourceType.Coal, fromStorage: true });
188
+ }
189
+ }
190
+ if (allowNorth && G.coalMarketNorth > 0) {
191
+ const hybridCapacityUsed = player.hybridCapacity > 0 ? Math.max(0, player.oilLeft - player.oilCapacity) : 0;
192
+ const coalPrices = G.coalPricesNorth;
193
+ const price = coalPrices[coalPrices.length - G.coalMarketNorth];
194
+ if (player.money >= price &&
195
+ player.coalCapacity + player.hybridCapacity > hybridCapacityUsed + player.coalLeft &&
196
+ price <= maxPriceAvailable) {
197
+ toBuy.push({ resource: gamestate_1.ResourceType.Coal, side: 'north' });
198
+ }
199
+ }
200
+ if (allowSouth && G.oilMarket > 0) {
158
201
  const hybridCapacityUsed = player.hybridCapacity > 0 ? Math.max(0, player.coalLeft - player.coalCapacity) : 0;
159
202
  const oilPrices = (_d = G.oilPrices) !== null && _d !== void 0 ? _d : prices_1.default[gamestate_1.ResourceType.Oil];
160
203
  const price = oilPrices[oilPrices.length - G.oilMarket];
161
204
  if (player.money >= price &&
162
205
  player.oilCapacity + player.hybridCapacity > hybridCapacityUsed + player.oilLeft &&
163
206
  price <= maxPriceAvailable) {
164
- toBuy.push({ resource: gamestate_1.ResourceType.Oil });
207
+ toBuy.push(isKorea ? { resource: gamestate_1.ResourceType.Oil, side: 'south' } : { resource: gamestate_1.ResourceType.Oil });
165
208
  }
166
209
  }
167
- if (G.garbageMarket > 0) {
210
+ if (allowNorth && G.oilMarketNorth > 0) {
211
+ const hybridCapacityUsed = player.hybridCapacity > 0 ? Math.max(0, player.coalLeft - player.coalCapacity) : 0;
212
+ const oilPrices = G.oilPricesNorth;
213
+ const price = oilPrices[oilPrices.length - G.oilMarketNorth];
214
+ if (player.money >= price &&
215
+ player.oilCapacity + player.hybridCapacity > hybridCapacityUsed + player.oilLeft &&
216
+ price <= maxPriceAvailable) {
217
+ toBuy.push({ resource: gamestate_1.ResourceType.Oil, side: 'north' });
218
+ }
219
+ }
220
+ if (allowSouth && G.garbageMarket > 0) {
168
221
  const garbagePrices = (_e = G.garbagePrices) !== null && _e !== void 0 ? _e : prices_1.default[gamestate_1.ResourceType.Garbage];
169
222
  let price = garbagePrices[garbagePrices.length - G.garbageMarket];
170
223
  // $1 cheaper for players in Wien in Central Europe
@@ -177,16 +230,26 @@ function availableMoves(G, player) {
177
230
  if (player.money >= price &&
178
231
  player.garbageCapacity > player.garbageLeft &&
179
232
  price <= maxPriceAvailable) {
180
- toBuy.push({ resource: gamestate_1.ResourceType.Garbage });
233
+ toBuy.push(isKorea ? { resource: gamestate_1.ResourceType.Garbage, side: 'south' } : { resource: gamestate_1.ResourceType.Garbage });
234
+ }
235
+ }
236
+ if (allowNorth && G.garbageMarketNorth > 0) {
237
+ const garbagePrices = G.garbagePricesNorth;
238
+ const price = garbagePrices[garbagePrices.length - G.garbageMarketNorth];
239
+ if (player.money >= price &&
240
+ player.garbageCapacity > player.garbageLeft &&
241
+ price <= maxPriceAvailable) {
242
+ toBuy.push({ resource: gamestate_1.ResourceType.Garbage, side: 'north' });
181
243
  }
182
244
  }
183
- if (G.uraniumMarket > 0) {
245
+ // Uranium is South only (or non-Korea maps).
246
+ if (allowSouth && G.uraniumMarket > 0) {
184
247
  const uraniumPrices = (_f = G.uraniumPrices) !== null && _f !== void 0 ? _f : prices_1.default[gamestate_1.ResourceType.Uranium];
185
248
  const price = uraniumPrices[uraniumPrices.length - G.uraniumMarket];
186
249
  if (player.money >= price &&
187
250
  player.uraniumCapacity > player.uraniumLeft &&
188
251
  price <= maxPriceAvailable) {
189
- toBuy.push({ resource: gamestate_1.ResourceType.Uranium });
252
+ toBuy.push(isKorea ? { resource: gamestate_1.ResourceType.Uranium, side: 'south' } : { resource: gamestate_1.ResourceType.Uranium });
190
253
  }
191
254
  }
192
255
  if (toBuy.length > 0) {
@@ -221,6 +284,44 @@ function availableMoves(G, player) {
221
284
  }
222
285
  return;
223
286
  }
287
+ // UK & Ireland: starting a network on an island where the player has
288
+ // no city yet pays the first-house base + crossIslandSurcharge. There
289
+ // is no sea edge so dijkstra reports the target city as unreachable
290
+ // (price=9999); we override here. The first build ever (player.cities
291
+ // empty) goes through the normal first-build path and pays no surcharge.
292
+ if (cityData.island && G.map.crossIslandSurcharge !== undefined && player.cities.length > 0) {
293
+ const playerIslands = new Set(player.cities
294
+ .map((c) => { var _a; return (_a = G.map.cities.find((mc) => mc.name == c.name)) === null || _a === void 0 ? void 0 : _a.island; })
295
+ .filter((i) => !!i));
296
+ if (!playerIslands.has(cityData.island)) {
297
+ city.price = 10 + othersCount * 5 + G.map.crossIslandSurcharge;
298
+ if (othersCount == G.step) {
299
+ city.price = 9999;
300
+ }
301
+ if (player.cities.find((c) => c.name == city.name)) {
302
+ city.price = 9999;
303
+ }
304
+ return;
305
+ }
306
+ }
307
+ // South Africa's cross-border foreign-country spaces: cap at 1 occupant
308
+ // ever, and the dijkstra path cost (30 via the cross-border edge) is the
309
+ // complete cost — no 10+position*5 house base is added. Players cannot
310
+ // start in one of these (you have to build INTO South Africa first).
311
+ if (cityData.singleOccupancy) {
312
+ if (player.cities.length == 0) {
313
+ city.price = 9999;
314
+ return;
315
+ }
316
+ if (othersCount >= 1) {
317
+ city.price = 9999;
318
+ return;
319
+ }
320
+ if (player.cities.find((c) => c.name == city.name)) {
321
+ city.price = 9999;
322
+ }
323
+ return;
324
+ }
224
325
  city.price += 10 + othersCount * 5;
225
326
  if (othersCount == G.step) {
226
327
  city.price = 9999;