@civ-clone/library-city 0.1.3 → 0.1.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.
- package/Specialists/Entertainer.d.ts +3 -0
- package/Specialists/Entertainer.js +9 -0
- package/Specialists/Entertainer.js.map +1 -0
- package/Specialists/Entertainer.ts +5 -0
- package/Specialists/Scientist.d.ts +3 -0
- package/Specialists/Scientist.js +9 -0
- package/Specialists/Scientist.js.map +1 -0
- package/Specialists/Scientist.ts +5 -0
- package/Specialists/TaxCollector.d.ts +3 -0
- package/Specialists/TaxCollector.js +9 -0
- package/Specialists/TaxCollector.js.map +1 -0
- package/Specialists/TaxCollector.ts +5 -0
- package/Specialists.d.ts +3 -0
- package/Specialists.js +10 -0
- package/Specialists.js.map +1 -0
- package/Specialists.ts +3 -0
- package/lib/assignWorkers.d.ts +65 -7
- package/lib/assignWorkers.js +98 -14
- package/lib/assignWorkers.js.map +1 -1
- package/lib/assignWorkers.ts +183 -18
- package/package.json +2 -1
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Entertainer = void 0;
|
|
4
|
+
const Specialist_1 = require("@civ-clone/core-city/Specialist");
|
|
5
|
+
class Entertainer extends Specialist_1.default {
|
|
6
|
+
}
|
|
7
|
+
exports.Entertainer = Entertainer;
|
|
8
|
+
exports.default = Entertainer;
|
|
9
|
+
//# sourceMappingURL=Entertainer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Entertainer.js","sourceRoot":"","sources":["Entertainer.ts"],"names":[],"mappings":";;;AAAA,gEAAyD;AAEzD,MAAa,WAAY,SAAQ,oBAAU;CAAG;AAA9C,kCAA8C;AAE9C,kBAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Scientist = void 0;
|
|
4
|
+
const Specialist_1 = require("@civ-clone/core-city/Specialist");
|
|
5
|
+
class Scientist extends Specialist_1.default {
|
|
6
|
+
}
|
|
7
|
+
exports.Scientist = Scientist;
|
|
8
|
+
exports.default = Scientist;
|
|
9
|
+
//# sourceMappingURL=Scientist.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Scientist.js","sourceRoot":"","sources":["Scientist.ts"],"names":[],"mappings":";;;AAAA,gEAAyD;AAEzD,MAAa,SAAU,SAAQ,oBAAU;CAAG;AAA5C,8BAA4C;AAE5C,kBAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TaxCollector = void 0;
|
|
4
|
+
const Specialist_1 = require("@civ-clone/core-city/Specialist");
|
|
5
|
+
class TaxCollector extends Specialist_1.default {
|
|
6
|
+
}
|
|
7
|
+
exports.TaxCollector = TaxCollector;
|
|
8
|
+
exports.default = TaxCollector;
|
|
9
|
+
//# sourceMappingURL=TaxCollector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TaxCollector.js","sourceRoot":"","sources":["TaxCollector.ts"],"names":[],"mappings":";;;AAAA,gEAAyD;AAEzD,MAAa,YAAa,SAAQ,oBAAU;CAAG;AAA/C,oCAA+C;AAE/C,kBAAe,YAAY,CAAC"}
|
package/Specialists.d.ts
ADDED
package/Specialists.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Scientist = exports.TaxCollector = exports.Entertainer = void 0;
|
|
4
|
+
var Entertainer_1 = require("./Specialists/Entertainer");
|
|
5
|
+
Object.defineProperty(exports, "Entertainer", { enumerable: true, get: function () { return Entertainer_1.Entertainer; } });
|
|
6
|
+
var TaxCollector_1 = require("./Specialists/TaxCollector");
|
|
7
|
+
Object.defineProperty(exports, "TaxCollector", { enumerable: true, get: function () { return TaxCollector_1.TaxCollector; } });
|
|
8
|
+
var Scientist_1 = require("./Specialists/Scientist");
|
|
9
|
+
Object.defineProperty(exports, "Scientist", { enumerable: true, get: function () { return Scientist_1.Scientist; } });
|
|
10
|
+
//# sourceMappingURL=Specialists.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Specialists.js","sourceRoot":"","sources":["Specialists.ts"],"names":[],"mappings":";;;AAAA,yDAAwD;AAA/C,0GAAA,WAAW,OAAA;AACpB,2DAA0D;AAAjD,4GAAA,YAAY,OAAA;AACrB,qDAAoD;AAA3C,sGAAA,SAAS,OAAA"}
|
package/Specialists.ts
ADDED
package/lib/assignWorkers.d.ts
CHANGED
|
@@ -1,10 +1,40 @@
|
|
|
1
|
+
import { AvailableSpecialistRegistry } from '@civ-clone/core-city/AvailableSpecialistRegistry';
|
|
1
2
|
import { CityGrowthRegistry } from '@civ-clone/core-city-growth/CityGrowthRegistry';
|
|
2
3
|
import { PlayerWorldRegistry } from '@civ-clone/core-player-world/PlayerWorldRegistry';
|
|
4
|
+
import { SpecialistRegistry } from '@civ-clone/core-city/SpecialistRegistry';
|
|
3
5
|
import { WorkedTileRegistry } from '@civ-clone/core-city/WorkedTileRegistry';
|
|
4
6
|
import City from '@civ-clone/core-city/City';
|
|
5
7
|
import Tile from '@civ-clone/core-world/Tile';
|
|
6
8
|
import Yield from '@civ-clone/core-yield/Yield';
|
|
7
9
|
import CityGrowth from '@civ-clone/core-city-growth/CityGrowth';
|
|
10
|
+
import Specialist from '@civ-clone/core-city/Specialist';
|
|
11
|
+
/**
|
|
12
|
+
* How many citizens `city` has placed: one per worked tile, the city centre included, and one per `Specialist`. A city
|
|
13
|
+
* of size `n` has `n + 1`.
|
|
14
|
+
*/
|
|
15
|
+
export declare const citizenCount: (
|
|
16
|
+
city: City,
|
|
17
|
+
workedTileRegistry?: WorkedTileRegistry,
|
|
18
|
+
specialistRegistry?: SpecialistRegistry
|
|
19
|
+
) => number;
|
|
20
|
+
/**
|
|
21
|
+
* Makes a citizen of `city` a `Specialist` of the first available kind (an Entertainer, in Civ1). Returns `null` when
|
|
22
|
+
* the ruleset offers no specialists.
|
|
23
|
+
*/
|
|
24
|
+
export declare const addSpecialist: (
|
|
25
|
+
city: City,
|
|
26
|
+
specialistRegistry?: SpecialistRegistry,
|
|
27
|
+
availableSpecialistRegistry?: AvailableSpecialistRegistry
|
|
28
|
+
) => Specialist | null;
|
|
29
|
+
/**
|
|
30
|
+
* Turns `specialist` into the next available kind, wrapping back to the first. Returns the `Specialist` that replaces
|
|
31
|
+
* it, or `specialist` itself when there is nothing to change it to.
|
|
32
|
+
*/
|
|
33
|
+
export declare const changeSpecialist: (
|
|
34
|
+
specialist: Specialist,
|
|
35
|
+
specialistRegistry?: SpecialistRegistry,
|
|
36
|
+
availableSpecialistRegistry?: AvailableSpecialistRegistry
|
|
37
|
+
) => Specialist;
|
|
8
38
|
export declare const getHighestValueCityTiles: (city: City) => Tile[];
|
|
9
39
|
export declare const sortTiles: (
|
|
10
40
|
tiles: Tile[],
|
|
@@ -16,39 +46,67 @@ export declare const getHighestValueAvailableCityTiles: (
|
|
|
16
46
|
playerWorldRegistry?: PlayerWorldRegistry,
|
|
17
47
|
workedTileRegistry?: WorkedTileRegistry
|
|
18
48
|
) => Tile[];
|
|
49
|
+
/**
|
|
50
|
+
* Rearranges the tiles `city` works from scratch. Its specialists stay as they are.
|
|
51
|
+
*/
|
|
19
52
|
export declare const reassignWorkers: (
|
|
20
53
|
city: City,
|
|
21
54
|
playerWorldRegistry?: PlayerWorldRegistry,
|
|
22
55
|
cityGrowthRegistry?: CityGrowthRegistry,
|
|
23
|
-
workedTileRegistry?: WorkedTileRegistry
|
|
56
|
+
workedTileRegistry?: WorkedTileRegistry,
|
|
57
|
+
specialistRegistry?: SpecialistRegistry,
|
|
58
|
+
availableSpecialistRegistry?: AvailableSpecialistRegistry
|
|
24
59
|
) => void;
|
|
60
|
+
/**
|
|
61
|
+
* Places each of `city`'s citizens that has no job on the best tile available, or makes them a specialist if there is
|
|
62
|
+
* no tile left to work.
|
|
63
|
+
*/
|
|
25
64
|
export declare const assignWorkers: (
|
|
26
65
|
city: City,
|
|
27
66
|
playerWorldRegistry?: PlayerWorldRegistry,
|
|
28
67
|
cityGrowthRegistry?: CityGrowthRegistry,
|
|
29
|
-
workedTileRegistry?: WorkedTileRegistry
|
|
68
|
+
workedTileRegistry?: WorkedTileRegistry,
|
|
69
|
+
specialistRegistry?: SpecialistRegistry,
|
|
70
|
+
availableSpecialistRegistry?: AvailableSpecialistRegistry
|
|
30
71
|
) => void;
|
|
72
|
+
/**
|
|
73
|
+
* Places one new citizen of `city` on the best tile available, or makes them a specialist if there is no tile left.
|
|
74
|
+
*/
|
|
31
75
|
export declare const assignWorker: (
|
|
32
76
|
city: City,
|
|
33
77
|
playerWorldRegistry?: PlayerWorldRegistry,
|
|
34
78
|
cityGrowthRegistry?: CityGrowthRegistry,
|
|
35
|
-
workedTileRegistry?: WorkedTileRegistry
|
|
79
|
+
workedTileRegistry?: WorkedTileRegistry,
|
|
80
|
+
specialistRegistry?: SpecialistRegistry,
|
|
81
|
+
availableSpecialistRegistry?: AvailableSpecialistRegistry
|
|
36
82
|
) => void;
|
|
37
83
|
export type WorkedTileChange = 'removed' | 'added' | 'reassigned' | 'none';
|
|
38
84
|
/**
|
|
39
85
|
* Changes whether `tile` is worked by `city`, as a player clicking it on the city map would.
|
|
40
86
|
*
|
|
41
|
-
* A tile the city works stops being worked. Any other tile is worked by a
|
|
42
|
-
*
|
|
43
|
-
* always worked.
|
|
87
|
+
* A tile the city works stops being worked, and its worker becomes a specialist. Any other tile is worked by a
|
|
88
|
+
* specialist, or by a citizen with no job, if the city has one and is allowed to work it. With every citizen already
|
|
89
|
+
* working a tile, the city's workers are reassigned instead. The city centre is always worked.
|
|
44
90
|
*/
|
|
45
91
|
export declare const changeWorkedTile: (
|
|
46
92
|
city: City,
|
|
47
93
|
tile: Tile,
|
|
48
94
|
playerWorldRegistry?: PlayerWorldRegistry,
|
|
49
95
|
cityGrowthRegistry?: CityGrowthRegistry,
|
|
50
|
-
workedTileRegistry?: WorkedTileRegistry
|
|
96
|
+
workedTileRegistry?: WorkedTileRegistry,
|
|
97
|
+
specialistRegistry?: SpecialistRegistry,
|
|
98
|
+
availableSpecialistRegistry?: AvailableSpecialistRegistry
|
|
51
99
|
) => WorkedTileChange;
|
|
100
|
+
/**
|
|
101
|
+
* Takes jobs away from `city`'s citizens until it has no more than its size allows: specialists first, then the
|
|
102
|
+
* workers on the least valuable tiles.
|
|
103
|
+
*/
|
|
104
|
+
export declare const releaseCitizens: (
|
|
105
|
+
city: City,
|
|
106
|
+
cityGrowth: CityGrowth,
|
|
107
|
+
workedTileRegistry?: WorkedTileRegistry,
|
|
108
|
+
specialistRegistry?: SpecialistRegistry
|
|
109
|
+
) => void;
|
|
52
110
|
export declare const reduceWorkers: (
|
|
53
111
|
city: City,
|
|
54
112
|
cityGrowth: CityGrowth
|
package/lib/assignWorkers.js
CHANGED
|
@@ -1,12 +1,64 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.reduceWorkers = exports.changeWorkedTile = exports.assignWorker = exports.assignWorkers = exports.reassignWorkers = exports.getHighestValueAvailableCityTiles = exports.sortTiles = exports.getHighestValueCityTiles = void 0;
|
|
3
|
+
exports.reduceWorkers = exports.releaseCitizens = exports.changeWorkedTile = exports.assignWorker = exports.assignWorkers = exports.reassignWorkers = exports.getHighestValueAvailableCityTiles = exports.sortTiles = exports.getHighestValueCityTiles = exports.changeSpecialist = exports.addSpecialist = exports.citizenCount = void 0;
|
|
4
|
+
const AvailableSpecialistRegistry_1 = require("@civ-clone/core-city/AvailableSpecialistRegistry");
|
|
4
5
|
const CityGrowthRegistry_1 = require("@civ-clone/core-city-growth/CityGrowthRegistry");
|
|
5
6
|
const Yields_1 = require("../Yields");
|
|
6
7
|
const PlayerWorldRegistry_1 = require("@civ-clone/core-player-world/PlayerWorldRegistry");
|
|
8
|
+
const SpecialistRegistry_1 = require("@civ-clone/core-city/SpecialistRegistry");
|
|
7
9
|
const WorkedTileRegistry_1 = require("@civ-clone/core-city/WorkedTileRegistry");
|
|
8
10
|
const reduceYields_1 = require("@civ-clone/core-yield/lib/reduceYields");
|
|
9
11
|
const WorkedTile_1 = require("@civ-clone/core-city/WorkedTile");
|
|
12
|
+
/**
|
|
13
|
+
* How many citizens `city` has placed: one per worked tile, the city centre included, and one per `Specialist`. A city
|
|
14
|
+
* of size `n` has `n + 1`.
|
|
15
|
+
*/
|
|
16
|
+
const citizenCount = (city, workedTileRegistry = WorkedTileRegistry_1.instance, specialistRegistry = SpecialistRegistry_1.instance) => workedTileRegistry.getByCity(city).length +
|
|
17
|
+
specialistRegistry.getByCity(city).length;
|
|
18
|
+
exports.citizenCount = citizenCount;
|
|
19
|
+
/**
|
|
20
|
+
* Makes a citizen of `city` a `Specialist` of the first available kind (an Entertainer, in Civ1). Returns `null` when
|
|
21
|
+
* the ruleset offers no specialists.
|
|
22
|
+
*/
|
|
23
|
+
const addSpecialist = (city, specialistRegistry = SpecialistRegistry_1.instance, availableSpecialistRegistry = AvailableSpecialistRegistry_1.instance) => {
|
|
24
|
+
const [SpecialistType] = availableSpecialistRegistry.entries();
|
|
25
|
+
if (!SpecialistType) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const specialist = new SpecialistType(city);
|
|
29
|
+
specialistRegistry.register(specialist);
|
|
30
|
+
return specialist;
|
|
31
|
+
};
|
|
32
|
+
exports.addSpecialist = addSpecialist;
|
|
33
|
+
/**
|
|
34
|
+
* Turns `specialist` into the next available kind, wrapping back to the first. Returns the `Specialist` that replaces
|
|
35
|
+
* it, or `specialist` itself when there is nothing to change it to.
|
|
36
|
+
*/
|
|
37
|
+
const changeSpecialist = (specialist, specialistRegistry = SpecialistRegistry_1.instance, availableSpecialistRegistry = AvailableSpecialistRegistry_1.instance) => {
|
|
38
|
+
const city = specialist.city(), types = availableSpecialistRegistry.entries(), NextType = types[(types.indexOf(specialist.constructor) + 1) %
|
|
39
|
+
types.length];
|
|
40
|
+
if (!NextType || specialist instanceof NextType) {
|
|
41
|
+
return specialist;
|
|
42
|
+
}
|
|
43
|
+
const replacement = new NextType(city);
|
|
44
|
+
specialistRegistry.unregister(specialist);
|
|
45
|
+
specialistRegistry.register(replacement);
|
|
46
|
+
return replacement;
|
|
47
|
+
};
|
|
48
|
+
exports.changeSpecialist = changeSpecialist;
|
|
49
|
+
/**
|
|
50
|
+
* Puts one of `city`'s specialists back to work, preferring the first available kind (Entertainers), and returns
|
|
51
|
+
* whether there was one to remove.
|
|
52
|
+
*/
|
|
53
|
+
const removeSpecialist = (city, specialistRegistry, availableSpecialistRegistry) => {
|
|
54
|
+
var _a;
|
|
55
|
+
const specialists = specialistRegistry.getByCity(city), [DefaultType] = availableSpecialistRegistry.entries(), specialist = (_a = specialists.find((specialist) => DefaultType && specialist instanceof DefaultType)) !== null && _a !== void 0 ? _a : specialists[specialists.length - 1];
|
|
56
|
+
if (!specialist) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
specialistRegistry.unregister(specialist);
|
|
60
|
+
return true;
|
|
61
|
+
};
|
|
10
62
|
const getHighestValueCityTiles = (city) => (0, exports.sortTiles)(city.tiles().entries(), city);
|
|
11
63
|
exports.getHighestValueCityTiles = getHighestValueCityTiles;
|
|
12
64
|
const sortTiles = (tiles, city, weights = [
|
|
@@ -30,28 +82,42 @@ exports.sortTiles = sortTiles;
|
|
|
30
82
|
const getHighestValueAvailableCityTiles = (city, playerWorldRegistry = PlayerWorldRegistry_1.instance, workedTileRegistry = WorkedTileRegistry_1.instance) => (0, exports.getHighestValueCityTiles)(city).filter((tile) => workedTileRegistry.tileCanBeWorkedBy(tile, city) &&
|
|
31
83
|
playerWorldRegistry.getByPlayer(city.player()).includes(tile));
|
|
32
84
|
exports.getHighestValueAvailableCityTiles = getHighestValueAvailableCityTiles;
|
|
33
|
-
|
|
85
|
+
/**
|
|
86
|
+
* Rearranges the tiles `city` works from scratch. Its specialists stay as they are.
|
|
87
|
+
*/
|
|
88
|
+
const reassignWorkers = (city, playerWorldRegistry = PlayerWorldRegistry_1.instance, cityGrowthRegistry = CityGrowthRegistry_1.instance, workedTileRegistry = WorkedTileRegistry_1.instance, specialistRegistry = SpecialistRegistry_1.instance, availableSpecialistRegistry = AvailableSpecialistRegistry_1.instance) => {
|
|
34
89
|
workedTileRegistry
|
|
35
90
|
.getBy('city', city)
|
|
36
91
|
.forEach((workedTile) => workedTileRegistry.unregister(workedTile));
|
|
37
92
|
workedTileRegistry.register(new WorkedTile_1.default(city.tile(), city));
|
|
38
|
-
(0, exports.assignWorkers)(city, playerWorldRegistry, cityGrowthRegistry, workedTileRegistry);
|
|
93
|
+
(0, exports.assignWorkers)(city, playerWorldRegistry, cityGrowthRegistry, workedTileRegistry, specialistRegistry, availableSpecialistRegistry);
|
|
39
94
|
};
|
|
40
95
|
exports.reassignWorkers = reassignWorkers;
|
|
41
|
-
|
|
42
|
-
|
|
96
|
+
/**
|
|
97
|
+
* Places each of `city`'s citizens that has no job on the best tile available, or makes them a specialist if there is
|
|
98
|
+
* no tile left to work.
|
|
99
|
+
*/
|
|
100
|
+
const assignWorkers = (city, playerWorldRegistry = PlayerWorldRegistry_1.instance, cityGrowthRegistry = CityGrowthRegistry_1.instance, workedTileRegistry = WorkedTileRegistry_1.instance, specialistRegistry = SpecialistRegistry_1.instance, availableSpecialistRegistry = AvailableSpecialistRegistry_1.instance) => {
|
|
101
|
+
const cityGrowth = cityGrowthRegistry.getByCity(city), placed = () => (0, exports.citizenCount)(city, workedTileRegistry, specialistRegistry) >=
|
|
102
|
+
cityGrowth.size() + 1;
|
|
43
103
|
(0, exports.getHighestValueAvailableCityTiles)(city, playerWorldRegistry, workedTileRegistry).some((tile) => {
|
|
44
|
-
if (
|
|
104
|
+
if (placed()) {
|
|
45
105
|
return true;
|
|
46
106
|
}
|
|
47
107
|
workedTileRegistry.register(new WorkedTile_1.default(tile, city));
|
|
48
108
|
return false;
|
|
49
109
|
});
|
|
110
|
+
while (!placed() &&
|
|
111
|
+
(0, exports.addSpecialist)(city, specialistRegistry, availableSpecialistRegistry)) { }
|
|
50
112
|
};
|
|
51
113
|
exports.assignWorkers = assignWorkers;
|
|
52
|
-
|
|
114
|
+
/**
|
|
115
|
+
* Places one new citizen of `city` on the best tile available, or makes them a specialist if there is no tile left.
|
|
116
|
+
*/
|
|
117
|
+
const assignWorker = (city, playerWorldRegistry = PlayerWorldRegistry_1.instance, cityGrowthRegistry = CityGrowthRegistry_1.instance, workedTileRegistry = WorkedTileRegistry_1.instance, specialistRegistry = SpecialistRegistry_1.instance, availableSpecialistRegistry = AvailableSpecialistRegistry_1.instance) => {
|
|
53
118
|
const [newTile] = (0, exports.getHighestValueAvailableCityTiles)(city, playerWorldRegistry, workedTileRegistry);
|
|
54
119
|
if (!newTile) {
|
|
120
|
+
(0, exports.addSpecialist)(city, specialistRegistry, availableSpecialistRegistry);
|
|
55
121
|
return;
|
|
56
122
|
}
|
|
57
123
|
workedTileRegistry.register(new WorkedTile_1.default(newTile, city));
|
|
@@ -60,32 +126,50 @@ exports.assignWorker = assignWorker;
|
|
|
60
126
|
/**
|
|
61
127
|
* Changes whether `tile` is worked by `city`, as a player clicking it on the city map would.
|
|
62
128
|
*
|
|
63
|
-
* A tile the city works stops being worked. Any other tile is worked by a
|
|
64
|
-
*
|
|
65
|
-
* always worked.
|
|
129
|
+
* A tile the city works stops being worked, and its worker becomes a specialist. Any other tile is worked by a
|
|
130
|
+
* specialist, or by a citizen with no job, if the city has one and is allowed to work it. With every citizen already
|
|
131
|
+
* working a tile, the city's workers are reassigned instead. The city centre is always worked.
|
|
66
132
|
*/
|
|
67
|
-
const changeWorkedTile = (city, tile, playerWorldRegistry = PlayerWorldRegistry_1.instance, cityGrowthRegistry = CityGrowthRegistry_1.instance, workedTileRegistry = WorkedTileRegistry_1.instance) => {
|
|
133
|
+
const changeWorkedTile = (city, tile, playerWorldRegistry = PlayerWorldRegistry_1.instance, cityGrowthRegistry = CityGrowthRegistry_1.instance, workedTileRegistry = WorkedTileRegistry_1.instance, specialistRegistry = SpecialistRegistry_1.instance, availableSpecialistRegistry = AvailableSpecialistRegistry_1.instance) => {
|
|
68
134
|
var _a;
|
|
69
135
|
if (tile === city.tile() || !city.tiles().includes(tile)) {
|
|
70
136
|
return 'none';
|
|
71
137
|
}
|
|
72
138
|
if (((_a = workedTileRegistry.getByTile(tile)) === null || _a === void 0 ? void 0 : _a.city()) === city) {
|
|
73
139
|
workedTileRegistry.unregisterByTile(tile);
|
|
140
|
+
(0, exports.addSpecialist)(city, specialistRegistry, availableSpecialistRegistry);
|
|
74
141
|
return 'removed';
|
|
75
142
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
(0, exports.reassignWorkers)(city, playerWorldRegistry, cityGrowthRegistry, workedTileRegistry);
|
|
143
|
+
const size = cityGrowthRegistry.getByCity(city).size();
|
|
144
|
+
if (workedTileRegistry.getByCity(city).length >= size + 1) {
|
|
145
|
+
(0, exports.reassignWorkers)(city, playerWorldRegistry, cityGrowthRegistry, workedTileRegistry, specialistRegistry, availableSpecialistRegistry);
|
|
79
146
|
return 'reassigned';
|
|
80
147
|
}
|
|
81
148
|
if (!workedTileRegistry.tileCanBeWorkedBy(tile, city) ||
|
|
82
149
|
!playerWorldRegistry.getByPlayer(city.player()).includes(tile)) {
|
|
83
150
|
return 'none';
|
|
84
151
|
}
|
|
152
|
+
if ((0, exports.citizenCount)(city, workedTileRegistry, specialistRegistry) >= size + 1) {
|
|
153
|
+
removeSpecialist(city, specialistRegistry, availableSpecialistRegistry);
|
|
154
|
+
}
|
|
85
155
|
workedTileRegistry.register(new WorkedTile_1.default(tile, city));
|
|
86
156
|
return 'added';
|
|
87
157
|
};
|
|
88
158
|
exports.changeWorkedTile = changeWorkedTile;
|
|
159
|
+
/**
|
|
160
|
+
* Takes jobs away from `city`'s citizens until it has no more than its size allows: specialists first, then the
|
|
161
|
+
* workers on the least valuable tiles.
|
|
162
|
+
*/
|
|
163
|
+
const releaseCitizens = (city, cityGrowth, workedTileRegistry = WorkedTileRegistry_1.instance, specialistRegistry = SpecialistRegistry_1.instance) => {
|
|
164
|
+
const specialists = specialistRegistry.getByCity(city);
|
|
165
|
+
while (specialists.length > 0 &&
|
|
166
|
+
(0, exports.citizenCount)(city, workedTileRegistry, specialistRegistry) >
|
|
167
|
+
cityGrowth.size() + 1) {
|
|
168
|
+
specialistRegistry.unregister(specialists.pop());
|
|
169
|
+
}
|
|
170
|
+
(0, exports.reduceWorkers)(city, cityGrowth).forEach((tile) => workedTileRegistry.unregisterByTile(tile));
|
|
171
|
+
};
|
|
172
|
+
exports.releaseCitizens = releaseCitizens;
|
|
89
173
|
const reduceWorkers = (city, cityGrowth) => (0, exports.sortTiles)(city
|
|
90
174
|
.tilesWorked()
|
|
91
175
|
.entries()
|
package/lib/assignWorkers.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assignWorkers.js","sourceRoot":"","sources":["assignWorkers.ts"],"names":[],"mappings":";;;AAAA,uFAGwD;AACxD,sCAAoD;AACpD,0FAG0D;AAC1D,gFAGiD;AAIjD,yEAAqE;AACrE,gEAAyD;
|
|
1
|
+
{"version":3,"file":"assignWorkers.js","sourceRoot":"","sources":["assignWorkers.ts"],"names":[],"mappings":"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"}
|
package/lib/assignWorkers.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AvailableSpecialistRegistry,
|
|
3
|
+
instance as availableSpecialistRegistryInstance,
|
|
4
|
+
} from '@civ-clone/core-city/AvailableSpecialistRegistry';
|
|
1
5
|
import {
|
|
2
6
|
CityGrowthRegistry,
|
|
3
7
|
instance as cityGrowthRegistryInstance,
|
|
@@ -7,6 +11,10 @@ import {
|
|
|
7
11
|
PlayerWorldRegistry,
|
|
8
12
|
instance as playerWorldRegistryInstance,
|
|
9
13
|
} from '@civ-clone/core-player-world/PlayerWorldRegistry';
|
|
14
|
+
import {
|
|
15
|
+
SpecialistRegistry,
|
|
16
|
+
instance as specialistRegistryInstance,
|
|
17
|
+
} from '@civ-clone/core-city/SpecialistRegistry';
|
|
10
18
|
import {
|
|
11
19
|
WorkedTileRegistry,
|
|
12
20
|
instance as workedTileRegistryInstance,
|
|
@@ -17,6 +25,95 @@ import Yield from '@civ-clone/core-yield/Yield';
|
|
|
17
25
|
import { reduceYield } from '@civ-clone/core-yield/lib/reduceYields';
|
|
18
26
|
import WorkedTile from '@civ-clone/core-city/WorkedTile';
|
|
19
27
|
import CityGrowth from '@civ-clone/core-city-growth/CityGrowth';
|
|
28
|
+
import Specialist from '@civ-clone/core-city/Specialist';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* How many citizens `city` has placed: one per worked tile, the city centre included, and one per `Specialist`. A city
|
|
32
|
+
* of size `n` has `n + 1`.
|
|
33
|
+
*/
|
|
34
|
+
export const citizenCount = (
|
|
35
|
+
city: City,
|
|
36
|
+
workedTileRegistry: WorkedTileRegistry = workedTileRegistryInstance,
|
|
37
|
+
specialistRegistry: SpecialistRegistry = specialistRegistryInstance
|
|
38
|
+
): number =>
|
|
39
|
+
workedTileRegistry.getByCity(city).length +
|
|
40
|
+
specialistRegistry.getByCity(city).length;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Makes a citizen of `city` a `Specialist` of the first available kind (an Entertainer, in Civ1). Returns `null` when
|
|
44
|
+
* the ruleset offers no specialists.
|
|
45
|
+
*/
|
|
46
|
+
export const addSpecialist = (
|
|
47
|
+
city: City,
|
|
48
|
+
specialistRegistry: SpecialistRegistry = specialistRegistryInstance,
|
|
49
|
+
availableSpecialistRegistry: AvailableSpecialistRegistry = availableSpecialistRegistryInstance
|
|
50
|
+
): Specialist | null => {
|
|
51
|
+
const [SpecialistType] = availableSpecialistRegistry.entries();
|
|
52
|
+
|
|
53
|
+
if (!SpecialistType) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const specialist = new SpecialistType(city);
|
|
58
|
+
|
|
59
|
+
specialistRegistry.register(specialist);
|
|
60
|
+
|
|
61
|
+
return specialist;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Turns `specialist` into the next available kind, wrapping back to the first. Returns the `Specialist` that replaces
|
|
66
|
+
* it, or `specialist` itself when there is nothing to change it to.
|
|
67
|
+
*/
|
|
68
|
+
export const changeSpecialist = (
|
|
69
|
+
specialist: Specialist,
|
|
70
|
+
specialistRegistry: SpecialistRegistry = specialistRegistryInstance,
|
|
71
|
+
availableSpecialistRegistry: AvailableSpecialistRegistry = availableSpecialistRegistryInstance
|
|
72
|
+
): Specialist => {
|
|
73
|
+
const city = specialist.city(),
|
|
74
|
+
types = availableSpecialistRegistry.entries(),
|
|
75
|
+
NextType =
|
|
76
|
+
types[
|
|
77
|
+
(types.indexOf(specialist.constructor as typeof Specialist) + 1) %
|
|
78
|
+
types.length
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
if (!NextType || specialist instanceof NextType) {
|
|
82
|
+
return specialist;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const replacement = new NextType(city);
|
|
86
|
+
|
|
87
|
+
specialistRegistry.unregister(specialist);
|
|
88
|
+
specialistRegistry.register(replacement);
|
|
89
|
+
|
|
90
|
+
return replacement;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Puts one of `city`'s specialists back to work, preferring the first available kind (Entertainers), and returns
|
|
95
|
+
* whether there was one to remove.
|
|
96
|
+
*/
|
|
97
|
+
const removeSpecialist = (
|
|
98
|
+
city: City,
|
|
99
|
+
specialistRegistry: SpecialistRegistry,
|
|
100
|
+
availableSpecialistRegistry: AvailableSpecialistRegistry
|
|
101
|
+
): boolean => {
|
|
102
|
+
const specialists = specialistRegistry.getByCity(city),
|
|
103
|
+
[DefaultType] = availableSpecialistRegistry.entries(),
|
|
104
|
+
specialist =
|
|
105
|
+
specialists.find(
|
|
106
|
+
(specialist) => DefaultType && specialist instanceof DefaultType
|
|
107
|
+
) ?? specialists[specialists.length - 1];
|
|
108
|
+
|
|
109
|
+
if (!specialist) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
specialistRegistry.unregister(specialist);
|
|
114
|
+
|
|
115
|
+
return true;
|
|
116
|
+
};
|
|
20
117
|
|
|
21
118
|
export const getHighestValueCityTiles = (city: City) =>
|
|
22
119
|
sortTiles(city.tiles().entries(), city);
|
|
@@ -58,11 +155,16 @@ export const getHighestValueAvailableCityTiles = (
|
|
|
58
155
|
playerWorldRegistry.getByPlayer(city.player()).includes(tile)
|
|
59
156
|
);
|
|
60
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Rearranges the tiles `city` works from scratch. Its specialists stay as they are.
|
|
160
|
+
*/
|
|
61
161
|
export const reassignWorkers = (
|
|
62
162
|
city: City,
|
|
63
163
|
playerWorldRegistry: PlayerWorldRegistry = playerWorldRegistryInstance,
|
|
64
164
|
cityGrowthRegistry: CityGrowthRegistry = cityGrowthRegistryInstance,
|
|
65
|
-
workedTileRegistry: WorkedTileRegistry = workedTileRegistryInstance
|
|
165
|
+
workedTileRegistry: WorkedTileRegistry = workedTileRegistryInstance,
|
|
166
|
+
specialistRegistry: SpecialistRegistry = specialistRegistryInstance,
|
|
167
|
+
availableSpecialistRegistry: AvailableSpecialistRegistry = availableSpecialistRegistryInstance
|
|
66
168
|
) => {
|
|
67
169
|
workedTileRegistry
|
|
68
170
|
.getBy('city', city)
|
|
@@ -76,29 +178,42 @@ export const reassignWorkers = (
|
|
|
76
178
|
city,
|
|
77
179
|
playerWorldRegistry,
|
|
78
180
|
cityGrowthRegistry,
|
|
79
|
-
workedTileRegistry
|
|
181
|
+
workedTileRegistry,
|
|
182
|
+
specialistRegistry,
|
|
183
|
+
availableSpecialistRegistry
|
|
80
184
|
);
|
|
81
185
|
};
|
|
82
186
|
|
|
187
|
+
/**
|
|
188
|
+
* Places each of `city`'s citizens that has no job on the best tile available, or makes them a specialist if there is
|
|
189
|
+
* no tile left to work.
|
|
190
|
+
*/
|
|
83
191
|
export const assignWorkers: (
|
|
84
192
|
city: City,
|
|
85
193
|
playerWorldRegistry?: PlayerWorldRegistry,
|
|
86
194
|
cityGrowthRegistry?: CityGrowthRegistry,
|
|
87
|
-
workedTileRegistry?: WorkedTileRegistry
|
|
195
|
+
workedTileRegistry?: WorkedTileRegistry,
|
|
196
|
+
specialistRegistry?: SpecialistRegistry,
|
|
197
|
+
availableSpecialistRegistry?: AvailableSpecialistRegistry
|
|
88
198
|
) => void = (
|
|
89
199
|
city: City,
|
|
90
200
|
playerWorldRegistry: PlayerWorldRegistry = playerWorldRegistryInstance,
|
|
91
201
|
cityGrowthRegistry: CityGrowthRegistry = cityGrowthRegistryInstance,
|
|
92
|
-
workedTileRegistry: WorkedTileRegistry = workedTileRegistryInstance
|
|
202
|
+
workedTileRegistry: WorkedTileRegistry = workedTileRegistryInstance,
|
|
203
|
+
specialistRegistry: SpecialistRegistry = specialistRegistryInstance,
|
|
204
|
+
availableSpecialistRegistry: AvailableSpecialistRegistry = availableSpecialistRegistryInstance
|
|
93
205
|
): void => {
|
|
94
|
-
const cityGrowth = cityGrowthRegistry.getByCity(city)
|
|
206
|
+
const cityGrowth = cityGrowthRegistry.getByCity(city),
|
|
207
|
+
placed = () =>
|
|
208
|
+
citizenCount(city, workedTileRegistry, specialistRegistry) >=
|
|
209
|
+
cityGrowth.size() + 1;
|
|
95
210
|
|
|
96
211
|
getHighestValueAvailableCityTiles(
|
|
97
212
|
city,
|
|
98
213
|
playerWorldRegistry,
|
|
99
214
|
workedTileRegistry
|
|
100
215
|
).some((tile) => {
|
|
101
|
-
if (
|
|
216
|
+
if (placed()) {
|
|
102
217
|
return true;
|
|
103
218
|
}
|
|
104
219
|
|
|
@@ -106,18 +221,30 @@ export const assignWorkers: (
|
|
|
106
221
|
|
|
107
222
|
return false;
|
|
108
223
|
});
|
|
224
|
+
|
|
225
|
+
while (
|
|
226
|
+
!placed() &&
|
|
227
|
+
addSpecialist(city, specialistRegistry, availableSpecialistRegistry)
|
|
228
|
+
) {}
|
|
109
229
|
};
|
|
110
230
|
|
|
231
|
+
/**
|
|
232
|
+
* Places one new citizen of `city` on the best tile available, or makes them a specialist if there is no tile left.
|
|
233
|
+
*/
|
|
111
234
|
export const assignWorker: (
|
|
112
235
|
city: City,
|
|
113
236
|
playerWorldRegistry?: PlayerWorldRegistry,
|
|
114
237
|
cityGrowthRegistry?: CityGrowthRegistry,
|
|
115
|
-
workedTileRegistry?: WorkedTileRegistry
|
|
238
|
+
workedTileRegistry?: WorkedTileRegistry,
|
|
239
|
+
specialistRegistry?: SpecialistRegistry,
|
|
240
|
+
availableSpecialistRegistry?: AvailableSpecialistRegistry
|
|
116
241
|
) => void = (
|
|
117
242
|
city: City,
|
|
118
243
|
playerWorldRegistry: PlayerWorldRegistry = playerWorldRegistryInstance,
|
|
119
244
|
cityGrowthRegistry: CityGrowthRegistry = cityGrowthRegistryInstance,
|
|
120
|
-
workedTileRegistry: WorkedTileRegistry = workedTileRegistryInstance
|
|
245
|
+
workedTileRegistry: WorkedTileRegistry = workedTileRegistryInstance,
|
|
246
|
+
specialistRegistry: SpecialistRegistry = specialistRegistryInstance,
|
|
247
|
+
availableSpecialistRegistry: AvailableSpecialistRegistry = availableSpecialistRegistryInstance
|
|
121
248
|
): void => {
|
|
122
249
|
const [newTile] = getHighestValueAvailableCityTiles(
|
|
123
250
|
city,
|
|
@@ -126,6 +253,8 @@ export const assignWorker: (
|
|
|
126
253
|
);
|
|
127
254
|
|
|
128
255
|
if (!newTile) {
|
|
256
|
+
addSpecialist(city, specialistRegistry, availableSpecialistRegistry);
|
|
257
|
+
|
|
129
258
|
return;
|
|
130
259
|
}
|
|
131
260
|
|
|
@@ -137,22 +266,26 @@ export type WorkedTileChange = 'removed' | 'added' | 'reassigned' | 'none';
|
|
|
137
266
|
/**
|
|
138
267
|
* Changes whether `tile` is worked by `city`, as a player clicking it on the city map would.
|
|
139
268
|
*
|
|
140
|
-
* A tile the city works stops being worked. Any other tile is worked by a
|
|
141
|
-
*
|
|
142
|
-
* always worked.
|
|
269
|
+
* A tile the city works stops being worked, and its worker becomes a specialist. Any other tile is worked by a
|
|
270
|
+
* specialist, or by a citizen with no job, if the city has one and is allowed to work it. With every citizen already
|
|
271
|
+
* working a tile, the city's workers are reassigned instead. The city centre is always worked.
|
|
143
272
|
*/
|
|
144
273
|
export const changeWorkedTile: (
|
|
145
274
|
city: City,
|
|
146
275
|
tile: Tile,
|
|
147
276
|
playerWorldRegistry?: PlayerWorldRegistry,
|
|
148
277
|
cityGrowthRegistry?: CityGrowthRegistry,
|
|
149
|
-
workedTileRegistry?: WorkedTileRegistry
|
|
278
|
+
workedTileRegistry?: WorkedTileRegistry,
|
|
279
|
+
specialistRegistry?: SpecialistRegistry,
|
|
280
|
+
availableSpecialistRegistry?: AvailableSpecialistRegistry
|
|
150
281
|
) => WorkedTileChange = (
|
|
151
282
|
city: City,
|
|
152
283
|
tile: Tile,
|
|
153
284
|
playerWorldRegistry: PlayerWorldRegistry = playerWorldRegistryInstance,
|
|
154
285
|
cityGrowthRegistry: CityGrowthRegistry = cityGrowthRegistryInstance,
|
|
155
|
-
workedTileRegistry: WorkedTileRegistry = workedTileRegistryInstance
|
|
286
|
+
workedTileRegistry: WorkedTileRegistry = workedTileRegistryInstance,
|
|
287
|
+
specialistRegistry: SpecialistRegistry = specialistRegistryInstance,
|
|
288
|
+
availableSpecialistRegistry: AvailableSpecialistRegistry = availableSpecialistRegistryInstance
|
|
156
289
|
): WorkedTileChange => {
|
|
157
290
|
if (tile === city.tile() || !city.tiles().includes(tile)) {
|
|
158
291
|
return 'none';
|
|
@@ -161,18 +294,21 @@ export const changeWorkedTile: (
|
|
|
161
294
|
if (workedTileRegistry.getByTile(tile)?.city() === city) {
|
|
162
295
|
workedTileRegistry.unregisterByTile(tile);
|
|
163
296
|
|
|
297
|
+
addSpecialist(city, specialistRegistry, availableSpecialistRegistry);
|
|
298
|
+
|
|
164
299
|
return 'removed';
|
|
165
300
|
}
|
|
166
301
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
) {
|
|
302
|
+
const size = cityGrowthRegistry.getByCity(city).size();
|
|
303
|
+
|
|
304
|
+
if (workedTileRegistry.getByCity(city).length >= size + 1) {
|
|
171
305
|
reassignWorkers(
|
|
172
306
|
city,
|
|
173
307
|
playerWorldRegistry,
|
|
174
308
|
cityGrowthRegistry,
|
|
175
|
-
workedTileRegistry
|
|
309
|
+
workedTileRegistry,
|
|
310
|
+
specialistRegistry,
|
|
311
|
+
availableSpecialistRegistry
|
|
176
312
|
);
|
|
177
313
|
|
|
178
314
|
return 'reassigned';
|
|
@@ -185,11 +321,40 @@ export const changeWorkedTile: (
|
|
|
185
321
|
return 'none';
|
|
186
322
|
}
|
|
187
323
|
|
|
324
|
+
if (citizenCount(city, workedTileRegistry, specialistRegistry) >= size + 1) {
|
|
325
|
+
removeSpecialist(city, specialistRegistry, availableSpecialistRegistry);
|
|
326
|
+
}
|
|
327
|
+
|
|
188
328
|
workedTileRegistry.register(new WorkedTile(tile, city));
|
|
189
329
|
|
|
190
330
|
return 'added';
|
|
191
331
|
};
|
|
192
332
|
|
|
333
|
+
/**
|
|
334
|
+
* Takes jobs away from `city`'s citizens until it has no more than its size allows: specialists first, then the
|
|
335
|
+
* workers on the least valuable tiles.
|
|
336
|
+
*/
|
|
337
|
+
export const releaseCitizens = (
|
|
338
|
+
city: City,
|
|
339
|
+
cityGrowth: CityGrowth,
|
|
340
|
+
workedTileRegistry: WorkedTileRegistry = workedTileRegistryInstance,
|
|
341
|
+
specialistRegistry: SpecialistRegistry = specialistRegistryInstance
|
|
342
|
+
): void => {
|
|
343
|
+
const specialists = specialistRegistry.getByCity(city);
|
|
344
|
+
|
|
345
|
+
while (
|
|
346
|
+
specialists.length > 0 &&
|
|
347
|
+
citizenCount(city, workedTileRegistry, specialistRegistry) >
|
|
348
|
+
cityGrowth.size() + 1
|
|
349
|
+
) {
|
|
350
|
+
specialistRegistry.unregister(specialists.pop()!);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
reduceWorkers(city, cityGrowth).forEach((tile: Tile): void =>
|
|
354
|
+
workedTileRegistry.unregisterByTile(tile)
|
|
355
|
+
);
|
|
356
|
+
};
|
|
357
|
+
|
|
193
358
|
export const reduceWorkers = (city: City, cityGrowth: CityGrowth): Tile[] =>
|
|
194
359
|
sortTiles(
|
|
195
360
|
city
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@civ-clone/library-city",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"repository": "git@github.com:civ-clone/library-city.git",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
"@civ-clone/base-terrain-yield-food": "^0.1.0",
|
|
60
60
|
"@civ-clone/base-terrain-yield-production": "^0.1.0",
|
|
61
61
|
"@civ-clone/base-terrain-yield-trade": "^0.1.0",
|
|
62
|
+
"@civ-clone/core-city": "^0.1.16",
|
|
62
63
|
"@civ-clone/core-city-growth": "^0.1.0",
|
|
63
64
|
"@civ-clone/core-player-world": "^0.1.9"
|
|
64
65
|
}
|