powergrid-viewer 1.5.4

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.
Files changed (57) hide show
  1. package/README.md +35 -0
  2. package/dist/img/help.ba7779cc.svg +1 -0
  3. package/dist/img/log.04ef6981.svg +1 -0
  4. package/dist/img/pass.da9065dc.svg +3 -0
  5. package/dist/img/rules.64f9aae5.svg +28 -0
  6. package/dist/img/sound-off.72ada995.svg +3 -0
  7. package/dist/img/sound-on.c55edd90.svg +3 -0
  8. package/dist/img/undo.208666d2.svg +3 -0
  9. package/dist/media/notification.55fa47dd.ogg +0 -0
  10. package/dist/media/notification.ac905963.mp3 +0 -0
  11. package/dist/media/piece-drop.eef5f607.mp3 +0 -0
  12. package/dist/powergrid-viewer.css +1 -0
  13. package/dist/powergrid-viewer.umd.min.js +35 -0
  14. package/package.json +49 -0
  15. package/src/audio/notification.mp3 +0 -0
  16. package/src/audio/notification.ogg +0 -0
  17. package/src/audio/piece-drop.mp3 +0 -0
  18. package/src/components/Calculator.vue +62 -0
  19. package/src/components/Game.vue +1354 -0
  20. package/src/components/PlayerBoard.vue +230 -0
  21. package/src/components/boards/CityCount.vue +82 -0
  22. package/src/components/boards/Map.vue +196 -0
  23. package/src/components/boards/PlayerOrder.vue +68 -0
  24. package/src/components/boards/PowerPlantMarket.vue +184 -0
  25. package/src/components/boards/Resources.vue +446 -0
  26. package/src/components/buttons/Button.vue +26 -0
  27. package/src/components/buttons/HelpButton.vue +18 -0
  28. package/src/components/buttons/LogButton.vue +15 -0
  29. package/src/components/buttons/PassButton.vue +18 -0
  30. package/src/components/buttons/RulesButton.vue +14 -0
  31. package/src/components/buttons/SoundButton.vue +18 -0
  32. package/src/components/buttons/UndoButton.vue +17 -0
  33. package/src/components/buttons/index.js +9 -0
  34. package/src/components/pieces/Card.vue +131 -0
  35. package/src/components/pieces/Coal.vue +40 -0
  36. package/src/components/pieces/Garbage.vue +40 -0
  37. package/src/components/pieces/House.vue +51 -0
  38. package/src/components/pieces/Hybrid.vue +37 -0
  39. package/src/components/pieces/Oil.vue +40 -0
  40. package/src/components/pieces/Piece.vue +104 -0
  41. package/src/components/pieces/Uranium.vue +32 -0
  42. package/src/components/pieces/index.js +10 -0
  43. package/src/icons/help.svg +1 -0
  44. package/src/icons/log.svg +1 -0
  45. package/src/icons/pass.svg +3 -0
  46. package/src/icons/rules.svg +28 -0
  47. package/src/icons/sound-off.svg +3 -0
  48. package/src/icons/sound-on.svg +3 -0
  49. package/src/icons/undo.svg +3 -0
  50. package/src/launch.ts +87 -0
  51. package/src/main.ts +3 -0
  52. package/src/self-contained.ts +97 -0
  53. package/src/shims-tsx.d.ts +13 -0
  54. package/src/shims-vue.d.ts +4 -0
  55. package/src/types/ui-data.ts +34 -0
  56. package/src/wrapper.ts +8 -0
  57. package/tsconfig.json +23 -0
@@ -0,0 +1,184 @@
1
+ <template>
2
+ <g>
3
+ <text x="10" y="14" font-weight="600" fill="black">Power Plant Deck:</text>
4
+ <template v-if="cardsLeft > 0">
5
+ <rect
6
+ v-for="index in cardsLeft"
7
+ :key="'card' + index"
8
+ :x="35 + index / 5"
9
+ :y="38 - index / 10"
10
+ width="60"
11
+ height="40"
12
+ fill="gray"
13
+ stroke="black"
14
+ stroke-width="2"
15
+ rx="4"
16
+ />
17
+ <rect
18
+ :x="35 + cardsLeft / 5"
19
+ :y="38 - cardsLeft / 10"
20
+ width="60"
21
+ height="40"
22
+ :fill="nextCardWeak ? 'gray' : 'lightgray'"
23
+ stroke="black"
24
+ stroke-width="2"
25
+ rx="4"
26
+ >
27
+ <title>{{ cardsLeft }} cards left{{ nextCardWeak ? ', next is an initial plant' : '' }}</title>
28
+ </rect>
29
+ </template>
30
+
31
+ <text x="165" y="14" font-weight="600" fill="black">Actual Market:</text>
32
+ <template v-for="(card, i) in actualMarketCards">
33
+ <Card
34
+ :key="card.id"
35
+ :targetState="{ x: card.x, y: card.y }"
36
+ :powerPlant="card.powerPlant"
37
+ :canClick="chooseablePowerPlants && chooseablePowerPlants.includes(card.powerPlant.number)"
38
+ :hasDiscount="plantDiscountActive && i == 0"
39
+ @click="choosePowerPlant(card.powerPlant)"
40
+ />
41
+ </template>
42
+
43
+ <template v-if="futureMarketCards.length > 0">
44
+ <text x="165" y="80" font-weight="600" fill="black">Future Market:</text>
45
+ <template v-for="card in futureMarketCards">
46
+ <Card :key="card.id" :targetState="{ x: card.x, y: card.y }" :powerPlant="card.powerPlant" />
47
+ </template>
48
+ </template>
49
+
50
+ <template v-if="chosenPowerPlant">
51
+ <text :x="actualMarketWidth" y="14" font-weight="600" fill="black">Current Auction:</text>
52
+ <Card
53
+ :key="chosenPowerPlant.id"
54
+ :targetState="{ x: chosenPowerPlant.x, y: chosenPowerPlant.y }"
55
+ :powerPlant="chosenPowerPlant.powerPlant"
56
+ />
57
+ <Calculator
58
+ v-if="canBid"
59
+ :transform="`translate(${actualMarketWidth}, 80)`"
60
+ :minValue="minBid"
61
+ :maxValue="maxBid"
62
+ @bid="bid($event)"
63
+ />
64
+ </template>
65
+
66
+ <template v-if="!preferences.disableHelp">
67
+ <g v-if="canChoose">
68
+ <rect
69
+ v-if="futureMarketCards.length > 0"
70
+ x="160"
71
+ y="5"
72
+ :width="65 * actualMarketCards.length + 5"
73
+ height="65"
74
+ fill="none"
75
+ stroke="blue"
76
+ stroke-width="2px"
77
+ rx="2px"
78
+ />
79
+
80
+ <rect
81
+ v-else
82
+ x="160"
83
+ y="5"
84
+ width="200"
85
+ height="120"
86
+ fill="none"
87
+ stroke="blue"
88
+ stroke-width="2px"
89
+ rx="2px"
90
+ />
91
+ </g>
92
+ </template>
93
+ </g>
94
+ </template>
95
+
96
+ <script lang="ts">
97
+ import type { GameState } from 'powergrid-engine';
98
+ import { PowerPlant } from 'powergrid-engine/src/gamestate';
99
+ import { Vue, Component, Prop, Inject } from 'vue-property-decorator';
100
+ import { Card } from './../pieces';
101
+ import { Piece, Preferences } from '../../types/ui-data';
102
+ import Calculator from './../Calculator.vue';
103
+
104
+ @Component({
105
+ components: {
106
+ Card,
107
+ Calculator
108
+ },
109
+ })
110
+ export default class PowerPlantMarket extends Vue {
111
+ @Prop() cardsLeft?: number;
112
+ @Prop() nextCardWeak?: boolean;
113
+ @Prop() plantDiscountActive?: boolean;
114
+ @Prop() canBid?: boolean;
115
+ @Prop() canChoose?: boolean;
116
+ @Prop() chooseablePowerPlants?: number[];
117
+ @Prop() minBid?: number;
118
+ @Prop() maxBid?: number;
119
+
120
+ @Inject() preferences!: Preferences;
121
+
122
+ actualMarketCards: Piece[] = [];
123
+ futureMarketCards: Piece[] = [];
124
+ chosenPowerPlant: Piece | null = null;
125
+ actualMarketWidth: number = 430;
126
+
127
+ createPieces(gameState: GameState) {
128
+ this.actualMarketWidth = gameState.map.actualMarketWidth ?? 430;
129
+ this.actualMarketCards = [];
130
+ gameState.actualMarket.forEach((card, i) => {
131
+ if (gameState.futureMarket.length > 0) {
132
+ if (card.number != gameState.chosenPowerPlant?.number) {
133
+ this.actualMarketCards.push({
134
+ id: 'actual_' + i,
135
+ x: 165 + i * 65,
136
+ y: 24,
137
+ powerPlant: card
138
+ });
139
+ }
140
+ } else {
141
+ if (card.number != gameState.chosenPowerPlant?.number) {
142
+ this.actualMarketCards.push({
143
+ id: 'actual_' + i,
144
+ x: 165 + (i % 3) * 65,
145
+ y: i < 3 ? 24 : 80,
146
+ powerPlant: card
147
+ });
148
+ }
149
+ }
150
+ });
151
+
152
+ this.futureMarketCards = [];
153
+ gameState.futureMarket.forEach((card, i) => {
154
+ if (card.number != gameState.chosenPowerPlant?.number) {
155
+ this.futureMarketCards.push({
156
+ id: 'future_' + i,
157
+ x: 165 + i * 65,
158
+ y: 90,
159
+ powerPlant: card
160
+ });
161
+ }
162
+ });
163
+
164
+ if (gameState.chosenPowerPlant) {
165
+ this.chosenPowerPlant = {
166
+ id: 'chosen',
167
+ x: this.actualMarketWidth + 30,
168
+ y: 30,
169
+ powerPlant: gameState.chosenPowerPlant
170
+ };
171
+ } else {
172
+ this.chosenPowerPlant = null;
173
+ }
174
+ }
175
+
176
+ choosePowerPlant(powerPlant: PowerPlant) {
177
+ this.$emit('choosePowerPlant', powerPlant);
178
+ }
179
+
180
+ bid(bid: number) {
181
+ this.$emit('bid', bid);
182
+ }
183
+ }
184
+ </script>
@@ -0,0 +1,446 @@
1
+ <template>
2
+ <g>
3
+ <text v-if="resourceResupply[0] < 10" x="30" y="20" font-weight="600" fill="black" style="font-size: 24px"
4
+ >Resource Resupply:</text
5
+ >
6
+ <text v-else x="20" y="20" font-weight="600" fill="black" style="font-size: 24px">Resource Resupply:</text>
7
+ <text v-if="resourceResupply[0] < 10" x="276" y="20" font-weight="600" fill="black" style="font-size: 24px">
8
+ {{ resourceResupply[0] }}
9
+ </text>
10
+ <text v-else x="262" y="20" font-weight="600" fill="black" style="font-size: 24px">
11
+ {{ resourceResupply[0] }}
12
+ </text>
13
+ <Coal :pieceId="-1" :targetState="{ x: 288, y: 12 }" :canClick="false" :transparent="false" />
14
+ <text x="321" y="20" font-weight="600" fill="black" style="font-size: 24px">
15
+ {{ resourceResupply[1] }}
16
+ </text>
17
+ <Oil :pieceId="-1" :targetState="{ x: 331, y: 11 }" :canClick="false" :transparent="false" />
18
+ <text x="368" y="20" font-weight="600" fill="black" style="font-size: 24px">
19
+ {{ resourceResupply[2] }}
20
+ </text>
21
+ <Garbage :pieceId="-1" :targetState="{ x: 382, y: 11 }" :canClick="false" :transparent="false" />
22
+ <text x="414" y="20" font-weight="600" fill="black" style="font-size: 24px">
23
+ {{ resourceResupply[3] }}
24
+ </text>
25
+ <Uranium :pieceId="-1" :targetState="{ x: 428, y: 12 }" :canClick="false" :transparent="false" />
26
+
27
+ <rect v-if="!isIndiaResourceMarket" width="760" height="80" x="20" y="40" rx="3" fill="goldenrod" />
28
+ <rect v-if="isIndiaResourceMarket" width="680" height="80" x="20" y="40" rx="3" fill="goldenrod" />
29
+ <template v-for="index in 8">
30
+ <rect
31
+ :key="'resources' + index"
32
+ width="70"
33
+ height="70"
34
+ :x="25 + 85 * (index - 1)"
35
+ y="45"
36
+ rx="2"
37
+ fill="darkgoldenrod"
38
+ />
39
+ <circle :key="'resourcesCircle' + index" r="10" :cx="92 + 85 * (index - 1)" cy="48" fill="yellow" />
40
+ <text
41
+ :key="'resourcesText' + index"
42
+ text-anchor="middle"
43
+ style="font-size: 16px; font-family: monospace"
44
+ :x="92 + 85 * (index - 1)"
45
+ y="48"
46
+ fill="darkgoldenrod"
47
+ >
48
+ {{ index }}
49
+ </text>
50
+ <g :key="'lines' + index" v-if="!isIndiaResourceMarket">
51
+ <line :x1="25 + 85 * (index - 1)" y1="68" :x2="95 + 85 * (index - 1)" y2="68" stroke="goldenrod" />
52
+ <line :x1="25 + 85 * (index - 1)" y1="92" :x2="95 + 85 * (index - 1)" y2="92" stroke="goldenrod" />
53
+
54
+ <line :x1="48 + 85 * (index - 1)" y1="40" :x2="48 + 85 * (index - 1)" y2="68" stroke="goldenrod" />
55
+ <line :x1="72 + 85 * (index - 1)" y1="40" :x2="72 + 85 * (index - 1)" y2="68" stroke="goldenrod" />
56
+ <line :x1="42 + 85 * (index - 1)" y1="68" :x2="42 + 85 * (index - 1)" y2="92" stroke="goldenrod" />
57
+ <line :x1="58 + 85 * (index - 1)" y1="68" :x2="58 + 85 * (index - 1)" y2="92" stroke="goldenrod" />
58
+ <line :x1="74 + 85 * (index - 1)" y1="68" :x2="74 + 85 * (index - 1)" y2="92" stroke="goldenrod" />
59
+ <line :x1="48 + 85 * (index - 1)" y1="92" :x2="48 + 85 * (index - 1)" y2="120" stroke="goldenrod" />
60
+ <line :x1="72 + 85 * (index - 1)" y1="92" :x2="72 + 85 * (index - 1)" y2="120" stroke="goldenrod" />
61
+ </g>
62
+ <g :key="'lines' + index" v-if="isIndiaResourceMarket">
63
+ <line :x1="25 + 85 * (index - 1)" y1="68" :x2="95 + 85 * (index - 1)" y2="68" stroke="goldenrod" />
64
+ <line :x1="25 + 85 * (index - 1)" y1="92" :x2="95 + 85 * (index - 1)" y2="92" stroke="goldenrod" />
65
+
66
+ <line :x1="42 + 85 * (index - 1)" y1="40" :x2="42 + 85 * (index - 1)" y2="68" stroke="goldenrod" />
67
+ <line :x1="59 + 85 * (index - 1)" y1="40" :x2="59 + 85 * (index - 1)" y2="68" stroke="goldenrod" />
68
+ <line :x1="76 + 85 * (index - 1)" y1="40" :x2="76 + 85 * (index - 1)" y2="68" stroke="goldenrod" />
69
+ <line :x1="42 + 85 * (index - 1)" y1="68" :x2="42 + 85 * (index - 1)" y2="92" stroke="goldenrod" />
70
+ <line :x1="58 + 85 * (index - 1)" y1="68" :x2="58 + 85 * (index - 1)" y2="92" stroke="goldenrod" />
71
+ <line :x1="74 + 85 * (index - 1)" y1="68" :x2="74 + 85 * (index - 1)" y2="92" stroke="goldenrod" />
72
+ <line :x1="42 + 85 * (index - 1)" y1="92" :x2="42 + 85 * (index - 1)" y2="120" stroke="goldenrod" />
73
+ <line :x1="59 + 85 * (index - 1)" y1="92" :x2="59 + 85 * (index - 1)" y2="120" stroke="goldenrod" />
74
+ <line :x1="76 + 85 * (index - 1)" y1="92" :x2="76 + 85 * (index - 1)" y2="120" stroke="goldenrod" />
75
+ </g>
76
+ </template>
77
+
78
+ <template v-if="isIndiaResourceMarket">
79
+ <g :key="'separators'">
80
+ <line x1="275" y1="40" x2="275" y2="140" stroke="red" />
81
+ <line x1="445" y1="40" x2="445" y2="140" stroke="red" />
82
+
83
+ <text x="220" y="130" stroke="red">Step 1</text>
84
+ <text x="390" y="130" stroke="red">Step 2</text>
85
+ </g>
86
+ </template>
87
+
88
+ <template v-if="!isIndiaResourceMarket">
89
+ <rect width="30" height="30" x="705" y="45" rx="2" fill="darkgoldenrod" />
90
+ <circle r="10" cx="732" cy="48" fill="yellow" />
91
+ <text
92
+ text-anchor="middle"
93
+ style="font-size: 12px; font-family: monospace"
94
+ x="732"
95
+ y="48"
96
+ fill="darkgoldenrod"
97
+ >
98
+ 10
99
+ </text>
100
+
101
+ <rect width="30" height="30" x="745" y="45" rx="2" fill="darkgoldenrod" />
102
+ <circle r="10" cx="772" cy="48" fill="yellow" />
103
+ <text
104
+ text-anchor="middle"
105
+ style="font-size: 12px; font-family: monospace"
106
+ x="772"
107
+ y="48"
108
+ fill="darkgoldenrod"
109
+ >
110
+ 12
111
+ </text>
112
+
113
+ <rect width="30" height="30" x="705" y="85" rx="2" fill="darkgoldenrod" />
114
+ <circle r="10" cx="732" cy="88" fill="yellow" />
115
+ <text
116
+ text-anchor="middle"
117
+ style="font-size: 12px; font-family: monospace"
118
+ x="732"
119
+ y="88"
120
+ fill="darkgoldenrod"
121
+ >
122
+ 14
123
+ </text>
124
+
125
+ <rect width="30" height="30" x="745" y="85" rx="2" fill="darkgoldenrod" />
126
+ <circle r="10" cx="772" cy="88" fill="yellow" />
127
+ <text
128
+ text-anchor="middle"
129
+ style="font-size: 12px; font-family: monospace"
130
+ x="772"
131
+ y="88"
132
+ fill="darkgoldenrod"
133
+ >
134
+ 16
135
+ </text>
136
+ </template>
137
+
138
+ <template v-if="isUsaRecharged">
139
+ <rect
140
+ width="180"
141
+ height="70"
142
+ x="795"
143
+ y="45"
144
+ rx="2"
145
+ fill="chocolate"
146
+ stroke="sandybrown"
147
+ stroke-width="4px"
148
+ />
149
+ <circle r="10" cx="973" cy="45" fill="yellow" />
150
+ <text
151
+ text-anchor="middle"
152
+ style="font-size: 16px; font-family: monospace"
153
+ x="973"
154
+ y="45"
155
+ fill="darkgoldenrod"
156
+ >
157
+ 8
158
+ </text>
159
+ <Coal :pieceId="-1" :targetState="{ x: 858, y: 57 }" :canClick="false" :transparent="true" :scale="0.2" />
160
+ </template>
161
+
162
+ <template v-for="coal in coals">
163
+ <Coal
164
+ :key="coal.id"
165
+ :pieceId="coal.id"
166
+ :targetState="{ x: coal.x, y: coal.y }"
167
+ :canClick="!coal.transparent && canBuyResource('coal')"
168
+ :transparent="coal.transparent"
169
+ :scale="isIndiaResourceMarket ? 0.06 : 0.08"
170
+ @click="buyResource('coal')"
171
+ />
172
+ </template>
173
+
174
+ <template v-for="oil in oils">
175
+ <Oil
176
+ :key="oil.id"
177
+ :pieceId="oil.id"
178
+ :targetState="{ x: oil.x, y: oil.y }"
179
+ :canClick="!oil.transparent && canBuyResource('oil')"
180
+ :transparent="oil.transparent"
181
+ @click="buyResource('oil')"
182
+ />
183
+ </template>
184
+
185
+ <template v-for="garbage in garbages">
186
+ <Garbage
187
+ :key="garbage.id"
188
+ :pieceId="garbage.id"
189
+ :targetState="{ x: garbage.x, y: garbage.y }"
190
+ :canClick="!garbage.transparent && canBuyResource('garbage')"
191
+ :transparent="garbage.transparent"
192
+ :scale="isIndiaResourceMarket ? 0.8 : 1"
193
+ @click="buyResource('garbage')"
194
+ />
195
+ </template>
196
+
197
+ <template v-for="uranium in uraniums">
198
+ <Uranium
199
+ :key="uranium.id"
200
+ :pieceId="uranium.id"
201
+ :targetState="{ x: uranium.x, y: uranium.y }"
202
+ :canClick="!uranium.transparent && canBuyResource('uranium')"
203
+ :transparent="uranium.transparent"
204
+ @click="buyResource('uranium')"
205
+ />
206
+ </template>
207
+
208
+ <template v-if="isMiddleEast">
209
+ <rect width="80" height="50" x="20" y="70" rx="2" fill="gray" stroke="darkgray" stroke-width="4px" />
210
+ <Oil
211
+ :pieceId="-1"
212
+ :targetState="{ x: 35, y: 80 }"
213
+ :scale="1.5"
214
+ :canClick="availableSurplusOil > 0 && canBuyResource('oil')"
215
+ :transparent="availableSurplusOil == 0"
216
+ @click="buyResource('oil')"
217
+ />
218
+ <text text-anchor="middle" style="font-size: 16px; font-family: monospace" x="70" y="93.5">
219
+ x{{ availableSurplusOil }}
220
+ </text>
221
+ </template>
222
+
223
+ <template v-if="!preferences.disableHelp">
224
+ <rect
225
+ v-if="buyableResources.length > 0"
226
+ x="15"
227
+ y="35"
228
+ width="770"
229
+ height="90"
230
+ rx="2"
231
+ fill="none"
232
+ stroke="blue"
233
+ stroke-width="2px"
234
+ />
235
+ </template>
236
+ </g>
237
+ </template>
238
+
239
+ <script lang="ts">
240
+ import type { GameState } from 'powergrid-engine';
241
+ import { Vue, Component, Prop, Inject } from 'vue-property-decorator';
242
+ import { Coal, Garbage, Oil, Uranium } from '../pieces';
243
+ import { Piece, Preferences } from '../../types/ui-data';
244
+ import { range } from 'lodash';
245
+
246
+ @Component({
247
+ components: {
248
+ Coal, Oil, Garbage, Uranium
249
+ },
250
+ })
251
+ export default class Resources extends Vue {
252
+ @Prop() resourceResupply?: number[];
253
+ @Prop() isUsaRecharged?: boolean;
254
+ @Prop() isMiddleEast?: boolean;
255
+ @Prop() isIndiaResourceMarket?: boolean;
256
+ @Prop() availableSurplusOil?: number;
257
+ @Prop() buyableResources?: string[];
258
+
259
+ @Inject() preferences!: Preferences;
260
+
261
+ coals: Piece[] = [];
262
+ oils: Piece[] = [];
263
+ garbages: Piece[] = [];
264
+ uraniums: Piece[] = [];
265
+
266
+ createPieces(gameState: GameState) {
267
+ if (gameState) {
268
+ this.coals = [];
269
+ if (gameState.map?.name == 'India') {
270
+ Array(24)
271
+ .fill(0)
272
+ .forEach((_, i) => {
273
+ // Convert i to which of the 32 slots it belongs in, some of which are empty.
274
+ let index = i;
275
+ if (i >= 0) {
276
+ index += 2; // 2 empty slots for $8
277
+ }
278
+ if (i >= 2) {
279
+ index += 2; // 2 empty slots for $7
280
+ }
281
+ if (i >= 4) {
282
+ index++; // 1 empty slot for $6
283
+ }
284
+ if (i >= 7) {
285
+ index++; // 1 empty slot for $5
286
+ }
287
+ if (i >= 10) {
288
+ index++; // 1 empty slot for $4
289
+ }
290
+ if (i >= 13) {
291
+ index++; // 1 empty slot for $3
292
+ }
293
+
294
+ this.coals.push({
295
+ id: 'coal_' + i,
296
+ x: 672 - 17 * index - 17 * Math.floor(index / 4),
297
+ y: 48,
298
+ transparent: i >= gameState!.coalMarket
299
+ });
300
+ });
301
+ } else {
302
+ Array(24)
303
+ .fill(0)
304
+ .forEach((_, i) => {
305
+ this.coals.push({
306
+ id: 'coal_' + i,
307
+ x: 668 - 23.5 * i - 14.5 * Math.floor(i / 3),
308
+ y: 48,
309
+ transparent: i >= gameState!.coalMarket,
310
+ });
311
+ });
312
+ }
313
+
314
+ if (gameState.options.variant == 'recharged' && gameState.map?.name == 'USA') {
315
+ range(gameState.coalSupply).forEach((i) => {
316
+ this.coals.push({
317
+ id: 'coal_supply_' + i,
318
+ x: 800 + (i % 8) * 20 + (i >= 8 && i < 16 ? 10 : 0),
319
+ y: 50 + Math.floor(i / 8) * 20,
320
+ transparent: false,
321
+ });
322
+ });
323
+ }
324
+
325
+ this.oils = [];
326
+ if (gameState.map?.name == 'Middle East') {
327
+ let maxRegularOil = gameState.oilPrices!.filter(p => p > 1).length;
328
+ let maxSurplusOil = gameState.oilPrices!.filter(p => p == 1).length;
329
+ let availableRegularOil = Math.min(maxRegularOil, gameState.oilMarket);
330
+
331
+ Array(maxRegularOil)
332
+ .fill(0)
333
+ .forEach((_, i) => {
334
+ let adjustedIndex = i + (maxSurplusOil - 3);
335
+ this.oils.push({
336
+ id: 'normal_oil_' + adjustedIndex,
337
+ x: 651 - 16 * adjustedIndex - 37 * Math.floor(adjustedIndex / 3),
338
+ y: 70,
339
+ transparent: i >= availableRegularOil,
340
+ });
341
+ });
342
+ } else {
343
+ Array(24)
344
+ .fill(0)
345
+ .forEach((_, i) => {
346
+ this.oils.push({
347
+ id: 'oil_' + i,
348
+ x: 651 - 16 * i - 37 * Math.floor(i / 3),
349
+ y: 70,
350
+ transparent: i >= gameState!.oilMarket,
351
+ });
352
+ });
353
+ }
354
+
355
+ this.garbages = [];
356
+ if (gameState.map?.name == 'India') {
357
+ Array(24)
358
+ .fill(0)
359
+ .forEach((_, i) => {
360
+ let index = i + 8; // Leave $7 and $8 empty.
361
+ this.garbages.push({
362
+ id: 'garbage_' + i,
363
+ x: 672 - 17 * index - 17 * Math.floor(index / 4),
364
+ y: 94,
365
+ transparent: i >= gameState!.garbageMarket,
366
+ });
367
+ });
368
+ } else {
369
+ Array(24)
370
+ .fill(0)
371
+ .forEach((_, i) => {
372
+ this.garbages.push({
373
+ id: 'garbage_' + i,
374
+ x: 668 - 23.5 * i - 14.5 * Math.floor(i / 3),
375
+ y: 94,
376
+ transparent: i >= gameState!.garbageMarket,
377
+ });
378
+ });
379
+ }
380
+
381
+ this.uraniums = [];
382
+ if (gameState.map?.name == 'India') {
383
+ Array(8)
384
+ .fill(0)
385
+ .forEach((_, i) => {
386
+ this.uraniums.push({
387
+ id: 'uranium_' + i,
388
+ x: 670 - 85 * i,
389
+ y: 72,
390
+ transparent: i >= gameState!.uraniumMarket
391
+ });
392
+ });
393
+ } else {
394
+ Array(12)
395
+ .fill(0)
396
+ .forEach((_, i) => {
397
+ if (i == 0) {
398
+ this.uraniums.push({
399
+ id: 'uranium_' + i,
400
+ x: 750,
401
+ y: 91,
402
+ transparent: i >= gameState!.uraniumMarket,
403
+ });
404
+ } else if (i == 1) {
405
+ this.uraniums.push({
406
+ id: 'uranium_' + i,
407
+ x: 710,
408
+ y: 91,
409
+ transparent: i >= gameState!.uraniumMarket,
410
+ });
411
+ } else if (i == 2) {
412
+ this.uraniums.push({
413
+ id: 'uranium_' + i,
414
+ x: 750,
415
+ y: 52,
416
+ transparent: i >= gameState!.uraniumMarket,
417
+ });
418
+ } else if (i == 3) {
419
+ this.uraniums.push({
420
+ id: 'uranium_' + i,
421
+ x: 710,
422
+ y: 52,
423
+ transparent: i >= gameState!.uraniumMarket,
424
+ });
425
+ } else {
426
+ this.uraniums.push({
427
+ id: 'uranium_' + i,
428
+ x: 1010 - 85 * i,
429
+ y: 72,
430
+ transparent: i >= gameState!.uraniumMarket,
431
+ });
432
+ }
433
+ });
434
+ }
435
+ }
436
+ }
437
+
438
+ canBuyResource(resource: string) {
439
+ return !!this.buyableResources!.find(r => r == resource);
440
+ }
441
+
442
+ buyResource(resource: string) {
443
+ this.$emit('buyResource', resource);
444
+ }
445
+ }
446
+ </script>
@@ -0,0 +1,26 @@
1
+ <template>
2
+ <g :class="['button', { enabled }]" @click="enabled && $emit('click')">
3
+ <rect :width="width" height="30" fill="gainsboro" stroke="black" rx="2" />
4
+ <text text-anchor="middle" fill="black" :x="width / 2" y="16">{{ getText() }}</text>
5
+ <title>{{ text }}</title>
6
+ </g>
7
+ </template>
8
+ <script lang="ts">
9
+ import { Vue, Component, Prop } from 'vue-property-decorator';
10
+
11
+ @Component
12
+ export default class Button extends Vue {
13
+ @Prop()
14
+ text?: string;
15
+
16
+ @Prop()
17
+ width?: number;
18
+
19
+ @Prop({ default: true })
20
+ enabled!: boolean;
21
+
22
+ getText() {
23
+ return this.text!.length > 15 ? this.text?.substring(0, 12).concat('...') : this.text;
24
+ }
25
+ }
26
+ </script>
@@ -0,0 +1,18 @@
1
+ <template>
2
+ <g class="button enabled" @click="$emit('click')">
3
+ <circle cx="15" cy="15" r="15" fill="gainsboro" stroke="black" stroke-width="2px" />
4
+ <image x="5" y="5" width="20" height="20" href="../../icons/help.svg" />
5
+ <line v-if="!isOn" x1="5" y1="25" x2="25" y2="5" stroke="black" stroke-width="3px" stroke-linecap="round" />
6
+ <title v-if="isOn">Help off</title>
7
+ <title v-else>Help on</title>
8
+ </g>
9
+ </template>
10
+ <script lang="ts">
11
+ import { Vue, Component, Prop } from 'vue-property-decorator';
12
+
13
+ @Component
14
+ export default class HelpButton extends Vue {
15
+ @Prop()
16
+ isOn?: boolean;
17
+ }
18
+ </script>