Compare commits

...

31 Commits

Author SHA1 Message Date
Cmdr McDonald
178d38f28d Merge branch 'release/2.2.17' 2017-02-18 10:00:10 +00:00
Cmdr McDonald
e42a0d1210 Bump 2017-02-18 10:00:07 +00:00
Cmdr McDonald
ddb89c47e7 Merge branch 'feature/multicrew' into develop 2017-02-18 09:51:24 +00:00
Cmdr McDonald
8b9aae342b Fix incorrect terminology for shield metrics. Fixes #5 2017-02-18 09:07:18 +00:00
Cmdr McDonald
ab1d73a6ea Add crew 2017-02-16 22:43:06 +00:00
Cmdr McDonald
d73a3cc2b4 Merge branch 'release/2.2.16' into develop 2017-02-15 20:44:21 +00:00
Cmdr McDonald
230351b959 Merge branch 'release/2.2.16' 2017-02-15 20:44:17 +00:00
Cmdr McDonald
4ee5c03cd1 Bump version 2017-02-15 20:44:09 +00:00
Cmdr McDonald
d8e9733170 Fix issue where extreme values didn't know if a given value was higher == better or higher == worse 2017-02-15 19:10:58 +00:00
Cmdr McDonald
aba2abe507 Merge branch 'release/2.2.15' into develop 2017-02-13 19:50:55 +00:00
Cmdr McDonald
45e6b71ec9 Merge branch 'release/2.2.15' 2017-02-13 19:50:51 +00:00
Cmdr McDonald
15a14dc280 Package version 2017-02-13 19:50:47 +00:00
Cmdr McDonald
cbac650b9e Added miner and shielded miner roles 2017-02-13 08:07:35 +00:00
Cmdr McDonald
f011f1f4d5 Add ability to export module list to EDDB to find where they can be purchased 2017-02-13 07:59:29 +00:00
Cmdr McDonald
d467ad5f7c Merge branch 'feature/fixes' into develop 2017-02-12 11:11:10 +00:00
Cmdr McDonald
b56ac177d9 Merge branch 'willyb321-master' into feature/fixes 2017-02-12 11:08:05 +00:00
Cmdr McDonald
5b13d64a1d Merge branch 'master' of https://github.com/willyb321/coriolis into willyb321-master 2017-02-12 11:07:46 +00:00
Cmdr McDonald
2620935745 Add additional explanation for import failures 2017-02-12 08:31:09 +00:00
Cmdr McDonald
45852db507 Add 'Extreme' roll 2017-02-11 19:57:46 +00:00
Cmdr McDonald
7fbcbb75ed Do not rely on slot sizes being correct 2017-02-11 19:45:28 +00:00
Cmdr McDonald
abf65ee436 Reload page if Safari throws a security error 2017-02-10 18:22:39 +00:00
Cmdr McDonald
24849cee08 Ensure that standard slots are repainted when any component changes 2017-02-08 10:09:30 +00:00
Cmdr McDonald
9e5efe50dc Merge branch 'release/2.2.14' into develop 2017-02-08 09:29:08 +00:00
Cmdr McDonald
39e9a38068 Merge branch 'release/2.2.14' 2017-02-08 09:29:04 +00:00
Cmdr McDonald
73d5915b3a Package bump 2017-02-08 09:27:27 +00:00
Cmdr McDonald
b06d2d1f72 Merge branch 'feature/mods' into develop 2017-02-08 09:26:09 +00:00
Cmdr McDonald
6e71f5e6db Use ship name rather than model if possible 2017-02-08 09:24:13 +00:00
William
588cfc3990 fix wiki link 2017-02-08 16:14:34 +11:00
Cmdr McDonald
191e31ff18 Use new-style blueprint data; fix numeric special effect calculations 2017-02-05 15:38:04 +00:00
Cmdr McDonald
c655b65779 Ensure TTD is recalculated when EPS is recalculated 2017-02-02 23:40:24 +00:00
Cmdr McDonald
3e168a3e5f Merge branch 'release/2.2.13' into develop 2017-02-02 23:05:50 +00:00
25 changed files with 672 additions and 132 deletions

View File

@@ -1,3 +1,40 @@
#2.2.17
* Use in-game terminology for shield generator optmul and optmass items
* Add crew to shipyard and outfitting page information
* Use coriolis-data 2.2.17:
* Add mass as potential SCB modification
* Fix mining laser statistics
* Remove non-existent grade 4 and 5 wake scanner modifications
* Add number of crew for each ship
#2.2.16
* Fix 'Extreme' blueprint roll where some incorrect ranges were chosen
* Use coriolis-data 2.2.16:
* Fix incorrect thermal load modifiers for dirty drives
* Provide explicit information about if values are higher numeric value == better or not
#2.2.15
* Ensure that standard slots are repainted when any component changes
* Reload page if Safari throws a security error
* Handle import of ships with incorrectly-sized slots
* Add 'Extreme' blueprint roll: best beneficial and worst detrimental outcome (in place of 'Average' roll)
* Display information about Microsoft browser issues when an import fails
* Add 'purchase this build' icon link to EDDB
* Add 'miner' and 'shielded miner' ship roles
* Use coriolis-data 2.2.15:
* Fix location of initial cargo rack for Vulture
* Fix broken regeneration rate for 6B shield generators
* Tidy up breach damage values
#2.2.14
* Ensure that jitter is shown correctly when the result of a special effect
* Use restyled blueprint information
* Use the ship name (if available) rather than the ship model for the window title
* Use coriolis-data 2.2.14:
* Alter blueprint structure to combine components and features
* Make hidden value of modifications its own attribute
* Fix incorrect ED ID for class 6 passenger cabins
#2.2.13
* Add 'time to drain' summary value. This is the time to drain the WEP capacitor if firing all enabled weapons
* Do not include utility slot DPS/EPS/HPS in summary information

View File

@@ -16,7 +16,7 @@ Chat to us on [Discord](https://discord.gg/0uwCh6R62aPRjk9w)!
## Development
See the [Developer's Guide](https://github.com/cmmcleod/coriolis/wiki/Developer's-Guide) in the wiki.
See the [Developer's Guide](https://github.com/EDCD/coriolis/wiki/Developing-for-Coriolis) in the wiki.
### Ship and Module Database

View File

@@ -320,6 +320,7 @@
"shieldExplRes": 0.5,
"shieldKinRes": 0.4,
"shieldThermRes": -0.2,
"timeToDrain": 7.04
"timeToDrain": 7.04,
"crew": 3
}
}

View File

@@ -0,0 +1,314 @@
{
"cargo": {
"capacity": 264
},
"free": false,
"fuel": {
"main": {
"capacity": 32
},
"reserve": {
"capacity": 0.52
}
},
"id": 4,
"modules": {
"Armour": {
"module": {
"free": false,
"id": 128049298,
"name": "Type7_Armour_Grade1",
"on": true,
"priority": 1,
"unloaned": 0,
"value": 0
}
},
"Bobble01": [],
"Bobble02": [],
"Bobble03": [],
"Bobble04": [],
"Bobble05": [],
"Bobble06": [],
"Bobble07": [],
"Bobble08": [],
"Bobble09": [],
"Bobble10": [],
"Decal1": {
"module": {
"free": false,
"id": 128667746,
"name": "Decal_Trade_Dealer",
"on": true,
"priority": 1,
"unloaned": 0,
"value": 0
}
},
"Decal2": {
"module": {
"free": false,
"id": 128667738,
"name": "Decal_Combat_Competent",
"on": true,
"priority": 1,
"unloaned": 0,
"value": 0
}
},
"Decal3": {
"module": {
"free": false,
"id": 128667753,
"name": "Decal_Explorer_Scout",
"on": true,
"priority": 1,
"unloaned": 0,
"value": 0
}
},
"EngineColour": [],
"FrameShiftDrive": {
"module": {
"free": false,
"id": 128064122,
"name": "Int_Hyperdrive_Size5_Class5",
"on": true,
"priority": 0,
"unloaned": 0,
"value": 5103953
}
},
"FuelTank": {
"module": {
"free": false,
"id": 128064350,
"name": "Int_FuelTank_Size5_Class3",
"on": true,
"priority": 1,
"unloaned": 97754,
"value": 97754
}
},
"LifeSupport": {
"module": {
"free": false,
"id": 128064154,
"name": "Int_LifeSupport_Size4_Class2",
"on": true,
"priority": 0,
"unloaned": 0,
"value": 28373
}
},
"MainEngines": {
"module": {
"free": false,
"id": 128064087,
"name": "Int_Engine_Size5_Class5",
"on": true,
"priority": 0,
"unloaned": 0,
"value": 5103953
}
},
"PaintJob": {
"module": {
"free": false,
"id": 128671422,
"name": "PaintJob_Type7_Tactical_White",
"on": true,
"priority": 1,
"unloaned": 0,
"value": 0
}
},
"PlanetaryApproachSuite": {
"module": {
"free": false,
"id": 128672317,
"name": "Int_PlanetApproachSuite",
"on": true,
"priority": 1,
"unloaned": 500,
"value": 500
}
},
"PowerDistributor": {
"module": {
"free": false,
"id": 128064192,
"name": "Int_PowerDistributor_Size3_Class5",
"on": true,
"priority": 0,
"unloaned": 0,
"value": 158331
}
},
"PowerPlant": {
"module": {
"free": false,
"id": 128064047,
"name": "Int_Powerplant_Size4_Class5",
"on": true,
"priority": 1,
"unloaned": 0,
"value": 1610080
}
},
"Radar": {
"module": {
"free": false,
"id": 128064229,
"name": "Int_Sensors_Size3_Class2",
"on": true,
"priority": 0,
"unloaned": 0,
"value": 10133
}
},
"Slot01_Size6": {
"module": {
"free": false,
"id": 128064343,
"name": "Int_CargoRack_Size6_Class1",
"on": true,
"priority": 1,
"unloaned": 0,
"value": 362591
}
},
"Slot02_Size6": {
"module": {
"free": false,
"id": 128064343,
"name": "Int_CargoRack_Size6_Class1",
"on": true,
"priority": 1,
"unloaned": 0,
"value": 362591
}
},
"Slot03_Size5": {
"module": {
"free": false,
"id": 128064343,
"name": "Int_CargoRack_Size6_Class1",
"on": true,
"priority": 1,
"unloaned": 0,
"value": 362591
}
},
"Slot04_Size5": {
"module": {
"free": false,
"id": 128064342,
"name": "Int_CargoRack_Size5_Class1",
"on": true,
"priority": 1,
"unloaned": 111566,
"value": 111566
}
},
"Slot05_Size4": {
"module": {
"free": false,
"id": 128064342,
"name": "Int_CargoRack_Size5_Class1",
"on": true,
"priority": 1,
"unloaned": 111566,
"value": 111566
}
},
"Slot06_Size4": {
"module": {
"free": false,
"id": 128064279,
"name": "Int_ShieldGenerator_Size5_Class2",
"on": true,
"priority": 0,
"unloaned": 0,
"value": 189035
}
},
"Slot07_Size2": {
"module": {
"free": false,
"id": 128049549,
"name": "Int_DockingComputer_Standard",
"on": true,
"priority": 0,
"unloaned": 0,
"value": 4500
}
},
"Slot08_Size2": {
"module": {
"free": false,
"id": 128064340,
"name": "Int_CargoRack_Size3_Class1",
"on": true,
"priority": 1,
"unloaned": 0,
"value": 10563
}
},
"SmallHardpoint1": [],
"SmallHardpoint2": [],
"SmallHardpoint3": [],
"SmallHardpoint4": [],
"TinyHardpoint1": {
"module": {
"free": false,
"id": 128668536,
"name": "Hpt_ShieldBooster_Size0_Class5",
"on": true,
"priority": 0,
"unloaned": 0,
"value": 281000
}
},
"TinyHardpoint2": {
"module": {
"free": false,
"id": 128668536,
"name": "Hpt_ShieldBooster_Size0_Class5",
"on": true,
"priority": 0,
"unloaned": 0,
"value": 281000
}
},
"TinyHardpoint3": {
"module": {
"free": false,
"id": 128668536,
"name": "Hpt_ShieldBooster_Size0_Class5",
"on": true,
"priority": 0,
"unloaned": 0,
"value": 281000
}
},
"TinyHardpoint4": {
"module": {
"free": false,
"id": 128049513,
"name": "Hpt_ChaffLauncher_Tiny",
"on": true,
"priority": 0,
"unloaned": 0,
"value": 8500
}
},
"WeaponColour": []
},
"name": "Type7",
"value": {
"hull": 16780009,
"modules": 14479580,
"unloaned": 321386
}
}

View File

@@ -229,7 +229,7 @@ describe('Import Modal', function() {
beforeEach(reset);
it('imports a valid v4 build', function() {
it('imports a valid companion API build', function() {
const importData = require('./fixtures/companion-api-import-1');
pasteText(JSON.stringify(importData));
@@ -241,7 +241,7 @@ describe('Import Modal', function() {
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/federal_corvette?code=A2putsFklndzsxf50x0x7l28281919040404040402020l06p05sf63c5ifr--v66g2f.AwRj4zNaqA%3D%3D.CwRgDBldUExuBiIlUA%3D%3D.H4sIAAAAAAAAA02SPy9DURjG3%2F65vW1v47TXVbeqqF7EQtIIBomRJswsYmISH8BgkFhqFZ9AwlALMYitkXQyEF2k4SMYJNK0dV7PK7nc5ck55%2Fm9z%2FnznpBeJqLvECQbM4hUjZnjO5hyWGfFikAGGjGiku0QuddhQCNdZmdWM9snsDmih4REOdlnNvz9DrPrJIicPdSwoZf8pAnTIpq8x7DYADS%2Bi5DERY85%2BYqpmkc6x%2FWGf6beKCR3YBIZFZCxCgrtczjuOmo4qTf94F4KYuxhz5jjEhXmUJNexFrpIUo02ALN1j9u1JMgD%2FMga1GfbMNRd9iHUwGy%2BpspZF3IBSGvMFJluS%2FuR24FJ2KlV%2Fxju6sQq4lhRsQTUVUJTgegLtS6EUjEE1HPAmUC0KdAjwKJeCKqD8zoURx72gHyDW9nvQhJGHkyUscS1x%2BAZnAlqwU%2FI%2BKJKEvextXrf93eQrR1KUlS5HWwGC61mfOn0oN3IM4OHoBzuuIHj33hS5jT8KeamIYa0sjhgH%2BLfplP4kcwD5Xl3xR1wfeHtqWzBHHX8I9SH9Je%2FgGvXxeungIAAA%3D%3D&bn=Imported%20Federal%20Corvette');
});
it('imports a valid v4 build', function() {
it('imports a valid companion API build', function() {
const importData = require('./fixtures/companion-api-import-2');
pasteText(JSON.stringify(importData));
@@ -252,6 +252,18 @@ describe('Import Modal', function() {
expect(MockRouter.go.mock.calls.length).toBe(1);
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/beluga?code=A0pktsFplCdpsnf70t0t2727270004040404043c4fmimlmm04mc0iv62i2f.AwRj4yukg%3D%3D%3D.CwRgDBldHi8IUA%3D%3D.H4sIAAAAAAAAA2P8Z8%2FAwPCXEUiIKTMxMPCv%2F%2Ff%2FP8cFIPGf6Z8YTEr0GjMDg%2FJWICERBOTzn%2Fn7%2F7%2FIO5Ai5n9SIEWsQEIoSxAolfbt%2F3%2BJPk4GBhE7YQYGYVmgcuVnf4Aq%2FwMAIrEcGGsAAAA%3D&bn=Imported%20Beluga%20Liner');
});
it('imports a valid companion API build', function() {
const importData = require('./fixtures/companion-api-import-3');
pasteText(JSON.stringify(importData));
expect(modal.state.importValid).toBeTruthy();
expect(modal.state.errorMsg).toEqual(null);
expect(modal.state.singleBuild).toBe(true);
clickProceed();
expect(MockRouter.go.mock.calls.length).toBe(1);
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/type_7_transport?code=A0patfFflidasdf5----0404040005050504044d2402.AwRj4yrI.CwRgDBlVK7EiA%3D%3D%3D.&bn=Imported%20Type-7%20Transporter');
});
});
describe('Import E:D Shipyard Builds', function() {

View File

@@ -1,6 +1,6 @@
{
"name": "coriolis_shipyard",
"version": "2.2.13",
"version": "2.2.17",
"repository": {
"type": "git",
"url": "https://github.com/EDCD/coriolis"

View File

@@ -76,7 +76,16 @@ Router.go = function(path, state) {
if (isStandAlone()) {
Persist.setState(ctx);
}
history.pushState(ctx.state, ctx.title, ctx.canonicalPath);
try {
history.pushState(ctx.state, ctx.title, ctx.canonicalPath);
} catch (ex) {
sessionStorage.setItem('__safari_history_fix', JSON.stringify({
state: ctx.state,
title: ctx.title,
path: ctx.canonicalPath
}));
location.reload();
}
}
return ctx;
};
@@ -99,7 +108,16 @@ Router.replace = function(path, state, dispatch) {
if (isStandAlone()) {
Persist.setState(ctx);
}
history.replaceState(ctx.state, ctx.title, ctx.canonicalPath);
try {
history.replaceState(ctx.state, ctx.title, ctx.canonicalPath);
} catch (ex) {
sessionStorage.setItem('__safari_history_fix', JSON.stringify({
state: ctx.state,
title: ctx.title,
path: ctx.canonicalPath
}));
location.reload();
}
return ctx;
};

View File

@@ -39,8 +39,8 @@ export default class InternalSlot extends Slot {
<div className={'r'}>{formats.round(mass)}{u.T}</div>
</div>
<div className={'cb'}>
{ m.getOptMass() ? <div className={'l'}>{translate('optimal mass')}: {formats.int(m.getOptMass())}{u.T}</div> : null }
{ m.getMaxMass() ? <div className={'l'}>{translate('max mass')}: {formats.int(m.getMaxMass())}{u.T}</div> : null }
{ m.getOptMass() ? <div className={'l'}>{translate('optmass', m.grp)}: {formats.int(m.getOptMass())}{u.T}</div> : null }
{ m.getMaxMass() ? <div className={'l'}>{translate('maxmass', m.grp)}: {formats.int(m.getMaxMass())}{u.T}</div> : null }
{ m.bins ? <div className={'l'}>{m.bins} <u>{translate('bins')}</u></div> : null }
{ m.bays ? <div className={'l'}>{translate('bays')}: {m.bays}</div> : null }
{ m.rebuildsperbay ? <div className={'l'}>{translate('rebuildsperbay')}: {m.rebuildsperbay}</div> : null }

View File

@@ -81,7 +81,7 @@ export default class Modification extends TranslatedComponent {
return (
<div className={'cb'} key={name}>
<div className={'cb'}>{translate(name)}{symbol}</div>
<div className={'cb'}>{translate(name, m.grp)}{symbol}</div>
<NumberEditor className={'cb'} style={{ width: '90%', textAlign: 'center' }} step={0.01} stepModifier={1} decimals={2} value={this.state.value} onValueChange={this._updateValue.bind(this)} />
</div>
);

View File

@@ -32,8 +32,8 @@ export default class ModificationsMenu extends TranslatedComponent {
this._toggleSpecialsMenu = this._toggleSpecialsMenu.bind(this);
this._rollWorst = this._rollWorst.bind(this);
this._rollRandom = this._rollRandom.bind(this);
this._rollAverage = this._rollAverage.bind(this);
this._rollBest = this._rollBest.bind(this);
this._rollExtreme = this._rollExtreme.bind(this);
this._reset = this._reset.bind(this);
}
@@ -87,7 +87,7 @@ export default class ModificationsMenu extends TranslatedComponent {
const { m, onChange, ship } = props;
let modifications = [];
for (const modName of Modifications.modules[m.grp].modifications) {
if (Modifications.modifications[modName].type === 'percentage' || Modifications.modifications[modName].type === 'numeric') {
if (!Modifications.modifications[modName].hidden) {
const key = modName + (m.getModValue(modName) / 100 || 0);
modifications.push(<Modification key={ key } ship={ ship } m={ m } name={ modName } value={ m.getModValue(modName) / 100 || 0 } onChange={ onChange }/>);
}
@@ -147,58 +147,40 @@ export default class ModificationsMenu extends TranslatedComponent {
this.props.onChange();
}
/**
* Set the result of a roll
* @param {object} ship The ship to which the roll applies
* @param {object} m The module to which the roll applies
* @param {string} featureName The modification feature to which the roll applies
* @param {number} value The value of the roll
*/
_setRollResult(ship, m, featureName, value) {
if (Modifications.modifications[featureName].method !== 'overwrite') {
if (m.grp == 'sb' && featureName == 'shieldboost') {
// Shield boosters are a special case. Their boost is dependent on their base so we need to calculate the value here
value = ((1 + m.shieldboost) * (1 + value) - 1) / m.shieldboost - 1;
}
}
if (Modifications.modifications[featureName].type == 'percentage') {
ship.setModification(m, featureName, value * 10000);
} else if (Modifications.modifications[featureName].type == 'numeric') {
ship.setModification(m, featureName, value * 100);
} else {
ship.setModification(m, featureName, value);
}
}
/**
* Provide a 'worst' roll within the information we have
*/
_rollWorst() {
const { m, ship } = this.props;
const features = m.blueprint.features[m.blueprint.grade];
const features = m.blueprint.grades[m.blueprint.grade].features;
for (const featureName in features) {
if (Modifications.modifications[featureName].method == 'overwrite') {
ship.setModification(m, featureName, features[featureName][1]);
} else {
let value = features[featureName][0];
if (m.grp == 'sb' && featureName == 'shieldboost') {
// Shield boosters are a special case. Their boost is dependent on their base so we need to calculate the value here
value = ((1 + m.shieldboost) * (1 + value) - 1) / m.shieldboost - 1;
}
if (Modifications.modifications[featureName].type == 'percentage') {
ship.setModification(m, featureName, value * 10000);
} else if (Modifications.modifications[featureName].type == 'numeric') {
ship.setModification(m, featureName, value * 100);
}
}
let value = features[featureName][0];
this._setRollResult(ship, m, featureName, value);
}
this.setState({ modifications: this._setModifications(this.props) });
this.props.onChange();
}
/**
* Provide an 'average' roll within the information we have
*/
_rollAverage() {
const { m, ship } = this.props;
const features = m.blueprint.features[m.blueprint.grade];
for (const featureName in features) {
if (Modifications.modifications[featureName].method == 'overwrite') {
ship.setModification(m, featureName, (features[featureName][0] + features[featureName][1]) / 2);
} else {
let value = (features[featureName][0] + features[featureName][1]) / 2;
if (m.grp == 'sb' && featureName == 'shieldboost') {
// Shield boosters are a special case. Their boost is dependent on their base so we need to calculate the value here
value = ((1 + m.shieldboost) * (1 + value) - 1) / m.shieldboost - 1;
}
if (Modifications.modifications[featureName].type == 'percentage') {
ship.setModification(m, featureName, value * 10000);
} else if (Modifications.modifications[featureName].type == 'numeric') {
ship.setModification(m, featureName, value * 100);
}
}
}
this.setState({ modifications: this._setModifications(this.props) });
this.props.onChange();
}
@@ -208,25 +190,11 @@ export default class ModificationsMenu extends TranslatedComponent {
*/
_rollRandom() {
const { m, ship } = this.props;
const features = m.blueprint.features[m.blueprint.grade];
const features = m.blueprint.grades[m.blueprint.grade].features;
for (const featureName in features) {
if (Modifications.modifications[featureName].method == 'overwrite') {
ship.setModification(m, featureName, features[featureName][1]);
} else {
let value = features[featureName][0] + (Math.random() * (features[featureName][1] - features[featureName][0]));
if (m.grp == 'sb' && featureName == 'shieldboost') {
// Shield boosters are a special case. Their boost is dependent on their base so we need to calculate the value here
value = ((1 + m.shieldboost) * (1 + value) - 1) / m.shieldboost - 1;
}
if (Modifications.modifications[featureName].type == 'percentage') {
ship.setModification(m, featureName, value * 10000);
} else if (Modifications.modifications[featureName].type == 'numeric') {
ship.setModification(m, featureName, value * 100);
}
}
let value = features[featureName][0] + (Math.random() * (features[featureName][1] - features[featureName][0]));
this._setRollResult(ship, m, featureName, value);
}
this.setState({ modifications: this._setModifications(this.props) });
this.props.onChange();
}
@@ -236,25 +204,25 @@ export default class ModificationsMenu extends TranslatedComponent {
*/
_rollBest() {
const { m, ship } = this.props;
const features = m.blueprint.features[m.blueprint.grade];
const features = m.blueprint.grades[m.blueprint.grade].features;
for (const featureName in features) {
if (Modifications.modifications[featureName].method == 'overwrite') {
ship.setModification(m, featureName, features[featureName][1]);
} else {
let value = features[featureName][1];
if (m.grp == 'sb' && featureName == 'shieldboost') {
// Shield boosters are a special case. Their boost is dependent on their base so we need to calculate the value here
value = ((1 + m.shieldboost) * (1 + value) - 1) / m.shieldboost - 1;
}
if (Modifications.modifications[featureName].type == 'percentage') {
ship.setModification(m, featureName, value * 10000);
} else if (Modifications.modifications[featureName].type == 'numeric') {
ship.setModification(m, featureName, value * 100);
}
}
let value = features[featureName][1];
this._setRollResult(ship, m, featureName, value);
}
this.setState({ modifications: this._setModifications(this.props) });
this.props.onChange();
}
/**
* Provide an 'extreme' roll within the information we have
*/
_rollExtreme() {
const { m, ship } = this.props;
const features = m.blueprint.grades[m.blueprint.grade].features;
for (const featureName in features) {
const value = Modifications.modifications[featureName].higherbetter ? features[featureName][1] : features[featureName][0];
this._setRollResult(ship, m, featureName, value);
}
this.setState({ modifications: this._setModifications(this.props) });
this.props.onChange();
}
@@ -284,8 +252,8 @@ export default class ModificationsMenu extends TranslatedComponent {
const _toggleBlueprintsMenu = this._toggleBlueprintsMenu;
const _toggleSpecialsMenu = this._toggleSpecialsMenu;
const _rollBest = this._rollBest;
const _rollExtreme = this._rollExtreme;
const _rollWorst = this._rollWorst;
const _rollAverage = this._rollAverage;
const _rollRandom = this._rollRandom;
const _reset = this._reset;
@@ -310,6 +278,7 @@ export default class ModificationsMenu extends TranslatedComponent {
const showSpecial = haveBlueprint && this.state.specials.length > 0;
const showSpecialsMenu = specialMenuOpened;
const showRolls = haveBlueprint && !blueprintMenuOpened && !specialMenuOpened;
const showReset = !blueprintMenuOpened && !specialMenuOpened;
const showMods = !blueprintMenuOpened && !specialMenuOpened;
return (
@@ -319,26 +288,30 @@ export default class ModificationsMenu extends TranslatedComponent {
onContextMenu={stopCtxPropagation}
>
<div className={ cn('section-menu', { selected: blueprintMenuOpened })} style={{ cursor: 'pointer' }} onClick={_toggleBlueprintsMenu}>{blueprintLabel}</div>
{ showBlueprintsMenu ? this.state.blueprints : '' }
{ showSpecial ? <div className={ cn('section-menu', { selected: specialMenuOpened })} style={{ cursor: 'pointer' }} onClick={_toggleSpecialsMenu}>{specialLabel}</div> : '' }
{ showSpecialsMenu ? this.state.specials : '' }
{ showRolls ?
{ showBlueprintsMenu ? this.state.blueprints : null }
{ showSpecial ? <div className={ cn('section-menu', { selected: specialMenuOpened })} style={{ cursor: 'pointer' }} onClick={_toggleSpecialsMenu}>{specialLabel}</div> : null }
{ showSpecialsMenu ? this.state.specials : null }
{ showRolls || showReset ?
<table style={{ width: '100%', backgroundColor: 'transparent' }}>
<tbody>
{ showRolls ?
<tr>
<td> { translate('roll') }: </td>
<td style={{ cursor: 'pointer' }} onClick={_rollWorst} onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_WORST')} onMouseOut={tooltip.bind(null, null)}> { translate('worst') } </td>
<td style={{ cursor: 'pointer' }} onClick={_rollAverage}onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_AVERAGE')} onMouseOut={tooltip.bind(null, null)}> { translate('average') } </td>
<td style={{ cursor: 'pointer' }} onClick={_rollBest}onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_BEST')} onMouseOut={tooltip.bind(null, null)}> { translate('best') } </td>
<td style={{ cursor: 'pointer' }} onClick={_rollExtreme}onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_EXTREME')} onMouseOut={tooltip.bind(null, null)}> { translate('extreme') } </td>
<td style={{ cursor: 'pointer' }} onClick={_rollRandom} onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_RANDOM')} onMouseOut={tooltip.bind(null, null)}> { translate('random') } </td>
<td style={{ cursor: 'pointer' }} onClick={_reset}onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_RESET')} onMouseOut={tooltip.bind(null, null)}> { translate('reset') } </td>
</tr>
</tr> : null }
{ showReset ?
<tr>
<td colSpan={'5'} style={{ cursor: 'pointer' }} onClick={_reset}onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_RESET')} onMouseOut={tooltip.bind(null, null)}> { translate('reset') } </td>
</tr> : null }
</tbody>
</table> : '' }
</table> : null }
{ showMods ?
<span onMouseOver={termtip.bind(null, 'HELP_MODIFICATIONS_MENU')} onMouseOut={tooltip.bind(null, null)} >
{ this.state.modifications }
</span> : '' }
</span> : null }
</div>
);
}

View File

@@ -52,6 +52,7 @@ export default class ShipSummaryTable extends TranslatedComponent {
<th rowSpan={2}>{translate('fuel')}</th>
<th colSpan={3}>{translate('jump range')}</th>
<th onMouseEnter={termtip.bind(null, 'PHRASE_FASTEST_RANGE')} onMouseLeave={hide} colSpan={3}>{translate('fastest range')}</th>
<th rowSpan={2}>{translate('crew')}</th>
<th onMouseEnter={termtip.bind(null, 'mass lock factor')} onMouseLeave={hide} rowSpan={2}>{translate('MLF')}</th>
</tr>
<tr>
@@ -88,6 +89,7 @@ export default class ShipSummaryTable extends TranslatedComponent {
<td>{int(ship.maxJumpCount)}</td>
<td>{f2(ship.unladenFastestRange)} {u.LY}</td>
<td>{f2(ship.ladenFastestRange)} {u.LY}</td>
<td>{ship.crew}</td>
<td>{ship.masslock}</td>
</tr>
</tbody>

View File

@@ -64,7 +64,7 @@ export default class SlotSection extends TranslatedComponent {
* @param {Object} m Selected module
*/
_selectModule(slot, m) {
this.props.ship.use(slot, m);
this.props.ship.use(slot, m, false);
this.props.onChange();
this._close();
}
@@ -123,7 +123,7 @@ export default class SlotSection extends TranslatedComponent {
// We want to copy the module in to the target slot
if (targetSlot && canMount(this.props.ship, targetSlot, m.grp, m.class)) {
const mCopy = m.clone();
this.props.ship.use(targetSlot, mCopy);
this.props.ship.use(targetSlot, mCopy, false);
this.props.onChange();
}
} else {

View File

@@ -53,6 +53,16 @@ export default class StandardSlotSection extends SlotSection {
this._close();
}
/**
* Miner Build
* @param {Boolean} shielded True if shield generator should be included
*/
_optimizeMiner(shielded) {
ShipRoles.miner(this.props.ship, shielded);
this.props.onChange();
this._close();
}
/**
* Explorer role
* @param {Boolean} planetary True if Planetary Vehicle Hangar (PVH) should be included
@@ -209,6 +219,8 @@ export default class StandardSlotSection extends SlotSection {
<li className='lc' onClick={this._optimizeCargo.bind(this, true)}>{translate('Shielded Trader')}</li>
<li className='lc' onClick={this._optimizeExplorer.bind(this, false)}>{translate('Explorer')}</li>
<li className={cn('lc', { disabled: planetaryDisabled })} onClick={!planetaryDisabled && this._optimizeExplorer.bind(this, true)}>{translate('Planetary Explorer')}</li>
<li className='lc' onClick={this._optimizeMiner.bind(this, false)}>{translate('Miner')}</li>
<li className='lc' onClick={this._optimizeMiner.bind(this, true)}>{translate('Shielded Miner')}</li>
</ul>
</div>;
}

View File

@@ -227,6 +227,26 @@ export class LinkIcon extends SvgIcon {
}
}
/**
* Shopping icon (dollar sign)
*/
export class ShoppingIcon extends SvgIcon {
/**
* Overriden view box
* @return {String} view box
*/
viewBox() { return '0 0 200 200'; }
/**
* Generate the SVG
* @return {React.Component} SVG Contents
*/
svg() {
return <g>
<path d='M94 188v-17c-9-1-16-3-21-6-6-3-11-7-15-14-4-6-6-14-6-23l17-3c2 9 4 16 7 21 5 6 11 9 18 10v-56c-7-1-14-4-22-8-6-3-10-8-13-13-3-6-4-12-4-19 0-13 4-23 13-31 6-5 15-8 26-9v-8h11v8c10 1 18 4 24 9 8 6 12 15 14 26l-18 3c-1-7-4-12-7-16s-8-6-13-7v50l17 6c6 2 10 5 13 8 4 4 7 8 8 13 2 4 3 10 3 15 0 12-4 22-11 31-8 8-18 12-30 13v17H94zm0-153c-7 1-12 3-16 8-4 4-6 9-6 15s2 11 5 16c4 4 9 7 17 9V35zm11 121a28 28 0 0 0 24-28c-1-6-2-11-6-15-3-4-9-7-18-10v53z'/>
</g>;
}
}
/**
* No Power - Lightning bolt + no entry
*/

View File

@@ -34,9 +34,9 @@ export function getLanguage(langCode) {
let gen = d3Locale.numberFormat('n');
if(lang === EN) {
translate = (t) => { return currentTerms[t] || t; };
translate = (t, x) => { return currentTerms[t + '_' + x] || currentTerms[t] || t; };
} else {
translate = (t) => { return currentTerms[t] || fallbackTerms[t] || t; };
translate = (t, x) => { return currentTerms[t + '_' + x] || currentTerms[t] || fallbackTerms[t + '_' + x] || fallbackTerms[t] || t; };
}
return {

View File

@@ -31,12 +31,13 @@ export const terms = {
PHRASE_ENGAGEMENT_RANGE: 'The distance between your ship and its target',
PHRASE_SELECT_BLUEPRINT: 'Click to select a blueprint',
PHRASE_BLUEPRINT_WORST: 'Worst primary values for this blueprint',
PHRASE_BLUEPRINT_AVERAGE: 'Average primary values for this blueprint',
PHRASE_BLUEPRINT_RANDOM: 'Random selection between worst and best primary values for this blueprint',
PHRASE_BLUEPRINT_BEST: 'Best primary values for this blueprint',
PHRASE_BLUEPRINT_EXTREME: 'Best beneficial and worst detrimental primary values for this blueprint',
PHRASE_BLUEPRINT_RESET: 'Remove all modifications and blueprint',
PHRASE_SELECT_SPECIAL: 'Click to select an experimental effect',
PHRASE_NO_SPECIAL: 'No experimental effect',
PHRASE_SHOPPING_LIST: 'Stations that sell this build',
HELP_MODIFICATIONS_MENU: 'Click on a number to enter a new value, or drag along the bar for small changes',
@@ -115,6 +116,7 @@ export const terms = {
average: 'Average',
random: 'Random',
best: 'Best',
extreme: 'Extreme',
reset: 'Reset',
// Weapon, offence, defence and movement
@@ -187,6 +189,14 @@ export const terms = {
wepcap: 'Weapons capacity',
weprate: 'Weapons recharge rate',
// Shield generators use a different terminology
minmass_sg: 'Minimum hull mass',
optmass_sg: 'Optimal hull mass',
maxmass_sg: 'Maximum hull mass',
minmul_sg: 'Minimum strength',
optmul_sg: 'Optimal strength',
maxmul_sg: 'Minimum strength',
// Help text
HELP_TEXT: `
<h1>Introduction</h1>
@@ -226,6 +236,8 @@ To remove a module from a slot right-click on the module. </p>
To move a module from one slot to another drag it. If you instead want to copy the module drag it whilst holding down the &apos;Alt&apos; key. </p>
Clicking on the headings for each set of modules gives you the ability to either select an overall role for your ship (when clicking the core internal header) or a specific module with which you want to fill all applicable slots (when clicking the other headers). </p>
<h2>Power Management</h2>
The power management panel provides information about power usage and priorities. It allows you to enable and disable individual modules, as well as set power priorities for each module.</p>

View File

@@ -39,10 +39,16 @@ export default class ErrorDetails extends React.Component {
</div>;
}
const importerror = ed && ed.scriptUrl && ed.scriptUrl.indexOf('/import') != -1;
return <div className='error'>
<h1>Jameson, we have a problem..</h1>
<h1><small>{error.message}</small></h1>
<br/>
{importerror ? <div>If you are attempting to import a ship from EDDI or EDMC and are seeing a 'Z_BUF_ERROR' it means that the URL has not been provided correctly. This is a common problem when using Microsoft Internet Explorer or Microsoft Edge, and you should use another browser instead.</div> : null }
<br/>
<div>Please note that this site uses Google Analytics to track performance and usage. If you are blocking cookies, for example using Ghostery, please disable blocking for this site and try again.</div>
<br/>
{content}
</div>;
}

View File

@@ -8,7 +8,7 @@ import Persist from '../stores/Persist';
import Ship from '../shipyard/Ship';
import { toDetailedBuild } from '../shipyard/Serializer';
import { outfitURL } from '../utils/UrlGenerators';
import { FloppyDisk, Bin, Switch, Download, Reload, Fuel, LinkIcon } from '../components/SvgIcons';
import { FloppyDisk, Bin, Switch, Download, Reload, Fuel, LinkIcon, ShoppingIcon } from '../components/SvgIcons';
import ShipSummaryTable from '../components/ShipSummaryTable';
import StandardSlotSection from '../components/StandardSlotSection';
import HardpointsSlotSection from '../components/HardpointsSlotSection';
@@ -36,7 +36,7 @@ const SPEED_COLORS = ['#0088d2', '#ff8c0d', '#D26D00', '#c06400'];
* @return {String} Document title
*/
function getTitle(shipName, buildName) {
return `${shipName}${buildName ? ` - ${buildName}` : ''}`;
return buildName ? buildName : shipName;
}
/**
@@ -284,6 +284,20 @@ export default class OutfittingPage extends Page {
this.context.showModal(<ModalPermalink url={window.location.href}/>);
}
/**
* Open up a window for EDDB with a shopping list of our components
*/
_eddbShoppingList() {
const ship = this.state.ship;
const shipId = Ships[ship.id].eddbID;
// Provide unique list of non-PP module EDDB IDs
const modIds = ship.internal.concat(ship.bulkheads, ship.standard, ship.hardpoints).filter(slot => slot !== null && slot.m !== null && !slot.m.pp).map(slot => slot.m.eddbID).filter((v, i, a) => a.indexOf(v) === i);
// Open up the relevant URL
window.open('https://eddb.io/station?s=' + shipId + '&m=' + modIds.join(','));
}
/**
* Handle Key Down
* @param {Event} e Keyboard Event
@@ -316,7 +330,6 @@ export default class OutfittingPage extends Page {
canRename = buildName && newBuildName && buildName != newBuildName,
canReload = savedCode && canSave,
hStr = ship.getHardpointsString() + '.' + ship.getModificationsString(),
sStr = ship.getStandardString() + '.' + ship.getModificationsString(),
iStr = ship.getInternalString() + '.' + ship.getModificationsString();
return (
@@ -343,19 +356,22 @@ export default class OutfittingPage extends Page {
<button onClick={buildName && this._exportBuild} disabled={!buildName} onMouseOver={termtip.bind(null, 'export')} onMouseOut={hide}>
<Download className='lg'/>
</button>
<button onClick={this._eddbShoppingList} onMouseOver={termtip.bind(null, 'PHRASE_SHOPPING_LIST')} onMouseOut={hide}>
<ShoppingIcon className='lg' />
</button>
<button onClick={this._genShortlink} onMouseOver={termtip.bind(null, 'shortlink')} onMouseOut={hide}>
<LinkIcon className='lg' />
</button>
</div>
</div>
<ShipSummaryTable ship={ship} code={code} />
<StandardSlotSection ship={ship} code={sStr} onChange={shipUpdated} currentMenu={menu} />
<ShipSummaryTable ship={ship} code={code || ''} />
<StandardSlotSection ship={ship} code={code || ''} onChange={shipUpdated} currentMenu={menu} />
<InternalSlotSection ship={ship} code={iStr} onChange={shipUpdated} currentMenu={menu} />
<HardpointsSlotSection ship={ship} code={hStr} onChange={shipUpdated} currentMenu={menu} />
<UtilitySlotSection ship={ship} code={hStr} onChange={shipUpdated} currentMenu={menu} />
<PowerManagement ship={ship} code={code} onChange={shipUpdated} />
<CostSection ship={ship} buildName={buildName} code={sStr + hStr + iStr} />
<HardpointsSlotSection ship={ship} code={hStr || ''} onChange={shipUpdated} currentMenu={menu} />
<UtilitySlotSection ship={ship} code={hStr || ''} onChange={shipUpdated} currentMenu={menu} />
<PowerManagement ship={ship} code={code || ''} onChange={shipUpdated} />
<CostSection ship={ship} buildName={buildName} code={code || ''} />
<div className='group third'>
<OffenceSummary ship={ship} code={code}/>

View File

@@ -39,6 +39,14 @@ export default class Page extends React.Component {
this[prop] = this[prop].bind(this);
}
});
let fix = sessionStorage.getItem('__safari_history_fix');
sessionStorage.removeItem('__safari_history_fix');
if (fix) {
fix = JSON.parse(fix);
history.replaceState(history.state, document.title, location.href);
history.pushState(fix.state, fix.title, fix.path);
}
}
/**
@@ -82,4 +90,4 @@ export default class Page extends React.Component {
return this.renderPage();
}
}
}

View File

@@ -143,6 +143,7 @@ export default class ShipyardPage extends Page {
<td className='cap'>{translate(SizeMap[s.class])}</td>
<td className='ri'>{fInt(s.agility)}</td>
<td className='ri'>{fInt(s.hardness)}</td>
<td className='ri'>{fInt(s.crew)}</td>
<td className='ri'>{fInt(s.speed)}{u['m/s']}</td>
<td className='ri'>{fInt(s.boost)}{u['m/s']}</td>
<td className='ri'>{fInt(s.baseArmour)}</td>
@@ -270,6 +271,7 @@ export default class ShipyardPage extends Page {
<th rowSpan={2} className='sortable' onClick={sortShips('class')}>{translate('size')}</th>
<th rowSpan={2} className='sortable' onClick={sortShips('agility')}>{translate('agility')}</th>
<th rowSpan={2} className='sortable' onClick={sortShips('hardness')}>{translate('hardness')}</th>
<th rowSpan={2} className='sortable' onClick={sortShips('crew')}>{translate('crew')}</th>
<th colSpan={4}>{translate('base')}</th>
<th colSpan={4}>{translate('max')}</th>
<th colSpan={6}>{translate('core module classes')}</th>

View File

@@ -60,7 +60,8 @@ export default class Module {
} else {
mod = modifierActions[name];
}
result = (((1 + result / 10000) * (1 + mod)) - 1) * 10000;
const multiplier = modification.type === 'percentage' ? 10000 : 100;
result = (((1 + result / multiplier) * (1 + mod)) - 1) * multiplier;
}
}
}

View File

@@ -897,6 +897,7 @@ export default class Ship {
}
if (epsChanged) {
this.recalculateEps();
this.recalculateTtd();
}
if (hpsChanged) {
this.recalculateHps();

View File

@@ -126,3 +126,104 @@ export function explorer(ship, planetary) {
ship.useLightestStandard(standardOpts);
}
/**
* Miner Role
* @param {Ship} ship Ship instance
* @param {Boolean} shielded True if shield generator should be included
*/
export function miner(ship, shielded) {
let standardOpts = { ppRating: 'A' },
miningLaserCount = 2,
usedSlots = [],
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
// Cargo hatch should be enabled
ship.setSlotEnabled(ship.cargoHatch, true);
// 4A or largest possible refinery
const refineryOrder = [4, 5, 6, 7, 8, 3, 2, 1];
const refineryInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.rf)
.sort((a,b) => refineryOrder.indexOf(a.maxClass) - refineryOrder.indexOf(b.maxClass));
for (let i = 0; i < refineryInternals.length; i++) {
if (canMount(ship, refineryInternals[i], 'rf')) {
ship.use(refineryInternals[i], ModuleUtils.findInternal('rf', refineryInternals[i].maxClass, 'A'));
usedSlots.push(refineryInternals[i]);
break;
}
}
// Prospector limpet controller - 3A if possible
const prospectorOrder = [3, 4, 5, 6, 7, 8, 2, 1];
const prospectorInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.pc)
.sort((a,b) => prospectorOrder.indexOf(a.maxClass) - prospectorOrder.indexOf(b.maxClass));
for (let i = 0; i < prospectorInternals.length; i++) {
if (canMount(ship, prospectorInternals[i], 'pc')) {
// Prospector only has odd classes
const prospectorClass = prospectorInternals[i].maxClass % 2 === 0 ? prospectorInternals[i].maxClass - 1 : prospectorInternals[i].maxClass;
ship.use(prospectorInternals[i], ModuleUtils.findInternal('pc', prospectorClass, 'A'));
usedSlots.push(prospectorInternals[i]);
break;
}
}
// Shield generator if required
if (shielded) {
const shieldOrder = [1, 2, 3, 4, 5, 6, 7, 8];
const shieldInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.pc)
.filter(a => a.maxClass >= sg.class)
.sort((a,b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass));
for (let i = 0; i < shieldInternals.length; i++) {
if (canMount(ship, shieldInternals[i], 'sg')) {
ship.use(shieldInternals[i], sg);
usedSlots.push(shieldInternals[i]);
break;
}
}
}
// Collector limpet controller if there are enough internals left
let collectorLimpetsRequired = Math.max(ship.internal.filter(a => (!a.eligible) || a.eligible.cr).length - 6, 0);
if (collectorLimpetsRequired > 0) {
const collectorOrder = [1, 2, 3, 4, 5, 6, 7, 8];
const collectorInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.cc)
.sort((a,b) => collectorOrder.indexOf(a.maxClass) - collectorOrder.indexOf(b.maxClass));
for (let i = 0; i < collectorInternals.length && collectorLimpetsRequired > 0; i++) {
if (canMount(ship, collectorInternals[i], 'cc')) {
// Collector only has odd classes
const collectorClass = collectorInternals[i].maxClass % 2 === 0 ? collectorInternals[i].maxClass - 1 : collectorInternals[i].maxClass;
ship.use(collectorInternals[i], ModuleUtils.findInternal('cc', collectorClass, 'A'));
usedSlots.push(collectorInternals[i]);
collectorLimpetsRequired -= collectorInternals[i].m.maximum;
}
}
}
// Dual mining lasers of highest possible class; remove anything else
const miningLaserOrder = [2, 3, 4, 1, 0];
const miningLaserHardpoints = ship.hardpoints.concat().sort(function(a,b) {
return miningLaserOrder.indexOf(a.maxClass) - miningLaserOrder.indexOf(b.maxClass);
});
for (let s of miningLaserHardpoints) {
if (s.maxClass >= 1 && miningLaserCount) {
ship.use(s, ModuleUtils.hardpoints(s.maxClass >= 2 ? '2m' : '2l'));
miningLaserCount--;
} else {
ship.use(s, null);
}
}
// Fill the empty internals with cargo racks
for (let i = ship.internal.length; i--;) {
let slot = ship.internal[i];
if (usedSlots.indexOf(slot) == -1 && canMount(ship, slot, 'cr')) {
ship.use(slot, ModuleUtils.findInternal('cr', slot.maxClass, 'E'));
}
}
ship.useLightestStandard(standardOpts);
}

View File

@@ -253,11 +253,15 @@ export function shipFromJson(json) {
internalSlot = json.modules[internalName];
militarySlotNum++;
} else {
// Slot numbers are not contiguous so handle skips.
while (internalSlot === null && internalSlotNum < 99) {
// Slot numbers are not contiguous so handle skips
const internalName = 'Slot' + (internalSlotNum <= 9 ? '0' : '') + internalSlotNum + '_Size' + internalClassNum;
if (json.modules[internalName]) {
internalSlot = json.modules[internalName];
// Slot sizes have no relationship to the actual size, either, so check all possibilities
for (let slotsize = 0; slotsize < 9; slotsize++) {
const internalName = 'Slot' + (internalSlotNum <= 9 ? '0' : '') + internalSlotNum + '_Size' + slotsize;
if (json.modules[internalName]) {
internalSlot = json.modules[internalName];
break;
}
}
internalSlotNum++;
}

View File

@@ -22,24 +22,24 @@
<meta name="msapplication-TileImage" content="/mstile-144x144.png">
<meta name="msapplication-config" content="/browserconfig.xml">
<meta name="theme-color" content="#000000">
</head>
<body style="background-color:#000;">
<section id="coriolis"></section>
<script>
window.CORIOLIS_GAPI_KEY = '{%= o.htmlWebpackPlugin.options.gapiKey %}';
window.CORIOLIS_VERSION = '{%= o.htmlWebpackPlugin.options.version %}';
window.CORIOLIS_DATE = '{%= new Date().toISOString().slice(0, 10) %}';
</script>
{% if (o.htmlWebpackPlugin.options.uaTracking) { %}
<script>
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
ga('create', '{%= o.htmlWebpackPlugin.options.uaTracking %}', 'auto');
ga('send', 'pageview');
</script>
<script async src='https://www.google-analytics.com/analytics.js'></script>
{% } %}
</head>
<body style="background-color:#000;">
<section id="coriolis"></section>
<script src="{%= o.htmlWebpackPlugin.files.chunks.lib.entry %}" charset="utf-8" crossorigin="anonymous"></script>
<script src="{%= o.htmlWebpackPlugin.files.chunks.app.entry %}" charset="utf-8" crossorigin="anonymous"></script>
<script>
{% if (o.htmlWebpackPlugin.options.uaTracking) { %}
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', '{%= o.htmlWebpackPlugin.options.uaTracking %}', 'auto');
{% } %}
</script>
</body>
</html>