@civ-clone/base-unit-fuel 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,277 @@
1
+ import { OutOfFuel, Refuel } from './Rules';
2
+ import {
3
+ RuleRegistry,
4
+ instance as ruleRegistryInstance,
5
+ } from '@civ-clone/core-rule/RuleRegistry';
6
+ import {
7
+ UnitImprovementRegistry,
8
+ instance as unitImprovementRegistryInstance,
9
+ } from '@civ-clone/core-unit-improvement/UnitImprovementRegistry';
10
+ import {
11
+ UnitRegistry,
12
+ instance as unitRegistryInstance,
13
+ } from '@civ-clone/core-unit/UnitRegistry';
14
+ import Action from '@civ-clone/core-unit/Action';
15
+ import Aloft from './Aloft';
16
+ import Criterion from '@civ-clone/core-rule/Criterion';
17
+ import Effect from '@civ-clone/core-rule/Effect';
18
+ import Fuel from './Fuel';
19
+ import Moved from '@civ-clone/core-unit/Rules/Moved';
20
+ import Player from '@civ-clone/core-player/Player';
21
+ import Tile from '@civ-clone/core-world/Tile';
22
+ import TurnEnd from '@civ-clone/core-player/Rules/TurnEnd';
23
+ import Unit from '@civ-clone/core-unit/Unit';
24
+ import UnitImprovement from '@civ-clone/core-unit-improvement/UnitImprovement';
25
+
26
+ export interface FuelDependencies {
27
+ ruleRegistry?: RuleRegistry;
28
+ unitImprovementRegistry?: UnitImprovementRegistry;
29
+ unitRegistry?: UnitRegistry;
30
+ }
31
+
32
+ /** A unit's range: how many turns it can end away from a refuelling point. */
33
+ export type Range = (unit: Unit) => number;
34
+
35
+ /**
36
+ * When a unit's turns out are counted:
37
+ *
38
+ * - `'turn-end'`: at the end of each of its player's turns, wherever it is (`checkFuel`);
39
+ * - `'out-of-moves'`: after each move, as the original does (`checkFuelAfterMove`).
40
+ */
41
+ export type CountOn = 'turn-end' | 'out-of-moves';
42
+
43
+ export interface FuelOptions {
44
+ /**
45
+ * The rules' ids are `<prefix>:player/turn-end/fuel` (or `<prefix>:unit/moved/fuel`) and
46
+ * `<prefix>:unit/out-of-fuel/destroy`. Unnamed without.
47
+ */
48
+ prefix?: string;
49
+ /** A unit's range: its `Fuel` yield by default. */
50
+ range?: Range;
51
+ /** When turns out are counted: `'turn-end'` by default. */
52
+ countOn?: CountOn;
53
+ /** For `'out-of-moves'`, whether a `Moved` action is a move: by default, one to another square (attacks included). */
54
+ countsAsMove?: (unit: Unit, action: Action) => boolean;
55
+ /** For `'out-of-moves'`, whether the action was an attack: by default, the unit didn't end up on its target. */
56
+ isAttack?: (unit: Unit, action: Action) => boolean;
57
+ }
58
+
59
+ /** A unit's `Fuel` yield. */
60
+ export const fuelRange: Range = (unit: Unit): number => {
61
+ const [range] = unit.yield(new Fuel());
62
+
63
+ return range.value();
64
+ };
65
+
66
+ /** `unit`'s `Aloft` mark, if it has one. */
67
+ export const aloftOf = (
68
+ unitImprovementRegistry: UnitImprovementRegistry,
69
+ unit: Unit
70
+ ): Aloft | undefined =>
71
+ unitImprovementRegistry
72
+ .getByUnit(unit)
73
+ .find(
74
+ (unitImprovement: UnitImprovement): boolean =>
75
+ unitImprovement instanceof Aloft
76
+ ) as Aloft | undefined;
77
+
78
+ /** How many turns `unit` has ended away from a refuelling point since it last refuelled. */
79
+ export const turnsAloft = (
80
+ unitImprovementRegistry: UnitImprovementRegistry,
81
+ unit: Unit
82
+ ): number => aloftOf(unitImprovementRegistry, unit)?.turns() ?? 0;
83
+
84
+ /** Whether `unit` refuels on `tile` (see `Refuel`). */
85
+ export const refuels = (
86
+ ruleRegistry: RuleRegistry,
87
+ unit: Unit,
88
+ tile: Tile = unit.tile()
89
+ ): boolean =>
90
+ ruleRegistry
91
+ .process(Refuel, unit, tile)
92
+ .some((answer: boolean | void): boolean => answer === true);
93
+
94
+ /**
95
+ * At the end of `player`'s turn, for each of its units with a range (above 0): one that refuels where it is loses its
96
+ * `Aloft` mark; any other has ended one more turn out, and runs out of fuel (`OutOfFuel`) once that reaches its range.
97
+ */
98
+ export const checkFuel =
99
+ (
100
+ ruleRegistry: RuleRegistry,
101
+ unitImprovementRegistry: UnitImprovementRegistry,
102
+ unitRegistry: UnitRegistry,
103
+ range: Range
104
+ ) =>
105
+ (player: Player): void =>
106
+ unitRegistry.getByPlayer(player).forEach((unit: Unit): void => {
107
+ if (unit.destroyed()) {
108
+ return;
109
+ }
110
+
111
+ const unitRange = range(unit);
112
+
113
+ if (!(unitRange > 0)) {
114
+ return;
115
+ }
116
+
117
+ const aloft = aloftOf(unitImprovementRegistry, unit);
118
+
119
+ if (refuels(ruleRegistry, unit)) {
120
+ if (aloft !== undefined) {
121
+ unitImprovementRegistry.unregister(aloft);
122
+ }
123
+
124
+ return;
125
+ }
126
+
127
+ const turns = (aloft?.turns() ?? 0) + 1;
128
+
129
+ if (turns < unitRange) {
130
+ if (aloft === undefined) {
131
+ unitImprovementRegistry.register(new Aloft(unit, turns));
132
+
133
+ return;
134
+ }
135
+
136
+ aloft.setTurns(turns);
137
+
138
+ return;
139
+ }
140
+
141
+ if (aloft !== undefined) {
142
+ unitImprovementRegistry.unregister(aloft);
143
+ }
144
+
145
+ ruleRegistry.process(OutOfFuel, unit);
146
+ });
147
+
148
+ /**
149
+ * After `unit` moves (OpenCiv2, `unit_move_dir_air_fuel`), for a unit with a range (above 0):
150
+ *
151
+ * - where it refuels, it loses its `Aloft` mark and its remaining moves (it has landed), except that a unit with a
152
+ * range of 1 that attacked and still has moves left hasn't landed;
153
+ * - anywhere else, once it has no moves left, it has spent one more turn out, and runs out of fuel (`OutOfFuel`) when
154
+ * that reaches its range.
155
+ */
156
+ export const checkFuelAfterMove =
157
+ (
158
+ ruleRegistry: RuleRegistry,
159
+ unitImprovementRegistry: UnitImprovementRegistry,
160
+ range: Range,
161
+ isAttack: (unit: Unit, action: Action) => boolean
162
+ ) =>
163
+ (unit: Unit, action: Action): void => {
164
+ if (unit.destroyed()) {
165
+ return;
166
+ }
167
+
168
+ const unitRange = range(unit);
169
+
170
+ if (!(unitRange > 0)) {
171
+ return;
172
+ }
173
+
174
+ const aloft = aloftOf(unitImprovementRegistry, unit),
175
+ landed =
176
+ refuels(ruleRegistry, unit) &&
177
+ !(
178
+ unitRange === 1 &&
179
+ unit.moves().value() > 0 &&
180
+ isAttack(unit, action)
181
+ );
182
+
183
+ if (landed) {
184
+ if (aloft !== undefined) {
185
+ unitImprovementRegistry.unregister(aloft);
186
+ }
187
+
188
+ unit.moves().set(0);
189
+
190
+ return;
191
+ }
192
+
193
+ if (unit.moves().value() > 0) {
194
+ return;
195
+ }
196
+
197
+ const turns = (aloft?.turns() ?? 0) + 1;
198
+
199
+ if (turns < unitRange) {
200
+ if (aloft === undefined) {
201
+ unitImprovementRegistry.register(new Aloft(unit, turns));
202
+
203
+ return;
204
+ }
205
+
206
+ aloft.setTurns(turns);
207
+
208
+ return;
209
+ }
210
+
211
+ if (aloft !== undefined) {
212
+ unitImprovementRegistry.unregister(aloft);
213
+ }
214
+
215
+ ruleRegistry.process(OutOfFuel, unit);
216
+ };
217
+
218
+ /**
219
+ * A ruleset's fuel rules: one that counts the turns each unit with a range spends away from a refuelling point, and an
220
+ * `OutOfFuel` rule that destroys a unit that runs out. A game adds its own `Refuel` rules (see `lib/refuel`), and its
221
+ * own `OutOfFuel` rules for anything else that should happen (a notice, say).
222
+ *
223
+ * With `countOn: 'turn-end'` (the default) the count is a `TurnEnd` rule (`checkFuel`): it doesn't matter whether a
224
+ * unit spent its moves. With `'out-of-moves'` it is a `Moved` rule (`checkFuelAfterMove`), as the original counts it.
225
+ */
226
+ export const fuelRules = (
227
+ {
228
+ ruleRegistry = ruleRegistryInstance,
229
+ unitImprovementRegistry = unitImprovementRegistryInstance,
230
+ unitRegistry = unitRegistryInstance,
231
+ }: FuelDependencies,
232
+ {
233
+ prefix,
234
+ range = fuelRange,
235
+ countOn = 'turn-end',
236
+ countsAsMove = (unit: Unit, action: Action): boolean =>
237
+ action.from() !== action.to(),
238
+ isAttack = (unit: Unit, action: Action): boolean =>
239
+ unit.tile() !== action.to(),
240
+ }: FuelOptions = {}
241
+ ): (TurnEnd | Moved | OutOfFuel)[] => {
242
+ const id = (name: string): string[] =>
243
+ prefix === undefined ? [] : [`${prefix}:${name}`];
244
+
245
+ return [
246
+ countOn === 'out-of-moves'
247
+ ? new Moved(
248
+ ...id('unit/moved/fuel'),
249
+ new Criterion(countsAsMove),
250
+ new Effect(
251
+ checkFuelAfterMove(
252
+ ruleRegistry,
253
+ unitImprovementRegistry,
254
+ range,
255
+ isAttack
256
+ )
257
+ )
258
+ )
259
+ : new TurnEnd(
260
+ ...id('player/turn-end/fuel'),
261
+ new Effect(
262
+ checkFuel(
263
+ ruleRegistry,
264
+ unitImprovementRegistry,
265
+ unitRegistry,
266
+ range
267
+ )
268
+ )
269
+ ),
270
+ new OutOfFuel(
271
+ ...id('unit/out-of-fuel/destroy'),
272
+ new Effect((unit: Unit): void => unit.destroy())
273
+ ),
274
+ ];
275
+ };
276
+
277
+ export default fuelRules;
package/lib/reach.d.ts ADDED
@@ -0,0 +1,41 @@
1
+ import { Range } from './fuelRules';
2
+ import RuleRegistry from '@civ-clone/core-rule/RuleRegistry';
3
+ import Tile from '@civ-clone/core-world/Tile';
4
+ import Unit from '@civ-clone/core-unit/Unit';
5
+ import UnitImprovementRegistry from '@civ-clone/core-unit-improvement/UnitImprovementRegistry';
6
+ export interface FuelState {
7
+ /** The unit's range. */
8
+ range: number;
9
+ /** The turns it has ended away from a refuelling point since it last refuelled. */
10
+ turnsAloft: number;
11
+ /**
12
+ * The turns it has left, this one included: it must be somewhere it refuels by the end of the last of them. 1 means
13
+ * by the end of this turn.
14
+ */
15
+ turnsLeft: number;
16
+ /** How many moves it has before then: its moves left, and its full movement for each turn after this one. */
17
+ reach: number;
18
+ }
19
+ /** Where a fuelled `unit` stands, for a computer player deciding where to send it; `null` for a unit with no range. */
20
+ export declare const fuelState: (
21
+ unitImprovementRegistry: UnitImprovementRegistry,
22
+ unit: Unit,
23
+ range?: Range
24
+ ) => FuelState | null;
25
+ export interface RefuelInReachOptions {
26
+ range?: Range;
27
+ /** How many moves apart two squares are: `Tile.distanceFrom` by default. */
28
+ distance?: (from: Tile, to: Tile) => number;
29
+ /** The squares to look at: by default the area around the unit as far as its reach. */
30
+ candidates?: (unit: Unit, reach: number) => Tile[];
31
+ }
32
+ /**
33
+ * The nearest square within `unit`'s reach (see `fuelState`) where it refuels (`Refuel`), its own square first; `null`
34
+ * if there is none, or the unit has no range. The first of equally near squares.
35
+ */
36
+ export declare const refuelInReach: (
37
+ ruleRegistry: RuleRegistry,
38
+ unitImprovementRegistry: UnitImprovementRegistry,
39
+ unit: Unit,
40
+ { range, distance, candidates }?: RefuelInReachOptions
41
+ ) => Tile | null;
package/lib/reach.js ADDED
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.refuelInReach = exports.fuelState = void 0;
4
+ const fuelRules_1 = require("./fuelRules");
5
+ /** Where a fuelled `unit` stands, for a computer player deciding where to send it; `null` for a unit with no range. */
6
+ const fuelState = (unitImprovementRegistry, unit, range = fuelRules_1.fuelRange) => {
7
+ const unitRange = range(unit);
8
+ if (!(unitRange > 0)) {
9
+ return null;
10
+ }
11
+ const aloft = (0, fuelRules_1.turnsAloft)(unitImprovementRegistry, unit), turnsLeft = Math.max(0, unitRange - aloft);
12
+ return {
13
+ range: unitRange,
14
+ turnsAloft: aloft,
15
+ turnsLeft,
16
+ reach: turnsLeft === 0
17
+ ? 0
18
+ : unit.moves().value() + unit.movement().value() * (turnsLeft - 1),
19
+ };
20
+ };
21
+ exports.fuelState = fuelState;
22
+ /**
23
+ * The nearest square within `unit`'s reach (see `fuelState`) where it refuels (`Refuel`), its own square first; `null`
24
+ * if there is none, or the unit has no range. The first of equally near squares.
25
+ */
26
+ const refuelInReach = (ruleRegistry, unitImprovementRegistry, unit, { range = fuelRules_1.fuelRange, distance = (from, to) => from.distanceFrom(to), candidates = (candidate, reach) => candidate.tile().getSurroundingArea(Math.floor(reach)).entries(), } = {}) => {
27
+ const state = (0, exports.fuelState)(unitImprovementRegistry, unit, range);
28
+ if (state === null) {
29
+ return null;
30
+ }
31
+ const from = unit.tile();
32
+ if ((0, fuelRules_1.refuels)(ruleRegistry, unit, from)) {
33
+ return from;
34
+ }
35
+ let nearest = null;
36
+ candidates(unit, state.reach).forEach((tile) => {
37
+ const away = distance(from, tile);
38
+ if (away <= state.reach &&
39
+ (nearest === null || away < nearest[1]) &&
40
+ (0, fuelRules_1.refuels)(ruleRegistry, unit, tile)) {
41
+ nearest = [tile, away];
42
+ }
43
+ });
44
+ return nearest === null ? null : nearest[0];
45
+ };
46
+ exports.refuelInReach = refuelInReach;
47
+ //# sourceMappingURL=reach.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reach.js","sourceRoot":"","sources":["reach.ts"],"names":[],"mappings":";;;AAAA,2CAAoE;AAoBpE,uHAAuH;AAChH,MAAM,SAAS,GAAG,CACvB,uBAAgD,EAChD,IAAU,EACV,QAAe,qBAAS,EACN,EAAE;IACpB,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAE9B,IAAI,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,EAAE;QACpB,OAAO,IAAI,CAAC;KACb;IAED,MAAM,KAAK,GAAG,IAAA,sBAAU,EAAC,uBAAuB,EAAE,IAAI,CAAC,EACrD,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC,CAAC;IAE7C,OAAO;QACL,KAAK,EAAE,SAAS;QAChB,UAAU,EAAE,KAAK;QACjB,SAAS;QACT,KAAK,EACH,SAAS,KAAK,CAAC;YACb,CAAC,CAAC,CAAC;YACH,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC;KACvE,CAAC;AACJ,CAAC,CAAC;AAvBW,QAAA,SAAS,aAuBpB;AAUF;;;GAGG;AACI,MAAM,aAAa,GAAG,CAC3B,YAA0B,EAC1B,uBAAgD,EAChD,IAAU,EACV,EACE,KAAK,GAAG,qBAAS,EACjB,QAAQ,GAAG,CAAC,IAAU,EAAE,EAAQ,EAAU,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,EAClE,UAAU,GAAG,CAAC,SAAe,EAAE,KAAa,EAAU,EAAE,CACtD,SAAS,CAAC,IAAI,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,MAC1C,EAAE,EACf,EAAE;IACf,MAAM,KAAK,GAAG,IAAA,iBAAS,EAAC,uBAAuB,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IAE9D,IAAI,KAAK,KAAK,IAAI,EAAE;QAClB,OAAO,IAAI,CAAC;KACb;IAED,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAEzB,IAAI,IAAA,mBAAO,EAAC,YAAY,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE;QACrC,OAAO,IAAI,CAAC;KACb;IAED,IAAI,OAAO,GAA0B,IAAI,CAAC;IAE1C,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,IAAU,EAAQ,EAAE;QACzD,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAElC,IACE,IAAI,IAAI,KAAK,CAAC,KAAK;YACnB,CAAC,OAAO,KAAK,IAAI,IAAI,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YACvC,IAAA,mBAAO,EAAC,YAAY,EAAE,IAAI,EAAE,IAAI,CAAC,EACjC;YACA,OAAO,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;SACxB;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAE,OAA0B,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC,CAAC;AAtCW,QAAA,aAAa,iBAsCxB"}
package/lib/reach.ts ADDED
@@ -0,0 +1,97 @@
1
+ import { Range, fuelRange, refuels, turnsAloft } from './fuelRules';
2
+ import RuleRegistry from '@civ-clone/core-rule/RuleRegistry';
3
+ import Tile from '@civ-clone/core-world/Tile';
4
+ import Unit from '@civ-clone/core-unit/Unit';
5
+ import UnitImprovementRegistry from '@civ-clone/core-unit-improvement/UnitImprovementRegistry';
6
+
7
+ export interface FuelState {
8
+ /** The unit's range. */
9
+ range: number;
10
+ /** The turns it has ended away from a refuelling point since it last refuelled. */
11
+ turnsAloft: number;
12
+ /**
13
+ * The turns it has left, this one included: it must be somewhere it refuels by the end of the last of them. 1 means
14
+ * by the end of this turn.
15
+ */
16
+ turnsLeft: number;
17
+ /** How many moves it has before then: its moves left, and its full movement for each turn after this one. */
18
+ reach: number;
19
+ }
20
+
21
+ /** Where a fuelled `unit` stands, for a computer player deciding where to send it; `null` for a unit with no range. */
22
+ export const fuelState = (
23
+ unitImprovementRegistry: UnitImprovementRegistry,
24
+ unit: Unit,
25
+ range: Range = fuelRange
26
+ ): FuelState | null => {
27
+ const unitRange = range(unit);
28
+
29
+ if (!(unitRange > 0)) {
30
+ return null;
31
+ }
32
+
33
+ const aloft = turnsAloft(unitImprovementRegistry, unit),
34
+ turnsLeft = Math.max(0, unitRange - aloft);
35
+
36
+ return {
37
+ range: unitRange,
38
+ turnsAloft: aloft,
39
+ turnsLeft,
40
+ reach:
41
+ turnsLeft === 0
42
+ ? 0
43
+ : unit.moves().value() + unit.movement().value() * (turnsLeft - 1),
44
+ };
45
+ };
46
+
47
+ export interface RefuelInReachOptions {
48
+ range?: Range;
49
+ /** How many moves apart two squares are: `Tile.distanceFrom` by default. */
50
+ distance?: (from: Tile, to: Tile) => number;
51
+ /** The squares to look at: by default the area around the unit as far as its reach. */
52
+ candidates?: (unit: Unit, reach: number) => Tile[];
53
+ }
54
+
55
+ /**
56
+ * The nearest square within `unit`'s reach (see `fuelState`) where it refuels (`Refuel`), its own square first; `null`
57
+ * if there is none, or the unit has no range. The first of equally near squares.
58
+ */
59
+ export const refuelInReach = (
60
+ ruleRegistry: RuleRegistry,
61
+ unitImprovementRegistry: UnitImprovementRegistry,
62
+ unit: Unit,
63
+ {
64
+ range = fuelRange,
65
+ distance = (from: Tile, to: Tile): number => from.distanceFrom(to),
66
+ candidates = (candidate: Unit, reach: number): Tile[] =>
67
+ candidate.tile().getSurroundingArea(Math.floor(reach)).entries(),
68
+ }: RefuelInReachOptions = {}
69
+ ): Tile | null => {
70
+ const state = fuelState(unitImprovementRegistry, unit, range);
71
+
72
+ if (state === null) {
73
+ return null;
74
+ }
75
+
76
+ const from = unit.tile();
77
+
78
+ if (refuels(ruleRegistry, unit, from)) {
79
+ return from;
80
+ }
81
+
82
+ let nearest: [Tile, number] | null = null;
83
+
84
+ candidates(unit, state.reach).forEach((tile: Tile): void => {
85
+ const away = distance(from, tile);
86
+
87
+ if (
88
+ away <= state.reach &&
89
+ (nearest === null || away < nearest[1]) &&
90
+ refuels(ruleRegistry, unit, tile)
91
+ ) {
92
+ nearest = [tile, away];
93
+ }
94
+ });
95
+
96
+ return nearest === null ? null : (nearest as [Tile, number])[0];
97
+ };
@@ -0,0 +1,38 @@
1
+ import { CityRegistry } from '@civ-clone/core-city/CityRegistry';
2
+ import { TileImprovementRegistry } from '@civ-clone/core-tile-improvement/TileImprovementRegistry';
3
+ import { TransportRegistry } from '@civ-clone/core-unit-transport/TransportRegistry';
4
+ import { UnitRegistry } from '@civ-clone/core-unit/UnitRegistry';
5
+ import { Refuel } from './Rules';
6
+ import TileImprovement from '@civ-clone/core-tile-improvement/TileImprovement';
7
+ import Unit from '@civ-clone/core-unit/Unit';
8
+ /** The units it applies to: all, without. */
9
+ export type Refuels = (unit: Unit) => boolean;
10
+ /** A `Refuel` rule: in one of the unit's player's own cities. */
11
+ export declare const refuelInOwnCity: (
12
+ cityRegistry?: CityRegistry,
13
+ applies?: Refuels,
14
+ id?: string
15
+ ) => Refuel;
16
+ /** A `Refuel` rule: on a square with an `Improvement` (an airfield, say). */
17
+ export declare const refuelOnTileImprovement: (
18
+ Improvement: typeof TileImprovement,
19
+ tileImprovementRegistry?: TileImprovementRegistry,
20
+ applies?: Refuels,
21
+ id?: string
22
+ ) => Refuel;
23
+ /**
24
+ * A `Refuel` rule: on a square with another of the player's units that `isBase` says the unit can refuel on (one that
25
+ * carries it, say).
26
+ */
27
+ export declare const refuelInStackWith: (
28
+ isBase: (base: Unit, unit: Unit) => boolean,
29
+ unitRegistry?: UnitRegistry,
30
+ applies?: Refuels,
31
+ id?: string
32
+ ) => Refuel;
33
+ /** A `Refuel` rule: aboard a transport. */
34
+ export declare const refuelAboard: (
35
+ transportRegistry?: TransportRegistry,
36
+ applies?: Refuels,
37
+ id?: string
38
+ ) => Refuel;
package/lib/refuel.js ADDED
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.refuelAboard = exports.refuelInStackWith = exports.refuelOnTileImprovement = exports.refuelInOwnCity = void 0;
4
+ const CityRegistry_1 = require("@civ-clone/core-city/CityRegistry");
5
+ const TileImprovementRegistry_1 = require("@civ-clone/core-tile-improvement/TileImprovementRegistry");
6
+ const TransportRegistry_1 = require("@civ-clone/core-unit-transport/TransportRegistry");
7
+ const UnitRegistry_1 = require("@civ-clone/core-unit/UnitRegistry");
8
+ const Criterion_1 = require("@civ-clone/core-rule/Criterion");
9
+ const Effect_1 = require("@civ-clone/core-rule/Effect");
10
+ const Rules_1 = require("./Rules");
11
+ const refuel = (id, applies, where) => new Rules_1.Refuel(...(id === undefined ? [] : [id]), new Criterion_1.default((unit) => applies(unit)), new Criterion_1.default(where), new Effect_1.default(() => true));
12
+ const all = () => true;
13
+ /** A `Refuel` rule: in one of the unit's player's own cities. */
14
+ const refuelInOwnCity = (cityRegistry = CityRegistry_1.instance, applies = all, id) => refuel(id, applies, (unit, tile) => { var _a; return ((_a = cityRegistry.getByTile(tile)) === null || _a === void 0 ? void 0 : _a.player()) === unit.player(); });
15
+ exports.refuelInOwnCity = refuelInOwnCity;
16
+ /** A `Refuel` rule: on a square with an `Improvement` (an airfield, say). */
17
+ const refuelOnTileImprovement = (Improvement, tileImprovementRegistry = TileImprovementRegistry_1.instance, applies = all, id) => refuel(id, applies, (unit, tile) => tileImprovementRegistry
18
+ .getByTile(tile)
19
+ .some((tileImprovement) => tileImprovement instanceof Improvement));
20
+ exports.refuelOnTileImprovement = refuelOnTileImprovement;
21
+ /**
22
+ * A `Refuel` rule: on a square with another of the player's units that `isBase` says the unit can refuel on (one that
23
+ * carries it, say).
24
+ */
25
+ const refuelInStackWith = (isBase, unitRegistry = UnitRegistry_1.instance, applies = all, id) => refuel(id, applies, (unit, tile) => unitRegistry
26
+ .getByTile(tile)
27
+ .some((base) => base !== unit &&
28
+ !base.destroyed() &&
29
+ base.player() === unit.player() &&
30
+ isBase(base, unit)));
31
+ exports.refuelInStackWith = refuelInStackWith;
32
+ /** A `Refuel` rule: aboard a transport. */
33
+ const refuelAboard = (transportRegistry = TransportRegistry_1.instance, applies = all, id) => refuel(id, applies, (unit) => transportRegistry.hasUnit(unit));
34
+ exports.refuelAboard = refuelAboard;
35
+ //# sourceMappingURL=refuel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refuel.js","sourceRoot":"","sources":["refuel.ts"],"names":[],"mappings":";;;AAAA,oEAG2C;AAC3C,sGAGkE;AAClE,wFAG0D;AAC1D,oEAG2C;AAC3C,8DAAuD;AACvD,wDAAiD;AACjD,mCAAiC;AAQjC,MAAM,MAAM,GAAG,CACb,EAAsB,EACtB,OAAgB,EAChB,KAA0C,EAClC,EAAE,CACV,IAAI,cAAM,CACR,GAAI,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAc,EAC/C,IAAI,mBAAS,CAAC,CAAC,IAAU,EAAW,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EACrD,IAAI,mBAAS,CAAC,KAAK,CAAC,EACpB,IAAI,gBAAM,CAAC,GAAY,EAAE,CAAC,IAAI,CAAC,CAChC,CAAC;AAEJ,MAAM,GAAG,GAAY,GAAY,EAAE,CAAC,IAAI,CAAC;AAEzC,iEAAiE;AAC1D,MAAM,eAAe,GAAG,CAC7B,eAA6B,uBAAoB,EACjD,UAAmB,GAAG,EACtB,EAAW,EACH,EAAE,CACV,MAAM,CACJ,EAAE,EACF,OAAO,EACP,CAAC,IAAU,EAAE,IAAU,EAAW,EAAE,WAClC,OAAA,CAAA,MAAA,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,0CAAE,MAAM,EAAE,MAAK,IAAI,CAAC,MAAM,EAAE,CAAA,EAAA,CAC3D,CAAC;AAVS,QAAA,eAAe,mBAUxB;AAEJ,6EAA6E;AACtE,MAAM,uBAAuB,GAAG,CACrC,WAAmC,EACnC,0BAAmD,kCAA+B,EAClF,UAAmB,GAAG,EACtB,EAAW,EACH,EAAE,CACV,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,IAAU,EAAE,IAAU,EAAW,EAAE,CACtD,uBAAuB;KACpB,SAAS,CAAC,IAAI,CAAC;KACf,IAAI,CACH,CAAC,eAAgC,EAAW,EAAE,CAC5C,eAAe,YAAY,WAAW,CACzC,CACJ,CAAC;AAbS,QAAA,uBAAuB,2BAahC;AAEJ;;;GAGG;AACI,MAAM,iBAAiB,GAAG,CAC/B,MAA2C,EAC3C,eAA6B,uBAAoB,EACjD,UAAmB,GAAG,EACtB,EAAW,EACH,EAAE,CACV,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,IAAU,EAAE,IAAU,EAAW,EAAE,CACtD,YAAY;KACT,SAAS,CAAC,IAAI,CAAC;KACf,IAAI,CACH,CAAC,IAAU,EAAW,EAAE,CACtB,IAAI,KAAK,IAAI;IACb,CAAC,IAAI,CAAC,SAAS,EAAE;IACjB,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,MAAM,EAAE;IAC/B,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CACrB,CACJ,CAAC;AAhBS,QAAA,iBAAiB,qBAgB1B;AAEJ,2CAA2C;AACpC,MAAM,YAAY,GAAG,CAC1B,oBAAuC,4BAAyB,EAChE,UAAmB,GAAG,EACtB,EAAW,EACH,EAAE,CACV,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,IAAU,EAAW,EAAE,CAAC,iBAAiB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AALnE,QAAA,YAAY,gBAKuD"}
package/lib/refuel.ts ADDED
@@ -0,0 +1,98 @@
1
+ import {
2
+ CityRegistry,
3
+ instance as cityRegistryInstance,
4
+ } from '@civ-clone/core-city/CityRegistry';
5
+ import {
6
+ TileImprovementRegistry,
7
+ instance as tileImprovementRegistryInstance,
8
+ } from '@civ-clone/core-tile-improvement/TileImprovementRegistry';
9
+ import {
10
+ TransportRegistry,
11
+ instance as transportRegistryInstance,
12
+ } from '@civ-clone/core-unit-transport/TransportRegistry';
13
+ import {
14
+ UnitRegistry,
15
+ instance as unitRegistryInstance,
16
+ } from '@civ-clone/core-unit/UnitRegistry';
17
+ import Criterion from '@civ-clone/core-rule/Criterion';
18
+ import Effect from '@civ-clone/core-rule/Effect';
19
+ import { Refuel } from './Rules';
20
+ import Tile from '@civ-clone/core-world/Tile';
21
+ import TileImprovement from '@civ-clone/core-tile-improvement/TileImprovement';
22
+ import Unit from '@civ-clone/core-unit/Unit';
23
+
24
+ /** The units it applies to: all, without. */
25
+ export type Refuels = (unit: Unit) => boolean;
26
+
27
+ const refuel = (
28
+ id: string | undefined,
29
+ applies: Refuels,
30
+ where: (unit: Unit, tile: Tile) => boolean
31
+ ): Refuel =>
32
+ new Refuel(
33
+ ...((id === undefined ? [] : [id]) as string[]),
34
+ new Criterion((unit: Unit): boolean => applies(unit)),
35
+ new Criterion(where),
36
+ new Effect((): boolean => true)
37
+ );
38
+
39
+ const all: Refuels = (): boolean => true;
40
+
41
+ /** A `Refuel` rule: in one of the unit's player's own cities. */
42
+ export const refuelInOwnCity = (
43
+ cityRegistry: CityRegistry = cityRegistryInstance,
44
+ applies: Refuels = all,
45
+ id?: string
46
+ ): Refuel =>
47
+ refuel(
48
+ id,
49
+ applies,
50
+ (unit: Unit, tile: Tile): boolean =>
51
+ cityRegistry.getByTile(tile)?.player() === unit.player()
52
+ );
53
+
54
+ /** A `Refuel` rule: on a square with an `Improvement` (an airfield, say). */
55
+ export const refuelOnTileImprovement = (
56
+ Improvement: typeof TileImprovement,
57
+ tileImprovementRegistry: TileImprovementRegistry = tileImprovementRegistryInstance,
58
+ applies: Refuels = all,
59
+ id?: string
60
+ ): Refuel =>
61
+ refuel(id, applies, (unit: Unit, tile: Tile): boolean =>
62
+ tileImprovementRegistry
63
+ .getByTile(tile)
64
+ .some(
65
+ (tileImprovement: TileImprovement): boolean =>
66
+ tileImprovement instanceof Improvement
67
+ )
68
+ );
69
+
70
+ /**
71
+ * A `Refuel` rule: on a square with another of the player's units that `isBase` says the unit can refuel on (one that
72
+ * carries it, say).
73
+ */
74
+ export const refuelInStackWith = (
75
+ isBase: (base: Unit, unit: Unit) => boolean,
76
+ unitRegistry: UnitRegistry = unitRegistryInstance,
77
+ applies: Refuels = all,
78
+ id?: string
79
+ ): Refuel =>
80
+ refuel(id, applies, (unit: Unit, tile: Tile): boolean =>
81
+ unitRegistry
82
+ .getByTile(tile)
83
+ .some(
84
+ (base: Unit): boolean =>
85
+ base !== unit &&
86
+ !base.destroyed() &&
87
+ base.player() === unit.player() &&
88
+ isBase(base, unit)
89
+ )
90
+ );
91
+
92
+ /** A `Refuel` rule: aboard a transport. */
93
+ export const refuelAboard = (
94
+ transportRegistry: TransportRegistry = transportRegistryInstance,
95
+ applies: Refuels = all,
96
+ id?: string
97
+ ): Refuel =>
98
+ refuel(id, applies, (unit: Unit): boolean => transportRegistry.hasUnit(unit));