@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
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CityRegistry,
|
|
3
|
+
instance as cityRegistryInstance,
|
|
4
|
+
} from '@civ-clone/core-city/CityRegistry';
|
|
5
|
+
import {
|
|
6
|
+
Engine,
|
|
7
|
+
instance as engineInstance,
|
|
8
|
+
} from '@civ-clone/core-engine/Engine';
|
|
9
|
+
import {
|
|
10
|
+
InteractionRegistry,
|
|
11
|
+
instance as interactionRegistryInstance,
|
|
12
|
+
} from '@civ-clone/core-diplomacy/InteractionRegistry';
|
|
13
|
+
import {
|
|
14
|
+
RuleRegistry,
|
|
15
|
+
instance as ruleRegistryInstance,
|
|
16
|
+
} from '@civ-clone/core-rule/RuleRegistry';
|
|
17
|
+
import {
|
|
18
|
+
TransportRegistry,
|
|
19
|
+
instance as transportRegistryInstance,
|
|
20
|
+
} from '@civ-clone/core-unit-transport/TransportRegistry';
|
|
21
|
+
import {
|
|
22
|
+
UnitRegistry,
|
|
23
|
+
instance as unitRegistryInstance,
|
|
24
|
+
} from '@civ-clone/core-unit/UnitRegistry';
|
|
25
|
+
import { Peace, Vendetta } from '@civ-clone/library-diplomacy/Declarations';
|
|
26
|
+
import Action from '@civ-clone/core-unit/Action';
|
|
27
|
+
import Air from '@civ-clone/base-unit-type-air/Air';
|
|
28
|
+
import AttackEndsTurn from '@civ-clone/base-unit-trait-attack-ends-turn/AttackEndsTurn';
|
|
29
|
+
import CoastBound from '@civ-clone/base-unit-trait-coast-bound/CoastBound';
|
|
30
|
+
import Criterion from '@civ-clone/core-rule/Criterion';
|
|
31
|
+
import Effect from '@civ-clone/core-rule/Effect';
|
|
32
|
+
import High from '@civ-clone/core-rule/Priorities/High';
|
|
33
|
+
import { ITransport } from '@civ-clone/core-unit-transport/Transport';
|
|
34
|
+
import LostAtSea from '@civ-clone/core-unit-transport/Rules/LostAtSea';
|
|
35
|
+
import Moved from '@civ-clone/core-unit/Rules/Moved';
|
|
36
|
+
import NavalTransport from '@civ-clone/base-unit-type-naval-transport/NavalTransport';
|
|
37
|
+
import Never from '@civ-clone/core-diplomacy/Expiries/Never';
|
|
38
|
+
import Player from '@civ-clone/core-player/Player';
|
|
39
|
+
import Sleeping from '@civ-clone/base-unit-action-sleep/Rules/Sleeping';
|
|
40
|
+
import Stowed from '@civ-clone/base-unit-action-embark/Busy/Stowed';
|
|
41
|
+
import Tile from '@civ-clone/core-world/Tile';
|
|
42
|
+
import Unit from '@civ-clone/core-unit/Unit';
|
|
43
|
+
import { hasVendetta } from '@civ-clone/library-diplomacy/lib/holds';
|
|
44
|
+
import { instance as rngInstance } from '@civ-clone/core-random';
|
|
45
|
+
|
|
46
|
+
type ActionType = abstract new (...args: any[]) => Action;
|
|
47
|
+
|
|
48
|
+
export interface MovedDependencies {
|
|
49
|
+
cityRegistry?: CityRegistry;
|
|
50
|
+
engine?: Engine;
|
|
51
|
+
interactionRegistry?: InteractionRegistry;
|
|
52
|
+
randomNumberGenerator?: () => number;
|
|
53
|
+
ruleRegistry?: RuleRegistry;
|
|
54
|
+
transportRegistry?: TransportRegistry;
|
|
55
|
+
unitRegistry?: UnitRegistry;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface MovedOptions {
|
|
59
|
+
// The ruleset's own action classes: a plain move, leaving a transport, and the attacks.
|
|
60
|
+
Move: ActionType;
|
|
61
|
+
Disembark: ActionType;
|
|
62
|
+
attacks: ActionType[];
|
|
63
|
+
// Actions with an enemy that end a peace treaty without a grudge (walking onto, or pillaging, the partner's land).
|
|
64
|
+
noVendetta: ActionType[];
|
|
65
|
+
// The chance a `CoastBound` unit that ends its move out of sight of land is lost.
|
|
66
|
+
coastBoundLoss: number;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* A ruleset's `Moved` rules, in order, with ids `<prefix>:unit/moved/<name>` as civ1-unit's are: telling the client,
|
|
71
|
+
* vision, ending a unit's moves, transports carrying and collecting their cargo, leaving a transport, a `CoastBound`
|
|
72
|
+
* unit lost at sea, an `AttackEndsTurn` unit's turn ending, and a broken peace treaty.
|
|
73
|
+
*/
|
|
74
|
+
export const movedRules = (
|
|
75
|
+
prefix: string,
|
|
76
|
+
{
|
|
77
|
+
cityRegistry = cityRegistryInstance,
|
|
78
|
+
engine = engineInstance,
|
|
79
|
+
interactionRegistry = interactionRegistryInstance,
|
|
80
|
+
randomNumberGenerator = rngInstance,
|
|
81
|
+
ruleRegistry = ruleRegistryInstance,
|
|
82
|
+
transportRegistry = transportRegistryInstance,
|
|
83
|
+
unitRegistry = unitRegistryInstance,
|
|
84
|
+
}: MovedDependencies,
|
|
85
|
+
{ Move, Disembark, attacks, noVendetta, coastBoundLoss }: MovedOptions
|
|
86
|
+
): Moved[] => {
|
|
87
|
+
const id = (name: string): string => `${prefix}:unit/moved/${name}`,
|
|
88
|
+
// Stows each of `units` aboard `transport`, as `Embark` and `LandAircraft` do, until it is full.
|
|
89
|
+
collect = (transport: NavalTransport, units: Unit[]): void =>
|
|
90
|
+
units.forEach((unit: Unit): void => {
|
|
91
|
+
if (!transport.hasCapacity() || !transport.canStow(unit)) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
transport.stow(unit, unit.tile());
|
|
96
|
+
|
|
97
|
+
unit.setBusy(new Stowed());
|
|
98
|
+
}),
|
|
99
|
+
// The transport's own units on the tile it has just moved onto, that aren't already aboard something.
|
|
100
|
+
unitsToCollect = (transport: Unit, tile: Tile = transport.tile()): Unit[] =>
|
|
101
|
+
unitRegistry
|
|
102
|
+
.getByTile(tile)
|
|
103
|
+
.filter(
|
|
104
|
+
(unit: Unit): boolean =>
|
|
105
|
+
unit !== transport &&
|
|
106
|
+
unit.player() === transport.player() &&
|
|
107
|
+
!transportRegistry.hasUnit(unit)
|
|
108
|
+
),
|
|
109
|
+
// A transport's own move that took it onto a new tile (not one it was carried along on, and not an attack).
|
|
110
|
+
transportMoved = [
|
|
111
|
+
new Criterion((unit: Unit): boolean => unit instanceof NavalTransport),
|
|
112
|
+
new Criterion(
|
|
113
|
+
(unit: Unit, action: Action): boolean => action instanceof Move
|
|
114
|
+
),
|
|
115
|
+
new Criterion(
|
|
116
|
+
(unit: Unit, action: Action): boolean => action.to() === unit.tile()
|
|
117
|
+
),
|
|
118
|
+
],
|
|
119
|
+
isOwnCity = (unit: Unit): boolean =>
|
|
120
|
+
cityRegistry.getByTile(unit.tile())?.player() === unit.player();
|
|
121
|
+
|
|
122
|
+
return [
|
|
123
|
+
new Moved(
|
|
124
|
+
id('emit'),
|
|
125
|
+
new Effect((unit: Unit, action: Action): void => {
|
|
126
|
+
engine.emit('unit:moved', unit, action);
|
|
127
|
+
})
|
|
128
|
+
),
|
|
129
|
+
new Moved(
|
|
130
|
+
id('apply-visibility'),
|
|
131
|
+
new Effect((unit: Unit): void => unit.applyVisibility())
|
|
132
|
+
),
|
|
133
|
+
new Moved(
|
|
134
|
+
id('end-moves-when-exhausted'),
|
|
135
|
+
new Criterion((unit: Unit): boolean => unit.moves().value() < 0.3),
|
|
136
|
+
new Effect((unit: Unit): void => {
|
|
137
|
+
unit.moves().set(0);
|
|
138
|
+
unit.setActive(false);
|
|
139
|
+
})
|
|
140
|
+
),
|
|
141
|
+
new Moved(
|
|
142
|
+
// A transport leaving one of its player's cities takes only the units sentried aboard (`Stowed` or `Sleeping`);
|
|
143
|
+
// at sea, all of its cargo goes with it, and so does an aircraft aboard, awake or not.
|
|
144
|
+
id('move-cargo'),
|
|
145
|
+
new Criterion((unit: Unit): boolean => unit instanceof NavalTransport),
|
|
146
|
+
new Criterion(
|
|
147
|
+
(unit: Unit, action: Action): boolean => action instanceof Move
|
|
148
|
+
),
|
|
149
|
+
new Criterion((unit: Unit): boolean =>
|
|
150
|
+
(unit as NavalTransport).hasCargo()
|
|
151
|
+
),
|
|
152
|
+
new Effect((unit: Unit, action: Action): void => {
|
|
153
|
+
const transport = unit as NavalTransport,
|
|
154
|
+
leftPort =
|
|
155
|
+
cityRegistry.getByTile(action.from())?.player() === unit.player();
|
|
156
|
+
|
|
157
|
+
transport.cargo().forEach((cargo: Unit): void => {
|
|
158
|
+
if (
|
|
159
|
+
leftPort &&
|
|
160
|
+
!(cargo instanceof Air) &&
|
|
161
|
+
!(cargo.busy() instanceof Stowed) &&
|
|
162
|
+
!(cargo.busy() instanceof Sleeping)
|
|
163
|
+
) {
|
|
164
|
+
transport.unload(cargo);
|
|
165
|
+
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
cargo.action(action.forUnit(cargo));
|
|
170
|
+
});
|
|
171
|
+
})
|
|
172
|
+
),
|
|
173
|
+
// These two come after `move-cargo`, so a unit collected here isn't also sent along the move just made.
|
|
174
|
+
new Moved(
|
|
175
|
+
// A carrier that moves onto its player's aircraft outside a city picks them up.
|
|
176
|
+
id('collect-aircraft'),
|
|
177
|
+
...transportMoved,
|
|
178
|
+
new Criterion((unit: Unit): boolean => !isOwnCity(unit)),
|
|
179
|
+
new Effect((unit: Unit): void =>
|
|
180
|
+
collect(
|
|
181
|
+
unit as NavalTransport,
|
|
182
|
+
unitsToCollect(unit).filter(
|
|
183
|
+
(tileUnit: Unit): boolean => tileUnit instanceof Air
|
|
184
|
+
)
|
|
185
|
+
)
|
|
186
|
+
)
|
|
187
|
+
),
|
|
188
|
+
new Moved(
|
|
189
|
+
// A transport that moves into one of its player's cities picks up the units sleeping there.
|
|
190
|
+
id('collect-sleeping'),
|
|
191
|
+
...transportMoved,
|
|
192
|
+
new Criterion((unit: Unit): boolean => isOwnCity(unit)),
|
|
193
|
+
new Effect((unit: Unit): void =>
|
|
194
|
+
collect(
|
|
195
|
+
unit as NavalTransport,
|
|
196
|
+
unitsToCollect(unit).filter(
|
|
197
|
+
(tileUnit: Unit): boolean => tileUnit.busy() instanceof Sleeping
|
|
198
|
+
)
|
|
199
|
+
)
|
|
200
|
+
)
|
|
201
|
+
),
|
|
202
|
+
new Moved(
|
|
203
|
+
id('disembark'),
|
|
204
|
+
new Criterion(
|
|
205
|
+
(unit: Unit, action: Action): boolean => action instanceof Disembark
|
|
206
|
+
),
|
|
207
|
+
new Effect((unit: Unit): void => {
|
|
208
|
+
const manifest = transportRegistry.getByUnit(unit);
|
|
209
|
+
|
|
210
|
+
manifest.transport().unload(unit);
|
|
211
|
+
|
|
212
|
+
transportRegistry.unregister(manifest);
|
|
213
|
+
})
|
|
214
|
+
),
|
|
215
|
+
new Moved(
|
|
216
|
+
// A unit that leaves its transport's tile with a plain move (an aircraft taking off, a unit walking off a ship in
|
|
217
|
+
// a city) is no longer aboard. A `Disembark` is a move too, which `disembark` unloads.
|
|
218
|
+
id('take-off'),
|
|
219
|
+
new Criterion(
|
|
220
|
+
(unit: Unit, action: Action): boolean => action instanceof Move
|
|
221
|
+
),
|
|
222
|
+
new Criterion(
|
|
223
|
+
(unit: Unit, action: Action): boolean => !(action instanceof Disembark)
|
|
224
|
+
),
|
|
225
|
+
new Criterion((unit: Unit): boolean => transportRegistry.hasUnit(unit)),
|
|
226
|
+
new Criterion(
|
|
227
|
+
(unit: Unit): boolean =>
|
|
228
|
+
transportRegistry.getByUnit(unit).transport().tile() !== unit.tile()
|
|
229
|
+
),
|
|
230
|
+
new Effect((unit: Unit): void => {
|
|
231
|
+
transportRegistry.getByUnit(unit).transport().unload(unit);
|
|
232
|
+
|
|
233
|
+
if (unit.busy() instanceof Stowed) {
|
|
234
|
+
unit.setBusy();
|
|
235
|
+
}
|
|
236
|
+
})
|
|
237
|
+
),
|
|
238
|
+
new Moved(
|
|
239
|
+
id('trireme-lost-at-sea'),
|
|
240
|
+
new Criterion((unit: Unit): boolean => unit.hasTrait(CoastBound)),
|
|
241
|
+
new Criterion((unit: Unit): boolean => unit.moves().value() === 0),
|
|
242
|
+
new Criterion((unit: Unit): boolean => !unit.tile().isCoast()),
|
|
243
|
+
new Criterion((): boolean => randomNumberGenerator() <= coastBoundLoss),
|
|
244
|
+
new Effect((unit: Unit): void => {
|
|
245
|
+
ruleRegistry.process(LostAtSea, unit as unknown as ITransport);
|
|
246
|
+
})
|
|
247
|
+
),
|
|
248
|
+
new Moved(
|
|
249
|
+
// A unit that `AttackEndsTurn` can't attack again until next turn.
|
|
250
|
+
id('bomber/end-turn-after-attack'),
|
|
251
|
+
new High(),
|
|
252
|
+
new Criterion((unit: Unit): boolean => unit.hasTrait(AttackEndsTurn)),
|
|
253
|
+
new Criterion((unit: Unit, action: Action): boolean =>
|
|
254
|
+
attacks.some(
|
|
255
|
+
(AttackType: ActionType): boolean => action instanceof AttackType
|
|
256
|
+
)
|
|
257
|
+
),
|
|
258
|
+
new Effect((unit: Unit): void => {
|
|
259
|
+
unit.moves().set(0);
|
|
260
|
+
unit.setActive(false);
|
|
261
|
+
})
|
|
262
|
+
),
|
|
263
|
+
new Moved(
|
|
264
|
+
id('break-peace-treaty'),
|
|
265
|
+
// Any action with an enemy: a sneak attack or capture, or a covert action at peace.
|
|
266
|
+
new Criterion(
|
|
267
|
+
(unit: Unit, action: Action) =>
|
|
268
|
+
typeof (action as unknown as { enemy?: unknown }).enemy === 'function'
|
|
269
|
+
),
|
|
270
|
+
new Effect((unit: Unit, action: Action) => {
|
|
271
|
+
const enemy = (action as unknown as { enemy(): Player }).enemy(),
|
|
272
|
+
peaceTreaties = interactionRegistry
|
|
273
|
+
.getByPlayers(unit.player(), enemy)
|
|
274
|
+
.filter(
|
|
275
|
+
(interaction): interaction is Peace =>
|
|
276
|
+
interaction instanceof Peace && interaction.active()
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
peaceTreaties.forEach((peaceTreaty) =>
|
|
280
|
+
peaceTreaty.expire(unit.player())
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
// The victim of an attack in peacetime holds a grudge; walking onto or pillaging its land only ends the treaty.
|
|
284
|
+
if (
|
|
285
|
+
peaceTreaties.length > 0 &&
|
|
286
|
+
!noVendetta.some(
|
|
287
|
+
(ActionType: ActionType): boolean => action instanceof ActionType
|
|
288
|
+
) &&
|
|
289
|
+
!hasVendetta(enemy, unit.player(), interactionRegistry)
|
|
290
|
+
) {
|
|
291
|
+
interactionRegistry.register(
|
|
292
|
+
new Vendetta(enemy, unit.player(), new Never(), ruleRegistry)
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
})
|
|
296
|
+
),
|
|
297
|
+
];
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
export default movedRules;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import Player from '@civ-clone/core-player/Player';
|
|
2
|
+
import PlayerAction from '@civ-clone/core-player/PlayerAction';
|
|
3
|
+
import Unit from '@civ-clone/core-unit/Unit';
|
|
4
|
+
import UnitRegistry from '@civ-clone/core-unit/UnitRegistry';
|
|
5
|
+
export type UnitPlayerActionType<T extends PlayerAction> = new (
|
|
6
|
+
player: Player,
|
|
7
|
+
unit: Unit
|
|
8
|
+
) => T;
|
|
9
|
+
export declare const hasActiveUnits: (
|
|
10
|
+
unitRegistry: UnitRegistry
|
|
11
|
+
) => (player: Player) => boolean;
|
|
12
|
+
export declare const activeUnits: <T extends PlayerAction<any>>(
|
|
13
|
+
unitRegistry: UnitRegistry,
|
|
14
|
+
PlayerActionType: UnitPlayerActionType<T>
|
|
15
|
+
) => (player: Player) => T[];
|
|
16
|
+
export declare const hasInactiveUnits: (
|
|
17
|
+
unitRegistry: UnitRegistry
|
|
18
|
+
) => (player: Player) => boolean;
|
|
19
|
+
export declare const inactiveUnits: <T extends PlayerAction<any>>(
|
|
20
|
+
unitRegistry: UnitRegistry,
|
|
21
|
+
PlayerActionType: UnitPlayerActionType<T>
|
|
22
|
+
) => (player: Player) => T[];
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.inactiveUnits = exports.hasInactiveUnits = exports.activeUnits = exports.hasActiveUnits = void 0;
|
|
4
|
+
// The player has an active unit with moves left.
|
|
5
|
+
const hasActiveUnits = (unitRegistry) => (player) => unitRegistry
|
|
6
|
+
.getByPlayer(player)
|
|
7
|
+
.some((unit) => unit.active() && unit.moves().value());
|
|
8
|
+
exports.hasActiveUnits = hasActiveUnits;
|
|
9
|
+
// The player's active units with moves left, as `PlayerActionType`s.
|
|
10
|
+
const activeUnits = (unitRegistry, PlayerActionType) => (player) => unitRegistry
|
|
11
|
+
.getByPlayer(player)
|
|
12
|
+
.filter((unit) => unit.active() && unit.moves().value() > 0)
|
|
13
|
+
.sort((a, b) => (a.waiting() ? 1 : 0) - (b.waiting() ? 1 : 0))
|
|
14
|
+
.map((unit) => new PlayerActionType(player, unit));
|
|
15
|
+
exports.activeUnits = activeUnits;
|
|
16
|
+
// The player has a unit that is inactive or has no moves left.
|
|
17
|
+
const hasInactiveUnits = (unitRegistry) => (player) => unitRegistry
|
|
18
|
+
.getByPlayer(player)
|
|
19
|
+
.some((unit) => !unit.active() || !unit.moves().value());
|
|
20
|
+
exports.hasInactiveUnits = hasInactiveUnits;
|
|
21
|
+
// The player's units that are inactive or have no moves left, as `PlayerActionType`s.
|
|
22
|
+
const inactiveUnits = (unitRegistry, PlayerActionType) => (player) => unitRegistry
|
|
23
|
+
.getByPlayer(player)
|
|
24
|
+
.filter((unit) => !unit.active() || unit.moves().value() === 0)
|
|
25
|
+
.sort((a, b) => (a.waiting() ? 1 : 0) - (b.waiting() ? 1 : 0))
|
|
26
|
+
.map((unit) => new PlayerActionType(player, unit));
|
|
27
|
+
exports.inactiveUnits = inactiveUnits;
|
|
28
|
+
//# sourceMappingURL=playerAction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playerAction.js","sourceRoot":"","sources":["playerAction.ts"],"names":[],"mappings":";;;AAeA,iDAAiD;AAC1C,MAAM,cAAc,GACzB,CAAC,YAA0B,EAAE,EAAE,CAC/B,CAAC,MAAc,EAAW,EAAE,CAC1B,YAAY;KACT,WAAW,CAAC,MAAM,CAAC;KACnB,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC;AALhD,QAAA,cAAc,kBAKkC;AAE7D,qEAAqE;AAC9D,MAAM,WAAW,GACtB,CACE,YAA0B,EAC1B,gBAAyC,EACzC,EAAE,CACJ,CAAC,MAAc,EAAO,EAAE,CACtB,YAAY;KACT,WAAW,CAAC,MAAM,CAAC;KACnB,MAAM,CACL,CAAC,IAAU,EAAW,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,GAAG,CAAC,CACnE;KACA,IAAI,CACH,CAAC,CAAO,EAAE,CAAO,EAAU,EAAE,CAC3B,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAChD;KACA,GAAG,CAAC,CAAC,IAAU,EAAK,EAAE,CAAC,IAAI,gBAAgB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;AAfrD,QAAA,WAAW,eAe0C;AAElE,+DAA+D;AACxD,MAAM,gBAAgB,GAC3B,CAAC,YAA0B,EAAE,EAAE,CAC/B,CAAC,MAAc,EAAW,EAAE,CAC1B,YAAY;KACT,WAAW,CAAC,MAAM,CAAC;KACnB,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC;AALlD,QAAA,gBAAgB,oBAKkC;AAE/D,sFAAsF;AAC/E,MAAM,aAAa,GACxB,CACE,YAA0B,EAC1B,gBAAyC,EACzC,EAAE,CACJ,CAAC,MAAc,EAAO,EAAE,CACtB,YAAY;KACT,WAAW,CAAC,MAAM,CAAC;KACnB,MAAM,CAAC,CAAC,IAAU,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;KACpE,IAAI,CACH,CAAC,CAAO,EAAE,CAAO,EAAU,EAAE,CAC3B,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAChD;KACA,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,gBAAgB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;AAb5C,QAAA,aAAa,iBAa+B"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import Player from '@civ-clone/core-player/Player';
|
|
2
|
+
import PlayerAction from '@civ-clone/core-player/PlayerAction';
|
|
3
|
+
import Unit from '@civ-clone/core-unit/Unit';
|
|
4
|
+
import UnitRegistry from '@civ-clone/core-unit/UnitRegistry';
|
|
5
|
+
|
|
6
|
+
// What a ruleset's player `Action` rules ask and offer: the player's units that can take orders this turn, and those
|
|
7
|
+
// that can't. Each list puts waiting units last and otherwise keeps the registry's order. `PlayerActionType` is the
|
|
8
|
+
// player action each unit is offered as (an active unit, an inactive one).
|
|
9
|
+
|
|
10
|
+
// The constructor of a player action for one unit.
|
|
11
|
+
export type UnitPlayerActionType<T extends PlayerAction> = new (
|
|
12
|
+
player: Player,
|
|
13
|
+
unit: Unit
|
|
14
|
+
) => T;
|
|
15
|
+
|
|
16
|
+
// The player has an active unit with moves left.
|
|
17
|
+
export const hasActiveUnits =
|
|
18
|
+
(unitRegistry: UnitRegistry) =>
|
|
19
|
+
(player: Player): boolean =>
|
|
20
|
+
unitRegistry
|
|
21
|
+
.getByPlayer(player)
|
|
22
|
+
.some((unit) => unit.active() && unit.moves().value());
|
|
23
|
+
|
|
24
|
+
// The player's active units with moves left, as `PlayerActionType`s.
|
|
25
|
+
export const activeUnits =
|
|
26
|
+
<T extends PlayerAction>(
|
|
27
|
+
unitRegistry: UnitRegistry,
|
|
28
|
+
PlayerActionType: UnitPlayerActionType<T>
|
|
29
|
+
) =>
|
|
30
|
+
(player: Player): T[] =>
|
|
31
|
+
unitRegistry
|
|
32
|
+
.getByPlayer(player)
|
|
33
|
+
.filter(
|
|
34
|
+
(unit: Unit): boolean => unit.active() && unit.moves().value() > 0
|
|
35
|
+
)
|
|
36
|
+
.sort(
|
|
37
|
+
(a: Unit, b: Unit): number =>
|
|
38
|
+
(a.waiting() ? 1 : 0) - (b.waiting() ? 1 : 0)
|
|
39
|
+
)
|
|
40
|
+
.map((unit: Unit): T => new PlayerActionType(player, unit));
|
|
41
|
+
|
|
42
|
+
// The player has a unit that is inactive or has no moves left.
|
|
43
|
+
export const hasInactiveUnits =
|
|
44
|
+
(unitRegistry: UnitRegistry) =>
|
|
45
|
+
(player: Player): boolean =>
|
|
46
|
+
unitRegistry
|
|
47
|
+
.getByPlayer(player)
|
|
48
|
+
.some((unit) => !unit.active() || !unit.moves().value());
|
|
49
|
+
|
|
50
|
+
// The player's units that are inactive or have no moves left, as `PlayerActionType`s.
|
|
51
|
+
export const inactiveUnits =
|
|
52
|
+
<T extends PlayerAction>(
|
|
53
|
+
unitRegistry: UnitRegistry,
|
|
54
|
+
PlayerActionType: UnitPlayerActionType<T>
|
|
55
|
+
) =>
|
|
56
|
+
(player: Player): T[] =>
|
|
57
|
+
unitRegistry
|
|
58
|
+
.getByPlayer(player)
|
|
59
|
+
.filter((unit: Unit) => !unit.active() || unit.moves().value() === 0)
|
|
60
|
+
.sort(
|
|
61
|
+
(a: Unit, b: Unit): number =>
|
|
62
|
+
(a.waiting() ? 1 : 0) - (b.waiting() ? 1 : 0)
|
|
63
|
+
)
|
|
64
|
+
.map((unit) => new PlayerActionType(player, unit));
|
package/lib/stowed.d.ts
ADDED
package/lib/stowed.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sleepAboard = void 0;
|
|
4
|
+
const Sleep_1 = require("@civ-clone/base-unit-action-sleep/Sleep");
|
|
5
|
+
// A unit that has just boarded a transport sleeps aboard it. Returns what `unit.action` returns.
|
|
6
|
+
const sleepAboard = (unit) => unit.action(new Sleep_1.default(unit.tile(), unit.tile(), unit));
|
|
7
|
+
exports.sleepAboard = sleepAboard;
|
|
8
|
+
//# sourceMappingURL=stowed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stowed.js","sourceRoot":"","sources":["stowed.ts"],"names":[],"mappings":";;;AAAA,mEAA4D;AAG5D,iGAAiG;AAC1F,MAAM,WAAW,GAAG,CAAC,IAAU,EAAE,EAAE,CACxC,IAAI,CAAC,MAAM,CAAC,IAAI,eAAK,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;AAD5C,QAAA,WAAW,eACiC"}
|
package/lib/stowed.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import Sleep from '@civ-clone/base-unit-action-sleep/Sleep';
|
|
2
|
+
import Unit from '@civ-clone/core-unit/Unit';
|
|
3
|
+
|
|
4
|
+
// A unit that has just boarded a transport sleeps aboard it. Returns what `unit.action` returns.
|
|
5
|
+
export const sleepAboard = (unit: Unit) =>
|
|
6
|
+
unit.action(new Sleep(unit.tile(), unit.tile(), unit));
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { InteractionRegistry } from '@civ-clone/core-diplomacy/InteractionRegistry';
|
|
2
|
+
import { TileImprovementRegistry } from '@civ-clone/core-tile-improvement/TileImprovementRegistry';
|
|
3
|
+
import { WorkedTileRegistry } from '@civ-clone/core-city/WorkedTileRegistry';
|
|
4
|
+
import Player from '@civ-clone/core-player/Player';
|
|
5
|
+
import Tile from '@civ-clone/core-world/Tile';
|
|
6
|
+
import TileImprovement from '@civ-clone/core-tile-improvement/TileImprovement';
|
|
7
|
+
import Unit from '@civ-clone/core-unit/Unit';
|
|
8
|
+
export interface TreatyPartnerDependencies {
|
|
9
|
+
interactionRegistry?: InteractionRegistry;
|
|
10
|
+
tileImprovementRegistry?: TileImprovementRegistry;
|
|
11
|
+
workedTileRegistry?: WorkedTileRegistry;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Whose land a tile is, among a unit's treaty partners, or `null`: a tile that one of the partner's cities is working
|
|
15
|
+
* and that has one of `improvements` on it, for a land unit that isn't a `NonCombatant`. Moving onto or pillaging such
|
|
16
|
+
* a tile breaks the treaty. A tile counts as land while it's worked (Civ1's territory model, simplified).
|
|
17
|
+
*/
|
|
18
|
+
export declare const treatyPartner: (
|
|
19
|
+
improvements: (typeof TileImprovement)[],
|
|
20
|
+
{
|
|
21
|
+
interactionRegistry,
|
|
22
|
+
tileImprovementRegistry,
|
|
23
|
+
workedTileRegistry,
|
|
24
|
+
}?: TreatyPartnerDependencies
|
|
25
|
+
) => (unit: Unit, tile: Tile) => Player | null;
|
|
26
|
+
export default treatyPartner;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.treatyPartner = void 0;
|
|
4
|
+
const InteractionRegistry_1 = require("@civ-clone/core-diplomacy/InteractionRegistry");
|
|
5
|
+
const TileImprovementRegistry_1 = require("@civ-clone/core-tile-improvement/TileImprovementRegistry");
|
|
6
|
+
const WorkedTileRegistry_1 = require("@civ-clone/core-city/WorkedTileRegistry");
|
|
7
|
+
const Land_1 = require("@civ-clone/base-unit-type-land/Land");
|
|
8
|
+
const NonCombatant_1 = require("@civ-clone/base-unit-trait-non-combatant/NonCombatant");
|
|
9
|
+
const Declarations_1 = require("@civ-clone/library-diplomacy/Declarations");
|
|
10
|
+
const traits_1 = require("@civ-clone/core-unit/traits");
|
|
11
|
+
/**
|
|
12
|
+
* Whose land a tile is, among a unit's treaty partners, or `null`: a tile that one of the partner's cities is working
|
|
13
|
+
* and that has one of `improvements` on it, for a land unit that isn't a `NonCombatant`. Moving onto or pillaging such
|
|
14
|
+
* a tile breaks the treaty. A tile counts as land while it's worked (Civ1's territory model, simplified).
|
|
15
|
+
*/
|
|
16
|
+
const treatyPartner = (improvements, { interactionRegistry = InteractionRegistry_1.instance, tileImprovementRegistry = TileImprovementRegistry_1.instance, workedTileRegistry = WorkedTileRegistry_1.instance, } = {}) => (unit, tile) => {
|
|
17
|
+
if (!(0, traits_1.isA)(unit, Land_1.default) || unit.hasTrait(NonCombatant_1.default)) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
const workedTile = workedTileRegistry.getByTile(tile);
|
|
21
|
+
if (workedTile === null) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const partner = workedTile.city().player();
|
|
25
|
+
if (partner === unit.player() ||
|
|
26
|
+
!interactionRegistry
|
|
27
|
+
.getByPlayers(unit.player(), partner)
|
|
28
|
+
.some((interaction) => interaction instanceof Declarations_1.Peace && interaction.active()) ||
|
|
29
|
+
!tileImprovementRegistry
|
|
30
|
+
.getByTile(tile)
|
|
31
|
+
.some((improvement) => improvements.some((Improvement) => improvement instanceof Improvement))) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return partner;
|
|
35
|
+
};
|
|
36
|
+
exports.treatyPartner = treatyPartner;
|
|
37
|
+
exports.default = exports.treatyPartner;
|
|
38
|
+
//# sourceMappingURL=treatyPartner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"treatyPartner.js","sourceRoot":"","sources":["treatyPartner.ts"],"names":[],"mappings":";;;AAAA,uFAGuD;AACvD,sGAGkE;AAClE,gFAGiD;AACjD,8DAAuD;AACvD,wFAAiF;AACjF,4EAAkE;AAKlE,wDAAkD;AAQlD;;;;GAIG;AACI,MAAM,aAAa,GACxB,CACE,YAAwC,EACxC,EACE,mBAAmB,GAAG,8BAA2B,EACjD,uBAAuB,GAAG,kCAA+B,EACzD,kBAAkB,GAAG,6BAA0B,MAClB,EAAE,EACjC,EAAE,CACJ,CAAC,IAAU,EAAE,IAAU,EAAiB,EAAE;IACxC,IAAI,CAAC,IAAA,YAAG,EAAC,IAAI,EAAE,cAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,sBAAY,CAAC,EAAE;QACnD,OAAO,IAAI,CAAC;KACb;IAED,MAAM,UAAU,GAAG,kBAAkB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAEtD,IAAI,UAAU,KAAK,IAAI,EAAE;QACvB,OAAO,IAAI,CAAC;KACb;IAED,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;IAE3C,IACE,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE;QACzB,CAAC,mBAAmB;aACjB,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,OAAO,CAAC;aACpC,IAAI,CACH,CAAC,WAAW,EAAwB,EAAE,CACpC,WAAW,YAAY,oBAAK,IAAI,WAAW,CAAC,MAAM,EAAE,CACvD;QACH,CAAC,uBAAuB;aACrB,SAAS,CAAC,IAAI,CAAC;aACf,IAAI,CAAC,CAAC,WAA4B,EAAW,EAAE,CAC9C,YAAY,CAAC,IAAI,CACf,CAAC,WAAmC,EAAW,EAAE,CAC/C,WAAW,YAAY,WAAW,CACrC,CACF,EACH;QACA,OAAO,IAAI,CAAC;KACb;IAED,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AA3CS,QAAA,aAAa,iBA2CtB;AAEJ,kBAAe,qBAAa,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import {
|
|
2
|
+
InteractionRegistry,
|
|
3
|
+
instance as interactionRegistryInstance,
|
|
4
|
+
} from '@civ-clone/core-diplomacy/InteractionRegistry';
|
|
5
|
+
import {
|
|
6
|
+
TileImprovementRegistry,
|
|
7
|
+
instance as tileImprovementRegistryInstance,
|
|
8
|
+
} from '@civ-clone/core-tile-improvement/TileImprovementRegistry';
|
|
9
|
+
import {
|
|
10
|
+
WorkedTileRegistry,
|
|
11
|
+
instance as workedTileRegistryInstance,
|
|
12
|
+
} from '@civ-clone/core-city/WorkedTileRegistry';
|
|
13
|
+
import Land from '@civ-clone/base-unit-type-land/Land';
|
|
14
|
+
import NonCombatant from '@civ-clone/base-unit-trait-non-combatant/NonCombatant';
|
|
15
|
+
import { Peace } from '@civ-clone/library-diplomacy/Declarations';
|
|
16
|
+
import Player from '@civ-clone/core-player/Player';
|
|
17
|
+
import Tile from '@civ-clone/core-world/Tile';
|
|
18
|
+
import TileImprovement from '@civ-clone/core-tile-improvement/TileImprovement';
|
|
19
|
+
import Unit from '@civ-clone/core-unit/Unit';
|
|
20
|
+
import { isA } from '@civ-clone/core-unit/traits';
|
|
21
|
+
|
|
22
|
+
export interface TreatyPartnerDependencies {
|
|
23
|
+
interactionRegistry?: InteractionRegistry;
|
|
24
|
+
tileImprovementRegistry?: TileImprovementRegistry;
|
|
25
|
+
workedTileRegistry?: WorkedTileRegistry;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Whose land a tile is, among a unit's treaty partners, or `null`: a tile that one of the partner's cities is working
|
|
30
|
+
* and that has one of `improvements` on it, for a land unit that isn't a `NonCombatant`. Moving onto or pillaging such
|
|
31
|
+
* a tile breaks the treaty. A tile counts as land while it's worked (Civ1's territory model, simplified).
|
|
32
|
+
*/
|
|
33
|
+
export const treatyPartner =
|
|
34
|
+
(
|
|
35
|
+
improvements: (typeof TileImprovement)[],
|
|
36
|
+
{
|
|
37
|
+
interactionRegistry = interactionRegistryInstance,
|
|
38
|
+
tileImprovementRegistry = tileImprovementRegistryInstance,
|
|
39
|
+
workedTileRegistry = workedTileRegistryInstance,
|
|
40
|
+
}: TreatyPartnerDependencies = {}
|
|
41
|
+
) =>
|
|
42
|
+
(unit: Unit, tile: Tile): Player | null => {
|
|
43
|
+
if (!isA(unit, Land) || unit.hasTrait(NonCombatant)) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const workedTile = workedTileRegistry.getByTile(tile);
|
|
48
|
+
|
|
49
|
+
if (workedTile === null) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const partner = workedTile.city().player();
|
|
54
|
+
|
|
55
|
+
if (
|
|
56
|
+
partner === unit.player() ||
|
|
57
|
+
!interactionRegistry
|
|
58
|
+
.getByPlayers(unit.player(), partner)
|
|
59
|
+
.some(
|
|
60
|
+
(interaction): interaction is Peace =>
|
|
61
|
+
interaction instanceof Peace && interaction.active()
|
|
62
|
+
) ||
|
|
63
|
+
!tileImprovementRegistry
|
|
64
|
+
.getByTile(tile)
|
|
65
|
+
.some((improvement: TileImprovement): boolean =>
|
|
66
|
+
improvements.some(
|
|
67
|
+
(Improvement: typeof TileImprovement): boolean =>
|
|
68
|
+
improvement instanceof Improvement
|
|
69
|
+
)
|
|
70
|
+
)
|
|
71
|
+
) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return partner;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export default treatyPartner;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.emitUnsupported = void 0;
|
|
4
|
+
// Emits `unit:unsupported` with the city that could no longer support the unit, and the unit.
|
|
5
|
+
const emitUnsupported = (engine) => (city, unit) => {
|
|
6
|
+
engine.emit('unit:unsupported', city, unit);
|
|
7
|
+
};
|
|
8
|
+
exports.emitUnsupported = emitUnsupported;
|
|
9
|
+
//# sourceMappingURL=unsupported.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unsupported.js","sourceRoot":"","sources":["unsupported.ts"],"names":[],"mappings":";;;AAIA,8FAA8F;AACvF,MAAM,eAAe,GAC1B,CAAC,MAAc,EAAE,EAAE,CACnB,CAAC,IAAU,EAAE,IAAU,EAAQ,EAAE;IAC/B,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAC9C,CAAC,CAAC;AAJS,QAAA,eAAe,mBAIxB"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import City from '@civ-clone/core-city/City';
|
|
2
|
+
import Engine from '@civ-clone/core-engine/Engine';
|
|
3
|
+
import Unit from '@civ-clone/core-unit/Unit';
|
|
4
|
+
|
|
5
|
+
// Emits `unit:unsupported` with the city that could no longer support the unit, and the unit.
|
|
6
|
+
export const emitUnsupported =
|
|
7
|
+
(engine: Engine) =>
|
|
8
|
+
(city: City, unit: Unit): void => {
|
|
9
|
+
engine.emit('unit:unsupported', city, unit);
|
|
10
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import Unit from '@civ-clone/core-unit/Unit';
|
|
2
|
+
export declare const hasMovesFor: (unit: Unit, movementCost: number) => boolean;
|
|
3
|
+
export declare const spendMoves: (unit: Unit, movementCost: number) => boolean;
|
|
4
|
+
export declare const shortOfMovesFor: (
|
|
5
|
+
unit: Unit,
|
|
6
|
+
movementCost: number
|
|
7
|
+
) => boolean;
|
|
8
|
+
export declare const spendShort: (
|
|
9
|
+
shortfallFactor: number,
|
|
10
|
+
randomNumberGenerator: () => number
|
|
11
|
+
) => (unit: Unit, movementCost: number) => boolean;
|