@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.
@@ -0,0 +1,3 @@
1
+ import Specialist from '@civ-clone/core-city/Specialist';
2
+ export declare class Entertainer extends Specialist {}
3
+ export default Entertainer;
@@ -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,5 @@
1
+ import Specialist from '@civ-clone/core-city/Specialist';
2
+
3
+ export class Entertainer extends Specialist {}
4
+
5
+ export default Entertainer;
@@ -0,0 +1,3 @@
1
+ import Specialist from '@civ-clone/core-city/Specialist';
2
+ export declare class Scientist extends Specialist {}
3
+ export default Scientist;
@@ -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,5 @@
1
+ import Specialist from '@civ-clone/core-city/Specialist';
2
+
3
+ export class Scientist extends Specialist {}
4
+
5
+ export default Scientist;
@@ -0,0 +1,3 @@
1
+ import Specialist from '@civ-clone/core-city/Specialist';
2
+ export declare class TaxCollector extends Specialist {}
3
+ export default TaxCollector;
@@ -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"}
@@ -0,0 +1,5 @@
1
+ import Specialist from '@civ-clone/core-city/Specialist';
2
+
3
+ export class TaxCollector extends Specialist {}
4
+
5
+ export default TaxCollector;
@@ -0,0 +1,3 @@
1
+ export { Entertainer } from './Specialists/Entertainer';
2
+ export { TaxCollector } from './Specialists/TaxCollector';
3
+ export { Scientist } from './Specialists/Scientist';
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
@@ -0,0 +1,3 @@
1
+ export { Entertainer } from './Specialists/Entertainer';
2
+ export { TaxCollector } from './Specialists/TaxCollector';
3
+ export { Scientist } from './Specialists/Scientist';
@@ -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 free worker, if the city has one and is
42
- * allowed to work it. With every worker already placed, the city's workers are reassigned instead. The city centre is
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
@@ -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
- const reassignWorkers = (city, playerWorldRegistry = PlayerWorldRegistry_1.instance, cityGrowthRegistry = CityGrowthRegistry_1.instance, workedTileRegistry = WorkedTileRegistry_1.instance) => {
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
- const assignWorkers = (city, playerWorldRegistry = PlayerWorldRegistry_1.instance, cityGrowthRegistry = CityGrowthRegistry_1.instance, workedTileRegistry = WorkedTileRegistry_1.instance) => {
42
- const cityGrowth = cityGrowthRegistry.getByCity(city);
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 (city.tilesWorked().length >= cityGrowth.size() + 1) {
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
- const assignWorker = (city, playerWorldRegistry = PlayerWorldRegistry_1.instance, cityGrowthRegistry = CityGrowthRegistry_1.instance, workedTileRegistry = WorkedTileRegistry_1.instance) => {
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 free worker, if the city has one and is
64
- * allowed to work it. With every worker already placed, the city's workers are reassigned instead. The city centre is
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
- if (workedTileRegistry.getByCity(city).length >=
77
- cityGrowthRegistry.getByCity(city).size() + 1) {
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()
@@ -1 +1 @@
1
- {"version":3,"file":"assignWorkers.js","sourceRoot":"","sources":["assignWorkers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"assignWorkers.js","sourceRoot":"","sources":["assignWorkers.ts"],"names":[],"mappings":"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"}
@@ -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 (city.tilesWorked().length >= cityGrowth.size() + 1) {
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 free worker, if the city has one and is
141
- * allowed to work it. With every worker already placed, the city's workers are reassigned instead. The city centre is
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
- if (
168
- workedTileRegistry.getByCity(city).length >=
169
- cityGrowthRegistry.getByCity(city).size() + 1
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",
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
  }