ogamejs 4.0.1 → 4.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.
- package/README.md +55 -2
- package/package.json +1 -1
- package/src/fleets/expedition.js +124 -0
- package/src/fleets/index.js +35 -0
- package/src/fleets/moonLock.js +31 -0
- package/src/fleets/moonbreak.js +133 -0
- package/src/trades/parseRate.js +5 -2
- package/src/trades/utils.js +7 -8
- package/types/fleets/expedition.d.ts +90 -0
- package/types/fleets/expedition.d.ts.map +1 -0
- package/types/fleets/index.d.ts +12 -0
- package/types/fleets/index.d.ts.map +1 -1
- package/types/fleets/moonLock.d.ts +18 -0
- package/types/fleets/moonLock.d.ts.map +1 -0
- package/types/fleets/moonbreak.d.ts +64 -0
- package/types/fleets/moonbreak.d.ts.map +1 -0
- package/types/index.d.ts +8 -0
- package/types/index.d.ts.map +1 -1
- package/types/trades/parseRate.d.ts.map +1 -1
- package/types/trades/utils.d.ts +1 -1
- package/types/trades/utils.d.ts.map +1 -1
package/README.md
CHANGED
|
@@ -354,6 +354,59 @@ const winRate = runs.filter((run) => run.winner === 'attacker').length / runs.le
|
|
|
354
354
|
|
|
355
355
|
Destroyed defenses are left out of the debris field unless you pass `defenseDebris: true`. Defense repair after a battle is not modelled.
|
|
356
356
|
|
|
357
|
+
#### `getMoonbreakChance(moonSize, fleets)` / `getMoonbreakLosses(moonSize, fleets)` / `getMoonbreakWaves(rip)`
|
|
358
|
+
|
|
359
|
+
A moon destruction with Deathstars. `fleets` lists each attacker's Deathstars in firing order; each attacker spreads them over 6 waves, the extra ships in the first ones, and the moon is gone as soon as one wave succeeds.
|
|
360
|
+
|
|
361
|
+
```javascript
|
|
362
|
+
Ogame.Fleets.getMoonbreakChance(8944, [100, 80]);
|
|
363
|
+
// → 0.9409… (94.09 %)
|
|
364
|
+
Ogame.Fleets.getMoonbreakLosses(8944, [100]);
|
|
365
|
+
// → { mean: 27.78…, sigma: 4.33…,
|
|
366
|
+
// bands: [{ confidence: 68, min: 23.45…, max: 32.11… }, { confidence: 95, … }, { confidence: 99, … }] }
|
|
367
|
+
Ogame.Fleets.getMoonbreakWaves(100);
|
|
368
|
+
// → [17, 17, 17, 17, 16, 16]
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
The values are unrounded. The loss bands are a gaussian approximation around the expected losses.
|
|
372
|
+
|
|
373
|
+
#### `getExpeditionMaxFind(options)` / `getExpeditionFindBase(topScore)`
|
|
374
|
+
|
|
375
|
+
The largest metal find of one expedition. A Discoverer's find is `base × (1 + explorerBonus × (1 + lifeformExplorerBonus)) × economySpeed`; other classes get `base` alone. A Pathfinder doubles it and the lifeform expedition resource bonus multiplies it.
|
|
376
|
+
|
|
377
|
+
```javascript
|
|
378
|
+
Ogame.Fleets.getExpeditionMaxFind({
|
|
379
|
+
topScore: 2e9, // points of the universe's top player
|
|
380
|
+
economySpeed: 10,
|
|
381
|
+
explorer: true, // Discoverer class
|
|
382
|
+
pathfinder: true,
|
|
383
|
+
explorerBonus: 0.5, // serverData `explorerBonusIncreasedExpeditionOutcome`
|
|
384
|
+
lifeformExplorerBonus: 0, // lifeform Discoverer enhancement, 0.2 for 20 %
|
|
385
|
+
lifeformResourceBonus: 0, // lifeform expedition resource bonus, 0.2 for 20 %
|
|
386
|
+
});
|
|
387
|
+
// → 150000000
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
The lifeform bonuses are the totals the in-game lifeform bonus page shows, as fractions.
|
|
391
|
+
|
|
392
|
+
#### `getCargoCapacity(ship, options = {})`
|
|
393
|
+
|
|
394
|
+
One ship's cargo with its bonuses, all shares of the base cargo that add up: Hyperspace Technology (`hyperspaceMultiplier` %, 5 by default, per level) plus any other `bonus` (Collector class, lifeform…).
|
|
395
|
+
|
|
396
|
+
```javascript
|
|
397
|
+
Ogame.Fleets.getCargoCapacity(Ogame.models.Destroyable[12], { hyperspaceLevel: 20, bonus: 0.25 });
|
|
398
|
+
// → 56250
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
#### `getMoonLockShips(ship, debrisFactor, threshold = 2000000)`
|
|
402
|
+
|
|
403
|
+
How many ships to destroy on a position to reach the 2 000 000 debris that give a moon its maximum 20 % chance.
|
|
404
|
+
|
|
405
|
+
```javascript
|
|
406
|
+
Ogame.Fleets.getMoonLockShips(Ogame.models.Destroyable[1], 0.5);
|
|
407
|
+
// → 1000
|
|
408
|
+
```
|
|
409
|
+
|
|
357
410
|
### `Ogame.Trader`
|
|
358
411
|
|
|
359
412
|
Converts one resource into the two others. Rates are a `metal:crystal:deut` string (default `'2:1.5:1'`), and the percentages split the traded amount between the two target resources. **All parameters are optional.**
|
|
@@ -366,7 +419,7 @@ Ogame.Trader.sellCrystal(10000); // → { deut, metal }
|
|
|
366
419
|
|
|
367
420
|
#### `parseRate(rate = '2:1.5:1', type = 'deut')`
|
|
368
421
|
|
|
369
|
-
Normalizes a rate relative to a reference resource (`'metal'`, `'crystal'` or `'deut'`). Throws if the rate is malformed.
|
|
422
|
+
Normalizes a rate relative to a reference resource (`'metal'`, `'crystal'` or `'deut'`). Throws if the rate is malformed — that includes a term that is not a number, but also a `0`, an empty one (`'2::1'`) and a negative one, none of which describe a trade.
|
|
370
423
|
|
|
371
424
|
```javascript
|
|
372
425
|
Ogame.Trader.parseRate('3:2:1', 'deut');
|
|
@@ -464,7 +517,7 @@ import type { BuildingEntry, FleetEntry, Coordinates } from 'ogamejs/types';
|
|
|
464
517
|
|
|
465
518
|
Stated plainly, so you know what you are not getting:
|
|
466
519
|
|
|
467
|
-
- **Lifeforms** (the 2021 expansion) are not modelled — neither their buildings nor their technologies. This is a data problem, not a code one: the tables run to roughly 120 entries and we would rather have them sourced than guessed.
|
|
520
|
+
- **Lifeforms** (the 2021 expansion) are not modelled — neither their buildings nor their technologies. This is a data problem, not a code one: the tables run to roughly 120 entries and we would rather have them sourced than guessed. Where a formula needs a lifeform bonus (expeditions, cargo), it takes the total the in-game bonus page shows.
|
|
468
521
|
- **Drive upgrade values** for the three ships that switch drive (small cargo, recycler, bomber) come from community tables rather than a first-party source. The speeds are solid; the post-switch fuel figures deserve an in-game check.
|
|
469
522
|
- **Defense repair** after a battle is not simulated, and neither are moon-creation odds.
|
|
470
523
|
- Officers other than the geologist, and alliance classes, are not modelled in the production bonuses.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ogamejs",
|
|
3
|
-
"version": "4.0
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "OGame formulas as a dependency-free ESM library: building and research costs, production, build times, fleet debris and marketplace rates.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The maximum metal an expedition can find, tiered by the score of the
|
|
3
|
+
* universe's top player. `below` is an exclusive upper bound; above the last
|
|
4
|
+
* tier every universe shares `EXPEDITION_TOP_TIER_BASE`.
|
|
5
|
+
*/
|
|
6
|
+
const EXPEDITION_FIND_TIERS = Object.freeze([
|
|
7
|
+
Object.freeze({ below: 1e4, base: 40000 }),
|
|
8
|
+
Object.freeze({ below: 1e5, base: 500000 }),
|
|
9
|
+
Object.freeze({ below: 1e6, base: 1200000 }),
|
|
10
|
+
Object.freeze({ below: 5e6, base: 1800000 }),
|
|
11
|
+
Object.freeze({ below: 25e6, base: 2400000 }),
|
|
12
|
+
Object.freeze({ below: 50e6, base: 3000000 }),
|
|
13
|
+
Object.freeze({ below: 75e6, base: 3600000 }),
|
|
14
|
+
Object.freeze({ below: 100e6, base: 4200000 }),
|
|
15
|
+
]);
|
|
16
|
+
const EXPEDITION_TOP_TIER_BASE = 5000000;
|
|
17
|
+
|
|
18
|
+
/** The Discoverer class bonus on expedition finds, `explorerBonusIncreasedExpeditionOutcome` in serverData. */
|
|
19
|
+
const DEFAULT_EXPLORER_BONUS = 0.5;
|
|
20
|
+
|
|
21
|
+
/** The share of base cargo each Hyperspace Technology level adds, `cargoHyperspaceTechMultiplier` in serverData. */
|
|
22
|
+
const DEFAULT_HYPERSPACE_MULTIPLIER = 5;
|
|
23
|
+
|
|
24
|
+
function assertBonus(name, value) {
|
|
25
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
26
|
+
throw new Error(`${name} must be a number >= 0, received ${value}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
*
|
|
32
|
+
* Return the expedition find base of a universe, before any multiplier
|
|
33
|
+
* @param {number} topScore The points of the universe's top player
|
|
34
|
+
* @return {number} The base, in metal
|
|
35
|
+
*/
|
|
36
|
+
function getExpeditionFindBase(topScore) {
|
|
37
|
+
if (!Number.isFinite(topScore) || topScore < 0) {
|
|
38
|
+
throw new Error(`topScore must be a number >= 0, received ${topScore}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const tier = EXPEDITION_FIND_TIERS.find(({ below }) => topScore < below);
|
|
42
|
+
return tier ? tier.base : EXPEDITION_TOP_TIER_BASE;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
*
|
|
47
|
+
* Return the largest metal find a single expedition can bring back
|
|
48
|
+
*
|
|
49
|
+
* `base * classFactor * (pathfinder ? 2 : 1) * (1 + lifeformResourceBonus)`
|
|
50
|
+
*
|
|
51
|
+
* - a Discoverer gets `classFactor = (1 + explorerBonus * (1 + lifeformExplorerBonus)) * economySpeed`:
|
|
52
|
+
* the lifeform class enhancement amplifies the class bonus itself, and only
|
|
53
|
+
* the Discoverer's finds scale with the economy speed;
|
|
54
|
+
* - any other class gets `classFactor = 1`.
|
|
55
|
+
*
|
|
56
|
+
* Crystal and deuterium finds are smaller than metal finds. Every bonus is a
|
|
57
|
+
* fraction: 0.2 for the 20 % the in-game lifeform bonus page shows.
|
|
58
|
+
* @param {object} options The universe and the player's bonuses
|
|
59
|
+
* @param {number} options.topScore The points of the universe's top player
|
|
60
|
+
* @param {number} options.economySpeed The universe economy speed
|
|
61
|
+
* @param {boolean} [options.explorer] Whether the player is a Discoverer
|
|
62
|
+
* @param {boolean} [options.pathfinder] Whether the fleet holds a Pathfinder
|
|
63
|
+
* @param {number} [options.explorerBonus] The Discoverer class bonus, 0.5 by default
|
|
64
|
+
* @param {number} [options.lifeformExplorerBonus] The lifeform Discoverer enhancement
|
|
65
|
+
* @param {number} [options.lifeformResourceBonus] The lifeform expedition resource bonus
|
|
66
|
+
* @return {number} The maximum find, in metal
|
|
67
|
+
*/
|
|
68
|
+
function getExpeditionMaxFind({
|
|
69
|
+
topScore,
|
|
70
|
+
economySpeed,
|
|
71
|
+
explorer = false,
|
|
72
|
+
pathfinder = false,
|
|
73
|
+
explorerBonus = DEFAULT_EXPLORER_BONUS,
|
|
74
|
+
lifeformExplorerBonus = 0,
|
|
75
|
+
lifeformResourceBonus = 0,
|
|
76
|
+
}) {
|
|
77
|
+
if (!(economySpeed > 0)) {
|
|
78
|
+
throw new Error(`economySpeed must be greater than 0, received ${economySpeed}`);
|
|
79
|
+
}
|
|
80
|
+
assertBonus('explorerBonus', explorerBonus);
|
|
81
|
+
assertBonus('lifeformExplorerBonus', lifeformExplorerBonus);
|
|
82
|
+
assertBonus('lifeformResourceBonus', lifeformResourceBonus);
|
|
83
|
+
|
|
84
|
+
const classFactor = explorer
|
|
85
|
+
? (1 + explorerBonus * (1 + lifeformExplorerBonus)) * economySpeed
|
|
86
|
+
: 1;
|
|
87
|
+
|
|
88
|
+
return getExpeditionFindBase(topScore) * classFactor * (pathfinder ? 2 : 1) * (1 + lifeformResourceBonus);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
*
|
|
93
|
+
* Return the cargo capacity of one ship, with its bonuses
|
|
94
|
+
*
|
|
95
|
+
* `ship.cargo * (1 + hyperspaceLevel * hyperspaceMultiplier / 100 + bonus)`:
|
|
96
|
+
* every bonus is a share of the base cargo, so they add up.
|
|
97
|
+
* @param {import('../types.js').DestroyableEntry} ship An entry of models/destroyable.js
|
|
98
|
+
* @param {object} [options] The bonuses
|
|
99
|
+
* @param {number} [options.hyperspaceLevel] The Hyperspace Technology level
|
|
100
|
+
* @param {number} [options.hyperspaceMultiplier] The % of base cargo per level, 5 by default
|
|
101
|
+
* @param {number} [options.bonus] Any other bonus as a fraction: class (Collector 0.25 on cargo ships), lifeform…
|
|
102
|
+
* @return {number} The capacity
|
|
103
|
+
*/
|
|
104
|
+
function getCargoCapacity(ship, {
|
|
105
|
+
hyperspaceLevel = 0,
|
|
106
|
+
hyperspaceMultiplier = DEFAULT_HYPERSPACE_MULTIPLIER,
|
|
107
|
+
bonus = 0,
|
|
108
|
+
} = {}) {
|
|
109
|
+
if (!Number.isInteger(hyperspaceLevel) || hyperspaceLevel < 0) {
|
|
110
|
+
throw new Error(`hyperspaceLevel must be an integer >= 0, received ${hyperspaceLevel}`);
|
|
111
|
+
}
|
|
112
|
+
assertBonus('hyperspaceMultiplier', hyperspaceMultiplier);
|
|
113
|
+
assertBonus('bonus', bonus);
|
|
114
|
+
|
|
115
|
+
return ship.cargo * (1 + (hyperspaceLevel * hyperspaceMultiplier) / 100 + bonus);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export {
|
|
119
|
+
getExpeditionFindBase,
|
|
120
|
+
getExpeditionMaxFind,
|
|
121
|
+
getCargoCapacity,
|
|
122
|
+
EXPEDITION_FIND_TIERS,
|
|
123
|
+
EXPEDITION_TOP_TIER_BASE,
|
|
124
|
+
};
|
package/src/fleets/index.js
CHANGED
|
@@ -3,6 +3,23 @@ import getDistance from './distance.js';
|
|
|
3
3
|
import getShipSpeed, { getActiveDrive, getFleetSpeed } from './speed.js';
|
|
4
4
|
import { getFlightTime, getFuelConsumption, getTrip } from './flight.js';
|
|
5
5
|
import simulateCombat from './combat.js';
|
|
6
|
+
import {
|
|
7
|
+
getWaveChance,
|
|
8
|
+
getMoonbreakWaves,
|
|
9
|
+
getMoonbreakChance,
|
|
10
|
+
getMoonbreakLosses,
|
|
11
|
+
MIN_MOON_SIZE,
|
|
12
|
+
MAX_MOON_SIZE,
|
|
13
|
+
WAVES_PER_ATTACKER,
|
|
14
|
+
} from './moonbreak.js';
|
|
15
|
+
import {
|
|
16
|
+
getExpeditionFindBase,
|
|
17
|
+
getExpeditionMaxFind,
|
|
18
|
+
getCargoCapacity,
|
|
19
|
+
EXPEDITION_FIND_TIERS,
|
|
20
|
+
EXPEDITION_TOP_TIER_BASE,
|
|
21
|
+
} from './expedition.js';
|
|
22
|
+
import { getMoonLockShips, MOON_DEBRIS_THRESHOLD, MAX_MOON_CHANCE } from './moonLock.js';
|
|
6
23
|
|
|
7
24
|
const Fleets = {
|
|
8
25
|
getDebris,
|
|
@@ -14,6 +31,24 @@ const Fleets = {
|
|
|
14
31
|
getFuelConsumption,
|
|
15
32
|
getTrip,
|
|
16
33
|
simulateCombat,
|
|
34
|
+
getWaveChance,
|
|
35
|
+
getMoonbreakWaves,
|
|
36
|
+
getMoonbreakChance,
|
|
37
|
+
getMoonbreakLosses,
|
|
38
|
+
getExpeditionFindBase,
|
|
39
|
+
getExpeditionMaxFind,
|
|
40
|
+
getCargoCapacity,
|
|
41
|
+
getMoonLockShips,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export {
|
|
45
|
+
MIN_MOON_SIZE,
|
|
46
|
+
MAX_MOON_SIZE,
|
|
47
|
+
WAVES_PER_ATTACKER,
|
|
48
|
+
EXPEDITION_FIND_TIERS,
|
|
49
|
+
EXPEDITION_TOP_TIER_BASE,
|
|
50
|
+
MOON_DEBRIS_THRESHOLD,
|
|
51
|
+
MAX_MOON_CHANCE,
|
|
17
52
|
};
|
|
18
53
|
|
|
19
54
|
export default Fleets;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** The debris that gives a moon its maximum chance to appear. */
|
|
2
|
+
const MOON_DEBRIS_THRESHOLD = 2000000;
|
|
3
|
+
|
|
4
|
+
/** The maximum moon chance, in %, reached at `MOON_DEBRIS_THRESHOLD`. */
|
|
5
|
+
const MAX_MOON_CHANCE = 20;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
*
|
|
9
|
+
* Return how many ships must be destroyed on a position to reach the maximum moon chance
|
|
10
|
+
*
|
|
11
|
+
* Only metal and crystal land in the debris field here, and the universe keeps
|
|
12
|
+
* `debrisFactor` of them.
|
|
13
|
+
* @param {import('../types.js').DestroyableEntry} ship An entry of models/destroyable.js
|
|
14
|
+
* @param {number} debrisFactor The universe debris factor, e.g. 0.3 for 30%
|
|
15
|
+
* @param {number} [threshold] The debris to reach, 2 000 000 by default
|
|
16
|
+
* @return {number} The number of ships
|
|
17
|
+
*/
|
|
18
|
+
function getMoonLockShips(ship, debrisFactor, threshold = MOON_DEBRIS_THRESHOLD) {
|
|
19
|
+
if (!(debrisFactor > 0)) {
|
|
20
|
+
throw new Error(`debrisFactor must be greater than 0, received ${debrisFactor}`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const debris = (ship.cost.metal ?? 0) + (ship.cost.crystal ?? 0);
|
|
24
|
+
if (!(debris > 0)) {
|
|
25
|
+
throw new Error('the ship leaves no metal or crystal debris');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return Math.ceil(threshold / (debrisFactor * debris));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export { getMoonLockShips, MOON_DEBRIS_THRESHOLD, MAX_MOON_CHANCE };
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/** A moon size, in km, can only be in this range. */
|
|
2
|
+
const MIN_MOON_SIZE = 3464;
|
|
3
|
+
const MAX_MOON_SIZE = 8944;
|
|
4
|
+
|
|
5
|
+
/** Each attacker spreads their Deathstars over this many waves. */
|
|
6
|
+
const WAVES_PER_ATTACKER = 6;
|
|
7
|
+
|
|
8
|
+
function assertMoonSize(moonSize) {
|
|
9
|
+
if (!Number.isFinite(moonSize) || moonSize < MIN_MOON_SIZE || moonSize > MAX_MOON_SIZE) {
|
|
10
|
+
throw new Error(`moonSize must be between ${MIN_MOON_SIZE} and ${MAX_MOON_SIZE}, received ${moonSize}`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function assertFleets(fleets) {
|
|
15
|
+
if (!Array.isArray(fleets) || fleets.length === 0) {
|
|
16
|
+
throw new Error('fleets must be a non-empty array of Deathstar counts');
|
|
17
|
+
}
|
|
18
|
+
for (const rip of fleets) {
|
|
19
|
+
if (!Number.isInteger(rip) || rip < 0) {
|
|
20
|
+
throw new Error(`each fleet must be an integer >= 0, received ${rip}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
*
|
|
27
|
+
* Return the chance that a single wave of Deathstars destroys the moon
|
|
28
|
+
*
|
|
29
|
+
* `(100 - sqrt(moonSize)) * sqrt(rip) / 100`, capped at 1
|
|
30
|
+
* @param {number} moonSize The moon diameter, in km
|
|
31
|
+
* @param {number} rip The number of Deathstars in the wave
|
|
32
|
+
* @return {number} The chance, between 0 and 1
|
|
33
|
+
*/
|
|
34
|
+
function getWaveChance(moonSize, rip) {
|
|
35
|
+
return Math.min(1, ((100 - Math.sqrt(moonSize)) * Math.sqrt(rip)) / 100);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
*
|
|
40
|
+
* Return the waves one attacker sends, in firing order
|
|
41
|
+
*
|
|
42
|
+
* The Deathstars are spread over 6 waves: when the count is not a multiple of 6,
|
|
43
|
+
* the first waves carry one extra ship. Under 6 Deathstars, the last waves are
|
|
44
|
+
* empty, which neither threaten the moon nor lose a ship.
|
|
45
|
+
* @param {number} rip The attacker's Deathstars
|
|
46
|
+
* @return {number[]} The size of each of the 6 waves
|
|
47
|
+
*/
|
|
48
|
+
function getMoonbreakWaves(rip) {
|
|
49
|
+
const base = Math.floor(rip / WAVES_PER_ATTACKER);
|
|
50
|
+
const remainder = rip % WAVES_PER_ATTACKER;
|
|
51
|
+
|
|
52
|
+
return Array.from({ length: WAVES_PER_ATTACKER }, (_, i) => (i < remainder ? base + 1 : base));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
*
|
|
57
|
+
* Return the chance that a coordinated attack destroys the moon
|
|
58
|
+
*
|
|
59
|
+
* The attackers fire one after the other and the moon is gone as soon as one
|
|
60
|
+
* wave succeeds, so the attack fails only when every wave fails.
|
|
61
|
+
* @param {number} moonSize The moon diameter, in km (3464 to 8944)
|
|
62
|
+
* @param {number[]} fleets The Deathstars of each attacker, in firing order
|
|
63
|
+
* @return {number} The chance, between 0 and 1
|
|
64
|
+
*/
|
|
65
|
+
function getMoonbreakChance(moonSize, fleets) {
|
|
66
|
+
assertMoonSize(moonSize);
|
|
67
|
+
assertFleets(fleets);
|
|
68
|
+
|
|
69
|
+
const failure = fleets
|
|
70
|
+
.flatMap(getMoonbreakWaves)
|
|
71
|
+
.reduce((acc, rip) => acc * (1 - getWaveChance(moonSize, rip)), 1);
|
|
72
|
+
|
|
73
|
+
return 1 - failure;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
*
|
|
78
|
+
* Return the expected Deathstar losses of a coordinated attack
|
|
79
|
+
*
|
|
80
|
+
* Each Deathstar of a wave is destroyed with probability `sqrt(moonSize) / 200`,
|
|
81
|
+
* and a wave only costs ships if every wave before it failed. The variance sums
|
|
82
|
+
* the per-wave binomial variances (the waves are treated as independent), and
|
|
83
|
+
* the spread is summarised as a gaussian around the mean: 1σ / 2σ / 3σ for the
|
|
84
|
+
* 68 / 95 / 99 % bands, clamped between 0 and the whole fleet.
|
|
85
|
+
* @param {number} moonSize The moon diameter, in km (3464 to 8944)
|
|
86
|
+
* @param {number[]} fleets The Deathstars of each attacker, in firing order
|
|
87
|
+
* @return {{
|
|
88
|
+
* mean: number, sigma: number,
|
|
89
|
+
* bands: { confidence: number, min: number, max: number }[],
|
|
90
|
+
* }} The losses, unrounded
|
|
91
|
+
*/
|
|
92
|
+
function getMoonbreakLosses(moonSize, fleets) {
|
|
93
|
+
assertMoonSize(moonSize);
|
|
94
|
+
assertFleets(fleets);
|
|
95
|
+
|
|
96
|
+
const destructionRate = Math.sqrt(moonSize) / 200;
|
|
97
|
+
const total = fleets.reduce((acc, rip) => acc + rip, 0);
|
|
98
|
+
|
|
99
|
+
let mean = 0;
|
|
100
|
+
let variance = 0;
|
|
101
|
+
// The chance that every wave so far has failed, so that this one fires.
|
|
102
|
+
let reached = 1;
|
|
103
|
+
|
|
104
|
+
for (const size of fleets.flatMap(getMoonbreakWaves)) {
|
|
105
|
+
const p = destructionRate * reached;
|
|
106
|
+
mean += size * p;
|
|
107
|
+
variance += size * p * (1 - p);
|
|
108
|
+
reached *= 1 - getWaveChance(moonSize, size);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const sigma = Math.sqrt(variance);
|
|
112
|
+
const band = (confidence, sigmas) => ({
|
|
113
|
+
confidence,
|
|
114
|
+
min: Math.max(mean - sigmas * sigma, 0),
|
|
115
|
+
max: Math.min(mean + sigmas * sigma, total),
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
mean,
|
|
120
|
+
sigma,
|
|
121
|
+
bands: [band(68, 1), band(95, 2), band(99, 3)],
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export {
|
|
126
|
+
getWaveChance,
|
|
127
|
+
getMoonbreakWaves,
|
|
128
|
+
getMoonbreakChance,
|
|
129
|
+
getMoonbreakLosses,
|
|
130
|
+
MIN_MOON_SIZE,
|
|
131
|
+
MAX_MOON_SIZE,
|
|
132
|
+
WAVES_PER_ATTACKER,
|
|
133
|
+
};
|
package/src/trades/parseRate.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import isUsableRate from './utils.js';
|
|
2
2
|
|
|
3
3
|
function extract(rate, type) {
|
|
4
4
|
let res = {};
|
|
@@ -46,7 +46,10 @@ export default function parseRate(rate = '2:1.5:1', type = 'deut') {
|
|
|
46
46
|
|
|
47
47
|
const res = extract(rate, type);
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
// Checked after normalizing rather than on the raw terms: whatever makes a
|
|
50
|
+
// rate unusable — a term that is not a number, `0`, empty, negative — shows
|
|
51
|
+
// up here as a NaN, an Infinity, a 0 or a negative ratio.
|
|
52
|
+
if (!isUsableRate(Object.values(res))) {
|
|
50
53
|
throw new Error('rate not parsed correctly');
|
|
51
54
|
}
|
|
52
55
|
|
package/src/trades/utils.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
return response;
|
|
1
|
+
// A normalized rate is usable when every term is a real, strictly positive
|
|
2
|
+
// number. Checking only for `NaN` let two kinds of nonsense through as if they
|
|
3
|
+
// were answers: `Infinity`, produced by dividing into a `0` term, and `0`
|
|
4
|
+
// itself, which is what an empty term (`'2::1'`) parses to. A negative worth is
|
|
5
|
+
// not something the game can express either.
|
|
6
|
+
export default function isUsableRate(values) {
|
|
7
|
+
return values.every((value) => Number.isFinite(value) && value > 0);
|
|
9
8
|
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The maximum metal an expedition can find, tiered by the score of the
|
|
3
|
+
* universe's top player. `below` is an exclusive upper bound; above the last
|
|
4
|
+
* tier every universe shares `EXPEDITION_TOP_TIER_BASE`.
|
|
5
|
+
*/
|
|
6
|
+
declare const EXPEDITION_FIND_TIERS: readonly (Readonly<{
|
|
7
|
+
below: 10000;
|
|
8
|
+
base: 40000;
|
|
9
|
+
}> | Readonly<{
|
|
10
|
+
below: 100000;
|
|
11
|
+
base: 500000;
|
|
12
|
+
}> | Readonly<{
|
|
13
|
+
below: 1000000;
|
|
14
|
+
base: 1200000;
|
|
15
|
+
}> | Readonly<{
|
|
16
|
+
below: 5000000;
|
|
17
|
+
base: 1800000;
|
|
18
|
+
}> | Readonly<{
|
|
19
|
+
below: 25000000;
|
|
20
|
+
base: 2400000;
|
|
21
|
+
}> | Readonly<{
|
|
22
|
+
below: 50000000;
|
|
23
|
+
base: 3000000;
|
|
24
|
+
}> | Readonly<{
|
|
25
|
+
below: 75000000;
|
|
26
|
+
base: 3600000;
|
|
27
|
+
}> | Readonly<{
|
|
28
|
+
below: 100000000;
|
|
29
|
+
base: 4200000;
|
|
30
|
+
}>)[];
|
|
31
|
+
declare const EXPEDITION_TOP_TIER_BASE = 5000000;
|
|
32
|
+
/**
|
|
33
|
+
*
|
|
34
|
+
* Return the expedition find base of a universe, before any multiplier
|
|
35
|
+
* @param {number} topScore The points of the universe's top player
|
|
36
|
+
* @return {number} The base, in metal
|
|
37
|
+
*/
|
|
38
|
+
declare function getExpeditionFindBase(topScore: number): number;
|
|
39
|
+
/**
|
|
40
|
+
*
|
|
41
|
+
* Return the largest metal find a single expedition can bring back
|
|
42
|
+
*
|
|
43
|
+
* `base * classFactor * (pathfinder ? 2 : 1) * (1 + lifeformResourceBonus)`
|
|
44
|
+
*
|
|
45
|
+
* - a Discoverer gets `classFactor = (1 + explorerBonus * (1 + lifeformExplorerBonus)) * economySpeed`:
|
|
46
|
+
* the lifeform class enhancement amplifies the class bonus itself, and only
|
|
47
|
+
* the Discoverer's finds scale with the economy speed;
|
|
48
|
+
* - any other class gets `classFactor = 1`.
|
|
49
|
+
*
|
|
50
|
+
* Crystal and deuterium finds are smaller than metal finds. Every bonus is a
|
|
51
|
+
* fraction: 0.2 for the 20 % the in-game lifeform bonus page shows.
|
|
52
|
+
* @param {object} options The universe and the player's bonuses
|
|
53
|
+
* @param {number} options.topScore The points of the universe's top player
|
|
54
|
+
* @param {number} options.economySpeed The universe economy speed
|
|
55
|
+
* @param {boolean} [options.explorer] Whether the player is a Discoverer
|
|
56
|
+
* @param {boolean} [options.pathfinder] Whether the fleet holds a Pathfinder
|
|
57
|
+
* @param {number} [options.explorerBonus] The Discoverer class bonus, 0.5 by default
|
|
58
|
+
* @param {number} [options.lifeformExplorerBonus] The lifeform Discoverer enhancement
|
|
59
|
+
* @param {number} [options.lifeformResourceBonus] The lifeform expedition resource bonus
|
|
60
|
+
* @return {number} The maximum find, in metal
|
|
61
|
+
*/
|
|
62
|
+
declare function getExpeditionMaxFind({ topScore, economySpeed, explorer, pathfinder, explorerBonus, lifeformExplorerBonus, lifeformResourceBonus, }: {
|
|
63
|
+
topScore: number;
|
|
64
|
+
economySpeed: number;
|
|
65
|
+
explorer?: boolean;
|
|
66
|
+
pathfinder?: boolean;
|
|
67
|
+
explorerBonus?: number;
|
|
68
|
+
lifeformExplorerBonus?: number;
|
|
69
|
+
lifeformResourceBonus?: number;
|
|
70
|
+
}): number;
|
|
71
|
+
/**
|
|
72
|
+
*
|
|
73
|
+
* Return the cargo capacity of one ship, with its bonuses
|
|
74
|
+
*
|
|
75
|
+
* `ship.cargo * (1 + hyperspaceLevel * hyperspaceMultiplier / 100 + bonus)`:
|
|
76
|
+
* every bonus is a share of the base cargo, so they add up.
|
|
77
|
+
* @param {import('../types.js').DestroyableEntry} ship An entry of models/destroyable.js
|
|
78
|
+
* @param {object} [options] The bonuses
|
|
79
|
+
* @param {number} [options.hyperspaceLevel] The Hyperspace Technology level
|
|
80
|
+
* @param {number} [options.hyperspaceMultiplier] The % of base cargo per level, 5 by default
|
|
81
|
+
* @param {number} [options.bonus] Any other bonus as a fraction: class (Collector 0.25 on cargo ships), lifeform…
|
|
82
|
+
* @return {number} The capacity
|
|
83
|
+
*/
|
|
84
|
+
declare function getCargoCapacity(ship: import('../types.js').DestroyableEntry, { hyperspaceLevel, hyperspaceMultiplier, bonus, }?: {
|
|
85
|
+
hyperspaceLevel?: number;
|
|
86
|
+
hyperspaceMultiplier?: number;
|
|
87
|
+
bonus?: number;
|
|
88
|
+
}): number;
|
|
89
|
+
export { getExpeditionFindBase, getExpeditionMaxFind, getCargoCapacity, EXPEDITION_FIND_TIERS, EXPEDITION_TOP_TIER_BASE, };
|
|
90
|
+
//# sourceMappingURL=expedition.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expedition.d.ts","sourceRoot":"","sources":["../../src/fleets/expedition.js"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,QAAA,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;KASzB,CAAC;AACH,QAAA,MAAM,wBAAwB,UAAU,CAAC;AAczC;;;;;GAKG;AACH,iBAAS,qBAAqB,CAAC,QAAQ,EAH5B,MAG4B,GAF3B,MAAM,CASjB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,iBAAS,oBAAoB,CAAC,EAC5B,QAAQ,EACR,YAAY,EACZ,QAAgB,EAChB,UAAkB,EAClB,aAAsC,EACtC,qBAAyB,EACzB,qBAAyB,GAC1B,EAjBE;IAAwB,QAAQ,EAAxB,MAAM,CACd;IAAwB,YAAY,EAA5B,MAAM,CACd;IAA0B,QAAQ,AAAlC,CACA,EADQ,OAAO,CACf;IAA0B,UAAU,AAApC,CACA,EADQ,OAAO,CACf;IAAyB,aAAa,AAAtC,CACA,EADQ,MAAM,CACd;IAAyB,qBAAqB,AAA9C,CACA,EADQ,MAAM,CACd;IAAyB,qBAAqB,AAA9C,CACA,EADQ,MAAM,CACd;CAUF,GAVW,MAAM,CAuBjB;AAED;;;;;;;;;;;;GAYG;AACH,iBAAS,gBAAgB,CAAC,IAAI,EAPnB,OAAO,aAAa,EAAE,gBAOH,EAAE,EAC9B,eAAmB,EACnB,oBAAoD,EACpD,KAAS,GACV,AAVE,CAIA,EAHA;IAAyB,eAAe,AAAxC,CACA,EADQ,MAAM,CACd;IAAyB,oBAAoB,AAA7C,CACA,EADQ,MAAM,CACd;IAAyB,KAAK,AAA9B,CACA,EADQ,MAAM,CACd;CAMG,GANM,MAAM,CAcjB;AAED,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EAChB,qBAAqB,EACrB,wBAAwB,GACzB,CAAC"}
|
package/types/fleets/index.d.ts
CHANGED
|
@@ -3,6 +3,9 @@ import getDistance from './distance.js';
|
|
|
3
3
|
import getShipSpeed, { getActiveDrive, getFleetSpeed } from './speed.js';
|
|
4
4
|
import { getFlightTime, getFuelConsumption, getTrip } from './flight.js';
|
|
5
5
|
import simulateCombat from './combat.js';
|
|
6
|
+
import { getWaveChance, getMoonbreakWaves, getMoonbreakChance, getMoonbreakLosses, MIN_MOON_SIZE, MAX_MOON_SIZE, WAVES_PER_ATTACKER } from './moonbreak.js';
|
|
7
|
+
import { getExpeditionFindBase, getExpeditionMaxFind, getCargoCapacity, EXPEDITION_FIND_TIERS, EXPEDITION_TOP_TIER_BASE } from './expedition.js';
|
|
8
|
+
import { getMoonLockShips, MOON_DEBRIS_THRESHOLD, MAX_MOON_CHANCE } from './moonLock.js';
|
|
6
9
|
declare const Fleets: {
|
|
7
10
|
getDebris: typeof getDebris;
|
|
8
11
|
getDistance: typeof getDistance;
|
|
@@ -13,6 +16,15 @@ declare const Fleets: {
|
|
|
13
16
|
getFuelConsumption: typeof getFuelConsumption;
|
|
14
17
|
getTrip: typeof getTrip;
|
|
15
18
|
simulateCombat: typeof simulateCombat;
|
|
19
|
+
getWaveChance: typeof getWaveChance;
|
|
20
|
+
getMoonbreakWaves: typeof getMoonbreakWaves;
|
|
21
|
+
getMoonbreakChance: typeof getMoonbreakChance;
|
|
22
|
+
getMoonbreakLosses: typeof getMoonbreakLosses;
|
|
23
|
+
getExpeditionFindBase: typeof getExpeditionFindBase;
|
|
24
|
+
getExpeditionMaxFind: typeof getExpeditionMaxFind;
|
|
25
|
+
getCargoCapacity: typeof getCargoCapacity;
|
|
26
|
+
getMoonLockShips: typeof getMoonLockShips;
|
|
16
27
|
};
|
|
28
|
+
export { MIN_MOON_SIZE, MAX_MOON_SIZE, WAVES_PER_ATTACKER, EXPEDITION_FIND_TIERS, EXPEDITION_TOP_TIER_BASE, MOON_DEBRIS_THRESHOLD, MAX_MOON_CHANCE, };
|
|
17
29
|
export default Fleets;
|
|
18
30
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fleets/index.js"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,WAAW,MAAM,eAAe,CAAC;AACxC,OAAO,YAAY,EAAE,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,cAAc,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fleets/index.js"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,WAAW,MAAM,eAAe,CAAC;AACxC,OAAO,YAAY,EAAE,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,cAAc,MAAM,aAAa,CAAC;AACzC,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,kBAAkB,EACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EAChB,qBAAqB,EACrB,wBAAwB,EACzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEzF,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;CAkBX,CAAC;AAEF,OAAO,EACL,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,qBAAqB,EACrB,wBAAwB,EACxB,qBAAqB,EACrB,eAAe,GAChB,CAAC;eAEa,MAAM"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** The debris that gives a moon its maximum chance to appear. */
|
|
2
|
+
declare const MOON_DEBRIS_THRESHOLD = 2000000;
|
|
3
|
+
/** The maximum moon chance, in %, reached at `MOON_DEBRIS_THRESHOLD`. */
|
|
4
|
+
declare const MAX_MOON_CHANCE = 20;
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
* Return how many ships must be destroyed on a position to reach the maximum moon chance
|
|
8
|
+
*
|
|
9
|
+
* Only metal and crystal land in the debris field here, and the universe keeps
|
|
10
|
+
* `debrisFactor` of them.
|
|
11
|
+
* @param {import('../types.js').DestroyableEntry} ship An entry of models/destroyable.js
|
|
12
|
+
* @param {number} debrisFactor The universe debris factor, e.g. 0.3 for 30%
|
|
13
|
+
* @param {number} [threshold] The debris to reach, 2 000 000 by default
|
|
14
|
+
* @return {number} The number of ships
|
|
15
|
+
*/
|
|
16
|
+
declare function getMoonLockShips(ship: import('../types.js').DestroyableEntry, debrisFactor: number, threshold?: number): number;
|
|
17
|
+
export { getMoonLockShips, MOON_DEBRIS_THRESHOLD, MAX_MOON_CHANCE };
|
|
18
|
+
//# sourceMappingURL=moonLock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"moonLock.d.ts","sourceRoot":"","sources":["../../src/fleets/moonLock.js"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,QAAA,MAAM,qBAAqB,UAAU,CAAC;AAEtC,yEAAyE;AACzE,QAAA,MAAM,eAAe,KAAK,CAAC;AAE3B;;;;;;;;;;GAUG;AACH,iBAAS,gBAAgB,CAAC,IAAI,EALnB,OAAO,aAAa,EAAE,gBAKH,EAAE,YAAY,EAJjC,MAIiC,EAAE,SAAS,AAHpD,CACA,EADQ,MAGoE,GAFnE,MAAM,CAajB;AAED,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,eAAe,EAAE,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/** A moon size, in km, can only be in this range. */
|
|
2
|
+
declare const MIN_MOON_SIZE = 3464;
|
|
3
|
+
declare const MAX_MOON_SIZE = 8944;
|
|
4
|
+
/** Each attacker spreads their Deathstars over this many waves. */
|
|
5
|
+
declare const WAVES_PER_ATTACKER = 6;
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
* Return the chance that a single wave of Deathstars destroys the moon
|
|
9
|
+
*
|
|
10
|
+
* `(100 - sqrt(moonSize)) * sqrt(rip) / 100`, capped at 1
|
|
11
|
+
* @param {number} moonSize The moon diameter, in km
|
|
12
|
+
* @param {number} rip The number of Deathstars in the wave
|
|
13
|
+
* @return {number} The chance, between 0 and 1
|
|
14
|
+
*/
|
|
15
|
+
declare function getWaveChance(moonSize: number, rip: number): number;
|
|
16
|
+
/**
|
|
17
|
+
*
|
|
18
|
+
* Return the waves one attacker sends, in firing order
|
|
19
|
+
*
|
|
20
|
+
* The Deathstars are spread over 6 waves: when the count is not a multiple of 6,
|
|
21
|
+
* the first waves carry one extra ship. Under 6 Deathstars, the last waves are
|
|
22
|
+
* empty, which neither threaten the moon nor lose a ship.
|
|
23
|
+
* @param {number} rip The attacker's Deathstars
|
|
24
|
+
* @return {number[]} The size of each of the 6 waves
|
|
25
|
+
*/
|
|
26
|
+
declare function getMoonbreakWaves(rip: number): number[];
|
|
27
|
+
/**
|
|
28
|
+
*
|
|
29
|
+
* Return the chance that a coordinated attack destroys the moon
|
|
30
|
+
*
|
|
31
|
+
* The attackers fire one after the other and the moon is gone as soon as one
|
|
32
|
+
* wave succeeds, so the attack fails only when every wave fails.
|
|
33
|
+
* @param {number} moonSize The moon diameter, in km (3464 to 8944)
|
|
34
|
+
* @param {number[]} fleets The Deathstars of each attacker, in firing order
|
|
35
|
+
* @return {number} The chance, between 0 and 1
|
|
36
|
+
*/
|
|
37
|
+
declare function getMoonbreakChance(moonSize: number, fleets: number[]): number;
|
|
38
|
+
/**
|
|
39
|
+
*
|
|
40
|
+
* Return the expected Deathstar losses of a coordinated attack
|
|
41
|
+
*
|
|
42
|
+
* Each Deathstar of a wave is destroyed with probability `sqrt(moonSize) / 200`,
|
|
43
|
+
* and a wave only costs ships if every wave before it failed. The variance sums
|
|
44
|
+
* the per-wave binomial variances (the waves are treated as independent), and
|
|
45
|
+
* the spread is summarised as a gaussian around the mean: 1σ / 2σ / 3σ for the
|
|
46
|
+
* 68 / 95 / 99 % bands, clamped between 0 and the whole fleet.
|
|
47
|
+
* @param {number} moonSize The moon diameter, in km (3464 to 8944)
|
|
48
|
+
* @param {number[]} fleets The Deathstars of each attacker, in firing order
|
|
49
|
+
* @return {{
|
|
50
|
+
* mean: number, sigma: number,
|
|
51
|
+
* bands: { confidence: number, min: number, max: number }[],
|
|
52
|
+
* }} The losses, unrounded
|
|
53
|
+
*/
|
|
54
|
+
declare function getMoonbreakLosses(moonSize: number, fleets: number[]): {
|
|
55
|
+
mean: number;
|
|
56
|
+
sigma: number;
|
|
57
|
+
bands: {
|
|
58
|
+
confidence: number;
|
|
59
|
+
min: number;
|
|
60
|
+
max: number;
|
|
61
|
+
}[];
|
|
62
|
+
};
|
|
63
|
+
export { getWaveChance, getMoonbreakWaves, getMoonbreakChance, getMoonbreakLosses, MIN_MOON_SIZE, MAX_MOON_SIZE, WAVES_PER_ATTACKER, };
|
|
64
|
+
//# sourceMappingURL=moonbreak.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"moonbreak.d.ts","sourceRoot":"","sources":["../../src/fleets/moonbreak.js"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,QAAA,MAAM,aAAa,OAAO,CAAC;AAC3B,QAAA,MAAM,aAAa,OAAO,CAAC;AAE3B,mEAAmE;AACnE,QAAA,MAAM,kBAAkB,IAAI,CAAC;AAmB7B;;;;;;;;GAQG;AACH,iBAAS,aAAa,CAAC,QAAQ,EAJpB,MAIoB,EAAE,GAAG,EAHzB,MAGyB,GAFxB,MAAM,CAIjB;AAED;;;;;;;;;GASG;AACH,iBAAS,iBAAiB,CAAC,GAAG,EAHnB,MAGmB,GAFlB,MAAM,EAAE,CAOnB;AAED;;;;;;;;;GASG;AACH,iBAAS,kBAAkB,CAAC,QAAQ,EAJzB,MAIyB,EAAE,MAAM,EAHjC,MAAM,EAG2B,GAFhC,MAAM,CAWjB;AAED;;;;;;;;;;;;;;;GAeG;AACH,iBAAS,kBAAkB,CAAC,QAAQ,EAPzB,MAOyB,EAAE,MAAM,EANjC,MAAM,EAM2B,GALhC;IACP,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAC5B,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC3D,CAiCH;AAED,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,kBAAkB,GACnB,CAAC"}
|
package/types/index.d.ts
CHANGED
|
@@ -31,6 +31,14 @@ declare const Ogame: {
|
|
|
31
31
|
getFuelConsumption: typeof import("./fleets/flight.js").getFuelConsumption;
|
|
32
32
|
getTrip: typeof import("./fleets/flight.js").getTrip;
|
|
33
33
|
simulateCombat: typeof import("./fleets/combat.js").default;
|
|
34
|
+
getWaveChance: typeof import("./fleets/moonbreak.js").getWaveChance;
|
|
35
|
+
getMoonbreakWaves: typeof import("./fleets/moonbreak.js").getMoonbreakWaves;
|
|
36
|
+
getMoonbreakChance: typeof import("./fleets/moonbreak.js").getMoonbreakChance;
|
|
37
|
+
getMoonbreakLosses: typeof import("./fleets/moonbreak.js").getMoonbreakLosses;
|
|
38
|
+
getExpeditionFindBase: typeof import("./fleets/expedition.js").getExpeditionFindBase;
|
|
39
|
+
getExpeditionMaxFind: typeof import("./fleets/expedition.js").getExpeditionMaxFind;
|
|
40
|
+
getCargoCapacity: typeof import("./fleets/expedition.js").getCargoCapacity;
|
|
41
|
+
getMoonLockShips: typeof import("./fleets/moonLock.js").getMoonLockShips;
|
|
34
42
|
};
|
|
35
43
|
Research: {
|
|
36
44
|
getResearchCost: typeof import("./cost.js").default;
|
package/types/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"AAOA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAS,MAAM,WAAW,CAAC;AAEvD,QAAA,MAAM,KAAK
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"AAOA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAS,MAAM,WAAW,CAAC;AAEvD,QAAA,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgBV,CAAC;eAEa,KAAK"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseRate.d.ts","sourceRoot":"","sources":["../../src/trades/parseRate.js"],"names":[],"mappings":"AAuCA,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,IAAI,SAAY,EAAE,IAAI,SAAS,
|
|
1
|
+
{"version":3,"file":"parseRate.d.ts","sourceRoot":"","sources":["../../src/trades/parseRate.js"],"names":[],"mappings":"AAuCA,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,IAAI,SAAY,EAAE,IAAI,SAAS,MAiBhE"}
|
package/types/trades/utils.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export default function
|
|
1
|
+
export default function isUsableRate(values: any): any;
|
|
2
2
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/trades/utils.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/trades/utils.js"],"names":[],"mappings":"AAKA,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,MAAM,KAAA,OAE1C"}
|