@civ-clone/base-unit-lifecycle 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -0
- package/lib/detonatedRules.d.ts +56 -0
- package/lib/detonatedRules.js +95 -0
- package/lib/detonatedRules.js.map +1 -0
- package/lib/detonatedRules.ts +196 -0
- package/lib/diplomatRules.d.ts +27 -0
- package/lib/diplomatRules.js +41 -0
- package/lib/diplomatRules.js.map +1 -0
- package/lib/diplomatRules.ts +83 -0
- package/lib/lifecycleRules.d.ts +118 -0
- package/lib/lifecycleRules.js +126 -0
- package/lib/lifecycleRules.js.map +1 -0
- package/lib/lifecycleRules.ts +378 -0
- package/lib/movedRules.d.ts +44 -0
- package/lib/movedRules.js +126 -0
- package/lib/movedRules.js.map +1 -0
- package/lib/movedRules.ts +300 -0
- package/lib/treatyPartner.d.ts +26 -0
- package/lib/treatyPartner.js +38 -0
- package/lib/treatyPartner.js.map +1 -0
- package/lib/treatyPartner.ts +78 -0
- package/package.json +20 -2
- package/tests/fixtures/civ1-unit-rules.json +89 -0
- package/tests/movedRules.test.ts +256 -0
- package/tests/rules.test.ts +434 -0
package/README.md
CHANGED
|
@@ -32,5 +32,31 @@ 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` and `vetoes` are for other rulesets (Civ2's short step and SDI
|
|
59
|
+
Defense), and leaving them out changes nothing.
|
|
60
|
+
|
|
35
61
|
A library: no `main`, so it registers nothing on its own. Import what you need, for example
|
|
36
62
|
`@civ-clone/base-unit-lifecycle/lib/destroyed`.
|
|
@@ -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;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { CityRegistry } from '@civ-clone/core-city/CityRegistry';
|
|
2
|
+
import { Engine } from '@civ-clone/core-engine/Engine';
|
|
3
|
+
import { RuleRegistry } from '@civ-clone/core-rule/RuleRegistry';
|
|
4
|
+
import { TransportRegistry } from '@civ-clone/core-unit-transport/TransportRegistry';
|
|
5
|
+
import { UnitImprovementRegistry } from '@civ-clone/core-unit-improvement/UnitImprovementRegistry';
|
|
6
|
+
import { UnitLossRegistry } from '@civ-clone/core-unit/UnitLossRegistry';
|
|
7
|
+
import { UnitPlayerActionType } from './playerAction';
|
|
8
|
+
import { UnitRegistry } from '@civ-clone/core-unit/UnitRegistry';
|
|
9
|
+
import Action from '@civ-clone/core-player/Rules/Action';
|
|
10
|
+
import Activate from '@civ-clone/core-unit/Rules/Activate';
|
|
11
|
+
import CanStow from '@civ-clone/core-unit-transport/Rules/CanStow';
|
|
12
|
+
import Created from '@civ-clone/core-unit/Rules/Created';
|
|
13
|
+
import Defeated from '@civ-clone/core-unit/Rules/Defeated';
|
|
14
|
+
import Destroyed from '@civ-clone/core-unit/Rules/Destroyed';
|
|
15
|
+
import ExpectedMovementCost from '@civ-clone/core-world-path/Rules/ExpectedMovementCost';
|
|
16
|
+
import Halted from '@civ-clone/base-unit-action-goto/Rules/Halted';
|
|
17
|
+
import Impassable from '@civ-clone/core-world-path/Rules/Impassable';
|
|
18
|
+
import LostAtSea from '@civ-clone/core-unit-transport/Rules/LostAtSea';
|
|
19
|
+
import Player from '@civ-clone/core-player/Player';
|
|
20
|
+
import PlayerAction from '@civ-clone/core-player/PlayerAction';
|
|
21
|
+
import Stowed from '@civ-clone/core-unit-transport/Rules/Stowed';
|
|
22
|
+
import Tile from '@civ-clone/core-world/Tile';
|
|
23
|
+
import Transferred from '@civ-clone/core-unit/Rules/Transferred';
|
|
24
|
+
import Unit from '@civ-clone/core-unit/Unit';
|
|
25
|
+
import UnitImprovement from '@civ-clone/core-unit-improvement/UnitImprovement';
|
|
26
|
+
import Unsupported from '@civ-clone/core-unit/Rules/Unsupported';
|
|
27
|
+
import ValidateMove from '@civ-clone/core-unit/Rules/ValidateMove';
|
|
28
|
+
export interface LifecycleDependencies {
|
|
29
|
+
cityRegistry?: CityRegistry;
|
|
30
|
+
engine?: Engine;
|
|
31
|
+
randomNumberGenerator?: () => number;
|
|
32
|
+
ruleRegistry?: RuleRegistry;
|
|
33
|
+
transportRegistry?: TransportRegistry;
|
|
34
|
+
unitImprovementRegistry?: UnitImprovementRegistry;
|
|
35
|
+
unitLossRegistry?: UnitLossRegistry;
|
|
36
|
+
unitRegistry?: UnitRegistry;
|
|
37
|
+
}
|
|
38
|
+
export interface LifecycleBaseOptions {
|
|
39
|
+
ActiveUnit: UnitPlayerActionType<PlayerAction>;
|
|
40
|
+
InactiveUnit: UnitPlayerActionType<PlayerAction>;
|
|
41
|
+
removedOnActivate: (typeof UnitImprovement)[];
|
|
42
|
+
stowable: (typeof Unit)[];
|
|
43
|
+
partnerOf?: (unit: Unit, tile: Tile) => Player | null;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* How a unit short of a step's moves fares: Civ1's `shortfallFactor` (`spendShort`), or a ruleset's own `shortStep`,
|
|
47
|
+
* which then needs no factor.
|
|
48
|
+
*/
|
|
49
|
+
export type LifecycleOptions = LifecycleBaseOptions &
|
|
50
|
+
(
|
|
51
|
+
| {
|
|
52
|
+
shortfallFactor: number;
|
|
53
|
+
shortStep?: undefined;
|
|
54
|
+
}
|
|
55
|
+
| {
|
|
56
|
+
shortfallFactor?: number;
|
|
57
|
+
shortStep: ShortStep;
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
/**
|
|
61
|
+
* A ruleset's own short step: whether `unit`, with `remaining` of its `movement` moves, gets onto a square costing
|
|
62
|
+
* `cost` (one draw of `randomNumberGenerator` at most), and what such a step is worth on average to route planning.
|
|
63
|
+
* The unit's moves are spent either way.
|
|
64
|
+
*/
|
|
65
|
+
export interface ShortStep {
|
|
66
|
+
succeeds: (
|
|
67
|
+
unit: Unit,
|
|
68
|
+
remaining: number,
|
|
69
|
+
movement: number,
|
|
70
|
+
cost: number,
|
|
71
|
+
randomNumberGenerator: () => number
|
|
72
|
+
) => boolean;
|
|
73
|
+
expectedCost: (movement: number, cost: number) => number;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* A ruleset's unit lifecycle rules, by the rule type they are, in the order each type's rules run. Their ids are
|
|
77
|
+
* `<prefix>:unit/<type>/<name>` (`<prefix>:player/action/<name>` for the player actions), as civ1-unit's are, so a
|
|
78
|
+
* ruleset registers each list where it wants it and keeps the ids another package may name.
|
|
79
|
+
*/
|
|
80
|
+
export declare const lifecycleRules: (
|
|
81
|
+
prefix: string,
|
|
82
|
+
{
|
|
83
|
+
cityRegistry,
|
|
84
|
+
engine,
|
|
85
|
+
randomNumberGenerator,
|
|
86
|
+
ruleRegistry,
|
|
87
|
+
transportRegistry,
|
|
88
|
+
unitImprovementRegistry,
|
|
89
|
+
unitLossRegistry,
|
|
90
|
+
unitRegistry,
|
|
91
|
+
}: LifecycleDependencies,
|
|
92
|
+
{
|
|
93
|
+
ActiveUnit,
|
|
94
|
+
InactiveUnit,
|
|
95
|
+
removedOnActivate,
|
|
96
|
+
stowable,
|
|
97
|
+
partnerOf,
|
|
98
|
+
shortfallFactor,
|
|
99
|
+
shortStep,
|
|
100
|
+
}: LifecycleOptions
|
|
101
|
+
) => {
|
|
102
|
+
activate: Activate[];
|
|
103
|
+
canStow: CanStow[];
|
|
104
|
+
created: Created[];
|
|
105
|
+
defeated: Defeated[];
|
|
106
|
+
destroyed: Destroyed[];
|
|
107
|
+
expectedMovementCost: ExpectedMovementCost[];
|
|
108
|
+
halted: Halted[];
|
|
109
|
+
impassable: Impassable[];
|
|
110
|
+
lostAtSea: LostAtSea[];
|
|
111
|
+
playerAction: Action[];
|
|
112
|
+
stowed: Stowed[];
|
|
113
|
+
transferred: Transferred[];
|
|
114
|
+
unsupported: Unsupported[];
|
|
115
|
+
validateMove: ValidateMove[];
|
|
116
|
+
};
|
|
117
|
+
export type LifecycleRules = ReturnType<typeof lifecycleRules>;
|
|
118
|
+
export default lifecycleRules;
|