ogamejs 3.0.0 → 4.0.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.
Files changed (92) hide show
  1. package/README.md +485 -228
  2. package/package.json +51 -4
  3. package/src/buildings/buildTime.js +25 -0
  4. package/src/buildings/crystal.js +18 -36
  5. package/src/buildings/deut.js +19 -34
  6. package/src/buildings/fusion-reactor.js +19 -34
  7. package/src/buildings/index.js +11 -0
  8. package/src/buildings/info.js +42 -0
  9. package/src/buildings/infocompte.js +116 -57
  10. package/src/buildings/metal.js +13 -28
  11. package/src/buildings/production.js +150 -0
  12. package/src/buildings/solar-plant.js +13 -21
  13. package/src/buildings/storage.js +59 -0
  14. package/src/cost.js +70 -0
  15. package/src/fleets/combat.js +291 -0
  16. package/src/fleets/distance.js +39 -0
  17. package/src/fleets/flight.js +105 -0
  18. package/src/fleets/getDebris.js +11 -10
  19. package/src/fleets/index.js +12 -0
  20. package/src/fleets/speed.js +108 -0
  21. package/src/i18n.js +43 -0
  22. package/src/index.js +12 -1
  23. package/src/models/buildings.js +285 -25
  24. package/src/models/destroyable.js +216 -110
  25. package/src/models/research.js +169 -0
  26. package/src/research/index.js +9 -0
  27. package/src/research/researchTime.js +25 -0
  28. package/src/types.js +146 -0
  29. package/types/buildings/buildTime.d.ts +16 -0
  30. package/types/buildings/buildTime.d.ts.map +1 -0
  31. package/types/buildings/crystal.d.ts +12 -0
  32. package/types/buildings/crystal.d.ts.map +1 -0
  33. package/types/buildings/deut.d.ts +12 -0
  34. package/types/buildings/deut.d.ts.map +1 -0
  35. package/types/buildings/fusion-reactor.d.ts +15 -0
  36. package/types/buildings/fusion-reactor.d.ts.map +1 -0
  37. package/types/buildings/index.d.ts +27 -0
  38. package/types/buildings/index.d.ts.map +1 -0
  39. package/types/buildings/info.d.ts +17 -0
  40. package/types/buildings/info.d.ts.map +1 -0
  41. package/types/buildings/infocompte.d.ts +41 -0
  42. package/types/buildings/infocompte.d.ts.map +1 -0
  43. package/types/buildings/metal.d.ts +11 -0
  44. package/types/buildings/metal.d.ts.map +1 -0
  45. package/types/buildings/production.d.ts +78 -0
  46. package/types/buildings/production.d.ts.map +1 -0
  47. package/types/buildings/solar-plant.d.ts +10 -0
  48. package/types/buildings/solar-plant.d.ts.map +1 -0
  49. package/types/buildings/storage.d.ts +29 -0
  50. package/types/buildings/storage.d.ts.map +1 -0
  51. package/types/cost.d.ts +25 -0
  52. package/types/cost.d.ts.map +1 -0
  53. package/types/fleets/combat.d.ts +57 -0
  54. package/types/fleets/combat.d.ts.map +1 -0
  55. package/types/fleets/distance.d.ts +13 -0
  56. package/types/fleets/distance.d.ts.map +1 -0
  57. package/types/fleets/flight.d.ts +57 -0
  58. package/types/fleets/flight.d.ts.map +1 -0
  59. package/types/fleets/getDebris.d.ts +12 -0
  60. package/types/fleets/getDebris.d.ts.map +1 -0
  61. package/types/fleets/index.d.ts +18 -0
  62. package/types/fleets/index.d.ts.map +1 -0
  63. package/types/fleets/speed.d.ts +54 -0
  64. package/types/fleets/speed.d.ts.map +1 -0
  65. package/types/i18n.d.ts +23 -0
  66. package/types/i18n.d.ts.map +1 -0
  67. package/types/index.d.ts +1316 -0
  68. package/types/index.d.ts.map +1 -0
  69. package/types/models/buildings.d.ts +373 -0
  70. package/types/models/buildings.d.ts.map +1 -0
  71. package/types/models/destroyable.d.ts +695 -0
  72. package/types/models/destroyable.d.ts.map +1 -0
  73. package/types/models/research.d.ts +262 -0
  74. package/types/models/research.d.ts.map +1 -0
  75. package/types/research/index.d.ts +8 -0
  76. package/types/research/index.d.ts.map +1 -0
  77. package/types/research/researchTime.d.ts +16 -0
  78. package/types/research/researchTime.d.ts.map +1 -0
  79. package/types/trades/crystal.d.ts +6 -0
  80. package/types/trades/crystal.d.ts.map +1 -0
  81. package/types/trades/deut.d.ts +6 -0
  82. package/types/trades/deut.d.ts.map +1 -0
  83. package/types/trades/index.d.ts +12 -0
  84. package/types/trades/index.d.ts.map +1 -0
  85. package/types/trades/metal.d.ts +6 -0
  86. package/types/trades/metal.d.ts.map +1 -0
  87. package/types/trades/parseRate.d.ts +2 -0
  88. package/types/trades/parseRate.d.ts.map +1 -0
  89. package/types/trades/utils.d.ts +2 -0
  90. package/types/trades/utils.d.ts.map +1 -0
  91. package/types/types.d.ts +449 -0
  92. 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 };
@@ -1,19 +1,20 @@
1
1
  /**
2
2
  *
3
- * Returns the number of debris generated
4
- * @param {number} shipId The ship identifier
5
- * @param {number} number The number of ship
6
- * @param {number} factor The universe debris factor
7
- * @return {Object} The debris generated
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 metalDebris = cost.metal ? cost.metal * factor : 0;
12
- const crystalDebris = cost.crystal ? cost.crystal * factor : 0;
12
+ const deuteriumCost = cost.deuterium ?? cost.deut ?? 0;
13
13
 
14
14
  return {
15
- metal: metalDebris * number,
16
- crystal: crystalDebris * number,
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
 
@@ -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
 
@@ -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
- name: 'Mine de métal',
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
- deutrium: 0,
10
- energy: 10,
33
+ deuterium: 0,
34
+ energyCost: 0,
35
+ energyConsumption: 10,
36
+ deuteriumConsumption: 0,
37
+ production: 30,
11
38
  },
12
39
  },
13
40
  2: {
14
- name: 'Mine de cristal',
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
- deutrium: 0,
21
- energy: 10,
48
+ deuterium: 0,
49
+ energyCost: 0,
50
+ energyConsumption: 10,
51
+ deuteriumConsumption: 0,
52
+ production: 20,
22
53
  },
23
54
  },
24
55
  3: {
25
- name: 'Synthétiseur de deutérium',
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
- deutrium: 0,
32
- energy: 20,
63
+ deuterium: 0,
64
+ energyCost: 0,
65
+ energyConsumption: 20,
66
+ deuteriumConsumption: 0,
67
+ production: 10,
33
68
  },
34
69
  },
35
70
  4: {
36
- name: 'Centrale électrique solaire',
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
- deutrium: 0,
43
- energy: 0,
78
+ deuterium: 0,
79
+ energyCost: 0,
80
+ energyConsumption: 0,
81
+ deuteriumConsumption: 0,
82
+ production: 20,
44
83
  },
45
84
  },
46
85
  5: {
47
- name: 'Centrale électrique de fusion',
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
- deutrium: 180,
54
- energy: 0,
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;