powergrid-viewer 1.10.0 → 1.11.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "powergrid-viewer",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/boardgamers/powergrid.git",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"vue": "^2.6.11",
|
|
19
19
|
"vue-class-component": "^7.2.3",
|
|
20
20
|
"vue-property-decorator": "^8.4.2",
|
|
21
|
-
"powergrid-engine": "1.14.
|
|
21
|
+
"powergrid-engine": "1.14.1"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/assert": "^1.4.7",
|
|
@@ -22,10 +22,26 @@
|
|
|
22
22
|
</template> -->
|
|
23
23
|
|
|
24
24
|
<template v-for="city in cities">
|
|
25
|
-
<circle
|
|
25
|
+
<circle
|
|
26
|
+
v-if="city.connectionCost == null"
|
|
27
|
+
:key="city.name + '_region'"
|
|
28
|
+
r="25"
|
|
29
|
+
:cx="city.x"
|
|
30
|
+
:cy="city.y"
|
|
31
|
+
:fill="city.region"
|
|
32
|
+
stroke="black"
|
|
33
|
+
>
|
|
26
34
|
<title>{{ city.name }}</title>
|
|
27
35
|
</circle>
|
|
28
|
-
<circle
|
|
36
|
+
<circle
|
|
37
|
+
v-if="city.connectionCost == null"
|
|
38
|
+
:key="city.name + '_circle'"
|
|
39
|
+
r="20"
|
|
40
|
+
:cx="city.x"
|
|
41
|
+
:cy="city.y"
|
|
42
|
+
fill="gray"
|
|
43
|
+
stroke="black"
|
|
44
|
+
>
|
|
29
45
|
<title>{{ city.name }}</title>
|
|
30
46
|
</circle>
|
|
31
47
|
<!-- South Africa cross-border spaces: render a small red pennant
|
|
@@ -72,8 +88,65 @@
|
|
|
72
88
|
/>
|
|
73
89
|
</template>
|
|
74
90
|
|
|
91
|
+
<!-- Bremen-style node-weighted districts: clean labeled tiles (entry-cost
|
|
92
|
+
number + 8/14/20 house slots), drawn AFTER the links so the gray lines
|
|
93
|
+
sit behind. Gated on connectionCost; other maps keep circular nodes. -->
|
|
94
|
+
<template v-for="city in cities">
|
|
95
|
+
<g v-if="city.connectionCost != null" :key="city.name + '_tile'">
|
|
96
|
+
<rect
|
|
97
|
+
:class="[{ canClick: canBuild(city) }]"
|
|
98
|
+
:x="city.x - 23"
|
|
99
|
+
:y="city.y - 23"
|
|
100
|
+
width="46"
|
|
101
|
+
height="46"
|
|
102
|
+
rx="7"
|
|
103
|
+
fill="gray"
|
|
104
|
+
:stroke="city.region"
|
|
105
|
+
stroke-width="4"
|
|
106
|
+
:transform="`rotate(45, ${city.x}, ${city.y})`"
|
|
107
|
+
@click="canBuild(city) && build(city)"
|
|
108
|
+
>
|
|
109
|
+
<title>{{ city.name }} — connect for {{ city.connectionCost }} (entry) + house</title>
|
|
110
|
+
</rect>
|
|
111
|
+
<!-- house slots laid out like the board: 8 top, 14 left, 20 right -->
|
|
112
|
+
<template v-for="(sc, i) in city.slotCosts">
|
|
113
|
+
<rect
|
|
114
|
+
:key="city.name + '_slot' + i"
|
|
115
|
+
:x="city.x + nodeSlotPos(i).dx - 6.5"
|
|
116
|
+
:y="city.y + nodeSlotPos(i).dy - 6.5"
|
|
117
|
+
width="13"
|
|
118
|
+
height="13"
|
|
119
|
+
rx="1"
|
|
120
|
+
fill="gray"
|
|
121
|
+
stroke="black"
|
|
122
|
+
stroke-width="1"
|
|
123
|
+
:transform="`rotate(45, ${city.x + nodeSlotPos(i).dx}, ${city.y + nodeSlotPos(i).dy})`"
|
|
124
|
+
/>
|
|
125
|
+
<text
|
|
126
|
+
:key="city.name + '_slotlbl' + i"
|
|
127
|
+
:x="city.x + nodeSlotPos(i).dx"
|
|
128
|
+
:y="city.y + nodeSlotPos(i).dy"
|
|
129
|
+
font-size="10"
|
|
130
|
+
text-anchor="middle"
|
|
131
|
+
dominant-baseline="central"
|
|
132
|
+
fill="black"
|
|
133
|
+
:transform="
|
|
134
|
+
mapRotation
|
|
135
|
+
? `rotate(${-mapRotation}, ${city.x + nodeSlotPos(i).dx}, ${
|
|
136
|
+
city.y + nodeSlotPos(i).dy
|
|
137
|
+
})`
|
|
138
|
+
: undefined
|
|
139
|
+
"
|
|
140
|
+
>
|
|
141
|
+
{{ sc }}
|
|
142
|
+
</text>
|
|
143
|
+
</template>
|
|
144
|
+
</g>
|
|
145
|
+
</template>
|
|
146
|
+
|
|
75
147
|
<template v-for="city in cities">
|
|
76
148
|
<circle
|
|
149
|
+
v-if="city.connectionCost == null"
|
|
77
150
|
:key="city.name + '_circle2'"
|
|
78
151
|
:class="[{ canClick: canBuild(city) }]"
|
|
79
152
|
r="20"
|
|
@@ -135,6 +208,33 @@
|
|
|
135
208
|
/>
|
|
136
209
|
</template>
|
|
137
210
|
|
|
211
|
+
<!-- Bremen entry-cost number, on top so it stays readable over houses -->
|
|
212
|
+
<template v-for="city in cities">
|
|
213
|
+
<g v-if="city.connectionCost != null" :key="city.name + '_cc'">
|
|
214
|
+
<circle
|
|
215
|
+
:cx="city.x"
|
|
216
|
+
:cy="city.y + 15"
|
|
217
|
+
r="11"
|
|
218
|
+
fill="goldenrod"
|
|
219
|
+
stroke="darkgoldenrod"
|
|
220
|
+
stroke-width="2"
|
|
221
|
+
/>
|
|
222
|
+
<circle :cx="city.x" :cy="city.y + 15" r="7.5" fill="gray" stroke="darkgoldenrod" stroke-width="1" />
|
|
223
|
+
<text
|
|
224
|
+
:x="city.x"
|
|
225
|
+
:y="city.y + 15"
|
|
226
|
+
font-size="11"
|
|
227
|
+
font-weight="bold"
|
|
228
|
+
text-anchor="middle"
|
|
229
|
+
dominant-baseline="central"
|
|
230
|
+
fill="black"
|
|
231
|
+
:transform="mapRotation ? `rotate(${-mapRotation}, ${city.x}, ${city.y + 15})` : undefined"
|
|
232
|
+
>
|
|
233
|
+
{{ city.connectionCost }}
|
|
234
|
+
</text>
|
|
235
|
+
</g>
|
|
236
|
+
</template>
|
|
237
|
+
|
|
138
238
|
<template v-for="city in cities">
|
|
139
239
|
<!-- [10,15] city: X at bottom-right -->
|
|
140
240
|
<template v-if="city.slotCosts && city.slotCosts.length === 2 && city.slotCosts[0] === 10">
|
|
@@ -251,8 +351,16 @@ export default class Map extends Vue {
|
|
|
251
351
|
player.cities.forEach((cityPiece) => {
|
|
252
352
|
const city = gameState.map.cities.find((city) => city.name == cityPiece.name)!;
|
|
253
353
|
let offsetX, offsetY;
|
|
354
|
+
const isNodeWeighted = city.connectionCost != null;
|
|
254
355
|
const is1520 = city.slotCosts?.length === 2 && city.slotCosts[0] === 15;
|
|
255
|
-
if (
|
|
356
|
+
if (isNodeWeighted) {
|
|
357
|
+
// Bremen tiles: 8 top, 14 left, 20 right — matches the board layout.
|
|
358
|
+
// The House piece is anchored top-left (~14×16 after its scale), so
|
|
359
|
+
// offset by half its size to center it on the slot.
|
|
360
|
+
const slot = this.nodeSlotPos(cityPiece.position);
|
|
361
|
+
offsetX = slot.dx - 7;
|
|
362
|
+
offsetY = slot.dy - 8;
|
|
363
|
+
} else if (is1520) {
|
|
256
364
|
// [15,20] city: slot 0 (cost 15) → bottom-left, slot 1 (cost 20) → bottom-right
|
|
257
365
|
if (cityPiece.position == 0) {
|
|
258
366
|
offsetX = -15;
|
|
@@ -303,6 +411,13 @@ export default class Map extends Vue {
|
|
|
303
411
|
return city.y;
|
|
304
412
|
}
|
|
305
413
|
|
|
414
|
+
nodeSlotPos(i: number) {
|
|
415
|
+
// House slots laid out like the printed board: 0 = 8 (top), 1 = 14 (left), 2 = 20 (right).
|
|
416
|
+
if (i === 0) return { dx: 0, dy: -15 };
|
|
417
|
+
if (i === 1) return { dx: -15, dy: 0 };
|
|
418
|
+
return { dx: 15, dy: 0 };
|
|
419
|
+
}
|
|
420
|
+
|
|
306
421
|
canBuild(city: City) {
|
|
307
422
|
return !!this.buildableCities!.find((cityName) => cityName == city.name);
|
|
308
423
|
}
|
package/src/self-contained.ts
CHANGED
|
@@ -10,7 +10,7 @@ function launchSelfContained(selector = '#app') {
|
|
|
10
10
|
|
|
11
11
|
const emitter = launch(selector);
|
|
12
12
|
|
|
13
|
-
let gameState = setup(6, { map: '
|
|
13
|
+
let gameState = setup(6, { map: 'Bremen', variant: 'recharged', showMoney: true, randomizeMap: false }, '0');
|
|
14
14
|
|
|
15
15
|
// Dev coord-picker example (commented; uncomment + drop a board photo into
|
|
16
16
|
// viewer/public/ to author city coordinates for a new map). See the picker
|