@civ-clone/base-unit-lifecycle 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +4 -0
- package/.github/workflows/build-on-push.yml +39 -0
- package/.prettierrc +4 -0
- package/LICENSE +21 -0
- package/README.md +61 -2
- package/lib/activate.d.ts +15 -0
- package/lib/activate.js +27 -0
- package/lib/activate.js.map +1 -0
- package/lib/activate.ts +47 -0
- package/lib/canStow.d.ts +8 -0
- package/lib/canStow.js +17 -0
- package/lib/canStow.js.map +1 -0
- package/lib/canStow.ts +25 -0
- package/lib/created.d.ts +9 -0
- package/lib/created.js +19 -0
- package/lib/created.js.map +1 -0
- package/lib/created.ts +24 -0
- package/lib/defeated.d.ts +25 -0
- package/lib/defeated.js +33 -0
- package/lib/defeated.js.map +1 -0
- package/lib/defeated.ts +55 -0
- package/lib/destroyed.d.ts +37 -0
- package/lib/destroyed.js +74 -0
- package/lib/destroyed.js.map +1 -0
- package/lib/destroyed.ts +106 -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/halted.d.ts +6 -0
- package/lib/halted.js +10 -0
- package/lib/halted.js.map +1 -0
- package/lib/halted.ts +11 -0
- package/lib/impassable.d.ts +8 -0
- package/lib/impassable.js +15 -0
- package/lib/impassable.js.map +1 -0
- package/lib/impassable.ts +19 -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/lostAtSea.d.ts +12 -0
- package/lib/lostAtSea.js +26 -0
- package/lib/lostAtSea.js.map +1 -0
- package/lib/lostAtSea.ts +37 -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/playerAction.d.ts +22 -0
- package/lib/playerAction.js +28 -0
- package/lib/playerAction.js.map +1 -0
- package/lib/playerAction.ts +64 -0
- package/lib/stowed.d.ts +2 -0
- package/lib/stowed.js +8 -0
- package/lib/stowed.js.map +1 -0
- package/lib/stowed.ts +6 -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/lib/unsupported.d.ts +6 -0
- package/lib/unsupported.js +9 -0
- package/lib/unsupported.js.map +1 -0
- package/lib/unsupported.ts +10 -0
- package/lib/validateMove.d.ts +11 -0
- package/lib/validateMove.js +26 -0
- package/lib/validateMove.js.map +1 -0
- package/lib/validateMove.ts +36 -0
- package/package.json +61 -4
- package/tests/fixtures/civ1-unit-rules.json +89 -0
- package/tests/lifecycle.test.ts +657 -0
- package/tests/movedRules.test.ts +256 -0
- package/tests/rules.test.ts +434 -0
- package/tsconfig.json +16 -0
package/lib/destroyed.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import Engine from '@civ-clone/core-engine/Engine';
|
|
2
|
+
import { ITransport } from '@civ-clone/core-unit-transport/Transport';
|
|
3
|
+
import Player from '@civ-clone/core-player/Player';
|
|
4
|
+
import Stowed from '@civ-clone/base-unit-action-embark/Busy/Stowed';
|
|
5
|
+
import TransportManifest from '@civ-clone/core-unit-transport/TransportManifest';
|
|
6
|
+
import TransportRegistry from '@civ-clone/core-unit-transport/TransportRegistry';
|
|
7
|
+
import Unit from '@civ-clone/core-unit/Unit';
|
|
8
|
+
import UnitImprovementRegistry from '@civ-clone/core-unit-improvement/UnitImprovementRegistry';
|
|
9
|
+
import UnitLossRegistry from '@civ-clone/core-unit/UnitLossRegistry';
|
|
10
|
+
import { Water } from '@civ-clone/core-terrain/Types';
|
|
11
|
+
|
|
12
|
+
// What a ruleset's `Destroyed` rules ask and do when `unit` is destroyed. `player` destroyed it, or is `null` when no
|
|
13
|
+
// one did (disbanding, founding or joining a city, a spent unit...).
|
|
14
|
+
|
|
15
|
+
// Emits `unit:destroyed` with the unit and the player who destroyed it.
|
|
16
|
+
export const emitDestroyed =
|
|
17
|
+
(engine: Engine) =>
|
|
18
|
+
(unit: Unit, player: Player | null): void => {
|
|
19
|
+
engine.emit('unit:destroyed', unit, player);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// Another player destroyed the unit.
|
|
23
|
+
export const destroyedByAnother = (
|
|
24
|
+
unit: Unit,
|
|
25
|
+
player: Player | null
|
|
26
|
+
): boolean => player !== null && player !== unit.player();
|
|
27
|
+
|
|
28
|
+
// The unit isn't marked destroyed yet: a rule that should act once per unit asks it before `deactivate` runs.
|
|
29
|
+
export const notYetDestroyed = (unit: Unit): boolean => !unit.destroyed();
|
|
30
|
+
|
|
31
|
+
// Records the unit's type as a loss of its player's in `unitLossRegistry`.
|
|
32
|
+
export const countLoss =
|
|
33
|
+
(unitLossRegistry: UnitLossRegistry) =>
|
|
34
|
+
(unit: Unit): void => {
|
|
35
|
+
unitLossRegistry.record(unit.player(), unit.sourceClass() as typeof Unit);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// Makes the unit inactive and marks it destroyed.
|
|
39
|
+
export const deactivate = (unit: Unit): void => {
|
|
40
|
+
unit.setActive(false);
|
|
41
|
+
unit.setDestroyed();
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Removes the unit's improvements (veteran status, fortification...).
|
|
45
|
+
export const removeImprovements =
|
|
46
|
+
(unitImprovementRegistry: UnitImprovementRegistry) =>
|
|
47
|
+
(unit: Unit): void =>
|
|
48
|
+
unitImprovementRegistry
|
|
49
|
+
.getByUnit(unit)
|
|
50
|
+
.forEach((unitImprovement) =>
|
|
51
|
+
unitImprovementRegistry.unregister(unitImprovement)
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
// Takes a unit off its transport. Nothing clears `Stowed` on its own (its criterion is `() => false`), so a unit taken
|
|
55
|
+
// off a transport, destroyed or not, would otherwise stay stowed aboard nothing.
|
|
56
|
+
export const leaveTransport =
|
|
57
|
+
(transportRegistry: TransportRegistry) =>
|
|
58
|
+
(manifest: TransportManifest): void => {
|
|
59
|
+
const cargo = manifest.unit();
|
|
60
|
+
|
|
61
|
+
transportRegistry.unregister(manifest);
|
|
62
|
+
|
|
63
|
+
if (cargo.busy() instanceof Stowed) {
|
|
64
|
+
cargo.setBusy();
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// The unit is a transport with something aboard.
|
|
69
|
+
export const carriesCargo =
|
|
70
|
+
(transportRegistry: TransportRegistry) =>
|
|
71
|
+
(unit: Unit): boolean =>
|
|
72
|
+
transportRegistry.getByTransport(unit as unknown as ITransport).length > 0;
|
|
73
|
+
|
|
74
|
+
// Takes everything off the transport (`leaveTransport`). At sea (on `Water`) the cargo goes down with it, destroyed by
|
|
75
|
+
// `player`; in a city it stays in the city.
|
|
76
|
+
export const loseCargo = (transportRegistry: TransportRegistry) => {
|
|
77
|
+
const leave = leaveTransport(transportRegistry);
|
|
78
|
+
|
|
79
|
+
return (unit: Unit, player: Player | null): void =>
|
|
80
|
+
transportRegistry
|
|
81
|
+
.getByTransport(unit as unknown as ITransport)
|
|
82
|
+
// A copy: unregistering changes the list.
|
|
83
|
+
.slice()
|
|
84
|
+
.forEach((manifest: TransportManifest): void => {
|
|
85
|
+
const cargo = manifest.unit();
|
|
86
|
+
|
|
87
|
+
leave(manifest);
|
|
88
|
+
|
|
89
|
+
if (unit.tile().terrain() instanceof Water && !cargo.destroyed()) {
|
|
90
|
+
cargo.destroy(player);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// The unit is aboard a transport.
|
|
96
|
+
export const isAboard =
|
|
97
|
+
(transportRegistry: TransportRegistry) =>
|
|
98
|
+
(unit: Unit): boolean =>
|
|
99
|
+
transportRegistry.hasUnit(unit);
|
|
100
|
+
|
|
101
|
+
// Takes the unit off the transport it's aboard (`leaveTransport`).
|
|
102
|
+
export const leaveOwnTransport = (transportRegistry: TransportRegistry) => {
|
|
103
|
+
const leave = leaveTransport(transportRegistry);
|
|
104
|
+
|
|
105
|
+
return (unit: Unit): void => leave(transportRegistry.getByUnit(unit));
|
|
106
|
+
};
|
|
@@ -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;
|
package/lib/halted.d.ts
ADDED
package/lib/halted.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.emitHalted = void 0;
|
|
4
|
+
// Emits `unit:halted` with the unit and its destination: a GoTo stopped next to it, for the player to choose what to
|
|
5
|
+
// do there.
|
|
6
|
+
const emitHalted = (engine) => (unit, target) => {
|
|
7
|
+
engine.emit('unit:halted', unit, target);
|
|
8
|
+
};
|
|
9
|
+
exports.emitHalted = emitHalted;
|
|
10
|
+
//# sourceMappingURL=halted.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"halted.js","sourceRoot":"","sources":["halted.ts"],"names":[],"mappings":";;;AAIA,qHAAqH;AACrH,aAAa;AACN,MAAM,UAAU,GACrB,CAAC,MAAc,EAAE,EAAE,CACnB,CAAC,IAAU,EAAE,MAAY,EAAQ,EAAE;IACjC,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AAC3C,CAAC,CAAC;AAJS,QAAA,UAAU,cAInB"}
|
package/lib/halted.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import Engine from '@civ-clone/core-engine/Engine';
|
|
2
|
+
import Tile from '@civ-clone/core-world/Tile';
|
|
3
|
+
import Unit from '@civ-clone/core-unit/Unit';
|
|
4
|
+
|
|
5
|
+
// Emits `unit:halted` with the unit and its destination: a GoTo stopped next to it, for the player to choose what to
|
|
6
|
+
// do there.
|
|
7
|
+
export const emitHalted =
|
|
8
|
+
(engine: Engine) =>
|
|
9
|
+
(unit: Unit, target: Tile): void => {
|
|
10
|
+
engine.emit('unit:halted', unit, target);
|
|
11
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { PartnerOf } from '@civ-clone/base-unit-action-rules/lib/criteria/partners';
|
|
2
|
+
import Tile from '@civ-clone/core-world/Tile';
|
|
3
|
+
import Unit from '@civ-clone/core-unit/Unit';
|
|
4
|
+
export declare const fromLand: (unit: Unit, to: Tile, from: Tile) => boolean;
|
|
5
|
+
export declare const toPartnersLand: (
|
|
6
|
+
partnerOf: PartnerOf
|
|
7
|
+
) => (unit: Unit, to: Tile) => boolean;
|
|
8
|
+
export declare const impassable: () => boolean;
|