@civ-clone/base-unit-lifecycle 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -20,7 +20,7 @@ registry, the engine or a number take it first and return the function.
20
20
  - `lib/halted`: `emitHalted(engine)` (`unit:halted`), a GoTo stopped next to its destination.
21
21
  - `lib/unsupported`: `emitUnsupported(engine)` (`unit:unsupported`).
22
22
  - `lib/defeated`: `emitAndDestroy(engine, ruleRegistry)` (`unit:defeated`, then `Destroyed`), and for a defeated
23
- defender's stack, `defended`, `notInCity(cityRegistry)`, `hasStack(unitRegistry)` and
23
+ defender's stack, `defended`, `notInCity(cityRegistry)`, `notSpared(sparesStack)`, `hasStack(unitRegistry)` and
24
24
  `destroyStack(unitRegistry, ruleRegistry)`.
25
25
  - `lib/destroyed`: `emitDestroyed(engine)` (`unit:destroyed`); `destroyedByAnother`, `notYetDestroyed` and
26
26
  `countLoss(unitLossRegistry)` for a loss report; `deactivate`; `removeImprovements(unitImprovementRegistry)`;
@@ -32,5 +32,33 @@ registry, the engine or a number take it first and return the function.
32
32
  - `lib/playerAction`: `hasActiveUnits(unitRegistry)` / `activeUnits(unitRegistry, ActiveUnit)` and
33
33
  `hasInactiveUnits(unitRegistry)` / `inactiveUnits(unitRegistry, InactiveUnit)`, waiting units last.
34
34
 
35
+ ## Rule assemblers
36
+
37
+ For a ruleset that wants the rules themselves, each takes the ruleset's id prefix, its registries and its options, and
38
+ returns the rules with ids `<prefix>:unit/<type>/<name>`, the same names and order civ1-unit uses
39
+ (`tests/fixtures/civ1-unit-rules.json` pins them):
40
+
41
+ - `lib/lifecycleRules`: `lifecycleRules(prefix, deps, options)`, by rule type (`activate`, `canStow`, `created`,
42
+ `defeated`, `destroyed`, `expectedMovementCost`, `halted`, `impassable`, `lostAtSea`, `playerAction`, `stowed`,
43
+ `transferred`, `unsupported`, `validateMove`), so each list can be registered where the ruleset wants it.
44
+ - `lib/movedRules`: `movedRules(prefix, deps, options)`, the `Moved` rules: cargo, collecting, taking off, a
45
+ `CoastBound` unit lost at sea, `AttackEndsTurn`, and a broken peace treaty.
46
+ - `lib/detonatedRules`: `detonatedRules(prefix, deps, options)`, what a nuclear detonation does to the 9 squares.
47
+ `sparesUnits` spares a city's units (Civ1's SDI Defense); an optional `vetoes` stops a detonation altogether.
48
+ - `lib/diplomatRules`: `diplomatRules(prefix, deps)`, the embassy, investigation and leader-meeting rules.
49
+ - `lib/treatyPartner`: `treatyPartner(improvements, deps)`, a `partnerOf` for `impassable` and the treaty actions: the
50
+ partner working an improved tile.
51
+
52
+ ### For civ1-unit's adoption (R2b)
53
+
54
+ - `lifecycle.transferred` holds only `transferred/emit`: civ1-unit must register its own `transferred/start-afresh`
55
+ rule (`START_AFRESH_RULE`) before it, as it does today.
56
+ - `HALVE_CITIES_PRIORITY` and `halveCity` now live in `lib/detonatedRules` as well as civ1-unit's `lib/nuclear`; R2b
57
+ makes civ1-unit re-export the base ones, so there is one copy.
58
+ - The defaults reproduce civ1-unit exactly: `shortStep`, `vetoes` and `sparesStack` are for other rulesets (Civ2's
59
+ short step, SDI Defense, and the squares besides a city where a stack outlives its defender), and leaving them out
60
+ changes nothing: `lifecycleRules`' `destroy-stack` rule only gains its `notSpared` criterion when `sparesStack` is
61
+ given.
62
+
35
63
  A library: no `main`, so it registers nothing on its own. Import what you need, for example
36
64
  `@civ-clone/base-unit-lifecycle/lib/destroyed`.
package/lib/defeated.d.ts CHANGED
@@ -2,6 +2,7 @@ import Action from '@civ-clone/core-unit/Action';
2
2
  import CityRegistry from '@civ-clone/core-city/CityRegistry';
3
3
  import Engine from '@civ-clone/core-engine/Engine';
4
4
  import RuleRegistry from '@civ-clone/core-rule/RuleRegistry';
5
+ import Tile from '@civ-clone/core-world/Tile';
5
6
  import Unit from '@civ-clone/core-unit/Unit';
6
7
  import UnitRegistry from '@civ-clone/core-unit/UnitRegistry';
7
8
  export declare const emitAndDestroy: (
@@ -16,6 +17,10 @@ export declare const defended: (
16
17
  export declare const notInCity: (
17
18
  cityRegistry: CityRegistry
18
19
  ) => (unit: Unit) => boolean;
20
+ export type SparesStack = (tile: Tile, defender: Unit) => boolean;
21
+ export declare const notSpared: (
22
+ sparesStack: SparesStack
23
+ ) => (unit: Unit) => boolean;
19
24
  export declare const hasStack: (
20
25
  unitRegistry: UnitRegistry
21
26
  ) => (unit: Unit) => boolean;
package/lib/defeated.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.destroyStack = exports.hasStack = exports.notInCity = exports.defended = exports.emitAndDestroy = void 0;
3
+ exports.destroyStack = exports.hasStack = exports.notSpared = exports.notInCity = exports.defended = exports.emitAndDestroy = void 0;
4
4
  const Destroyed_1 = require("@civ-clone/core-unit/Rules/Destroyed");
5
5
  // What a ruleset's `Defeated` rules ask and do when `unit` loses a fight to `by`. `action`, when given, is the attack:
6
6
  // `action.unit()` attacked.
@@ -17,6 +17,9 @@ exports.defended = defended;
17
17
  // The defeated unit is not in a city.
18
18
  const notInCity = (cityRegistry) => (unit) => cityRegistry.getByTile(unit.tile()) === null;
19
19
  exports.notInCity = notInCity;
20
+ // The square the defeated unit lost on doesn't keep its stack.
21
+ const notSpared = (sparesStack) => (unit) => !sparesStack(unit.tile(), unit);
22
+ exports.notSpared = notSpared;
20
23
  // Other units of the defeated unit's player share its tile.
21
24
  const hasStack = (unitRegistry) => (unit) => unitRegistry
22
25
  .getByTile(unit.tile())
@@ -1 +1 @@
1
- {"version":3,"file":"defeated.js","sourceRoot":"","sources":["defeated.ts"],"names":[],"mappings":";;;AAEA,oEAA6D;AAM7D,uHAAuH;AACvH,6BAA6B;AAE7B,oHAAoH;AACpH,wBAAwB;AACjB,MAAM,cAAc,GACzB,CAAC,MAAc,EAAE,YAA0B,EAAE,EAAE,CAC/C,CAAC,IAAU,EAAE,EAAQ,EAAE,MAAe,EAAQ,EAAE;IAC9C,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;IAE/C,YAAY,CAAC,OAAO,CAAC,mBAAS,EAAE,IAAI,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;AACrD,CAAC,CAAC;AANS,QAAA,cAAc,kBAMvB;AAEJ,uFAAuF;AAChF,MAAM,QAAQ,GAAG,CAAC,IAAU,EAAE,EAAQ,EAAE,MAAe,EAAW,EAAE,CACzE,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC;AADvB,QAAA,QAAQ,YACe;AAEpC,sCAAsC;AAC/B,MAAM,SAAS,GACpB,CAAC,YAA0B,EAAE,EAAE,CAC/B,CAAC,IAAU,EAAW,EAAE,CACtB,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;AAHpC,QAAA,SAAS,aAG2B;AAEjD,4DAA4D;AACrD,MAAM,QAAQ,GACnB,CAAC,YAA0B,EAAE,EAAE,CAC/B,CAAC,IAAU,EAAW,EAAE,CACtB,YAAY;KACT,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;KACtB,MAAM,CACL,CAAC,QAAc,EAAE,EAAE,CACjB,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,MAAM,EAAE,CAC3D,CAAC,MAAM,GAAG,CAAC,CAAC;AARN,QAAA,QAAQ,YAQF;AAEnB,sHAAsH;AAC/G,MAAM,YAAY,GACvB,CAAC,YAA0B,EAAE,YAA0B,EAAE,EAAE,CAC3D,CAAC,IAAU,EAAE,EAAQ,EAAQ,EAAE,CAC7B,YAAY;KACT,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;KACtB,MAAM,CACL,CAAC,QAAc,EAAW,EAAE,CAC1B,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,MAAM,EAAE,CAC3D;KACA,OAAO,CAAC,CAAC,QAAc,EAAQ,EAAE;IAChC,YAAY,CAAC,OAAO,CAAC,mBAAS,EAAE,QAAQ,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;AACzD,CAAC,CAAC,CAAC;AAXI,QAAA,YAAY,gBAWhB"}
1
+ {"version":3,"file":"defeated.js","sourceRoot":"","sources":["defeated.ts"],"names":[],"mappings":";;;AAEA,oEAA6D;AAO7D,uHAAuH;AACvH,6BAA6B;AAE7B,oHAAoH;AACpH,wBAAwB;AACjB,MAAM,cAAc,GACzB,CAAC,MAAc,EAAE,YAA0B,EAAE,EAAE,CAC/C,CAAC,IAAU,EAAE,EAAQ,EAAE,MAAe,EAAQ,EAAE;IAC9C,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;IAE/C,YAAY,CAAC,OAAO,CAAC,mBAAS,EAAE,IAAI,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;AACrD,CAAC,CAAC;AANS,QAAA,cAAc,kBAMvB;AAEJ,uFAAuF;AAChF,MAAM,QAAQ,GAAG,CAAC,IAAU,EAAE,EAAQ,EAAE,MAAe,EAAW,EAAE,CACzE,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC;AADvB,QAAA,QAAQ,YACe;AAEpC,sCAAsC;AAC/B,MAAM,SAAS,GACpB,CAAC,YAA0B,EAAE,EAAE,CAC/B,CAAC,IAAU,EAAW,EAAE,CACtB,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;AAHpC,QAAA,SAAS,aAG2B;AAMjD,+DAA+D;AACxD,MAAM,SAAS,GACpB,CAAC,WAAwB,EAAE,EAAE,CAC7B,CAAC,IAAU,EAAW,EAAE,CACtB,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC;AAHvB,QAAA,SAAS,aAGc;AAEpC,4DAA4D;AACrD,MAAM,QAAQ,GACnB,CAAC,YAA0B,EAAE,EAAE,CAC/B,CAAC,IAAU,EAAW,EAAE,CACtB,YAAY;KACT,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;KACtB,MAAM,CACL,CAAC,QAAc,EAAE,EAAE,CACjB,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,MAAM,EAAE,CAC3D,CAAC,MAAM,GAAG,CAAC,CAAC;AARN,QAAA,QAAQ,YAQF;AAEnB,sHAAsH;AAC/G,MAAM,YAAY,GACvB,CAAC,YAA0B,EAAE,YAA0B,EAAE,EAAE,CAC3D,CAAC,IAAU,EAAE,EAAQ,EAAQ,EAAE,CAC7B,YAAY;KACT,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;KACtB,MAAM,CACL,CAAC,QAAc,EAAW,EAAE,CAC1B,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,MAAM,EAAE,CAC3D;KACA,OAAO,CAAC,CAAC,QAAc,EAAQ,EAAE;IAChC,YAAY,CAAC,OAAO,CAAC,mBAAS,EAAE,QAAQ,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;AACzD,CAAC,CAAC,CAAC;AAXI,QAAA,YAAY,gBAWhB"}
package/lib/defeated.ts CHANGED
@@ -3,6 +3,7 @@ import CityRegistry from '@civ-clone/core-city/CityRegistry';
3
3
  import Destroyed from '@civ-clone/core-unit/Rules/Destroyed';
4
4
  import Engine from '@civ-clone/core-engine/Engine';
5
5
  import RuleRegistry from '@civ-clone/core-rule/RuleRegistry';
6
+ import Tile from '@civ-clone/core-world/Tile';
6
7
  import Unit from '@civ-clone/core-unit/Unit';
7
8
  import UnitRegistry from '@civ-clone/core-unit/UnitRegistry';
8
9
 
@@ -29,6 +30,16 @@ export const notInCity =
29
30
  (unit: Unit): boolean =>
30
31
  cityRegistry.getByTile(unit.tile()) === null;
31
32
 
33
+ // Whether the square `defender` lost on keeps the units sharing it: a ruleset's own places (a fortress, say) where only
34
+ // the defender is lost.
35
+ export type SparesStack = (tile: Tile, defender: Unit) => boolean;
36
+
37
+ // The square the defeated unit lost on doesn't keep its stack.
38
+ export const notSpared =
39
+ (sparesStack: SparesStack) =>
40
+ (unit: Unit): boolean =>
41
+ !sparesStack(unit.tile(), unit);
42
+
32
43
  // Other units of the defeated unit's player share its tile.
33
44
  export const hasStack =
34
45
  (unitRegistry: UnitRegistry) =>
@@ -0,0 +1,56 @@
1
+ import { CityGrowthRegistry } from '@civ-clone/core-city-growth/CityGrowthRegistry';
2
+ import { CityRegistry } from '@civ-clone/core-city/CityRegistry';
3
+ import { Engine } from '@civ-clone/core-engine/Engine';
4
+ import { RuleRegistry } from '@civ-clone/core-rule/RuleRegistry';
5
+ import { TileImprovementRegistry } from '@civ-clone/core-tile-improvement/TileImprovementRegistry';
6
+ import { UnitRegistry } from '@civ-clone/core-unit/UnitRegistry';
7
+ import City from '@civ-clone/core-city/City';
8
+ import Detonated from '@civ-clone/base-unit-action-nuclear-attack/Rules/Detonated';
9
+ import Tile from '@civ-clone/core-world/Tile';
10
+ import TileImprovement from '@civ-clone/core-tile-improvement/TileImprovement';
11
+ import Unit from '@civ-clone/core-unit/Unit';
12
+ /**
13
+ * Where `unit/detonated/halve-cities` runs among the `Detonated` rules: after the `Normal` ones (the units destroyed)
14
+ * and before `Low` (the fallout), so a rule that takes its place runs there too.
15
+ */
16
+ export declare const HALVE_CITIES_PRIORITY = 2500;
17
+ /** `city` loses half its size, rounded down, to `unit`'s detonation, so a city is never destroyed by it. */
18
+ export declare const halveCity: (
19
+ city: City,
20
+ unit: Unit,
21
+ cityGrowthRegistry?: CityGrowthRegistry
22
+ ) => void;
23
+ export interface DetonatedDependencies {
24
+ cityGrowthRegistry?: CityGrowthRegistry;
25
+ cityRegistry?: CityRegistry;
26
+ engine?: Engine;
27
+ randomNumberGenerator?: () => number;
28
+ ruleRegistry?: RuleRegistry;
29
+ tileImprovementRegistry?: TileImprovementRegistry;
30
+ unitRegistry?: UnitRegistry;
31
+ }
32
+ export interface DetonatedOptions {
33
+ sparesUnits: (city: City) => boolean;
34
+ vetoes?: (unit: Unit, tile: Tile) => boolean;
35
+ Pollution: new (tile: Tile, ruleRegistry: RuleRegistry) => TileImprovement;
36
+ falloutChance: number;
37
+ }
38
+ /**
39
+ * A ruleset's `Detonated` rules, with ids `<prefix>:unit/detonated/<name>` as civ1-unit's are, over the square a
40
+ * nuclear weapon detonates over and the 8 around it: tell the client, destroy every unit (but those `sparesUnits`
41
+ * keeps), halve every city, and fall out on the land.
42
+ */
43
+ export declare const detonatedRules: (
44
+ prefix: string,
45
+ {
46
+ cityGrowthRegistry,
47
+ cityRegistry,
48
+ engine,
49
+ randomNumberGenerator,
50
+ ruleRegistry,
51
+ tileImprovementRegistry,
52
+ unitRegistry,
53
+ }: DetonatedDependencies,
54
+ { sparesUnits, Pollution, falloutChance, vetoes }: DetonatedOptions
55
+ ) => Detonated[];
56
+ export default detonatedRules;
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.detonatedRules = exports.halveCity = exports.HALVE_CITIES_PRIORITY = void 0;
4
+ const CityGrowthRegistry_1 = require("@civ-clone/core-city-growth/CityGrowthRegistry");
5
+ const CityRegistry_1 = require("@civ-clone/core-city/CityRegistry");
6
+ const Engine_1 = require("@civ-clone/core-engine/Engine");
7
+ const RuleRegistry_1 = require("@civ-clone/core-rule/RuleRegistry");
8
+ const TileImprovementRegistry_1 = require("@civ-clone/core-tile-improvement/TileImprovementRegistry");
9
+ const UnitRegistry_1 = require("@civ-clone/core-unit/UnitRegistry");
10
+ const Destroyed_1 = require("@civ-clone/core-unit/Rules/Destroyed");
11
+ const Detonated_1 = require("@civ-clone/base-unit-action-nuclear-attack/Rules/Detonated");
12
+ const Effect_1 = require("@civ-clone/core-rule/Effect");
13
+ const High_1 = require("@civ-clone/core-rule/Priorities/High");
14
+ const Low_1 = require("@civ-clone/core-rule/Priorities/Low");
15
+ const Priority_1 = require("@civ-clone/core-rule/Priority");
16
+ const core_random_1 = require("@civ-clone/core-random");
17
+ /**
18
+ * Where `unit/detonated/halve-cities` runs among the `Detonated` rules: after the `Normal` ones (the units destroyed)
19
+ * and before `Low` (the fallout), so a rule that takes its place runs there too.
20
+ */
21
+ exports.HALVE_CITIES_PRIORITY = 2500;
22
+ /** `city` loses half its size, rounded down, to `unit`'s detonation, so a city is never destroyed by it. */
23
+ const halveCity = (city, unit, cityGrowthRegistry = CityGrowthRegistry_1.instance) => {
24
+ const cityGrowth = cityGrowthRegistry.getByCity(city), loss = Math.floor(cityGrowth.size() / 2);
25
+ for (let i = 0; i < loss; i++) {
26
+ cityGrowth.shrink(unit);
27
+ }
28
+ };
29
+ exports.halveCity = halveCity;
30
+ /**
31
+ * A ruleset's `Detonated` rules, with ids `<prefix>:unit/detonated/<name>` as civ1-unit's are, over the square a
32
+ * nuclear weapon detonates over and the 8 around it: tell the client, destroy every unit (but those `sparesUnits`
33
+ * keeps), halve every city, and fall out on the land.
34
+ */
35
+ const detonatedRules = (prefix, { cityGrowthRegistry = CityGrowthRegistry_1.instance, cityRegistry = CityRegistry_1.instance, engine = Engine_1.instance, randomNumberGenerator = core_random_1.instance, ruleRegistry = RuleRegistry_1.instance, tileImprovementRegistry = TileImprovementRegistry_1.instance, unitRegistry = UnitRegistry_1.instance, }, { sparesUnits, Pollution, falloutChance, vetoes }) => {
36
+ const id = (name) => `${prefix}:unit/detonated/${name}`, area = (tile) => [tile, ...tile.getNeighbours()],
37
+ // `vetoes` is asked once per detonation, by `emit` (which runs first, `High`), and the answer is kept for the
38
+ // three rules after it, so destroying the units can't change it halfway. Without `vetoes`, nothing is kept or asked.
39
+ vetoed = new WeakMap(), stopped = (unit, tile) => { var _a; return vetoes !== undefined && ((_a = vetoed.get(unit)) !== null && _a !== void 0 ? _a : vetoes(unit, tile)); };
40
+ return [
41
+ new Detonated_1.default(
42
+ // Before anything changes, so a client can see what's there to be hit.
43
+ id('emit'), new High_1.default(), new Effect_1.default((unit, tile) => {
44
+ if (vetoes !== undefined) {
45
+ vetoed.set(unit, vetoes(unit, tile));
46
+ }
47
+ engine.emit('unit:nuclear-detonation', unit, tile);
48
+ })),
49
+ new Detonated_1.default(id('destroy-units'), new Effect_1.default((unit, tile) => stopped(unit, tile)
50
+ ? undefined
51
+ : area(tile).forEach((areaTile) => {
52
+ const city = cityRegistry.getByTile(areaTile);
53
+ if (city !== null && sparesUnits(city)) {
54
+ engine.emit('city:sdi-protected', city, unit);
55
+ return;
56
+ }
57
+ unitRegistry
58
+ .getByTile(areaTile)
59
+ .forEach((areaUnit) => {
60
+ // Cargo is destroyed with its transport, earlier in this loop, if the transport is lost at sea.
61
+ if (areaUnit.destroyed()) {
62
+ return;
63
+ }
64
+ ruleRegistry.process(Destroyed_1.default, areaUnit, unit.player());
65
+ });
66
+ }))),
67
+ new Detonated_1.default(id('halve-cities'), new Priority_1.default(exports.HALVE_CITIES_PRIORITY), new Effect_1.default((unit, tile) => stopped(unit, tile)
68
+ ? undefined
69
+ : area(tile).forEach((areaTile) => {
70
+ const city = cityRegistry.getByTile(areaTile);
71
+ if (city === null) {
72
+ return;
73
+ }
74
+ (0, exports.halveCity)(city, unit, cityGrowthRegistry);
75
+ }))),
76
+ new Detonated_1.default(id('fallout'), new Low_1.default(), new Effect_1.default((unit, tile) => stopped(unit, tile)
77
+ ? undefined
78
+ : area(tile)
79
+ .filter((areaTile) => areaTile.isLand() &&
80
+ cityRegistry.getByTile(areaTile) === null &&
81
+ !tileImprovementRegistry
82
+ .getByTile(areaTile)
83
+ .some((improvement) => improvement instanceof Pollution))
84
+ .forEach((areaTile) => {
85
+ if (randomNumberGenerator() >= falloutChance) {
86
+ return;
87
+ }
88
+ // Building it processes `Built`, which puts it on the tile.
89
+ new Pollution(areaTile, ruleRegistry);
90
+ }))),
91
+ ];
92
+ };
93
+ exports.detonatedRules = detonatedRules;
94
+ exports.default = exports.detonatedRules;
95
+ //# sourceMappingURL=detonatedRules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detonatedRules.js","sourceRoot":"","sources":["detonatedRules.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,196 @@
1
+ import {
2
+ CityGrowthRegistry,
3
+ instance as cityGrowthRegistryInstance,
4
+ } from '@civ-clone/core-city-growth/CityGrowthRegistry';
5
+ import {
6
+ CityRegistry,
7
+ instance as cityRegistryInstance,
8
+ } from '@civ-clone/core-city/CityRegistry';
9
+ import {
10
+ Engine,
11
+ instance as engineInstance,
12
+ } from '@civ-clone/core-engine/Engine';
13
+ import {
14
+ RuleRegistry,
15
+ instance as ruleRegistryInstance,
16
+ } from '@civ-clone/core-rule/RuleRegistry';
17
+ import {
18
+ TileImprovementRegistry,
19
+ instance as tileImprovementRegistryInstance,
20
+ } from '@civ-clone/core-tile-improvement/TileImprovementRegistry';
21
+ import {
22
+ UnitRegistry,
23
+ instance as unitRegistryInstance,
24
+ } from '@civ-clone/core-unit/UnitRegistry';
25
+ import City from '@civ-clone/core-city/City';
26
+ import Destroyed from '@civ-clone/core-unit/Rules/Destroyed';
27
+ import Detonated from '@civ-clone/base-unit-action-nuclear-attack/Rules/Detonated';
28
+ import Effect from '@civ-clone/core-rule/Effect';
29
+ import High from '@civ-clone/core-rule/Priorities/High';
30
+ import Low from '@civ-clone/core-rule/Priorities/Low';
31
+ import Priority from '@civ-clone/core-rule/Priority';
32
+ import Tile from '@civ-clone/core-world/Tile';
33
+ import TileImprovement from '@civ-clone/core-tile-improvement/TileImprovement';
34
+ import Unit from '@civ-clone/core-unit/Unit';
35
+ import { instance as rngInstance } from '@civ-clone/core-random';
36
+
37
+ /**
38
+ * Where `unit/detonated/halve-cities` runs among the `Detonated` rules: after the `Normal` ones (the units destroyed)
39
+ * and before `Low` (the fallout), so a rule that takes its place runs there too.
40
+ */
41
+ export const HALVE_CITIES_PRIORITY = 2500;
42
+
43
+ /** `city` loses half its size, rounded down, to `unit`'s detonation, so a city is never destroyed by it. */
44
+ export const halveCity = (
45
+ city: City,
46
+ unit: Unit,
47
+ cityGrowthRegistry: CityGrowthRegistry = cityGrowthRegistryInstance
48
+ ): void => {
49
+ const cityGrowth = cityGrowthRegistry.getByCity(city),
50
+ loss = Math.floor(cityGrowth.size() / 2);
51
+
52
+ for (let i = 0; i < loss; i++) {
53
+ cityGrowth.shrink(unit);
54
+ }
55
+ };
56
+
57
+ export interface DetonatedDependencies {
58
+ cityGrowthRegistry?: CityGrowthRegistry;
59
+ cityRegistry?: CityRegistry;
60
+ engine?: Engine;
61
+ randomNumberGenerator?: () => number;
62
+ ruleRegistry?: RuleRegistry;
63
+ tileImprovementRegistry?: TileImprovementRegistry;
64
+ unitRegistry?: UnitRegistry;
65
+ }
66
+
67
+ export interface DetonatedOptions {
68
+ // Whether the units in `city` are spared (Civ1's SDI Defense: the city is still halved and the land falls out).
69
+ sparesUnits: (city: City) => boolean;
70
+ // Whether nothing happens at all over `tile` (Civ2's SDI Defense stops the whole attack). Without it, every
71
+ // detonation goes off. Asked once per rule, by the destroy, halve and fallout rules; the client is told either way.
72
+ vetoes?: (unit: Unit, tile: Tile) => boolean;
73
+ // The fallout a detonation leaves on land.
74
+ Pollution: new (tile: Tile, ruleRegistry: RuleRegistry) => TileImprovement;
75
+ // The chance each land square in the area without a city or fallout gets some.
76
+ falloutChance: number;
77
+ }
78
+
79
+ /**
80
+ * A ruleset's `Detonated` rules, with ids `<prefix>:unit/detonated/<name>` as civ1-unit's are, over the square a
81
+ * nuclear weapon detonates over and the 8 around it: tell the client, destroy every unit (but those `sparesUnits`
82
+ * keeps), halve every city, and fall out on the land.
83
+ */
84
+ export const detonatedRules = (
85
+ prefix: string,
86
+ {
87
+ cityGrowthRegistry = cityGrowthRegistryInstance,
88
+ cityRegistry = cityRegistryInstance,
89
+ engine = engineInstance,
90
+ randomNumberGenerator = rngInstance,
91
+ ruleRegistry = ruleRegistryInstance,
92
+ tileImprovementRegistry = tileImprovementRegistryInstance,
93
+ unitRegistry = unitRegistryInstance,
94
+ }: DetonatedDependencies,
95
+ { sparesUnits, Pollution, falloutChance, vetoes }: DetonatedOptions
96
+ ): Detonated[] => {
97
+ const id = (name: string): string => `${prefix}:unit/detonated/${name}`,
98
+ area = (tile: Tile): Tile[] => [tile, ...tile.getNeighbours()],
99
+ // `vetoes` is asked once per detonation, by `emit` (which runs first, `High`), and the answer is kept for the
100
+ // three rules after it, so destroying the units can't change it halfway. Without `vetoes`, nothing is kept or asked.
101
+ vetoed = new WeakMap<Unit, boolean>(),
102
+ stopped = (unit: Unit, tile: Tile): boolean =>
103
+ vetoes !== undefined && (vetoed.get(unit) ?? vetoes(unit, tile));
104
+
105
+ return [
106
+ new Detonated(
107
+ // Before anything changes, so a client can see what's there to be hit.
108
+ id('emit'),
109
+ new High(),
110
+ new Effect((unit: Unit, tile: Tile): void => {
111
+ if (vetoes !== undefined) {
112
+ vetoed.set(unit, vetoes(unit, tile));
113
+ }
114
+
115
+ engine.emit('unit:nuclear-detonation', unit, tile);
116
+ })
117
+ ),
118
+
119
+ new Detonated(
120
+ id('destroy-units'),
121
+ new Effect((unit: Unit, tile: Tile): void =>
122
+ stopped(unit, tile)
123
+ ? undefined
124
+ : area(tile).forEach((areaTile: Tile): void => {
125
+ const city = cityRegistry.getByTile(areaTile);
126
+
127
+ if (city !== null && sparesUnits(city)) {
128
+ engine.emit('city:sdi-protected', city, unit);
129
+
130
+ return;
131
+ }
132
+
133
+ unitRegistry
134
+ .getByTile(areaTile)
135
+ .forEach((areaUnit: Unit): void => {
136
+ // Cargo is destroyed with its transport, earlier in this loop, if the transport is lost at sea.
137
+ if (areaUnit.destroyed()) {
138
+ return;
139
+ }
140
+
141
+ ruleRegistry.process(Destroyed, areaUnit, unit.player());
142
+ });
143
+ })
144
+ )
145
+ ),
146
+
147
+ new Detonated(
148
+ id('halve-cities'),
149
+ new Priority(HALVE_CITIES_PRIORITY),
150
+ new Effect((unit: Unit, tile: Tile): void =>
151
+ stopped(unit, tile)
152
+ ? undefined
153
+ : area(tile).forEach((areaTile: Tile): void => {
154
+ const city = cityRegistry.getByTile(areaTile);
155
+
156
+ if (city === null) {
157
+ return;
158
+ }
159
+
160
+ halveCity(city, unit, cityGrowthRegistry);
161
+ })
162
+ )
163
+ ),
164
+
165
+ new Detonated(
166
+ id('fallout'),
167
+ new Low(),
168
+ new Effect((unit: Unit, tile: Tile): void =>
169
+ stopped(unit, tile)
170
+ ? undefined
171
+ : area(tile)
172
+ .filter(
173
+ (areaTile: Tile): boolean =>
174
+ areaTile.isLand() &&
175
+ cityRegistry.getByTile(areaTile) === null &&
176
+ !tileImprovementRegistry
177
+ .getByTile(areaTile)
178
+ .some(
179
+ (improvement: TileImprovement): boolean =>
180
+ improvement instanceof Pollution
181
+ )
182
+ )
183
+ .forEach((areaTile: Tile): void => {
184
+ if (randomNumberGenerator() >= falloutChance) {
185
+ return;
186
+ }
187
+
188
+ // Building it processes `Built`, which puts it on the tile.
189
+ new Pollution(areaTile, ruleRegistry);
190
+ })
191
+ )
192
+ ),
193
+ ];
194
+ };
195
+
196
+ export default detonatedRules;
@@ -0,0 +1,27 @@
1
+ import { Engine } from '@civ-clone/core-engine/Engine';
2
+ import { InteractionRegistry } from '@civ-clone/core-diplomacy/InteractionRegistry';
3
+ import { RuleRegistry } from '@civ-clone/core-rule/RuleRegistry';
4
+ import { Turn } from '@civ-clone/core-turn-based-game/Turn';
5
+ import CityInvestigated from '@civ-clone/base-unit-action-investigate-city/Rules/CityInvestigated';
6
+ import EmbassyEstablished from '@civ-clone/base-unit-action-establish-embassy/Rules/EmbassyEstablished';
7
+ import LeaderMet from '@civ-clone/base-unit-action-meet-with-leader/Rules/LeaderMet';
8
+ export interface DiplomatDependencies {
9
+ engine?: Engine;
10
+ interactionRegistry?: InteractionRegistry;
11
+ ruleRegistry?: RuleRegistry;
12
+ turn?: Turn;
13
+ }
14
+ /**
15
+ * A ruleset's rules for the diplomatic missions that need no numbers of its own, with ids `<prefix>:unit/<event>/<name>`
16
+ * as civ1-unit's are: an embassy is a one-way record for the Diplomat's player; an investigation is the client's to
17
+ * show; meeting a leader ends the Diplomat's turn and opens talks, which are the client's.
18
+ */
19
+ export declare const diplomatRules: (
20
+ prefix: string,
21
+ { engine, interactionRegistry, ruleRegistry, turn }: DiplomatDependencies
22
+ ) => {
23
+ embassyEstablished: EmbassyEstablished[];
24
+ cityInvestigated: CityInvestigated[];
25
+ leaderMet: LeaderMet[];
26
+ };
27
+ export default diplomatRules;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.diplomatRules = void 0;
4
+ const Engine_1 = require("@civ-clone/core-engine/Engine");
5
+ const InteractionRegistry_1 = require("@civ-clone/core-diplomacy/InteractionRegistry");
6
+ const RuleRegistry_1 = require("@civ-clone/core-rule/RuleRegistry");
7
+ const Turn_1 = require("@civ-clone/core-turn-based-game/Turn");
8
+ const CityInvestigated_1 = require("@civ-clone/base-unit-action-investigate-city/Rules/CityInvestigated");
9
+ const Effect_1 = require("@civ-clone/core-rule/Effect");
10
+ const Embassy_1 = require("@civ-clone/base-unit-action-establish-embassy/Embassy");
11
+ const EmbassyEstablished_1 = require("@civ-clone/base-unit-action-establish-embassy/Rules/EmbassyEstablished");
12
+ const LeaderMet_1 = require("@civ-clone/base-unit-action-meet-with-leader/Rules/LeaderMet");
13
+ /**
14
+ * A ruleset's rules for the diplomatic missions that need no numbers of its own, with ids `<prefix>:unit/<event>/<name>`
15
+ * as civ1-unit's are: an embassy is a one-way record for the Diplomat's player; an investigation is the client's to
16
+ * show; meeting a leader ends the Diplomat's turn and opens talks, which are the client's.
17
+ */
18
+ const diplomatRules = (prefix, { engine = Engine_1.instance, interactionRegistry = InteractionRegistry_1.instance, ruleRegistry = RuleRegistry_1.instance, turn = Turn_1.instance, }) => ({
19
+ embassyEstablished: [
20
+ new EmbassyEstablished_1.default(`${prefix}:unit/embassy-established/register`, new Effect_1.default((unit, city) => {
21
+ interactionRegistry.register(new Embassy_1.default(unit.player(), city.player(), ruleRegistry, turn));
22
+ engine.emit('player:embassy-established', unit.player(), city.player());
23
+ return true;
24
+ })),
25
+ ],
26
+ cityInvestigated: [
27
+ new CityInvestigated_1.default(`${prefix}:unit/city-investigated/emit`, new Effect_1.default((unit, city) => {
28
+ engine.emit('city:investigated', city, unit.player());
29
+ return true;
30
+ })),
31
+ ],
32
+ leaderMet: [
33
+ new LeaderMet_1.default(`${prefix}:unit/leader-met/meet`, new Effect_1.default((unit, player) => {
34
+ unit.moves().set(0);
35
+ engine.emit('player:meet-with-leader', unit.player(), player);
36
+ })),
37
+ ],
38
+ });
39
+ exports.diplomatRules = diplomatRules;
40
+ exports.default = exports.diplomatRules;
41
+ //# sourceMappingURL=diplomatRules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diplomatRules.js","sourceRoot":"","sources":["diplomatRules.ts"],"names":[],"mappings":";;;AAAA,0DAGuC;AACvC,uFAGuD;AACvD,oEAG2C;AAC3C,+DAG8C;AAE9C,0GAAmG;AACnG,wDAAiD;AACjD,mFAA4E;AAC5E,+GAAwG;AACxG,4FAAqF;AAWrF;;;;GAIG;AACI,MAAM,aAAa,GAAG,CAC3B,MAAc,EACd,EACE,MAAM,GAAG,iBAAc,EACvB,mBAAmB,GAAG,8BAA2B,EACjD,YAAY,GAAG,uBAAoB,EACnC,IAAI,GAAG,eAAY,GACE,EACvB,EAAE,CAAC,CAAC;IACJ,kBAAkB,EAAE;QAClB,IAAI,4BAAkB,CACpB,GAAG,MAAM,oCAAoC,EAC7C,IAAI,gBAAM,CAAC,CAAC,IAAU,EAAE,IAAU,EAAW,EAAE;YAC7C,mBAAmB,CAAC,QAAQ,CAC1B,IAAI,iBAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,YAAY,EAAE,IAAI,CAAU,CACvE,CAAC;YAEF,MAAM,CAAC,IAAI,CAAC,4BAA4B,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YAExE,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CACH;KACF;IACD,gBAAgB,EAAE;QAChB,IAAI,0BAAgB,CAClB,GAAG,MAAM,8BAA8B,EACvC,IAAI,gBAAM,CAAC,CAAC,IAAU,EAAE,IAAU,EAAW,EAAE;YAC7C,MAAM,CAAC,IAAI,CAAC,mBAAmB,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YAEtD,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CACH;KACF;IACD,SAAS,EAAE;QACT,IAAI,mBAAS,CACX,GAAG,MAAM,uBAAuB,EAChC,IAAI,gBAAM,CAAC,CAAC,IAAU,EAAE,MAAc,EAAQ,EAAE;YAC9C,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAEpB,MAAM,CAAC,IAAI,CAAC,yBAAyB,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,MAAM,CAAC,CAAC;QAChE,CAAC,CAAC,CACH;KACF;CACF,CAAC,CAAC;AA3CU,QAAA,aAAa,iBA2CvB;AAEH,kBAAe,qBAAa,CAAC"}
@@ -0,0 +1,83 @@
1
+ import {
2
+ Engine,
3
+ instance as engineInstance,
4
+ } from '@civ-clone/core-engine/Engine';
5
+ import {
6
+ InteractionRegistry,
7
+ instance as interactionRegistryInstance,
8
+ } from '@civ-clone/core-diplomacy/InteractionRegistry';
9
+ import {
10
+ RuleRegistry,
11
+ instance as ruleRegistryInstance,
12
+ } from '@civ-clone/core-rule/RuleRegistry';
13
+ import {
14
+ Turn,
15
+ instance as turnInstance,
16
+ } from '@civ-clone/core-turn-based-game/Turn';
17
+ import City from '@civ-clone/core-city/City';
18
+ import CityInvestigated from '@civ-clone/base-unit-action-investigate-city/Rules/CityInvestigated';
19
+ import Effect from '@civ-clone/core-rule/Effect';
20
+ import Embassy from '@civ-clone/base-unit-action-establish-embassy/Embassy';
21
+ import EmbassyEstablished from '@civ-clone/base-unit-action-establish-embassy/Rules/EmbassyEstablished';
22
+ import LeaderMet from '@civ-clone/base-unit-action-meet-with-leader/Rules/LeaderMet';
23
+ import Player from '@civ-clone/core-player/Player';
24
+ import Unit from '@civ-clone/core-unit/Unit';
25
+
26
+ export interface DiplomatDependencies {
27
+ engine?: Engine;
28
+ interactionRegistry?: InteractionRegistry;
29
+ ruleRegistry?: RuleRegistry;
30
+ turn?: Turn;
31
+ }
32
+
33
+ /**
34
+ * A ruleset's rules for the diplomatic missions that need no numbers of its own, with ids `<prefix>:unit/<event>/<name>`
35
+ * as civ1-unit's are: an embassy is a one-way record for the Diplomat's player; an investigation is the client's to
36
+ * show; meeting a leader ends the Diplomat's turn and opens talks, which are the client's.
37
+ */
38
+ export const diplomatRules = (
39
+ prefix: string,
40
+ {
41
+ engine = engineInstance,
42
+ interactionRegistry = interactionRegistryInstance,
43
+ ruleRegistry = ruleRegistryInstance,
44
+ turn = turnInstance,
45
+ }: DiplomatDependencies
46
+ ) => ({
47
+ embassyEstablished: [
48
+ new EmbassyEstablished(
49
+ `${prefix}:unit/embassy-established/register`,
50
+ new Effect((unit: Unit, city: City): boolean => {
51
+ interactionRegistry.register(
52
+ new Embassy(unit.player(), city.player(), ruleRegistry, turn) as never
53
+ );
54
+
55
+ engine.emit('player:embassy-established', unit.player(), city.player());
56
+
57
+ return true;
58
+ })
59
+ ),
60
+ ],
61
+ cityInvestigated: [
62
+ new CityInvestigated(
63
+ `${prefix}:unit/city-investigated/emit`,
64
+ new Effect((unit: Unit, city: City): boolean => {
65
+ engine.emit('city:investigated', city, unit.player());
66
+
67
+ return true;
68
+ })
69
+ ),
70
+ ],
71
+ leaderMet: [
72
+ new LeaderMet(
73
+ `${prefix}:unit/leader-met/meet`,
74
+ new Effect((unit: Unit, player: Player): void => {
75
+ unit.moves().set(0);
76
+
77
+ engine.emit('player:meet-with-leader', unit.player(), player);
78
+ })
79
+ ),
80
+ ],
81
+ });
82
+
83
+ export default diplomatRules;