ogamejs 3.0.0 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +492 -228
- package/package.json +51 -4
- package/src/buildings/buildTime.js +25 -0
- package/src/buildings/crystal.js +18 -36
- package/src/buildings/deut.js +19 -34
- package/src/buildings/fusion-reactor.js +19 -34
- package/src/buildings/index.js +11 -0
- package/src/buildings/info.js +42 -0
- package/src/buildings/infocompte.js +116 -57
- package/src/buildings/metal.js +13 -28
- package/src/buildings/production.js +150 -0
- package/src/buildings/solar-plant.js +13 -21
- package/src/buildings/storage.js +59 -0
- package/src/cost.js +70 -0
- package/src/fleets/combat.js +291 -0
- package/src/fleets/distance.js +39 -0
- package/src/fleets/flight.js +105 -0
- package/src/fleets/getDebris.js +11 -10
- package/src/fleets/index.js +12 -0
- package/src/fleets/speed.js +108 -0
- package/src/i18n.js +43 -0
- package/src/index.js +12 -1
- package/src/models/buildings.js +285 -25
- package/src/models/destroyable.js +216 -110
- package/src/models/research.js +169 -0
- package/src/research/index.js +9 -0
- package/src/research/researchTime.js +25 -0
- package/src/trades/parseRate.js +7 -2
- package/src/types.js +146 -0
- package/types/buildings/buildTime.d.ts +16 -0
- package/types/buildings/buildTime.d.ts.map +1 -0
- package/types/buildings/crystal.d.ts +12 -0
- package/types/buildings/crystal.d.ts.map +1 -0
- package/types/buildings/deut.d.ts +12 -0
- package/types/buildings/deut.d.ts.map +1 -0
- package/types/buildings/fusion-reactor.d.ts +15 -0
- package/types/buildings/fusion-reactor.d.ts.map +1 -0
- package/types/buildings/index.d.ts +27 -0
- package/types/buildings/index.d.ts.map +1 -0
- package/types/buildings/info.d.ts +17 -0
- package/types/buildings/info.d.ts.map +1 -0
- package/types/buildings/infocompte.d.ts +41 -0
- package/types/buildings/infocompte.d.ts.map +1 -0
- package/types/buildings/metal.d.ts +11 -0
- package/types/buildings/metal.d.ts.map +1 -0
- package/types/buildings/production.d.ts +78 -0
- package/types/buildings/production.d.ts.map +1 -0
- package/types/buildings/solar-plant.d.ts +10 -0
- package/types/buildings/solar-plant.d.ts.map +1 -0
- package/types/buildings/storage.d.ts +29 -0
- package/types/buildings/storage.d.ts.map +1 -0
- package/types/cost.d.ts +25 -0
- package/types/cost.d.ts.map +1 -0
- package/types/fleets/combat.d.ts +57 -0
- package/types/fleets/combat.d.ts.map +1 -0
- package/types/fleets/distance.d.ts +13 -0
- package/types/fleets/distance.d.ts.map +1 -0
- package/types/fleets/flight.d.ts +57 -0
- package/types/fleets/flight.d.ts.map +1 -0
- package/types/fleets/getDebris.d.ts +12 -0
- package/types/fleets/getDebris.d.ts.map +1 -0
- package/types/fleets/index.d.ts +18 -0
- package/types/fleets/index.d.ts.map +1 -0
- package/types/fleets/speed.d.ts +54 -0
- package/types/fleets/speed.d.ts.map +1 -0
- package/types/i18n.d.ts +23 -0
- package/types/i18n.d.ts.map +1 -0
- package/types/index.d.ts +1316 -0
- package/types/index.d.ts.map +1 -0
- package/types/models/buildings.d.ts +373 -0
- package/types/models/buildings.d.ts.map +1 -0
- package/types/models/destroyable.d.ts +695 -0
- package/types/models/destroyable.d.ts.map +1 -0
- package/types/models/research.d.ts +262 -0
- package/types/models/research.d.ts.map +1 -0
- package/types/research/index.d.ts +8 -0
- package/types/research/index.d.ts.map +1 -0
- package/types/research/researchTime.d.ts +16 -0
- package/types/research/researchTime.d.ts.map +1 -0
- package/types/trades/crystal.d.ts +6 -0
- package/types/trades/crystal.d.ts.map +1 -0
- package/types/trades/deut.d.ts +6 -0
- package/types/trades/deut.d.ts.map +1 -0
- package/types/trades/index.d.ts +12 -0
- package/types/trades/index.d.ts.map +1 -0
- package/types/trades/metal.d.ts +6 -0
- package/types/trades/metal.d.ts.map +1 -0
- package/types/trades/parseRate.d.ts +2 -0
- package/types/trades/parseRate.d.ts.map +1 -0
- package/types/trades/utils.d.ts +2 -0
- package/types/trades/utils.d.ts.map +1 -0
- package/types/types.d.ts +449 -0
- package/types/types.d.ts.map +1 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import getDistance from './distance.js';
|
|
2
|
+
import { getFleetSpeed, getActiveDrive } from './speed.js';
|
|
3
|
+
|
|
4
|
+
function assertSpeedPercent(speedPercent) {
|
|
5
|
+
if (!Number.isFinite(speedPercent) || speedPercent <= 0 || speedPercent > 100) {
|
|
6
|
+
throw new Error(`speedPercent must be between 1 and 100, received ${speedPercent}`);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
*
|
|
12
|
+
* Return the one way flight time of a fleet
|
|
13
|
+
*
|
|
14
|
+
* `(10 + 35000 / speedPercent * sqrt(distance * 10 / fleetSpeed)) / universeFleetSpeed`
|
|
15
|
+
* @param {number} distance The distance to cross, from `getDistance`
|
|
16
|
+
* @param {number} fleetSpeed The speed of the slowest ship, from `getFleetSpeed`
|
|
17
|
+
* @param {number} [speedPercent] The fleet speed slider, 10 to 100 in game
|
|
18
|
+
* @param {number} [universeFleetSpeed] The universe fleet speed
|
|
19
|
+
* @returns {number} The flight time, in seconds
|
|
20
|
+
*/
|
|
21
|
+
function getFlightTime(distance, fleetSpeed, speedPercent = 100, universeFleetSpeed = 1) {
|
|
22
|
+
assertSpeedPercent(speedPercent);
|
|
23
|
+
|
|
24
|
+
if (!(fleetSpeed > 0)) {
|
|
25
|
+
throw new Error(`fleetSpeed must be greater than 0, received ${fleetSpeed}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const seconds = 10 + (35000 / speedPercent) * Math.sqrt((distance * 10) / fleetSpeed);
|
|
29
|
+
|
|
30
|
+
return Math.round(seconds / universeFleetSpeed);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
*
|
|
35
|
+
* Return the deuterium a fleet burns for a one way trip
|
|
36
|
+
*
|
|
37
|
+
* `1 + round(sum(consumption * count) * distance / 35000 * (speedPercent / 100 + 1) ** 2)`
|
|
38
|
+
* @param {import('../types.js').FleetEntry[]} fleet The ships taking off
|
|
39
|
+
* @param {number} distance The distance to cross, from `getDistance`
|
|
40
|
+
* @param {number} [speedPercent] The fleet speed slider, 10 to 100 in game
|
|
41
|
+
* @param {import('../types.js').Drives} [drives] Drive levels, needed because a
|
|
42
|
+
* ship that switched drive also changed its consumption
|
|
43
|
+
* @returns {number} The fuel needed, in deuterium
|
|
44
|
+
*/
|
|
45
|
+
function getFuelConsumption(fleet, distance, speedPercent = 100, drives = {}) {
|
|
46
|
+
assertSpeedPercent(speedPercent);
|
|
47
|
+
|
|
48
|
+
if (!Array.isArray(fleet) || fleet.length === 0) {
|
|
49
|
+
throw new Error('fleet must be a non empty array of { ship, count }');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const speedFactor = (speedPercent / 100 + 1) ** 2;
|
|
53
|
+
|
|
54
|
+
const consumption = fleet.reduce((total, { ship, count }) => {
|
|
55
|
+
// A ship that switched drive also changed how much it burns.
|
|
56
|
+
const { fuelConsumption } = getActiveDrive(ship, drives);
|
|
57
|
+
|
|
58
|
+
return total + fuelConsumption * count;
|
|
59
|
+
}, 0);
|
|
60
|
+
|
|
61
|
+
return 1 + Math.round((consumption * distance) / 35000 * speedFactor);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
*
|
|
66
|
+
* Return everything about a trip: distance, duration, fuel and cargo left
|
|
67
|
+
* @param {import('../types.js').FleetEntry[]} fleet The ships taking off
|
|
68
|
+
* @param {import('../types.js').Coordinates} origin Where the fleet leaves from
|
|
69
|
+
* @param {import('../types.js').Coordinates} target Where it goes
|
|
70
|
+
* @param {object} [options] Trip options
|
|
71
|
+
* @param {number} [options.speedPercent] The fleet speed slider, 10 to 100 in game
|
|
72
|
+
* @param {number} [options.universeFleetSpeed] The universe fleet speed
|
|
73
|
+
* @param {import('../types.js').Drives} [options.drives] The drive technology levels
|
|
74
|
+
* @param {boolean} [options.roundTrip] Whether to account for the way back too
|
|
75
|
+
* @returns {{
|
|
76
|
+
* distance: number, fleetSpeed: number, duration: number, fuel: number,
|
|
77
|
+
* cargo: number, cargoAfterFuel: number,
|
|
78
|
+
* }} The trip, with durations in seconds and `cargoAfterFuel` the room left once
|
|
79
|
+
* the fuel is loaded
|
|
80
|
+
*/
|
|
81
|
+
function getTrip(fleet, origin, target, options = {}) {
|
|
82
|
+
const {
|
|
83
|
+
speedPercent = 100,
|
|
84
|
+
universeFleetSpeed = 1,
|
|
85
|
+
drives = {},
|
|
86
|
+
roundTrip = false,
|
|
87
|
+
} = options;
|
|
88
|
+
|
|
89
|
+
const distance = getDistance(origin, target);
|
|
90
|
+
const fleetSpeed = getFleetSpeed(fleet, drives);
|
|
91
|
+
const oneWay = getFlightTime(distance, fleetSpeed, speedPercent, universeFleetSpeed);
|
|
92
|
+
const fuel = getFuelConsumption(fleet, distance, speedPercent, drives) * (roundTrip ? 2 : 1);
|
|
93
|
+
const cargo = fleet.reduce((total, { ship, count }) => total + ship.cargo * count, 0);
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
distance,
|
|
97
|
+
fleetSpeed,
|
|
98
|
+
duration: roundTrip ? oneWay * 2 : oneWay,
|
|
99
|
+
fuel,
|
|
100
|
+
cargo,
|
|
101
|
+
cargoAfterFuel: Math.max(0, cargo - fuel),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export { getFlightTime, getFuelConsumption, getTrip };
|
package/src/fleets/getDebris.js
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
*
|
|
3
|
-
*
|
|
4
|
-
* @param {
|
|
5
|
-
* @param {number} number The number of
|
|
6
|
-
* @param {number} factor The universe debris factor
|
|
7
|
-
* @
|
|
3
|
+
* Return the debris field left behind by destroyed ships or defenses
|
|
4
|
+
* @param {import('../types.js').DestroyableEntry} ship An entry of models/destroyable.js
|
|
5
|
+
* @param {number} number The number of destroyed units
|
|
6
|
+
* @param {number} factor The universe debris factor, e.g. 0.3 for 30%
|
|
7
|
+
* @param {number} [deuteriumFactor] The universe deuterium debris factor, 0 on most universes
|
|
8
|
+
* @return {import('../types.js').Resources} The debris generated
|
|
8
9
|
*/
|
|
9
|
-
function getDebris(ship, number, factor) {
|
|
10
|
+
function getDebris(ship, number, factor, deuteriumFactor = 0) {
|
|
10
11
|
const { cost } = ship;
|
|
11
|
-
const
|
|
12
|
-
const crystalDebris = cost.crystal ? cost.crystal * factor : 0;
|
|
12
|
+
const deuteriumCost = cost.deuterium ?? cost.deut ?? 0;
|
|
13
13
|
|
|
14
14
|
return {
|
|
15
|
-
metal:
|
|
16
|
-
crystal:
|
|
15
|
+
metal: (cost.metal ?? 0) * factor * number,
|
|
16
|
+
crystal: (cost.crystal ?? 0) * factor * number,
|
|
17
|
+
deuterium: deuteriumCost * deuteriumFactor * number,
|
|
17
18
|
};
|
|
18
19
|
}
|
|
19
20
|
|
package/src/fleets/index.js
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
import getDebris from './getDebris.js';
|
|
2
|
+
import getDistance from './distance.js';
|
|
3
|
+
import getShipSpeed, { getActiveDrive, getFleetSpeed } from './speed.js';
|
|
4
|
+
import { getFlightTime, getFuelConsumption, getTrip } from './flight.js';
|
|
5
|
+
import simulateCombat from './combat.js';
|
|
2
6
|
|
|
3
7
|
const Fleets = {
|
|
4
8
|
getDebris,
|
|
9
|
+
getDistance,
|
|
10
|
+
getShipSpeed,
|
|
11
|
+
getActiveDrive,
|
|
12
|
+
getFleetSpeed,
|
|
13
|
+
getFlightTime,
|
|
14
|
+
getFuelConsumption,
|
|
15
|
+
getTrip,
|
|
16
|
+
simulateCombat,
|
|
5
17
|
};
|
|
6
18
|
|
|
7
19
|
export default Fleets;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { ATTRIBUTES } from '../models/destroyable.js';
|
|
2
|
+
|
|
3
|
+
const { DRIVES } = ATTRIBUTES;
|
|
4
|
+
|
|
5
|
+
/** Each drive level adds that share of the ship base speed. */
|
|
6
|
+
const DRIVE_BONUS = Object.freeze({
|
|
7
|
+
[DRIVES.COMBUSTION]: 0.1,
|
|
8
|
+
[DRIVES.IMPULSE]: 0.2,
|
|
9
|
+
[DRIVES.HYPERSPACE]: 0.3,
|
|
10
|
+
[DRIVES.NONE]: 0,
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
/** The research id backing each drive, handy to look the level up. */
|
|
14
|
+
const DRIVE_RESEARCH = Object.freeze({
|
|
15
|
+
[DRIVES.COMBUSTION]: 115,
|
|
16
|
+
[DRIVES.IMPULSE]: 117,
|
|
17
|
+
[DRIVES.HYPERSPACE]: 118,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
function driveLevel(drives, drive) {
|
|
21
|
+
if (!Object.hasOwn(DRIVE_BONUS, drive)) {
|
|
22
|
+
throw new Error(`unknown drive ${drive}`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// eslint-disable-next-line security/detect-object-injection -- drive is a known key
|
|
26
|
+
const level = drives?.[drive] ?? 0;
|
|
27
|
+
|
|
28
|
+
if (!Number.isInteger(level) || level < 0) {
|
|
29
|
+
throw new Error(`drives.${drive} must be an integer >= 0, received ${level}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return level;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function speedWith(baseSpeed, drive, drives) {
|
|
36
|
+
// eslint-disable-next-line security/detect-object-injection -- drive is a known key
|
|
37
|
+
return Math.floor(baseSpeed * (1 + DRIVE_BONUS[drive] * driveLevel(drives, drive)));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
*
|
|
42
|
+
* Return the drive a ship actually flies on, and the speed it reaches
|
|
43
|
+
*
|
|
44
|
+
* A few ships switch to a better drive once the matching technology is high
|
|
45
|
+
* enough — a small cargo moves to the impulse drive at Impulse 5. When several
|
|
46
|
+
* drives are available the ship uses whichever ends up fastest.
|
|
47
|
+
* @param {import('../types.js').DestroyableEntry} ship An entry of models/destroyable.js
|
|
48
|
+
* @param {import('../types.js').Drives} [drives] Drive levels
|
|
49
|
+
* @returns {{drive: string, speed: number, fuelConsumption: number}} The active drive
|
|
50
|
+
*/
|
|
51
|
+
function getActiveDrive(ship, drives = {}) {
|
|
52
|
+
if (!ship || !ship.drive) {
|
|
53
|
+
throw new Error('expected an entry of models/destroyable.js');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const candidates = [
|
|
57
|
+
{ drive: ship.drive, speed: ship.speed, fuelConsumption: ship.fuelConsumption },
|
|
58
|
+
...(ship.driveUpgrades ?? [])
|
|
59
|
+
.filter((upgrade) => driveLevel(drives, upgrade.drive) >= upgrade.minLevel),
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
return candidates
|
|
63
|
+
.map(({ drive, speed, fuelConsumption }) => ({
|
|
64
|
+
drive,
|
|
65
|
+
speed: speedWith(speed, drive, drives),
|
|
66
|
+
fuelConsumption,
|
|
67
|
+
}))
|
|
68
|
+
.reduce((best, candidate) => (candidate.speed > best.speed ? candidate : best));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
*
|
|
73
|
+
* Return the speed of a ship, drive technologies included
|
|
74
|
+
* @param {import('../types.js').DestroyableEntry} ship An entry of models/destroyable.js
|
|
75
|
+
* @param {import('../types.js').Drives} [drives] Drive levels
|
|
76
|
+
* @returns {number} The speed the ship flies at
|
|
77
|
+
*/
|
|
78
|
+
function getShipSpeed(ship, drives = {}) {
|
|
79
|
+
return getActiveDrive(ship, drives).speed;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
*
|
|
84
|
+
* Return the speed of a whole fleet, which is the speed of its slowest ship
|
|
85
|
+
* @param {import('../types.js').FleetEntry[]} fleet The ships taking off
|
|
86
|
+
* @param {import('../types.js').Drives} [drives] Drive levels
|
|
87
|
+
* @returns {number} The fleet speed
|
|
88
|
+
*/
|
|
89
|
+
function getFleetSpeed(fleet, drives = {}) {
|
|
90
|
+
if (!Array.isArray(fleet) || fleet.length === 0) {
|
|
91
|
+
throw new Error('fleet must be a non empty array of { ship, count }');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const speeds = fleet
|
|
95
|
+
.filter(({ count }) => count > 0)
|
|
96
|
+
.map(({ ship }) => getShipSpeed(ship, drives));
|
|
97
|
+
|
|
98
|
+
if (speeds.length === 0) {
|
|
99
|
+
throw new Error('fleet must hold at least one ship with a count above 0');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return Math.min(...speeds);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export {
|
|
106
|
+
getActiveDrive, getFleetSpeed, DRIVE_BONUS, DRIVE_RESEARCH,
|
|
107
|
+
};
|
|
108
|
+
export default getShipSpeed;
|
package/src/i18n.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const DEFAULT_LANG = 'en';
|
|
2
|
+
|
|
3
|
+
const LANGS = Object.freeze(['en', 'fr']);
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
* Return the localised name of a model entry
|
|
8
|
+
* @param {{names: import('./types.js').Names}} entry An entry of Buildings, Destroyable or Research
|
|
9
|
+
* @param {import('./types.js').Lang} [lang] 'en' or 'fr', defaults to 'en'
|
|
10
|
+
* @returns {string} The localised name
|
|
11
|
+
*/
|
|
12
|
+
function getName(entry, lang = DEFAULT_LANG) {
|
|
13
|
+
if (!entry || !entry.names) {
|
|
14
|
+
throw new Error('entry has no names, is it a model entry?');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
18
|
+
return entry.names[lang] ?? entry.names[DEFAULT_LANG];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
*
|
|
23
|
+
* Look an entry up by any of its localised names, case and accent insensitive
|
|
24
|
+
* @param {Record<string|number, {names: import('./types.js').Names}>} model Buildings, Destroyable or Research
|
|
25
|
+
* @param {string} name The name to look for, in any supported language
|
|
26
|
+
* @returns {object|undefined} The matching entry, or undefined
|
|
27
|
+
*/
|
|
28
|
+
function findByName(model, name) {
|
|
29
|
+
const normalize = (value) => value
|
|
30
|
+
.normalize('NFD')
|
|
31
|
+
.replace(/\p{Diacritic}/gu, '')
|
|
32
|
+
.trim()
|
|
33
|
+
.toLowerCase();
|
|
34
|
+
|
|
35
|
+
const needle = normalize(name);
|
|
36
|
+
|
|
37
|
+
return Object.values(model).find((entry) => LANGS
|
|
38
|
+
// `lang` comes from the LANGS constant, never from the caller.
|
|
39
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
40
|
+
.some((lang) => entry.names?.[lang] && normalize(entry.names[lang]) === needle));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export { getName, findByName, LANGS };
|
package/src/index.js
CHANGED
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
import Trader from './trades/index.js';
|
|
2
2
|
import Building from './buildings/index.js';
|
|
3
3
|
import Fleets from './fleets/index.js';
|
|
4
|
+
import Research from './research/index.js';
|
|
4
5
|
import Buildings from './models/buildings.js';
|
|
5
|
-
import Destroyable from './models/destroyable.js';
|
|
6
|
+
import Destroyable, { ATTRIBUTES } from './models/destroyable.js';
|
|
7
|
+
import ResearchModel from './models/research.js';
|
|
8
|
+
import { getName, findByName, LANGS } from './i18n.js';
|
|
6
9
|
|
|
7
10
|
const Ogame = {
|
|
8
11
|
Trader,
|
|
9
12
|
Building,
|
|
10
13
|
Fleets,
|
|
14
|
+
Research,
|
|
15
|
+
i18n: {
|
|
16
|
+
getName,
|
|
17
|
+
findByName,
|
|
18
|
+
LANGS,
|
|
19
|
+
},
|
|
11
20
|
models: {
|
|
12
21
|
Buildings,
|
|
13
22
|
Destroyable,
|
|
23
|
+
Research: ResearchModel,
|
|
24
|
+
ATTRIBUTES,
|
|
14
25
|
},
|
|
15
26
|
};
|
|
16
27
|
|
package/src/models/buildings.js
CHANGED
|
@@ -1,59 +1,319 @@
|
|
|
1
|
+
const CATEGORIES = Object.freeze({
|
|
2
|
+
RESOURCES: 'resources',
|
|
3
|
+
FACILITIES: 'facilities',
|
|
4
|
+
MOON: 'moon',
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Every building of the game, keyed by the id used by this library.
|
|
9
|
+
*
|
|
10
|
+
* Ids 1 to 5 are historical and kept for backward compatibility; every other
|
|
11
|
+
* entry uses the id OGame itself uses. `ogameId` always holds the official id,
|
|
12
|
+
* so it is the field to rely on when talking to the game.
|
|
13
|
+
*
|
|
14
|
+
* - `names` holds the localised labels.
|
|
15
|
+
* - `factor` is the per-level cost multiplier: cost(level) = base * factor ** (level - 1).
|
|
16
|
+
* - `base` holds the level 1 values, with every energy and deuterium flow named
|
|
17
|
+
* after what it actually is:
|
|
18
|
+
* - `metal` / `crystal` / `deuterium` — the resources paid to build it,
|
|
19
|
+
* - `energyCost` — the energy paid to build it (Terraformer and Space Dock only),
|
|
20
|
+
* - `energyConsumption` — the energy it consumes once built (mines),
|
|
21
|
+
* - `deuteriumConsumption` — the deuterium it burns once built (Fusion Reactor),
|
|
22
|
+
* - `production` — what it produces, resources or energy.
|
|
23
|
+
*/
|
|
1
24
|
const BUILDINGS = Object.freeze({
|
|
2
25
|
1: {
|
|
3
|
-
|
|
26
|
+
ogameId: 1,
|
|
27
|
+
names: { en: 'Metal Mine', fr: 'Mine de métal' },
|
|
28
|
+
category: CATEGORIES.RESOURCES,
|
|
29
|
+
factor: 1.5,
|
|
4
30
|
base: {
|
|
5
|
-
production: 30,
|
|
6
|
-
consumption: 0,
|
|
7
31
|
metal: 60,
|
|
8
32
|
crystal: 15,
|
|
9
|
-
|
|
10
|
-
|
|
33
|
+
deuterium: 0,
|
|
34
|
+
energyCost: 0,
|
|
35
|
+
energyConsumption: 10,
|
|
36
|
+
deuteriumConsumption: 0,
|
|
37
|
+
production: 30,
|
|
11
38
|
},
|
|
12
39
|
},
|
|
13
40
|
2: {
|
|
14
|
-
|
|
41
|
+
ogameId: 2,
|
|
42
|
+
names: { en: 'Crystal Mine', fr: 'Mine de cristal' },
|
|
43
|
+
category: CATEGORIES.RESOURCES,
|
|
44
|
+
factor: 1.6,
|
|
15
45
|
base: {
|
|
16
|
-
production: 20,
|
|
17
|
-
consumption: 0,
|
|
18
46
|
metal: 48,
|
|
19
47
|
crystal: 24,
|
|
20
|
-
|
|
21
|
-
|
|
48
|
+
deuterium: 0,
|
|
49
|
+
energyCost: 0,
|
|
50
|
+
energyConsumption: 10,
|
|
51
|
+
deuteriumConsumption: 0,
|
|
52
|
+
production: 20,
|
|
22
53
|
},
|
|
23
54
|
},
|
|
24
55
|
3: {
|
|
25
|
-
|
|
56
|
+
ogameId: 3,
|
|
57
|
+
names: { en: 'Deuterium Synthesizer', fr: 'Synthétiseur de deutérium' },
|
|
58
|
+
category: CATEGORIES.RESOURCES,
|
|
59
|
+
factor: 1.5,
|
|
26
60
|
base: {
|
|
27
|
-
production: 10,
|
|
28
|
-
consumption: 0,
|
|
29
61
|
metal: 225,
|
|
30
62
|
crystal: 75,
|
|
31
|
-
|
|
32
|
-
|
|
63
|
+
deuterium: 0,
|
|
64
|
+
energyCost: 0,
|
|
65
|
+
energyConsumption: 20,
|
|
66
|
+
deuteriumConsumption: 0,
|
|
67
|
+
production: 10,
|
|
33
68
|
},
|
|
34
69
|
},
|
|
35
70
|
4: {
|
|
36
|
-
|
|
71
|
+
ogameId: 4,
|
|
72
|
+
names: { en: 'Solar Plant', fr: 'Centrale électrique solaire' },
|
|
73
|
+
category: CATEGORIES.RESOURCES,
|
|
74
|
+
factor: 1.5,
|
|
37
75
|
base: {
|
|
38
|
-
production: 20,
|
|
39
|
-
consumption: 0,
|
|
40
76
|
metal: 75,
|
|
41
77
|
crystal: 30,
|
|
42
|
-
|
|
43
|
-
|
|
78
|
+
deuterium: 0,
|
|
79
|
+
energyCost: 0,
|
|
80
|
+
energyConsumption: 0,
|
|
81
|
+
deuteriumConsumption: 0,
|
|
82
|
+
production: 20,
|
|
44
83
|
},
|
|
45
84
|
},
|
|
46
85
|
5: {
|
|
47
|
-
|
|
86
|
+
ogameId: 12,
|
|
87
|
+
names: { en: 'Fusion Reactor', fr: 'Centrale électrique de fusion' },
|
|
88
|
+
category: CATEGORIES.RESOURCES,
|
|
89
|
+
factor: 1.8,
|
|
48
90
|
base: {
|
|
49
|
-
production: 30,
|
|
50
|
-
consumption: 10,
|
|
51
91
|
metal: 900,
|
|
52
92
|
crystal: 360,
|
|
53
|
-
|
|
54
|
-
|
|
93
|
+
deuterium: 180,
|
|
94
|
+
energyCost: 0,
|
|
95
|
+
energyConsumption: 0,
|
|
96
|
+
deuteriumConsumption: 10,
|
|
97
|
+
production: 30,
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
14: {
|
|
101
|
+
ogameId: 14,
|
|
102
|
+
names: { en: 'Robotics Factory', fr: 'Usine de robots' },
|
|
103
|
+
category: CATEGORIES.FACILITIES,
|
|
104
|
+
factor: 2,
|
|
105
|
+
base: {
|
|
106
|
+
metal: 400,
|
|
107
|
+
crystal: 120,
|
|
108
|
+
deuterium: 200,
|
|
109
|
+
energyCost: 0,
|
|
110
|
+
energyConsumption: 0,
|
|
111
|
+
deuteriumConsumption: 0,
|
|
112
|
+
production: 0,
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
15: {
|
|
116
|
+
ogameId: 15,
|
|
117
|
+
names: { en: 'Nanite Factory', fr: 'Usine de nanites' },
|
|
118
|
+
category: CATEGORIES.FACILITIES,
|
|
119
|
+
factor: 2,
|
|
120
|
+
base: {
|
|
121
|
+
metal: 1000000,
|
|
122
|
+
crystal: 500000,
|
|
123
|
+
deuterium: 100000,
|
|
124
|
+
energyCost: 0,
|
|
125
|
+
energyConsumption: 0,
|
|
126
|
+
deuteriumConsumption: 0,
|
|
127
|
+
production: 0,
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
21: {
|
|
131
|
+
ogameId: 21,
|
|
132
|
+
names: { en: 'Shipyard', fr: 'Chantier spatial' },
|
|
133
|
+
category: CATEGORIES.FACILITIES,
|
|
134
|
+
factor: 2,
|
|
135
|
+
base: {
|
|
136
|
+
metal: 400,
|
|
137
|
+
crystal: 200,
|
|
138
|
+
deuterium: 100,
|
|
139
|
+
energyCost: 0,
|
|
140
|
+
energyConsumption: 0,
|
|
141
|
+
deuteriumConsumption: 0,
|
|
142
|
+
production: 0,
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
22: {
|
|
146
|
+
ogameId: 22,
|
|
147
|
+
names: { en: 'Metal Storage', fr: 'Hangar de métal' },
|
|
148
|
+
category: CATEGORIES.RESOURCES,
|
|
149
|
+
factor: 2,
|
|
150
|
+
storage: 'metal',
|
|
151
|
+
base: {
|
|
152
|
+
metal: 1000,
|
|
153
|
+
crystal: 0,
|
|
154
|
+
deuterium: 0,
|
|
155
|
+
energyCost: 0,
|
|
156
|
+
energyConsumption: 0,
|
|
157
|
+
deuteriumConsumption: 0,
|
|
158
|
+
production: 0,
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
23: {
|
|
162
|
+
ogameId: 23,
|
|
163
|
+
names: { en: 'Crystal Storage', fr: 'Hangar de cristal' },
|
|
164
|
+
category: CATEGORIES.RESOURCES,
|
|
165
|
+
factor: 2,
|
|
166
|
+
storage: 'crystal',
|
|
167
|
+
base: {
|
|
168
|
+
metal: 1000,
|
|
169
|
+
crystal: 500,
|
|
170
|
+
deuterium: 0,
|
|
171
|
+
energyCost: 0,
|
|
172
|
+
energyConsumption: 0,
|
|
173
|
+
deuteriumConsumption: 0,
|
|
174
|
+
production: 0,
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
24: {
|
|
178
|
+
ogameId: 24,
|
|
179
|
+
names: { en: 'Deuterium Tank', fr: 'Réservoir de deutérium' },
|
|
180
|
+
category: CATEGORIES.RESOURCES,
|
|
181
|
+
factor: 2,
|
|
182
|
+
storage: 'deuterium',
|
|
183
|
+
base: {
|
|
184
|
+
metal: 1000,
|
|
185
|
+
crystal: 1000,
|
|
186
|
+
deuterium: 0,
|
|
187
|
+
energyCost: 0,
|
|
188
|
+
energyConsumption: 0,
|
|
189
|
+
deuteriumConsumption: 0,
|
|
190
|
+
production: 0,
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
31: {
|
|
194
|
+
ogameId: 31,
|
|
195
|
+
names: { en: 'Research Lab', fr: 'Laboratoire de recherche' },
|
|
196
|
+
category: CATEGORIES.FACILITIES,
|
|
197
|
+
factor: 2,
|
|
198
|
+
base: {
|
|
199
|
+
metal: 200,
|
|
200
|
+
crystal: 400,
|
|
201
|
+
deuterium: 200,
|
|
202
|
+
energyCost: 0,
|
|
203
|
+
energyConsumption: 0,
|
|
204
|
+
deuteriumConsumption: 0,
|
|
205
|
+
production: 0,
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
33: {
|
|
209
|
+
ogameId: 33,
|
|
210
|
+
names: { en: 'Terraformer', fr: 'Terraformeur' },
|
|
211
|
+
category: CATEGORIES.FACILITIES,
|
|
212
|
+
factor: 2,
|
|
213
|
+
base: {
|
|
214
|
+
metal: 0,
|
|
215
|
+
crystal: 50000,
|
|
216
|
+
deuterium: 100000,
|
|
217
|
+
energyCost: 1000,
|
|
218
|
+
energyConsumption: 0,
|
|
219
|
+
deuteriumConsumption: 0,
|
|
220
|
+
production: 0,
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
34: {
|
|
224
|
+
ogameId: 34,
|
|
225
|
+
names: { en: 'Alliance Depot', fr: 'Dépôt de ravitaillement' },
|
|
226
|
+
category: CATEGORIES.FACILITIES,
|
|
227
|
+
factor: 2,
|
|
228
|
+
base: {
|
|
229
|
+
metal: 20000,
|
|
230
|
+
crystal: 40000,
|
|
231
|
+
deuterium: 0,
|
|
232
|
+
energyCost: 0,
|
|
233
|
+
energyConsumption: 0,
|
|
234
|
+
deuteriumConsumption: 0,
|
|
235
|
+
production: 0,
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
36: {
|
|
239
|
+
ogameId: 36,
|
|
240
|
+
names: { en: 'Space Dock', fr: 'Dock spatial' },
|
|
241
|
+
category: CATEGORIES.FACILITIES,
|
|
242
|
+
factor: 5,
|
|
243
|
+
// The space dock is the only building whose energy cost grows on its own
|
|
244
|
+
// factor, hence the extra `energyFactor`.
|
|
245
|
+
energyFactor: 2.5,
|
|
246
|
+
base: {
|
|
247
|
+
metal: 200,
|
|
248
|
+
crystal: 0,
|
|
249
|
+
deuterium: 50,
|
|
250
|
+
energyCost: 50,
|
|
251
|
+
energyConsumption: 0,
|
|
252
|
+
deuteriumConsumption: 0,
|
|
253
|
+
production: 0,
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
41: {
|
|
257
|
+
ogameId: 41,
|
|
258
|
+
names: { en: 'Lunar Base', fr: 'Base lunaire' },
|
|
259
|
+
category: CATEGORIES.MOON,
|
|
260
|
+
factor: 2,
|
|
261
|
+
base: {
|
|
262
|
+
metal: 20000,
|
|
263
|
+
crystal: 40000,
|
|
264
|
+
deuterium: 20000,
|
|
265
|
+
energyCost: 0,
|
|
266
|
+
energyConsumption: 0,
|
|
267
|
+
deuteriumConsumption: 0,
|
|
268
|
+
production: 0,
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
42: {
|
|
272
|
+
ogameId: 42,
|
|
273
|
+
names: { en: 'Sensor Phalanx', fr: 'Phalange de capteur' },
|
|
274
|
+
category: CATEGORIES.MOON,
|
|
275
|
+
factor: 2,
|
|
276
|
+
base: {
|
|
277
|
+
metal: 20000,
|
|
278
|
+
crystal: 40000,
|
|
279
|
+
deuterium: 20000,
|
|
280
|
+
energyCost: 0,
|
|
281
|
+
energyConsumption: 0,
|
|
282
|
+
deuteriumConsumption: 0,
|
|
283
|
+
production: 0,
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
43: {
|
|
287
|
+
ogameId: 43,
|
|
288
|
+
names: { en: 'Jump Gate', fr: 'Porte de saut spatial' },
|
|
289
|
+
category: CATEGORIES.MOON,
|
|
290
|
+
factor: 2,
|
|
291
|
+
base: {
|
|
292
|
+
metal: 2000000,
|
|
293
|
+
crystal: 4000000,
|
|
294
|
+
deuterium: 2000000,
|
|
295
|
+
energyCost: 0,
|
|
296
|
+
energyConsumption: 0,
|
|
297
|
+
deuteriumConsumption: 0,
|
|
298
|
+
production: 0,
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
44: {
|
|
302
|
+
ogameId: 44,
|
|
303
|
+
names: { en: 'Missile Silo', fr: 'Silo de missiles' },
|
|
304
|
+
category: CATEGORIES.FACILITIES,
|
|
305
|
+
factor: 2,
|
|
306
|
+
base: {
|
|
307
|
+
metal: 20000,
|
|
308
|
+
crystal: 20000,
|
|
309
|
+
deuterium: 1000,
|
|
310
|
+
energyCost: 0,
|
|
311
|
+
energyConsumption: 0,
|
|
312
|
+
deuteriumConsumption: 0,
|
|
313
|
+
production: 0,
|
|
55
314
|
},
|
|
56
315
|
},
|
|
57
316
|
});
|
|
58
317
|
|
|
318
|
+
export { CATEGORIES };
|
|
59
319
|
export default BUILDINGS;
|