@civ-clone/base-city-lifecycle 0.0.0-stage → 0.1.1
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/.gitattributes +2 -0
- package/.github/workflows/build-on-push.yml +39 -0
- package/.prettierrc +4 -0
- package/LICENSE +21 -0
- package/README.md +42 -2
- package/lib/assignWorkers.d.ts +114 -0
- package/lib/assignWorkers.js +184 -0
- package/lib/assignWorkers.js.map +1 -0
- package/lib/assignWorkers.ts +372 -0
- package/lib/canBeWorked.d.ts +28 -0
- package/lib/canBeWorked.js +27 -0
- package/lib/canBeWorked.js.map +1 -0
- package/lib/canBeWorked.ts +43 -0
- package/lib/captured.d.ts +12 -0
- package/lib/captured.js +30 -0
- package/lib/captured.js.map +1 -0
- package/lib/captured.ts +31 -0
- package/lib/claimName.d.ts +12 -0
- package/lib/claimName.js +9 -0
- package/lib/claimName.js.map +1 -0
- package/lib/claimName.ts +13 -0
- package/lib/created.d.ts +41 -0
- package/lib/created.js +52 -0
- package/lib/created.js.map +1 -0
- package/lib/created.ts +110 -0
- package/lib/destroyed.d.ts +23 -0
- package/lib/destroyed.js +29 -0
- package/lib/destroyed.js.map +1 -0
- package/lib/destroyed.ts +39 -0
- package/lib/events.d.ts +39 -0
- package/lib/events.js +33 -0
- package/lib/events.js.map +1 -0
- package/lib/events.ts +51 -0
- package/lib/famine.d.ts +41 -0
- package/lib/famine.js +44 -0
- package/lib/famine.js.map +1 -0
- package/lib/famine.ts +68 -0
- package/lib/foodStorage.d.ts +21 -0
- package/lib/foodStorage.js +27 -0
- package/lib/foodStorage.js.map +1 -0
- package/lib/foodStorage.ts +30 -0
- package/lib/occupiedTiles.d.ts +39 -0
- package/lib/occupiedTiles.js +50 -0
- package/lib/occupiedTiles.js.map +1 -0
- package/lib/occupiedTiles.ts +84 -0
- package/lib/playerActions.d.ts +72 -0
- package/lib/playerActions.js +68 -0
- package/lib/playerActions.js.map +1 -0
- package/lib/playerActions.ts +114 -0
- package/lib/processYield.d.ts +30 -0
- package/lib/processYield.js +54 -0
- package/lib/processYield.js.map +1 -0
- package/lib/processYield.ts +82 -0
- package/lib/unsupported.d.ts +6 -0
- package/lib/unsupported.js +9 -0
- package/lib/unsupported.js.map +1 -0
- package/lib/unsupported.ts +8 -0
- package/package.json +45 -4
- package/tests/base-city-lifecycle.test.ts +536 -0
- package/tests/r3b.test.ts +341 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
// Lifted from library-city 0.1.4 (`lib/assignWorkers.ts`), unchanged but for where the yields come from, so a game's
|
|
2
|
+
// rules can place a city's citizens without depending on library-city (civ-clone/web-renderer Civ2 M2a, R3b).
|
|
3
|
+
// library-city re-exports this in R3b.
|
|
4
|
+
import {
|
|
5
|
+
AvailableSpecialistRegistry,
|
|
6
|
+
instance as availableSpecialistRegistryInstance,
|
|
7
|
+
} from '@civ-clone/core-city/AvailableSpecialistRegistry';
|
|
8
|
+
import {
|
|
9
|
+
CityGrowthRegistry,
|
|
10
|
+
instance as cityGrowthRegistryInstance,
|
|
11
|
+
} from '@civ-clone/core-city-growth/CityGrowthRegistry';
|
|
12
|
+
import Food from '@civ-clone/base-terrain-yield-food/Food';
|
|
13
|
+
import Production from '@civ-clone/base-terrain-yield-production/Production';
|
|
14
|
+
import Trade from '@civ-clone/base-terrain-yield-trade/Trade';
|
|
15
|
+
import {
|
|
16
|
+
PlayerWorldRegistry,
|
|
17
|
+
instance as playerWorldRegistryInstance,
|
|
18
|
+
} from '@civ-clone/core-player-world/PlayerWorldRegistry';
|
|
19
|
+
import {
|
|
20
|
+
SpecialistRegistry,
|
|
21
|
+
instance as specialistRegistryInstance,
|
|
22
|
+
} from '@civ-clone/core-city/SpecialistRegistry';
|
|
23
|
+
import {
|
|
24
|
+
WorkedTileRegistry,
|
|
25
|
+
instance as workedTileRegistryInstance,
|
|
26
|
+
} from '@civ-clone/core-city/WorkedTileRegistry';
|
|
27
|
+
import City from '@civ-clone/core-city/City';
|
|
28
|
+
import Tile from '@civ-clone/core-world/Tile';
|
|
29
|
+
import Yield from '@civ-clone/core-yield/Yield';
|
|
30
|
+
import { reduceYield } from '@civ-clone/core-yield/lib/reduceYields';
|
|
31
|
+
import WorkedTile from '@civ-clone/core-city/WorkedTile';
|
|
32
|
+
import CityGrowth from '@civ-clone/core-city-growth/CityGrowth';
|
|
33
|
+
import Specialist from '@civ-clone/core-city/Specialist';
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* How many citizens `city` has placed: one per worked tile, the city centre included, and one per `Specialist`. A city
|
|
37
|
+
* of size `n` has `n + 1`.
|
|
38
|
+
*/
|
|
39
|
+
export const citizenCount = (
|
|
40
|
+
city: City,
|
|
41
|
+
workedTileRegistry: WorkedTileRegistry = workedTileRegistryInstance,
|
|
42
|
+
specialistRegistry: SpecialistRegistry = specialistRegistryInstance
|
|
43
|
+
): number =>
|
|
44
|
+
workedTileRegistry.getByCity(city).length +
|
|
45
|
+
specialistRegistry.getByCity(city).length;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Makes a citizen of `city` a `Specialist` of the first available kind (an Entertainer, in Civ1). Returns `null` when
|
|
49
|
+
* the ruleset offers no specialists.
|
|
50
|
+
*/
|
|
51
|
+
export const addSpecialist = (
|
|
52
|
+
city: City,
|
|
53
|
+
specialistRegistry: SpecialistRegistry = specialistRegistryInstance,
|
|
54
|
+
availableSpecialistRegistry: AvailableSpecialistRegistry = availableSpecialistRegistryInstance
|
|
55
|
+
): Specialist | null => {
|
|
56
|
+
const [SpecialistType] = availableSpecialistRegistry.entries();
|
|
57
|
+
|
|
58
|
+
if (!SpecialistType) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const specialist = new SpecialistType(city);
|
|
63
|
+
|
|
64
|
+
specialistRegistry.register(specialist);
|
|
65
|
+
|
|
66
|
+
return specialist;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Turns `specialist` into the next available kind, wrapping back to the first. Returns the `Specialist` that replaces
|
|
71
|
+
* it, or `specialist` itself when there is nothing to change it to.
|
|
72
|
+
*/
|
|
73
|
+
export const changeSpecialist = (
|
|
74
|
+
specialist: Specialist,
|
|
75
|
+
specialistRegistry: SpecialistRegistry = specialistRegistryInstance,
|
|
76
|
+
availableSpecialistRegistry: AvailableSpecialistRegistry = availableSpecialistRegistryInstance
|
|
77
|
+
): Specialist => {
|
|
78
|
+
const city = specialist.city(),
|
|
79
|
+
types = availableSpecialistRegistry.entries(),
|
|
80
|
+
NextType =
|
|
81
|
+
types[
|
|
82
|
+
(types.indexOf(specialist.constructor as typeof Specialist) + 1) %
|
|
83
|
+
types.length
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
if (!NextType || specialist instanceof NextType) {
|
|
87
|
+
return specialist;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const replacement = new NextType(city);
|
|
91
|
+
|
|
92
|
+
specialistRegistry.unregister(specialist);
|
|
93
|
+
specialistRegistry.register(replacement);
|
|
94
|
+
|
|
95
|
+
return replacement;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Puts one of `city`'s specialists back to work, preferring the first available kind (Entertainers), and returns
|
|
100
|
+
* whether there was one to remove.
|
|
101
|
+
*/
|
|
102
|
+
const removeSpecialist = (
|
|
103
|
+
city: City,
|
|
104
|
+
specialistRegistry: SpecialistRegistry,
|
|
105
|
+
availableSpecialistRegistry: AvailableSpecialistRegistry
|
|
106
|
+
): boolean => {
|
|
107
|
+
const specialists = specialistRegistry.getByCity(city),
|
|
108
|
+
[DefaultType] = availableSpecialistRegistry.entries(),
|
|
109
|
+
specialist =
|
|
110
|
+
specialists.find(
|
|
111
|
+
(specialist) => DefaultType && specialist instanceof DefaultType
|
|
112
|
+
) ?? specialists[specialists.length - 1];
|
|
113
|
+
|
|
114
|
+
if (!specialist) {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
specialistRegistry.unregister(specialist);
|
|
119
|
+
|
|
120
|
+
return true;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export const getHighestValueCityTiles = (city: City) =>
|
|
124
|
+
sortTiles(city.tiles().entries(), city);
|
|
125
|
+
|
|
126
|
+
export const sortTiles = (
|
|
127
|
+
tiles: Tile[],
|
|
128
|
+
city: City,
|
|
129
|
+
weights: [typeof Yield, number][] = [
|
|
130
|
+
[Food, 8],
|
|
131
|
+
[
|
|
132
|
+
Production,
|
|
133
|
+
3 *
|
|
134
|
+
(reduceYield(city.tilesWorked().yields(city.player()), Production) === 0
|
|
135
|
+
? 3
|
|
136
|
+
: 1),
|
|
137
|
+
],
|
|
138
|
+
[
|
|
139
|
+
Trade,
|
|
140
|
+
1 *
|
|
141
|
+
(reduceYield(city.tilesWorked().yields(city.player()), Trade) === 0
|
|
142
|
+
? 2
|
|
143
|
+
: 1),
|
|
144
|
+
],
|
|
145
|
+
]
|
|
146
|
+
): Tile[] =>
|
|
147
|
+
tiles.sort(
|
|
148
|
+
(a: Tile, b: Tile) =>
|
|
149
|
+
b.score(city.player(), weights) - a.score(city.player(), weights)
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
export const getHighestValueAvailableCityTiles = (
|
|
153
|
+
city: City,
|
|
154
|
+
playerWorldRegistry: PlayerWorldRegistry = playerWorldRegistryInstance,
|
|
155
|
+
workedTileRegistry: WorkedTileRegistry = workedTileRegistryInstance
|
|
156
|
+
) =>
|
|
157
|
+
getHighestValueCityTiles(city).filter(
|
|
158
|
+
(tile) =>
|
|
159
|
+
workedTileRegistry.tileCanBeWorkedBy(tile, city) &&
|
|
160
|
+
playerWorldRegistry.getByPlayer(city.player()).includes(tile)
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Rearranges the tiles `city` works from scratch. Its specialists stay as they are.
|
|
165
|
+
*/
|
|
166
|
+
export const reassignWorkers = (
|
|
167
|
+
city: City,
|
|
168
|
+
playerWorldRegistry: PlayerWorldRegistry = playerWorldRegistryInstance,
|
|
169
|
+
cityGrowthRegistry: CityGrowthRegistry = cityGrowthRegistryInstance,
|
|
170
|
+
workedTileRegistry: WorkedTileRegistry = workedTileRegistryInstance,
|
|
171
|
+
specialistRegistry: SpecialistRegistry = specialistRegistryInstance,
|
|
172
|
+
availableSpecialistRegistry: AvailableSpecialistRegistry = availableSpecialistRegistryInstance
|
|
173
|
+
) => {
|
|
174
|
+
workedTileRegistry
|
|
175
|
+
.getBy('city', city)
|
|
176
|
+
.forEach((workedTile: WorkedTile) =>
|
|
177
|
+
workedTileRegistry.unregister(workedTile)
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
workedTileRegistry.register(new WorkedTile(city.tile(), city));
|
|
181
|
+
|
|
182
|
+
assignWorkers(
|
|
183
|
+
city,
|
|
184
|
+
playerWorldRegistry,
|
|
185
|
+
cityGrowthRegistry,
|
|
186
|
+
workedTileRegistry,
|
|
187
|
+
specialistRegistry,
|
|
188
|
+
availableSpecialistRegistry
|
|
189
|
+
);
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Places each of `city`'s citizens that has no job on the best tile available, or makes them a specialist if there is
|
|
194
|
+
* no tile left to work.
|
|
195
|
+
*/
|
|
196
|
+
export const assignWorkers: (
|
|
197
|
+
city: City,
|
|
198
|
+
playerWorldRegistry?: PlayerWorldRegistry,
|
|
199
|
+
cityGrowthRegistry?: CityGrowthRegistry,
|
|
200
|
+
workedTileRegistry?: WorkedTileRegistry,
|
|
201
|
+
specialistRegistry?: SpecialistRegistry,
|
|
202
|
+
availableSpecialistRegistry?: AvailableSpecialistRegistry
|
|
203
|
+
) => void = (
|
|
204
|
+
city: City,
|
|
205
|
+
playerWorldRegistry: PlayerWorldRegistry = playerWorldRegistryInstance,
|
|
206
|
+
cityGrowthRegistry: CityGrowthRegistry = cityGrowthRegistryInstance,
|
|
207
|
+
workedTileRegistry: WorkedTileRegistry = workedTileRegistryInstance,
|
|
208
|
+
specialistRegistry: SpecialistRegistry = specialistRegistryInstance,
|
|
209
|
+
availableSpecialistRegistry: AvailableSpecialistRegistry = availableSpecialistRegistryInstance
|
|
210
|
+
): void => {
|
|
211
|
+
const cityGrowth = cityGrowthRegistry.getByCity(city),
|
|
212
|
+
placed = () =>
|
|
213
|
+
citizenCount(city, workedTileRegistry, specialistRegistry) >=
|
|
214
|
+
cityGrowth.size() + 1;
|
|
215
|
+
|
|
216
|
+
getHighestValueAvailableCityTiles(
|
|
217
|
+
city,
|
|
218
|
+
playerWorldRegistry,
|
|
219
|
+
workedTileRegistry
|
|
220
|
+
).some((tile) => {
|
|
221
|
+
if (placed()) {
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
workedTileRegistry.register(new WorkedTile(tile, city));
|
|
226
|
+
|
|
227
|
+
return false;
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
while (
|
|
231
|
+
!placed() &&
|
|
232
|
+
addSpecialist(city, specialistRegistry, availableSpecialistRegistry)
|
|
233
|
+
) {}
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Places one new citizen of `city` on the best tile available, or makes them a specialist if there is no tile left.
|
|
238
|
+
*/
|
|
239
|
+
export const assignWorker: (
|
|
240
|
+
city: City,
|
|
241
|
+
playerWorldRegistry?: PlayerWorldRegistry,
|
|
242
|
+
cityGrowthRegistry?: CityGrowthRegistry,
|
|
243
|
+
workedTileRegistry?: WorkedTileRegistry,
|
|
244
|
+
specialistRegistry?: SpecialistRegistry,
|
|
245
|
+
availableSpecialistRegistry?: AvailableSpecialistRegistry
|
|
246
|
+
) => void = (
|
|
247
|
+
city: City,
|
|
248
|
+
playerWorldRegistry: PlayerWorldRegistry = playerWorldRegistryInstance,
|
|
249
|
+
cityGrowthRegistry: CityGrowthRegistry = cityGrowthRegistryInstance,
|
|
250
|
+
workedTileRegistry: WorkedTileRegistry = workedTileRegistryInstance,
|
|
251
|
+
specialistRegistry: SpecialistRegistry = specialistRegistryInstance,
|
|
252
|
+
availableSpecialistRegistry: AvailableSpecialistRegistry = availableSpecialistRegistryInstance
|
|
253
|
+
): void => {
|
|
254
|
+
const [newTile] = getHighestValueAvailableCityTiles(
|
|
255
|
+
city,
|
|
256
|
+
playerWorldRegistry,
|
|
257
|
+
workedTileRegistry
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
if (!newTile) {
|
|
261
|
+
addSpecialist(city, specialistRegistry, availableSpecialistRegistry);
|
|
262
|
+
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
workedTileRegistry.register(new WorkedTile(newTile, city));
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
export type WorkedTileChange = 'removed' | 'added' | 'reassigned' | 'none';
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Changes whether `tile` is worked by `city`, as a player clicking it on the city map would.
|
|
273
|
+
*
|
|
274
|
+
* A tile the city works stops being worked, and its worker becomes a specialist. Any other tile is worked by a
|
|
275
|
+
* specialist, or by a citizen with no job, if the city has one and is allowed to work it. With every citizen already
|
|
276
|
+
* working a tile, the city's workers are reassigned instead. The city centre is always worked.
|
|
277
|
+
*/
|
|
278
|
+
export const changeWorkedTile: (
|
|
279
|
+
city: City,
|
|
280
|
+
tile: Tile,
|
|
281
|
+
playerWorldRegistry?: PlayerWorldRegistry,
|
|
282
|
+
cityGrowthRegistry?: CityGrowthRegistry,
|
|
283
|
+
workedTileRegistry?: WorkedTileRegistry,
|
|
284
|
+
specialistRegistry?: SpecialistRegistry,
|
|
285
|
+
availableSpecialistRegistry?: AvailableSpecialistRegistry
|
|
286
|
+
) => WorkedTileChange = (
|
|
287
|
+
city: City,
|
|
288
|
+
tile: Tile,
|
|
289
|
+
playerWorldRegistry: PlayerWorldRegistry = playerWorldRegistryInstance,
|
|
290
|
+
cityGrowthRegistry: CityGrowthRegistry = cityGrowthRegistryInstance,
|
|
291
|
+
workedTileRegistry: WorkedTileRegistry = workedTileRegistryInstance,
|
|
292
|
+
specialistRegistry: SpecialistRegistry = specialistRegistryInstance,
|
|
293
|
+
availableSpecialistRegistry: AvailableSpecialistRegistry = availableSpecialistRegistryInstance
|
|
294
|
+
): WorkedTileChange => {
|
|
295
|
+
if (tile === city.tile() || !city.tiles().includes(tile)) {
|
|
296
|
+
return 'none';
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (workedTileRegistry.getByTile(tile)?.city() === city) {
|
|
300
|
+
workedTileRegistry.unregisterByTile(tile);
|
|
301
|
+
|
|
302
|
+
addSpecialist(city, specialistRegistry, availableSpecialistRegistry);
|
|
303
|
+
|
|
304
|
+
return 'removed';
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const size = cityGrowthRegistry.getByCity(city).size();
|
|
308
|
+
|
|
309
|
+
if (workedTileRegistry.getByCity(city).length >= size + 1) {
|
|
310
|
+
reassignWorkers(
|
|
311
|
+
city,
|
|
312
|
+
playerWorldRegistry,
|
|
313
|
+
cityGrowthRegistry,
|
|
314
|
+
workedTileRegistry,
|
|
315
|
+
specialistRegistry,
|
|
316
|
+
availableSpecialistRegistry
|
|
317
|
+
);
|
|
318
|
+
|
|
319
|
+
return 'reassigned';
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (
|
|
323
|
+
!workedTileRegistry.tileCanBeWorkedBy(tile, city) ||
|
|
324
|
+
!playerWorldRegistry.getByPlayer(city.player()).includes(tile)
|
|
325
|
+
) {
|
|
326
|
+
return 'none';
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (citizenCount(city, workedTileRegistry, specialistRegistry) >= size + 1) {
|
|
330
|
+
removeSpecialist(city, specialistRegistry, availableSpecialistRegistry);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
workedTileRegistry.register(new WorkedTile(tile, city));
|
|
334
|
+
|
|
335
|
+
return 'added';
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Takes jobs away from `city`'s citizens until it has no more than its size allows: specialists first, then the
|
|
340
|
+
* workers on the least valuable tiles.
|
|
341
|
+
*/
|
|
342
|
+
export const releaseCitizens = (
|
|
343
|
+
city: City,
|
|
344
|
+
cityGrowth: CityGrowth,
|
|
345
|
+
workedTileRegistry: WorkedTileRegistry = workedTileRegistryInstance,
|
|
346
|
+
specialistRegistry: SpecialistRegistry = specialistRegistryInstance
|
|
347
|
+
): void => {
|
|
348
|
+
const specialists = specialistRegistry.getByCity(city);
|
|
349
|
+
|
|
350
|
+
while (
|
|
351
|
+
specialists.length > 0 &&
|
|
352
|
+
citizenCount(city, workedTileRegistry, specialistRegistry) >
|
|
353
|
+
cityGrowth.size() + 1
|
|
354
|
+
) {
|
|
355
|
+
specialistRegistry.unregister(specialists.pop()!);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
reduceWorkers(city, cityGrowth).forEach((tile: Tile): void =>
|
|
359
|
+
workedTileRegistry.unregisterByTile(tile)
|
|
360
|
+
);
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
export const reduceWorkers = (city: City, cityGrowth: CityGrowth): Tile[] =>
|
|
364
|
+
sortTiles(
|
|
365
|
+
city
|
|
366
|
+
.tilesWorked()
|
|
367
|
+
.entries()
|
|
368
|
+
.filter((tile: Tile) => tile !== city.tile()),
|
|
369
|
+
city
|
|
370
|
+
).slice(cityGrowth.size());
|
|
371
|
+
|
|
372
|
+
export default assignWorkers;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import City from '@civ-clone/core-city/City';
|
|
2
|
+
import { CityRegistry } from '@civ-clone/core-city/CityRegistry';
|
|
3
|
+
import Tile from '@civ-clone/core-world/Tile';
|
|
4
|
+
import { UnitRegistry } from '@civ-clone/core-unit/UnitRegistry';
|
|
5
|
+
import { WorkedTileRegistry } from '@civ-clone/core-city/WorkedTileRegistry';
|
|
6
|
+
/**
|
|
7
|
+
* Whether no city works `tile` yet.
|
|
8
|
+
*/
|
|
9
|
+
export declare const isNotWorked: (
|
|
10
|
+
tile: Tile,
|
|
11
|
+
workedTileRegistry: WorkedTileRegistry
|
|
12
|
+
) => boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Whether no other player's unit stands on `tile`.
|
|
15
|
+
*/
|
|
16
|
+
export declare const isNotOccupiedByEnemy: (
|
|
17
|
+
tile: Tile,
|
|
18
|
+
city: City,
|
|
19
|
+
unitRegistry: UnitRegistry
|
|
20
|
+
) => boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Whether `tile` is not the centre of a city other than `city`.
|
|
23
|
+
*/
|
|
24
|
+
export declare const isNotAnotherCity: (
|
|
25
|
+
tile: Tile,
|
|
26
|
+
city: City,
|
|
27
|
+
cityRegistry: CityRegistry
|
|
28
|
+
) => boolean;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isNotAnotherCity = exports.isNotOccupiedByEnemy = exports.isNotWorked = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Whether no city works `tile` yet.
|
|
6
|
+
*/
|
|
7
|
+
const isNotWorked = (tile, workedTileRegistry) => !workedTileRegistry.tileIsWorked(tile);
|
|
8
|
+
exports.isNotWorked = isNotWorked;
|
|
9
|
+
/**
|
|
10
|
+
* Whether no other player's unit stands on `tile`.
|
|
11
|
+
*/
|
|
12
|
+
const isNotOccupiedByEnemy = (tile, city, unitRegistry) => !unitRegistry
|
|
13
|
+
.getByTile(tile)
|
|
14
|
+
.some((unit) => unit.player() !== city.player());
|
|
15
|
+
exports.isNotOccupiedByEnemy = isNotOccupiedByEnemy;
|
|
16
|
+
/**
|
|
17
|
+
* Whether `tile` is not the centre of a city other than `city`.
|
|
18
|
+
*/
|
|
19
|
+
const isNotAnotherCity = (tile, city, cityRegistry) => {
|
|
20
|
+
const otherTileCity = cityRegistry.getByTile(tile);
|
|
21
|
+
if (otherTileCity === null) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
return otherTileCity === city;
|
|
25
|
+
};
|
|
26
|
+
exports.isNotAnotherCity = isNotAnotherCity;
|
|
27
|
+
//# sourceMappingURL=canBeWorked.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canBeWorked.js","sourceRoot":"","sources":["canBeWorked.ts"],"names":[],"mappings":";;;AAOA;;GAEG;AACI,MAAM,WAAW,GAAG,CACzB,IAAU,EACV,kBAAsC,EAC7B,EAAE,CAAC,CAAC,kBAAkB,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;AAHxC,QAAA,WAAW,eAG6B;AAErD;;GAEG;AACI,MAAM,oBAAoB,GAAG,CAClC,IAAU,EACV,IAAU,EACV,YAA0B,EACjB,EAAE,CACX,CAAC,YAAY;KACV,SAAS,CAAC,IAAI,CAAC;KACf,IAAI,CAAC,CAAC,IAAU,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;AAP9C,QAAA,oBAAoB,wBAO0B;AAE3D;;GAEG;AACI,MAAM,gBAAgB,GAAG,CAC9B,IAAU,EACV,IAAU,EACV,YAA0B,EACjB,EAAE;IACX,MAAM,aAAa,GAAG,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAEnD,IAAI,aAAa,KAAK,IAAI,EAAE;QAC1B,OAAO,IAAI,CAAC;KACb;IAED,OAAO,aAAa,KAAK,IAAI,CAAC;AAChC,CAAC,CAAC;AAZW,QAAA,gBAAgB,oBAY3B"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import City from '@civ-clone/core-city/City';
|
|
2
|
+
import { CityRegistry } from '@civ-clone/core-city/CityRegistry';
|
|
3
|
+
import Tile from '@civ-clone/core-world/Tile';
|
|
4
|
+
import Unit from '@civ-clone/core-unit/Unit';
|
|
5
|
+
import { UnitRegistry } from '@civ-clone/core-unit/UnitRegistry';
|
|
6
|
+
import { WorkedTileRegistry } from '@civ-clone/core-city/WorkedTileRegistry';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Whether no city works `tile` yet.
|
|
10
|
+
*/
|
|
11
|
+
export const isNotWorked = (
|
|
12
|
+
tile: Tile,
|
|
13
|
+
workedTileRegistry: WorkedTileRegistry
|
|
14
|
+
): boolean => !workedTileRegistry.tileIsWorked(tile);
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Whether no other player's unit stands on `tile`.
|
|
18
|
+
*/
|
|
19
|
+
export const isNotOccupiedByEnemy = (
|
|
20
|
+
tile: Tile,
|
|
21
|
+
city: City,
|
|
22
|
+
unitRegistry: UnitRegistry
|
|
23
|
+
): boolean =>
|
|
24
|
+
!unitRegistry
|
|
25
|
+
.getByTile(tile)
|
|
26
|
+
.some((unit: Unit) => unit.player() !== city.player());
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Whether `tile` is not the centre of a city other than `city`.
|
|
30
|
+
*/
|
|
31
|
+
export const isNotAnotherCity = (
|
|
32
|
+
tile: Tile,
|
|
33
|
+
city: City,
|
|
34
|
+
cityRegistry: CityRegistry
|
|
35
|
+
): boolean => {
|
|
36
|
+
const otherTileCity = cityRegistry.getByTile(tile);
|
|
37
|
+
|
|
38
|
+
if (otherTileCity === null) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return otherTileCity === city;
|
|
43
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import CityBuild from '@civ-clone/core-city-build/CityBuild';
|
|
2
|
+
/**
|
|
3
|
+
* Clears what a captured city was building, so its new owner chooses: the item was its previous owner's choice, at
|
|
4
|
+
* its previous owner's price (civ-clone/web-renderer#670, #500). The city is asked for as a captured city's even if
|
|
5
|
+
* its previous owner had chosen nothing (civ-clone/web-renderer#716).
|
|
6
|
+
*/
|
|
7
|
+
export declare const clearCapturedBuild: (cityBuild: CityBuild) => void;
|
|
8
|
+
/**
|
|
9
|
+
* A captured city keeps what it was building, at its new owner's price, without its previous owner's queue
|
|
10
|
+
* (civ-clone/web-renderer#670). Asked for as a captured city's if nothing was being built (civ-clone/web-renderer#716).
|
|
11
|
+
*/
|
|
12
|
+
export declare const keepCapturedBuild: (cityBuild: CityBuild) => void;
|
package/lib/captured.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.keepCapturedBuild = exports.clearCapturedBuild = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Clears what a captured city was building, so its new owner chooses: the item was its previous owner's choice, at
|
|
6
|
+
* its previous owner's price (civ-clone/web-renderer#670, #500). The city is asked for as a captured city's even if
|
|
7
|
+
* its previous owner had chosen nothing (civ-clone/web-renderer#716).
|
|
8
|
+
*/
|
|
9
|
+
const clearCapturedBuild = (cityBuild) => {
|
|
10
|
+
if (cityBuild.building() === null) {
|
|
11
|
+
cityBuild.setCleared('captured');
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
cityBuild.cancel('captured');
|
|
15
|
+
};
|
|
16
|
+
exports.clearCapturedBuild = clearCapturedBuild;
|
|
17
|
+
/**
|
|
18
|
+
* A captured city keeps what it was building, at its new owner's price, without its previous owner's queue
|
|
19
|
+
* (civ-clone/web-renderer#670). Asked for as a captured city's if nothing was being built (civ-clone/web-renderer#716).
|
|
20
|
+
*/
|
|
21
|
+
const keepCapturedBuild = (cityBuild) => {
|
|
22
|
+
if (cityBuild.building() === null) {
|
|
23
|
+
cityBuild.setCleared('captured');
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
cityBuild.clearQueue();
|
|
27
|
+
cityBuild.reprice();
|
|
28
|
+
};
|
|
29
|
+
exports.keepCapturedBuild = keepCapturedBuild;
|
|
30
|
+
//# sourceMappingURL=captured.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"captured.js","sourceRoot":"","sources":["captured.ts"],"names":[],"mappings":";;;AAEA;;;;GAIG;AACI,MAAM,kBAAkB,GAAG,CAAC,SAAoB,EAAQ,EAAE;IAC/D,IAAI,SAAS,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;QACjC,SAAS,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QAEjC,OAAO;KACR;IAED,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;AAC/B,CAAC,CAAC;AARW,QAAA,kBAAkB,sBAQ7B;AAEF;;;GAGG;AACI,MAAM,iBAAiB,GAAG,CAAC,SAAoB,EAAQ,EAAE;IAC9D,IAAI,SAAS,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;QACjC,SAAS,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QAEjC,OAAO;KACR;IAED,SAAS,CAAC,UAAU,EAAE,CAAC;IACvB,SAAS,CAAC,OAAO,EAAE,CAAC;AACtB,CAAC,CAAC;AATW,QAAA,iBAAiB,qBAS5B"}
|
package/lib/captured.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import CityBuild from '@civ-clone/core-city-build/CityBuild';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Clears what a captured city was building, so its new owner chooses: the item was its previous owner's choice, at
|
|
5
|
+
* its previous owner's price (civ-clone/web-renderer#670, #500). The city is asked for as a captured city's even if
|
|
6
|
+
* its previous owner had chosen nothing (civ-clone/web-renderer#716).
|
|
7
|
+
*/
|
|
8
|
+
export const clearCapturedBuild = (cityBuild: CityBuild): void => {
|
|
9
|
+
if (cityBuild.building() === null) {
|
|
10
|
+
cityBuild.setCleared('captured');
|
|
11
|
+
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
cityBuild.cancel('captured');
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A captured city keeps what it was building, at its new owner's price, without its previous owner's queue
|
|
20
|
+
* (civ-clone/web-renderer#670). Asked for as a captured city's if nothing was being built (civ-clone/web-renderer#716).
|
|
21
|
+
*/
|
|
22
|
+
export const keepCapturedBuild = (cityBuild: CityBuild): void => {
|
|
23
|
+
if (cityBuild.building() === null) {
|
|
24
|
+
cityBuild.setCleared('captured');
|
|
25
|
+
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
cityBuild.clearQueue();
|
|
30
|
+
cityBuild.reprice();
|
|
31
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import City from '@civ-clone/core-city/City';
|
|
2
|
+
/**
|
|
3
|
+
* What keeps the names cities have been given: a game's `cityNames` (core-civilization's `CityNameRegistry`), of which
|
|
4
|
+
* only this much is asked.
|
|
5
|
+
*/
|
|
6
|
+
export type CityNames = {
|
|
7
|
+
claim(name: string): void;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* `city`'s name is claimed, so that no city founded later is given it too.
|
|
11
|
+
*/
|
|
12
|
+
export declare const claimName: (city: City, cityNames: CityNames) => void;
|
package/lib/claimName.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.claimName = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* `city`'s name is claimed, so that no city founded later is given it too.
|
|
6
|
+
*/
|
|
7
|
+
const claimName = (city, cityNames) => cityNames.claim(city.name());
|
|
8
|
+
exports.claimName = claimName;
|
|
9
|
+
//# sourceMappingURL=claimName.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claimName.js","sourceRoot":"","sources":["claimName.ts"],"names":[],"mappings":";;;AAQA;;GAEG;AACI,MAAM,SAAS,GAAG,CAAC,IAAU,EAAE,SAAoB,EAAQ,EAAE,CAClE,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;AADlB,QAAA,SAAS,aACS"}
|
package/lib/claimName.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import City from '@civ-clone/core-city/City';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* What keeps the names cities have been given: a game's `cityNames` (core-civilization's `CityNameRegistry`), of which
|
|
5
|
+
* only this much is asked.
|
|
6
|
+
*/
|
|
7
|
+
export type CityNames = { claim(name: string): void };
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* `city`'s name is claimed, so that no city founded later is given it too.
|
|
11
|
+
*/
|
|
12
|
+
export const claimName = (city: City, cityNames: CityNames): void =>
|
|
13
|
+
cityNames.claim(city.name());
|
package/lib/created.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { AvailableSpecialistRegistry } from '@civ-clone/core-city/AvailableSpecialistRegistry';
|
|
2
|
+
import { CityGrowthRegistry } from '@civ-clone/core-city-growth/CityGrowthRegistry';
|
|
3
|
+
import { PlayerWorldRegistry } from '@civ-clone/core-player-world/PlayerWorldRegistry';
|
|
4
|
+
import { RuleRegistry } from '@civ-clone/core-rule/RuleRegistry';
|
|
5
|
+
import { SpecialistRegistry } from '@civ-clone/core-city/SpecialistRegistry';
|
|
6
|
+
import { WorkedTileRegistry } from '@civ-clone/core-city/WorkedTileRegistry';
|
|
7
|
+
import { AvailableCityBuildItemsRegistry } from '@civ-clone/core-city-build/AvailableCityBuildItemsRegistry';
|
|
8
|
+
import City from '@civ-clone/core-city/City';
|
|
9
|
+
import CityBuild from '@civ-clone/core-city-build/CityBuild';
|
|
10
|
+
import { CityBuildRegistry } from '@civ-clone/core-city-build/CityBuildRegistry';
|
|
11
|
+
import CityGrowth from '@civ-clone/core-city-growth/CityGrowth';
|
|
12
|
+
/**
|
|
13
|
+
* Gives a new city its build, whose first item is asked for as a new city's (civ-clone/web-renderer#716).
|
|
14
|
+
*/
|
|
15
|
+
export declare const registerCityBuild: (
|
|
16
|
+
city: City,
|
|
17
|
+
cityBuildRegistry: CityBuildRegistry,
|
|
18
|
+
availableBuildItemsRegistry: AvailableCityBuildItemsRegistry,
|
|
19
|
+
ruleRegistry?: RuleRegistry
|
|
20
|
+
) => CityBuild;
|
|
21
|
+
/**
|
|
22
|
+
* Gives a new city its growth: its size and food store.
|
|
23
|
+
*/
|
|
24
|
+
export declare const registerCityGrowth: (
|
|
25
|
+
city: City,
|
|
26
|
+
cityGrowthRegistry?: CityGrowthRegistry,
|
|
27
|
+
ruleRegistry?: RuleRegistry
|
|
28
|
+
) => CityGrowth;
|
|
29
|
+
/**
|
|
30
|
+
* A new city works its own centre, taking it from any city that worked it, which its `TileReassigned` rules then let
|
|
31
|
+
* choose another, and puts its citizens to work.
|
|
32
|
+
*/
|
|
33
|
+
export declare const workCityTile: (
|
|
34
|
+
city: City,
|
|
35
|
+
ruleRegistry?: RuleRegistry,
|
|
36
|
+
playerWorldRegistry?: PlayerWorldRegistry,
|
|
37
|
+
cityGrowthRegistry?: CityGrowthRegistry,
|
|
38
|
+
workedTileRegistry?: WorkedTileRegistry,
|
|
39
|
+
specialistRegistry?: SpecialistRegistry,
|
|
40
|
+
availableSpecialistRegistry?: AvailableSpecialistRegistry
|
|
41
|
+
) => void;
|