From fdb202e7d6bb21f976ba2f27bc812cb092f504fc Mon Sep 17 00:00:00 2001 From: Cmdr McDonald Date: Tue, 22 Nov 2016 15:52:31 +0000 Subject: [PATCH 1/6] Add blueprints --- .../fixtures/asp-test-detailed-export-v4.json | 255 ++++++++++++++++++ __tests__/fixtures/expected-builds.json | 10 +- __tests__/test-import.js | 27 +- package.json | 2 +- src/app/components/HardpointSlot.jsx | 8 +- src/app/components/InternalSlot.jsx | 8 +- src/app/components/StandardSlot.jsx | 8 +- src/app/shipyard/Module.js | 1 - src/app/shipyard/Serializer.js | 17 +- src/app/shipyard/Ship.js | 82 ++++-- src/app/utils/CompanionApiUtils.js | 30 ++- src/schemas/ship-loadout/4.json | 10 + 12 files changed, 415 insertions(+), 43 deletions(-) create mode 100644 __tests__/fixtures/asp-test-detailed-export-v4.json diff --git a/__tests__/fixtures/asp-test-detailed-export-v4.json b/__tests__/fixtures/asp-test-detailed-export-v4.json new file mode 100644 index 00000000..ba14ef4d --- /dev/null +++ b/__tests__/fixtures/asp-test-detailed-export-v4.json @@ -0,0 +1,255 @@ +{ + "$schema": "http://cdn.coriolis.io/schemas/ship-loadout/4.json#", + "name": "Multi-purpose Asp Explorer", + "ship": "Asp Explorer", + "references": [ + { + "name": "Coriolis.io", + "url": "https://coriolis.edcd.io/outfit/asp?code=0pftiFflfddsnf5------020202033c044002v62f2i.AwRj4yvI.CwRgDBldHnJA.H4sIAAAAAAAAA2P858DAwPCXEUhwHPvx%2F78YG5AltB7I%2F8%2F0TwImJboDSPJ%2F%2B%2Ff%2Fv%2FKlX%2F%2F%2Fi3AwMTBIfARK%2FGf%2BJwVSxArStVAYqOjvz%2F%2F%2FJVo5GRhE2IBc4SKQSSz%2FDGEmCa398P8%2F%2F2%2BgTf%2F%2FAwDFxwtofAAAAA%3D%3D&bn=Multi-purpose%20Asp%20Explorer", + "code": "0pftiFflfddsnf5------020202033c044002v62f2i.AwRj4yvI.CwRgDBldHnJA.H4sIAAAAAAAAA2P858DAwPCXEUhwHPvx/78YG5AltB7I/8/0TwImJboDSPJ/+/f/v/KlX///i3AwMTBIfARK/Gf+JwVSxArStVAYqOjvz///JVo5GRhE2IBc4SKQSSz/DGEmCa398P8//2+gTf//AwDFxwtofAAAAA==", + "shipId": "asp" + } + ], + "components": { + "standard": { + "bulkheads": "Lightweight Alloy", + "cargoHatch": { + "enabled": false, + "priority": 5 + }, + "powerPlant": { + "class": 5, + "rating": "A", + "enabled": true, + "priority": 2, + "modifications": { + "eff": -1850, + "pgen": 6, + "mass": 431 + }, + "blueprint": { + "id": 64, + "name": "Low emissions", + "grade": 1 + } + }, + "thrusters": { + "class": 5, + "rating": "D", + "enabled": true, + "priority": 1, + "modifications": { + "optmul": 440, + "integrity": -266, + "thermload": -1326, + "optmass": 520, + "power": 241 + }, + "blueprint": { + "id": 24, + "name": "Clean", + "grade": 1 + } + }, + "frameShiftDrive": { + "class": 5, + "rating": "A", + "enabled": true, + "priority": 1, + "modifications": { + "mass": 5025, + "integrity": -1539, + "power": 2437, + "optmass": 4870, + "maxfuel": 370 + }, + "blueprint": { + "id": 26, + "name": "Increased range", + "grade": 5 + } + }, + "lifeSupport": { + "class": 4, + "rating": "A", + "enabled": true, + "priority": 1, + "modifications": { + "mass": -3923, + "integrity": -1797 + }, + "blueprint": { + "id": 49, + "name": "Lightweight", + "grade": 1 + } + }, + "powerDistributor": { + "class": 3, + "rating": "D", + "enabled": true, + "priority": 1 + }, + "sensors": { + "class": 5, + "rating": "D", + "enabled": true, + "priority": 1 + }, + "fuelTank": { + "class": 5, + "rating": "C", + "enabled": true, + "priority": 1 + } + }, + "hardpoints": [ + null, + null, + null, + null, + null, + null + ], + "utility": [ + { + "class": 0, + "rating": "I", + "enabled": true, + "priority": 1, + "group": "Heat Sink Launcher", + "name": "Heat Sink Launcher" + }, + { + "class": 0, + "rating": "I", + "enabled": true, + "priority": 1, + "group": "Heat Sink Launcher", + "name": "Heat Sink Launcher" + }, + { + "class": 0, + "rating": "I", + "enabled": true, + "priority": 1, + "group": "Heat Sink Launcher", + "name": "Heat Sink Launcher" + }, + { + "class": 0, + "rating": "I", + "enabled": true, + "priority": 1, + "group": "Point Defence", + "name": "Point Defence" + } + ], + "internal": [ + { + "class": 6, + "rating": "A", + "enabled": true, + "priority": 1, + "group": "Fuel Scoop" + }, + { + "class": 5, + "rating": "E", + "enabled": true, + "priority": 2, + "group": "Cargo Rack" + }, + { + "class": 3, + "rating": "A", + "enabled": true, + "priority": 1, + "group": "Shield Generator" + }, + { + "class": 3, + "rating": "E", + "enabled": true, + "priority": 2, + "group": "Cargo Rack" + }, + { + "class": 2, + "rating": "G", + "enabled": true, + "priority": 1, + "group": "Planetary Vehicle Hangar" + }, + { + "class": 1, + "rating": "C", + "enabled": true, + "priority": 2, + "group": "Scanner", + "name": "Advanced Discovery Scanner" + }, + { + "class": 1, + "rating": "C", + "enabled": true, + "priority": 2, + "group": "Scanner", + "name": "Detailed Surface Scanner" + } + ] + }, + "stats": { + "class": 2, + "hullCost": 6135660, + "speed": 250, + "boost": 340, + "boostEnergy": 13, + "agility": 6, + "baseShieldStrength": 140, + "baseArmour": 210, + "hullMass": 280, + "masslock": 11, + "pipSpeed": 0.13, + "moduleCostMultiplier": 1, + "fuelCapacity": 32, + "cargoCapacity": 40, + "ladenMass": 435.26, + "armour": 378, + "shield": 113.43, + "shieldCells": 0, + "totalCost": 48402550, + "unladenMass": 363.26, + "totalDpe": 0, + "totalExplDpe": 0, + "totalKinDpe": 0, + "totalThermDpe": 0, + "totalDps": 0, + "totalExplDps": 0, + "totalKinDps": 0, + "totalThermDps": 0, + "totalSDps": 0, + "totalExplSDps": 0, + "totalKinSDps": 0, + "totalThermSDps": 0, + "totalEps": 1.2, + "totalHps": 1, + "shieldExplRes": 0.5, + "shieldKinRes": 0.6, + "shieldThermRes": 1.2, + "hullExplRes": 1.4, + "hullKinRes": 1.2, + "hullThermRes": 1, + "powerAvailable": 20.41, + "powerRetracted": 11.91, + "powerDeployed": 11.91, + "unladenRange": 50.45, + "fullTankRange": 47.03, + "ladenRange": 42.71, + "unladenFastestRange": 317.24, + "ladenFastestRange": 287.02, + "maxJumpCount": 7, + "topSpeed": 274.01, + "topBoost": 372.65 + } +} diff --git a/__tests__/fixtures/expected-builds.json b/__tests__/fixtures/expected-builds.json index 2b985df4..054de777 100644 --- a/__tests__/fixtures/expected-builds.json +++ b/__tests__/fixtures/expected-builds.json @@ -1,8 +1,8 @@ { "type_6_transporter": { - "Cargo": "0p0tdFal8d8s8f4-----04040303430101.Iw1-kA==.Aw1-kA==.", - "Miner": "0p5tdFal8d8s8f42l2l---040403451q0101.Iw1-kA==.Aw1-kA==.", - "Hopper": "0p0tdFal8d0s8f41717---030302024300-.Iw1-kA==.Aw1-kA==." + "Cargo": "0p0tdFal8d8s8f4-----04040303430101.Iw1/kA==.Aw1/kA==.", + "Miner": "0p5tdFal8d8s8f42l2l---040403451q0101.Iw1/kA==.Aw1/kA==.", + "Hopper": "0p0tdFal8d0s8f41717---030302024300-.Iw1/kA==.Aw1/kA==." }, "type_7_transport": { "Cargo": "0p0tiFfliddsdf5--------0505040403480101.Iw18aQ==.Aw18aQ==.", @@ -36,7 +36,7 @@ "Test": "4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04--0303326b.Iw18ZlA=.Aw18ZlA=." }, "diamondback_explorer": { - "Explorer": "0p0tdFfldddsdf5---0202--320p432i2f.Iw1-kA==.Aw1-kA==." + "Explorer": "0p0tdFfldddsdf5---0202--320p432i2f.Iw1/kA==.Aw1/kA==." }, "vulture": { "Bounty Hunter": "3patcFalddksff31e1e0404-0l4a5d27662j.Iw19kA==.Aw19kA==." @@ -45,6 +45,6 @@ "Attack": "2pfthFalidpsff31r0s0s0s0s000404-04-4a-5d27-.Iw18aQ==.Aw18aQ==." }, "eagle": { - "Figther": "4p0t5F5l3d5s5f20p0p24-40532j-.Iw1-EA==.Aw1-EA==." + "Figther": "4p0t5F5l3d5s5f20p0p24-40532j-.Iw1/EA==.Aw1/EA==." } } diff --git a/__tests__/test-import.js b/__tests__/test-import.js index fd5ef1b1..7f863270 100644 --- a/__tests__/test-import.js +++ b/__tests__/test-import.js @@ -142,7 +142,7 @@ describe('Import Modal', function() { expect(modal.state.singleBuild).toBe(true); clickProceed(); expect(MockRouter.go.mock.calls.length).toBe(1); - expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/anaconda/4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04--0303326b.AwRj4zNKqA==.CwBhCYzBGW9qCTSqs5xA.?bn=Test%20My%20Ship'); + expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/anaconda?code=4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04--0303326b.AwRj4zNKqA%3D%3D.CwBhCYzBGW9qCTSqs5xA.&bn=Test%20My%20Ship'); }); it('catches an invalid build', function() { @@ -167,7 +167,24 @@ describe('Import Modal', function() { expect(modal.state.singleBuild).toBe(true); clickProceed(); expect(MockRouter.go.mock.calls.length).toBe(1); - expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/anaconda/4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04--0303326b.AwRj4zNKqA==.CwBhCYzBGW9qCTSqs5xA.H4sIAAAAAAAAA2MUe8HMwPD-PwDDhxeuCAAAAA==?bn=Test%20My%20Ship'); + expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/anaconda?code=4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04--0303326b.AwRj4zNKqA%3D%3D.CwBhCYzBGW9qCTSqs5xA.H4sIAAAAAAAAA2P8xwAEf0GE2AtmBob%2F%2FwFvM%2BjKEgAAAA%3D%3D&bn=Test%20My%20Ship'); + }); + }); + + describe('Import Detailed Engineered V4 Build', function() { + + beforeEach(reset); + + it('imports a valid v4 build', function() { + const importData = require('./fixtures/asp-test-detailed-export-v4'); + 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/asp?code=0pftiFflfddsnf5------020202033c044002v62f2i.AwRj4yvI.CwRgDBldHnJA.H4sIAAAAAAAAA2P858DAwPCXEUhwHPvx%2F78YG5AltB7I%2F8%2F0TwImJboDSPJ%2F%2B%2Ff%2Fv%2FKlX%2F%2F%2Fi3AwMTBIfARK%2FGf%2BJwVSxArStVAYqOjvz%2F%2F%2FJVo5GRhE2IBc4SKQSSz%2FDGEmCa398P8%2F%2F2%2BgTf%2F%2FAwDFxwtofAAAAA%3D%3D&bn=Multi-purpose%20Asp%20Explorer'); }); }); @@ -209,13 +226,13 @@ describe('Import Modal', function() { expect(modal.state.singleBuild).toBe(true); clickProceed(); expect(MockRouter.go.mock.calls.length).toBe(1); - expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/federal_corvette/2putsFklndzsxf50x0x7l28281919040404040402020l06p05sf63c5ifhv66g2f.AwRj4zNaKA==.CwRgDBldUExuBiQqA===.H4sIAAAAAAAAAx2Rzy4DURTGz7TuzHRu47ZjWreKlg5iQ9KFZ9CENyBWtWo8gIUFsamteAIJi0qEWIhdN11ZEN1IwyNYVKRpcXzH5su553f_XyfvKiLTYma-TkScyHVcokoYEdmbBNDsiDla-WUOT5LgyfAshHdvyGyjFFHUQCSrBU8TLT4gYq4DNL_LhNTFN3PwiqdZQyX2C-sekep-Mrs1RIbnDppsIogD1UAtN7JEM9eIzZg8hmhsEU32gFmrdgB_UARvjYEr4QMUMffoxGnV-M8X3hZ_lAO-gmWq2Eq2IVtDOzZ2Hbbuws6KxCKmKUUydgRb3woSiUXMs6Cs7Qt6FCQSi5hxkNKhj6qhfcPU_kU4wYrFMseSOmFXMKbuwZsViUWMlq1sbhvJ_lKyfqTqEJGJyoC5eIpU9x2TRnUswYXyF77BW4Z3qQuv05GDTpfvcDzvSbxJ5DtV_aHS1I4clyB2A5_b-pAL8x_enn626gEAAA==?bn=Imported%20Federal%20Corvette'); + expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/federal_corvette?code=2putsFklndzsxf50x0x7l28281919040404040402020l06p05sf63c5ifhv66g2f.AwRj4zNaKA%3D%3D.CwRgDBldUExuBiQqA%3D%3D%3D.H4sIAAAAAAAAA02Svy9DURTHT1t9%2FfEat32eem1V0YdYSDpgkBhpwsxATDU1%2FgCDQWKpVfwFEoZKhBjE1qWTgegiDX%2BCoSJNyz2%2BR%2FLkLd%2Bce7%2Bf8333vnMDeoWIfgKQtBEmUnVmjlaw5KBOixWCDDcNoqJlEzk3QUBjfWZ7XjNbJ7A5pLNCop2sMwv%2Bfo%2FZsWNEdhU9HNbLXtJUxCSafkA50QQ0uYeQ2MU3c%2FwVS7WAdI7qTe9MmYMIUbjzyWyU0WOdY9PZAM5xveVlhqv4kmE7RPlr9CeXsFesbhONtAGy6SMbcZCHOZD1AY%2FswlH3OAcnfGTtL1PIhpCLQl6hUiW5JW5FThmHYaVXvcM6axCzhTIl4oqomgQnfVAfat4KJOKKqGeBUj6oI9CjQCKuiBoEUziK4puWj3zDjc0XIQmVK5U6lrghHzSHK5lt%2BCkRV0SZ8m8cvfE%2F4x1Em5eSJE1uD5vBYpc5d4o44x2IXcEP4Iwue8HjX3gIkVn4My0sA00Z36jPv8OoIk%2Fih7AOlOS1FHTe87O7MlSCOOt4PYkPmSz%2FAiP2EO%2BUAgAA&bn=Imported%20Federal%20Corvette'); }); }); describe('Import E:D Shipyard Builds', function() { - it('imports a valid builds', function() { + it('imports a valid build', function() { const imports = require('./fixtures/ed-shipyard-import-valid'); for (let i = 0; i < imports.length; i++ ) { @@ -226,7 +243,7 @@ describe('Import Modal', function() { expect(modal.state.errorMsg).toEqual(null); clickProceed(); expect(MockRouter.go.mock.calls.length).toBe(1); - expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/' + fixture.shipId + '/' + fixture.buildCode + '?bn=' + encodeURIComponent(fixture.buildName)); + expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/' + fixture.shipId + '?code=' + encodeURIComponent(fixture.buildCode) + '&bn=' + encodeURIComponent(fixture.buildName)); } }); diff --git a/package.json b/package.json index 113483eb..7f54a676 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "coriolis_shipyard", - "version": "2.2.2", + "version": "2.2.3beta", "repository": { "type": "git", "url": "https://github.com/EDCD/coriolis" diff --git a/src/app/components/HardpointSlot.jsx b/src/app/components/HardpointSlot.jsx index fa3e29e5..b3851423 100644 --- a/src/app/components/HardpointSlot.jsx +++ b/src/app/components/HardpointSlot.jsx @@ -44,6 +44,12 @@ export default class HardpointSlot extends Slot { let validMods = Modifications.validity[m.grp] || []; let showModuleResistances = Persist.showModuleResistances(); + // Modifications tooltip shows blueprint and grade, if available + let modTT = translate('modified'); + if (m && m.blueprint) { + modTT = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade; + } + return
@@ -53,7 +59,7 @@ export default class HardpointSlot extends Slot { {m.type && m.type.match('K') ? : ''} {m.type && m.type.match('T') ? : ''} {m.type && m.type.match('E') ? : ''} - {classRating} {translate(m.name || m.grp)}{ m.mods && Object.keys(m.mods).length > 0 ? : null } + {classRating} {translate(m.name || m.grp)}{ m.mods && Object.keys(m.mods).length > 0 ? : null }
{formats.round(m.getMass())}{u.T}
diff --git a/src/app/components/InternalSlot.jsx b/src/app/components/InternalSlot.jsx index f936b6be..2f8fb206 100644 --- a/src/app/components/InternalSlot.jsx +++ b/src/app/components/InternalSlot.jsx @@ -26,10 +26,16 @@ export default class InternalSlot extends Slot { let validMods = Modifications.validity[m.grp] || []; let showModuleResistances = Persist.showModuleResistances(); + // Modifications tooltip shows blueprint and grade, if available + let modTT = translate('modified'); + if (m && m.blueprint) { + modTT = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade; + } + let mass = m.getMass() || m.cargo || m.fuel || 0; return
-
{classRating} {translate(m.name || m.grp)}{m.mods && Object.keys(m.mods).length > 0 ? : ''}
+
{classRating} {translate(m.name || m.grp)}{m.mods && Object.keys(m.mods).length > 0 ? : ''}
{formats.round(mass)}{u.T}
diff --git a/src/app/components/StandardSlot.jsx b/src/app/components/StandardSlot.jsx index f4a61415..9bd56da9 100644 --- a/src/app/components/StandardSlot.jsx +++ b/src/app/components/StandardSlot.jsx @@ -50,6 +50,12 @@ export default class StandardSlot extends TranslatedComponent { let showModuleResistances = Persist.showModuleResistances(); let mass = m.getMass() || m.cargo || m.fuel || 0; + // Modifications tooltip shows blueprint and grade, if available + let modTT = translate('modified'); + if (m && m.blueprint) { + modTT = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade; + } + if (!selected) { // If not selected then sure that modifications flag is unset this._modificationsSelected = false; @@ -81,7 +87,7 @@ export default class StandardSlot extends TranslatedComponent {
{slot.maxClass}
-
{classRating} {translate(m.name || m.grp)}{m.mods && Object.keys(m.mods).length > 0 ? : null }
+
{classRating} {translate(m.name || m.grp)}{m.mods && Object.keys(m.mods).length > 0 ? : null }
{formats.round(mass)}{units.T}
diff --git a/src/app/shipyard/Module.js b/src/app/shipyard/Module.js index d995ef16..e6d3bae9 100755 --- a/src/app/shipyard/Module.js +++ b/src/app/shipyard/Module.js @@ -533,7 +533,6 @@ export default class Module { return this._getModifiedValue('cells'); } - /** * Get the jitter for this module, taking in to account modifications * @return {Number} the jitter for this module diff --git a/src/app/shipyard/Serializer.js b/src/app/shipyard/Serializer.js index df2a1a7a..6aeefe0d 100644 --- a/src/app/shipyard/Serializer.js +++ b/src/app/shipyard/Serializer.js @@ -30,6 +30,10 @@ function standardToSchema(standard) { o.modifications = standard.m.mods; } + if (standard.m.blueprint && Object.keys(standard.m.blueprint).length > 0) { + o.blueprint = standard.m.blueprint; + } + return o; } return null; @@ -62,6 +66,10 @@ function slotToSchema(slot) { if (slot.m.mods && Object.keys(slot.m.mods).length > 0) { o.modifications = slot.m.mods; } + if (slot.m.blueprint && Object.keys(slot.m.blueprint).length > 0) { + o.blueprint = slot.m.blueprint; + } + return o; } return null; @@ -137,6 +145,7 @@ export function fromDetailedBuild(detailedBuild) { let ship = new Ship(shipId, shipData.properties, shipData.slots); let bulkheads = ModuleUtils.bulkheadIndex(stn.bulkheads); let modifications = new Array(stn.bulkheads.modifications); + let blueprints = new Array(stn.bulkheads.blueprint); if (bulkheads < 0) { throw 'Invalid bulkheads: ' + stn.bulkheads; @@ -149,6 +158,7 @@ export function fromDetailedBuild(detailedBuild) { priorities.push(stn[c].priority === undefined ? 0 : stn[c].priority - 1); enabled.push(stn[c].enabled === undefined ? true : stn[c].enabled); modifications.push(stn[c].modifications); + blueprints.push(stn[c].blueprint); return stn[c].class + stn[c].rating; }); @@ -174,8 +184,13 @@ export function fromDetailedBuild(detailedBuild) { comps.utility.map(c => (c && c.m ? c.m.modifications : null)), comps.internal.map(c => (c && c.m ? c.m.modifications : null)) ); + blueprints = blueprints.concat( + comps.hardpoints.map(c => (c && c.m ? c.m.blueprint : null)), + comps.utility.map(c => (c && c.m ? c.m.blueprint : null)), + comps.internal.map(c => (c && c.m ? c.m.blueprint : null)) + ); - ship.buildWith({ bulkheads, standard, hardpoints, internal }, priorities, enabled, modifications); + ship.buildWith({ bulkheads, standard, hardpoints, internal }, priorities, enabled, modifications, blueprints); return ship; }; diff --git a/src/app/shipyard/Ship.js b/src/app/shipyard/Ship.js index 46f77500..a8e74fc7 100755 --- a/src/app/shipyard/Ship.js +++ b/src/app/shipyard/Ship.js @@ -3,12 +3,20 @@ import * as ModuleUtils from './ModuleUtils'; import * as Utils from '../utils/UtilityFunctions'; import Module from './Module'; import LZString from 'lz-string'; +import * as _ from 'lodash'; import isEqual from 'lodash/lang'; import { Modifications } from 'coriolis-data/dist'; const zlib = require('zlib'); const UNIQUE_MODULES = ['psg', 'sg', 'bsg', 'rf', 'fs', 'fh']; +// Constants for modifications struct +const SLOT_ID_DONE = -1; +const MODIFICATION_ID_DONE = -1; +const MODIFICATION_ID_BLUEPRINT = -2; +const MODIFICATION_ID_GRADE = -3; +const MODIFICATION_ID_SPECIAL = -4; + /** * Returns the power usage type of a slot and it's particular module * @param {Object} slot The Slot @@ -472,9 +480,10 @@ export default class Ship { * @param {array} priorities Slot priorities * @param {Array} enabled Slot active/inactive * @param {Array} mods Modifications + * @param {Array} blueprints Blueprints * @return {this} The current ship instance for chaining */ - buildWith(comps, priorities, enabled, mods) { + buildWith(comps, priorities, enabled, mods, blueprints) { let internal = this.internal, standard = this.standard, hps = this.hardpoints, @@ -514,6 +523,7 @@ export default class Ship { this.bulkheads.m = null; this.useBulkhead(comps && comps.bulkheads ? comps.bulkheads : 0, true); this.bulkheads.m.mods = mods && mods[0] ? mods[0] : {}; + this.bulkheads.m.blueprint = blueprints && blueprints[0] ? blueprints[0] : {}; this.cargoHatch.priority = priorities ? priorities[0] * 1 : 0; this.cargoHatch.enabled = enabled ? enabled[0] * 1 : true; @@ -526,7 +536,10 @@ export default class Ship { standard[i].discountedCost = 0; if (comps) { let module = ModuleUtils.standard(i, comps.standard[i]); - if (module != null) { module.mods = mods && mods[i + 1] ? mods[i + 1] : {}; } + if (module != null) { + module.mods = mods && mods[i + 1] ? mods[i + 1] : {}; + module.blueprint = blueprints && blueprints[i + 1] ? blueprints[i + 1] : {}; + } this.use(standard[i], module, true); } } @@ -545,7 +558,10 @@ export default class Ship { if (comps && comps.hardpoints[i] !== 0) { let module = ModuleUtils.hardpoints(comps.hardpoints[i]); - if (module != null) { module.mods = mods && mods[cl + i] ? mods[cl + i] : {}; } + if (module != null) { + module.mods = mods && mods[cl + i] ? mods[cl + i] : {}; + module.blueprint = blueprints && blueprints[cl + i] ? blueprints[cl + i] : {}; + } this.use(hps[i], module, true); } } @@ -562,7 +578,10 @@ export default class Ship { if (comps && comps.internal[i] !== 0) { let module = ModuleUtils.internal(comps.internal[i]); - if (module != null) { module.mods = mods && mods[cl + i] ? mods[cl + i] : {}; } + if (module != null) { + module.mods = mods && mods[cl + i] ? mods[cl + i] : {}; + module.blueprint = blueprints && blueprints[cl + i] ? blueprints[cl + i] : {}; + } this.use(internal[i], module, true); } } @@ -596,6 +615,7 @@ export default class Ship { hardpoints = new Array(this.hardpoints.length), internal = new Array(this.internal.length), modifications = new Array(1 + this.standard.length + this.hardpoints.length + this.internal.length), + blueprints = new Array(1 + this.standard.length + this.hardpoints.length + this.internal.length), parts = serializedString.split('.'), priorities = null, enabled = null, @@ -615,7 +635,7 @@ export default class Ship { this.decodeModificationsString(modstr, modifications); } else { try { - this.decodeModificationsStruct(zlib.gunzipSync(new Buffer(Utils.fromUrlSafe(modstr), 'base64')), modifications); + this.decodeModificationsStruct(zlib.gunzipSync(new Buffer(Utils.fromUrlSafe(modstr), 'base64')), modifications, blueprints); } catch (err) { // Could be out-of-date URL; ignore } @@ -633,7 +653,8 @@ export default class Ship { }, priorities, enabled, - modifications + modifications, + blueprints, ); }; @@ -1305,8 +1326,11 @@ export default class Ship { updateModificationsString() { // Start off by gathering the information that we need let slots = new Array(); + let blueprints = new Array(); let bulkheadMods = new Array(); + let bulkheadBlueprint = undefined; + let bulkheadBlueprintGrade = undefined; if (this.bulkheads.m && this.bulkheads.m.mods) { for (let modKey in this.bulkheads.m.mods) { // Filter out invalid modifications @@ -1314,8 +1338,10 @@ export default class Ship { bulkheadMods.push({ id: Modifications.modifications.indexOf(modKey), value: this.bulkheads.m.getModValue(modKey) }); } } + bulkheadBlueprint = this.bulkheads.m.blueprint; } slots.push(bulkheadMods); + blueprints.push(bulkheadBlueprint) for (let slot of this.standard) { let slotMods = new Array(); @@ -1328,6 +1354,7 @@ export default class Ship { } } slots.push(slotMods); + blueprints.push(slot.m ? slot.m.blueprint : undefined); } for (let slot of this.hardpoints) { @@ -1341,6 +1368,7 @@ export default class Ship { } } slots.push(slotMods); + blueprints.push(slot.m ? slot.m.blueprint : undefined); } for (let slot of this.internal) { @@ -1354,13 +1382,15 @@ export default class Ship { } } slots.push(slotMods); + blueprints.push(slot.m ? slot.m.blueprint : undefined); } // Now work out the size of the binary buffer from our modifications array let bufsize = 0; for (let slot of slots) { if (slot.length > 0) { - bufsize = bufsize + 1 + (5 * slot.length) + 1; + // Length is 1 for the slot ID, 10 for the blueprint name and grade, 5 for each modification, and 1 for the end marker + bufsize = bufsize + 1 + 10 + (5 * slot.length) + 1; } } @@ -1373,18 +1403,26 @@ export default class Ship { for (let slot of slots) { if (slot.length > 0) { buffer.writeInt8(i, curpos++); + if (blueprints[i]) { + buffer.writeInt8(MODIFICATION_ID_BLUEPRINT, curpos++); + buffer.writeInt32LE(blueprints[i].id, curpos); + curpos += 4; + buffer.writeInt8(MODIFICATION_ID_GRADE, curpos++); + buffer.writeInt32LE(blueprints[i].grade, curpos); + curpos += 4; + } for (let slotMod of slot) { buffer.writeInt8(slotMod.id, curpos++); buffer.writeInt32LE(slotMod.value, curpos); // console.log('ENCODE Slot ' + i + ': ' + Modifications.modifications[slotMod.id] + ' = ' + slotMod.value); curpos += 4; } - buffer.writeInt8(-1, curpos++); + buffer.writeInt8(MODIFICATION_ID_DONE, curpos++); } i++; } if (curpos > 0) { - buffer.writeInt8(-1, curpos++); + buffer.writeInt8(SLOT_ID_DONE, curpos++); } this.serialized.modifications = zlib.gzipSync(buffer).toString('base64'); @@ -1397,23 +1435,33 @@ export default class Ship { /** * Populate the modifications array with modification values from the code. * See updateModificationsString() for details of the structure. - * @param {String} buffer Buffer holding modification info - * @param {Array} arr Modification array + * @param {String} buffer Buffer holding modification info + * @param {Array} modArr Modification array + * @param {Array} bluprintArr Blueprint array */ - decodeModificationsStruct(buffer, arr) { + decodeModificationsStruct(buffer, modArr, blueprintArr) { let curpos = 0; let slot = buffer.readInt8(curpos++); - while (slot != -1) { + while (slot != SLOT_ID_DONE) { let modifications = {}; + let blueprint = {}; let modificationId = buffer.readInt8(curpos++); - while (modificationId != -1) { + while (modificationId != MODIFICATION_ID_DONE) { let modificationValue = buffer.readInt32LE(curpos); curpos += 4; - // console.log('DECODE Slot ' + slot + ': ' + Modifications.modifications[modificationId] + ' = ' + modificationValue); - modifications[Modifications.modifications[modificationId]] = modificationValue; + // There are a number of 'special' modification IDs, check for them here + if (modificationId === MODIFICATION_ID_BLUEPRINT) { + blueprint = Object.assign(blueprint, _.find(Modifications.blueprints, function(o) { return o.id === modificationValue; })); + } else if (modificationId === MODIFICATION_ID_GRADE) { + blueprint.grade = modificationValue; + } else { + // console.log('DECODE Slot ' + slot + ': ' + Modifications.modifications[modificationId] + ' = ' + modificationValue); + modifications[Modifications.modifications[modificationId]] = modificationValue; + } modificationId = buffer.readInt8(curpos++); } - arr[slot] = modifications; + modArr[slot] = modifications; + blueprintArr[slot] = blueprint; slot = buffer.readInt8(curpos++); } } diff --git a/src/app/utils/CompanionApiUtils.js b/src/app/utils/CompanionApiUtils.js index c6c3b71f..599cb6db 100644 --- a/src/app/utils/CompanionApiUtils.js +++ b/src/app/utils/CompanionApiUtils.js @@ -149,13 +149,13 @@ export function shipFromJson(json) { throw 'Unknown bulkheads "' + armourJson.name + '"'; } ship.bulkheads.enabled = true; - if (armourJson.modifiers) _addModifications(ship.bulkheads.m, armourJson.modifiers); + if (armourJson.modifiers) _addModifications(ship.bulkheads.m, armourJson.modifiers, armourJson.recipeName, armourJson.recipeLevel); // Add the standard modules // Power plant const powerplantJson = json.modules.PowerPlant.module; const powerplant = _moduleFromEdId(powerplantJson.id); - if (powerplantJson.modifiers) _addModifications(powerplant, powerplantJson.modifiers); + if (powerplantJson.modifiers) _addModifications(powerplant, powerplantJson.modifiers, powerplantJson.recipeName, powerplantJson.recipeLevel); ship.use(ship.standard[0], powerplant, true); ship.standard[0].enabled = powerplantJson.on === true; ship.standard[0].priority = powerplantJson.priority; @@ -163,7 +163,7 @@ export function shipFromJson(json) { // Thrusters const thrustersJson = json.modules.MainEngines.module; const thrusters = _moduleFromEdId(thrustersJson.id); - if (thrustersJson.modifiers) _addModifications(thrusters, thrustersJson.modifiers); + if (thrustersJson.modifiers) _addModifications(thrusters, thrustersJson.modifiers, thrustersJson.recipeName, thrustersJson.recipeLevel); ship.use(ship.standard[1], thrusters, true); ship.standard[1].enabled = thrustersJson.on === true; ship.standard[1].priority = thrustersJson.priority; @@ -171,7 +171,7 @@ export function shipFromJson(json) { // FSD const frameshiftdriveJson = json.modules.FrameShiftDrive.module; const frameshiftdrive = _moduleFromEdId(frameshiftdriveJson.id); - if (frameshiftdriveJson.modifiers) _addModifications(frameshiftdrive, frameshiftdriveJson.modifiers); + if (frameshiftdriveJson.modifiers) _addModifications(frameshiftdrive, frameshiftdriveJson.modifiers, frameshiftdriveJson.recipeName, frameshiftdriveJson.recipeLevel); ship.use(ship.standard[2], frameshiftdrive, true); ship.standard[2].enabled = frameshiftdriveJson.on === true; ship.standard[2].priority = frameshiftdriveJson.priority; @@ -179,7 +179,7 @@ export function shipFromJson(json) { // Life support const lifesupportJson = json.modules.LifeSupport.module; const lifesupport = _moduleFromEdId(lifesupportJson.id); - if (lifesupportJson.modifiers)_addModifications(lifesupport, lifesupportJson.modifiers); + if (lifesupportJson.modifiers)_addModifications(lifesupport, lifesupportJson.modifiers, lifesupportJson.recipeName, lifesupportJson.recipeLevel); ship.use(ship.standard[3], lifesupport, true); ship.standard[3].enabled = lifesupportJson.on === true; ship.standard[3].priority = lifesupportJson.priority; @@ -187,7 +187,7 @@ export function shipFromJson(json) { // Power distributor const powerdistributorJson = json.modules.PowerDistributor.module; const powerdistributor = _moduleFromEdId(powerdistributorJson.id); - if (powerdistributorJson.modifiers) _addModifications(powerdistributor, powerdistributorJson.modifiers); + if (powerdistributorJson.modifiers) _addModifications(powerdistributor, powerdistributorJson.modifiers, powerdistributorJson.recipeName, powerdistributorJson.recipeLevel); ship.use(ship.standard[4], powerdistributor, true); ship.standard[4].enabled = powerdistributorJson.on === true; ship.standard[4].priority = powerdistributorJson.priority; @@ -195,7 +195,7 @@ export function shipFromJson(json) { // Sensors const sensorsJson = json.modules.Radar.module; const sensors = _moduleFromEdId(sensorsJson.id); - if (sensorsJson.modifiers) _addModifications(sensors, sensorsJson.modifiers); + if (sensorsJson.modifiers) _addModifications(sensors, sensorsJson.modifiers, sensorsJson.recipeName, sensorsJson.recipeLevel); ship.use(ship.standard[5], sensors, true); ship.standard[5].enabled = sensorsJson.on === true; ship.standard[5].priority = sensorsJson.priority; @@ -229,7 +229,7 @@ export function shipFromJson(json) { } else { const hardpointJson = hardpointSlot.module; const hardpoint = _moduleFromEdId(hardpointJson.id); - if (hardpointJson.modifiers) _addModifications(hardpoint, hardpointJson.modifiers); + if (hardpointJson.modifiers) _addModifications(hardpoint, hardpointJson.modifiers, hardpointJson.recipeName, hardpointJson.recipeLevel); ship.use(ship.hardpoints[hardpointArrayNum], hardpoint, true); ship.hardpoints[hardpointArrayNum].enabled = hardpointJson.on === true; ship.hardpoints[hardpointArrayNum].priority = hardpointJson.priority; @@ -256,7 +256,7 @@ export function shipFromJson(json) { } else { const internalJson = internalSlot.module; const internal = _moduleFromEdId(internalJson.id); - if (internalJson.modifiers) _addModifications(internal, internalJson.modifiers); + if (internalJson.modifiers) _addModifications(internal, internalJson.modifiers, internalJson.recipeName, internalJson.recipeLevel); ship.use(ship.internal[i], internal, true); ship.internal[i].enabled = internalJson.on === true; ship.internal[i].priority = internalJson.priority; @@ -271,8 +271,10 @@ export function shipFromJson(json) { * Add the modifications for a module * @param {Module} module the module * @param {Object} modifiers the modifiers + * @param {Object} blueprint the blueprint of the modification + * @param {Object} grade the grade of the modification */ -function _addModifications(module, modifiers) { +function _addModifications(module, modifiers, blueprint, grade) { if (!modifiers || !modifiers.modifiers) return; for (const i in modifiers.modifiers) { @@ -291,6 +293,14 @@ function _addModifications(module, modifiers) { } } + // Add the blueprint ID and grade + if (blueprint) { + module.blueprint = Modifications.blueprints[blueprint]; + if (grade) { + module.blueprint.grade = Number(grade); + } + } + // Need to fix up a few items // Shield boosters are treated internally as straight modifiers, so rather than (for example) diff --git a/src/schemas/ship-loadout/4.json b/src/schemas/ship-loadout/4.json index d3158f9f..a1c946ac 100644 --- a/src/schemas/ship-loadout/4.json +++ b/src/schemas/ship-loadout/4.json @@ -68,6 +68,7 @@ "rating": { "$ref": "#/definitions/standardRatings" }, "enabled": { "type": "boolean" }, "priority": { "type": "integer", "minimum": 1, "maximum": 5 }, + "blueprint": { "type": "object" }, "modifications": { "type": "object" } } }, @@ -82,6 +83,7 @@ "description": "The name identifing the thrusters (if applicable), e.g. 'Enhanced Performance'", "type": "string" }, + "blueprint": { "type": "object" }, "modifications": { "type": "object" } } }, @@ -92,6 +94,7 @@ "rating": { "$ref": "#/definitions/standardRatings" }, "enabled": { "type": "boolean" }, "priority": { "type": "integer", "minimum": 1, "maximum": 5 }, + "blueprint": { "type": "object" }, "modifications": { "type": "object" } } }, @@ -102,6 +105,7 @@ "rating": { "$ref": "#/definitions/standardRatings" }, "enabled": { "type": "boolean" }, "priority": { "type": "integer", "minimum": 1, "maximum": 5 }, + "blueprint": { "type": "object" }, "modifications": { "type": "object" } } }, @@ -112,6 +116,7 @@ "rating": { "$ref": "#/definitions/standardRatings" }, "enabled": { "type": "boolean" }, "priority": { "type": "integer", "minimum": 1, "maximum": 5 }, + "blueprint": { "type": "object" }, "modifications": { "type": "object" } } }, @@ -122,6 +127,7 @@ "rating": { "$ref": "#/definitions/standardRatings" }, "enabled": { "type": "boolean" }, "priority": { "type": "integer", "minimum": 1, "maximum": 5 }, + "blueprint": { "type": "object" }, "modifications": { "type": "object" } } }, @@ -132,6 +138,7 @@ "rating": { "$ref": "#/definitions/standardRatings" }, "enabled": { "type": "boolean" }, "priority": { "type": "integer", "minimum": 1, "maximum": 5 }, + "blueprint": { "type": "object" }, "modifications": { "type": "object" } } } @@ -155,6 +162,7 @@ "description": "The name identifying the component (if applicable), e.g. 'Advance Discovery Scanner', or 'Detailed Surface Scanner'", "type": "string" }, + "blueprint": { "type": "object" }, "modifications": { "type": "object" } } }, @@ -179,6 +187,7 @@ "description": "The name identifing the component (if applicable), e.g. 'Retributor', or 'Mining Lance'", "type": "string" }, + "blueprint": { "type": "object" }, "modifications": { "type": "object" } } }, @@ -202,6 +211,7 @@ "description": "The name identifing the component (if applicable), e.g. 'Point Defence', or 'Electronic Countermeasure'", "type": "string" }, + "blueprint": { "type": "object" }, "modifications": { "type": "object" } } }, From f863daa347b01e32bfa1eed5fdd5cd5bbafaf196 Mon Sep 17 00:00:00 2001 From: Cmdr McDonald Date: Wed, 23 Nov 2016 00:54:42 +0000 Subject: [PATCH 2/6] Fix hull boost calculation. Partial fix for #29 --- ChangeLog.md | 5 ++++- src/app/utils/CompanionApiUtils.js | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 777085b7..c9c5400e 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,4 +1,7 @@ -#2.2.x +#2.2.3 + * Fix hull boost calculation + +#2.2.2 * Update DPS/HPS/EPS in real-time as modifiers change * Use coriolis-data 2.2.2: * Add distributor draw modifier to shield generators diff --git a/src/app/utils/CompanionApiUtils.js b/src/app/utils/CompanionApiUtils.js index c6c3b71f..713e6e70 100644 --- a/src/app/utils/CompanionApiUtils.js +++ b/src/app/utils/CompanionApiUtils.js @@ -355,6 +355,12 @@ function _addModifications(module, modifiers) { } } + // Bulkhead boost is based off the inherent boost of the module + if (module.grp == 'bh') { + const alteredBoost = (1 + module.hullboost) * (1 + module.getModValue('hullboost') / 10000) - 1; + module.setModValue('hullboost', (alteredBoost / module.hullboost - 1) * 10000); + } + // Jitter is an absolute number, so we need to divide it by 100 if (module.getModValue('jitter')) { module.setModValue('jitter', module.getModValue('jitter') / 100); From 9042de422ae1234b31eb385542820be8f154ee8b Mon Sep 17 00:00:00 2001 From: Cmdr McDonald Date: Wed, 23 Nov 2016 01:05:13 +0000 Subject: [PATCH 3/6] patch --- __tests__/test-import.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__tests__/test-import.js b/__tests__/test-import.js index 7f863270..e3f13dd2 100644 --- a/__tests__/test-import.js +++ b/__tests__/test-import.js @@ -226,7 +226,7 @@ describe('Import Modal', function() { expect(modal.state.singleBuild).toBe(true); clickProceed(); expect(MockRouter.go.mock.calls.length).toBe(1); - expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/federal_corvette?code=2putsFklndzsxf50x0x7l28281919040404040402020l06p05sf63c5ifhv66g2f.AwRj4zNaKA%3D%3D.CwRgDBldUExuBiQqA%3D%3D%3D.H4sIAAAAAAAAA02Svy9DURTHT1t9%2FfEat32eem1V0YdYSDpgkBhpwsxATDU1%2FgCDQWKpVfwFEoZKhBjE1qWTgegiDX%2BCoSJNyz2%2BR%2FLkLd%2Bce7%2Bf8333vnMDeoWIfgKQtBEmUnVmjlaw5KBOixWCDDcNoqJlEzk3QUBjfWZ7XjNbJ7A5pLNCop2sMwv%2Bfo%2FZsWNEdhU9HNbLXtJUxCSafkA50QQ0uYeQ2MU3c%2FwVS7WAdI7qTe9MmYMIUbjzyWyU0WOdY9PZAM5xveVlhqv4kmE7RPlr9CeXsFesbhONtAGy6SMbcZCHOZD1AY%2FswlH3OAcnfGTtL1PIhpCLQl6hUiW5JW5FThmHYaVXvcM6axCzhTIl4oqomgQnfVAfat4KJOKKqGeBUj6oI9CjQCKuiBoEUziK4puWj3zDjc0XIQmVK5U6lrghHzSHK5lt%2BCkRV0SZ8m8cvfE%2F4x1Em5eSJE1uD5vBYpc5d4o44x2IXcEP4Iwue8HjX3gIkVn4My0sA00Z36jPv8OoIk%2Fih7AOlOS1FHTe87O7MlSCOOt4PYkPmSz%2FAiP2EO%2BUAgAA&bn=Imported%20Federal%20Corvette'); + expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/federal_corvette?code=2putsFklndzsxf50x0x7l28281919040404040402020l06p05sf63c5ifrv66g2f.AwRj4zNaKA%3D%3D.CwRgDBldUExuBiQqA%3D%3D%3D.H4sIAAAAAAAAA02SP0sDQRDFJ4m5%2FLngJucZL4kxak7FRiGFWgiWGtBaC8UqVsEPYGEh2MRW%2FASCFhFEsRC7NKksIqaRoB%2FBQggh0R3fCCfXPGb3%2Febd7s0G9BoR%2FQQgaSNMpOrMHK1gyUGdFisEGW0aREXLJnLugoAmBsz2oma2zmBzSGeFRDtZFxb8wz6zY8eI7Cp6OKxXvaSZiEk0%2B4Ryqglo%2BgAhsatv5vgblmoJ6RzV296ZMkcRonCry2yU0WNdYtPZAs5xveNlhqv4kmE7RPlb9CdXsFes7hKNdQCy6SMbcZDHOZD1IY%2FswVGPOAcnfGTtL1PIhpDLQt6gUiW5JW5FThmHYaXXvcM6GxCzjTIl4oqomgQnfdAAat4LJOKKqBeBUj7oS6BngURcETUMpnASxTctH%2FmOG5uvQhIqVyp1KnEjPmgBVzI78FMirogy5d84eut%2FxnuINq8lSZrcPjaDxR5z7hxxxgcQu4IfwBld9oInu3gIkXn4c20sA00Z37jPf8CoIi3xQ1gHSvJaCjrv%2Bdl9GSpBnE28nsSnTJZ%2FAWD7326UAgAA&bn=Imported%20Federal%20Corvette'); }); }); From 0ab59c1f9a6a52bfdd540a08dd3fce16d71467a1 Mon Sep 17 00:00:00 2001 From: Cmdr McDonald Date: Thu, 24 Nov 2016 11:10:41 +0000 Subject: [PATCH 4/6] Handle import of restricted slots - fix for #35 --- .../fixtures/companion-api-import-2.json | 552 ++++++++++++++++++ __tests__/test-import.js | 12 + src/app/utils/CompanionApiUtils.js | 2 +- 3 files changed, 565 insertions(+), 1 deletion(-) create mode 100644 __tests__/fixtures/companion-api-import-2.json diff --git a/__tests__/fixtures/companion-api-import-2.json b/__tests__/fixtures/companion-api-import-2.json new file mode 100644 index 00000000..e5d44e88 --- /dev/null +++ b/__tests__/fixtures/companion-api-import-2.json @@ -0,0 +1,552 @@ +{ + "cargo": { + "capacity": 32 + }, + "free": false, + "fuel": { + "main": { + "capacity": 128 + }, + "reserve": { + "capacity": 0.81 + } + }, + "id": 31, + "modules": { + "Armour": { + "module": { + "free": false, + "id": 128049346, + "name": "BelugaLiner_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": 128667757, + "name": "Decal_Explorer_Ranger", + "on": true, + "priority": 1, + "unloaned": 0, + "value": 0 + } + }, + "Decal2": { + "module": { + "free": false, + "id": 128667742, + "name": "Decal_Combat_Deadly", + "on": true, + "priority": 1, + "unloaned": 0, + "value": 0 + } + }, + "Decal3": { + "module": { + "free": false, + "id": 128667750, + "name": "Decal_Trade_Tycoon", + "on": true, + "priority": 1, + "unloaned": 0, + "value": 0 + } + }, + "EngineColour": [], + "FrameShiftDrive": { + "module": { + "free": false, + "id": 128064132, + "modifiers": { + "engineerID": 300100, + "id": 175, + "modifiers": [ + { + "name": "mod_mass", + "type": 1, + "value": 0.4457540512085 + }, + { + "name": "mod_health", + "type": 1, + "value": -0.24584779143333 + }, + { + "name": "mod_passive_power", + "type": 1, + "value": 0.24457727372646 + }, + { + "name": "mod_fsd_optimised_mass", + "type": 1, + "value": 0.49257898330688 + }, + { + "name": "mod_fsd_max_fuel_per_jump", + "type": 2, + "value": 0.028505677357316 + }, + { + "name": "mod_fsd_heat_rate", + "type": 2, + "value": -0.079360365867615 + } + ], + "moduleTags": [ + 16 + ], + "recipeID": 128673694, + "slotIndex": 53 + }, + "name": "Int_Hyperdrive_Size7_Class5", + "on": true, + "priority": 0, + "recipeLevel": 5, + "recipeName": "FSD_LongRange", + "recipeValue": 0, + "unloaned": 0, + "value": 46160201 + } + }, + "FuelTank": { + "module": { + "free": false, + "id": 128064352, + "name": "Int_FuelTank_Size7_Class3", + "on": true, + "priority": 1, + "unloaned": 1602822, + "value": 1602822 + } + }, + "LifeSupport": { + "module": { + "free": false, + "id": 128064174, + "name": "Int_LifeSupport_Size8_Class2", + "on": true, + "priority": 0, + "unloaned": 0, + "value": 1569565 + } + }, + "MainEngines": { + "module": { + "free": false, + "id": 128064094, + "modifiers": { + "engineerID": 300100, + "id": 253, + "modifiers": [ + { + "name": "mod_engine_mass_curve_multiplier", + "type": 1, + "value": 0.098235413432121 + }, + { + "name": "mod_engine_heat", + "type": 1, + "value": 0.18069696426392 + }, + { + "name": "mod_passive_power", + "type": 1, + "value": 0.033788848668337 + }, + { + "name": "mod_health", + "type": 1, + "value": -0.056404989212751 + }, + { + "name": "mod_engine_mass_curve", + "type": 1, + "value": -0.027384582906961 + }, + { + "name": "mod_engine_heat", + "type": 2, + "value": -0.072683908045292 + } + ], + "moduleTags": [ + 17 + ], + "recipeID": 128673655, + "slotIndex": 52 + }, + "name": "Int_Engine_Size7_Class2", + "on": true, + "priority": 0, + "recipeLevel": 1, + "recipeName": "Engine_Dirty", + "recipeValue": 0, + "unloaned": 0, + "value": 1709638 + } + }, + "MediumHardpoint1": { + "module": { + "free": false, + "id": 128049436, + "name": "Hpt_BeamLaser_Turret_Medium", + "on": true, + "priority": 0, + "unloaned": 0, + "value": 1889910 + } + }, + "MediumHardpoint2": { + "module": { + "free": false, + "id": 128049436, + "name": "Hpt_BeamLaser_Turret_Medium", + "on": true, + "priority": 0, + "unloaned": 0, + "value": 1889910 + } + }, + "MediumHardpoint3": { + "module": { + "free": false, + "id": 128049460, + "name": "Hpt_MultiCannon_Gimbal_Medium", + "on": true, + "priority": 0, + "unloaned": 0, + "value": 51300 + } + }, + "MediumHardpoint4": { + "module": { + "free": false, + "id": 128049460, + "name": "Hpt_MultiCannon_Gimbal_Medium", + "on": true, + "priority": 0, + "unloaned": 0, + "value": 51300 + } + }, + "MediumHardpoint5": { + "module": { + "free": false, + "id": 128049460, + "name": "Hpt_MultiCannon_Gimbal_Medium", + "on": true, + "priority": 0, + "unloaned": 0, + "value": 51300 + } + }, + "PaintJob": { + "module": { + "free": false, + "id": 128732290, + "name": "PaintJob_BelugaLiner_Tactical_White", + "on": true, + "priority": 1, + "unloaned": 0, + "value": 0 + } + }, + "PlanetaryApproachSuite": { + "module": { + "free": false, + "id": 128672317, + "name": "Int_PlanetApproachSuite", + "on": true, + "priority": 1, + "unloaned": 450, + "value": 450 + } + }, + "PowerDistributor": { + "module": { + "free": false, + "id": 128064207, + "name": "Int_PowerDistributor_Size6_Class5", + "on": true, + "priority": 0, + "unloaned": 0, + "value": 3128120 + } + }, + "PowerPlant": { + "module": { + "free": false, + "id": 128064057, + "modifiers": { + "engineerID": 300100, + "id": 277, + "modifiers": [ + { + "name": "mod_powerplant_power", + "type": 1, + "value": 0.054692290723324 + }, + { + "name": "mod_health", + "type": 1, + "value": -0.033690698444843 + }, + { + "name": "mod_powerplant_heat", + "type": 1, + "value": 0.027470717206597 + }, + { + "name": "mod_powerplant_heat", + "type": 2, + "value": -0.056317910552025 + } + ], + "moduleTags": [ + 18 + ], + "recipeID": 128673765, + "slotIndex": 51 + }, + "name": "Int_Powerplant_Size6_Class5", + "on": true, + "priority": 1, + "recipeLevel": 1, + "recipeName": "PowerPlant_Boosted", + "recipeValue": 0, + "unloaned": 0, + "value": 14561578 + } + }, + "Radar": { + "module": { + "free": false, + "id": 128064239, + "name": "Int_Sensors_Size5_Class2", + "on": true, + "priority": 0, + "unloaned": 0, + "value": 71500 + } + }, + "Slot01_Size6": { + "module": { + "free": false, + "id": 128666681, + "name": "Int_FuelScoop_Size6_Class5", + "on": true, + "priority": 1, + "unloaned": 0, + "value": 25887249 + } + }, + "Slot02_Size6": { + "module": { + "free": false, + "id": 128064287, + "name": "Int_ShieldGenerator_Size6_Class5", + "on": true, + "priority": 0, + "unloaned": 0, + "value": 14561578 + } + }, + "Slot03_Size6": { + "module": { + "free": false, + "id": 128727927, + "name": "Int_PassengerCabin_Size6_Class2", + "on": true, + "priority": 1, + "unloaned": 165808, + "value": 165808 + } + }, + "Slot04_Size6": { + "module": { + "free": false, + "id": 128727928, + "name": "Int_PassengerCabin_Size6_Class3", + "on": true, + "priority": 1, + "unloaned": 0, + "value": 497429 + } + }, + "Slot05_Size5": { + "module": { + "free": false, + "id": 128727925, + "name": "Int_PassengerCabin_Size5_Class4", + "on": true, + "priority": 1, + "unloaned": 0, + "value": 1492286 + } + }, + "Slot06_Size5": { + "module": { + "free": false, + "id": 128064342, + "name": "Int_CargoRack_Size5_Class1", + "on": true, + "priority": 1, + "unloaned": 100409, + "value": 100409 + } + }, + "Slot07_Size4": { + "module": { + "free": false, + "id": 128727922, + "name": "Int_PassengerCabin_Size4_Class1", + "on": true, + "priority": 1, + "unloaned": 0, + "value": 17059 + } + }, + "Slot08_Size3": { + "module": { + "free": false, + "id": 128667632, + "name": "Int_Repairer_Size3_Class5", + "on": true, + "priority": 1, + "unloaned": 0, + "value": 2361960 + } + }, + "Slot09_Size3": { + "module": { + "free": false, + "id": 128672289, + "name": "Int_BuggyBay_Size2_Class2", + "on": true, + "priority": 1, + "unloaned": 0, + "value": 19440 + } + }, + "Slot10_Size3": { + "module": { + "free": false, + "id": 128666634, + "name": "Int_DetailedSurfaceScanner_Tiny", + "on": true, + "priority": 1, + "unloaned": 0, + "value": 225000 + } + }, + "Slot11_Size3": { + "module": { + "free": false, + "id": 128663561, + "name": "Int_StellarBodyDiscoveryScanner_Advanced", + "on": true, + "priority": 1, + "unloaned": 0, + "value": 1390500 + } + }, + "TinyHardpoint1": { + "module": { + "free": false, + "id": 128049513, + "name": "Hpt_ChaffLauncher_Tiny", + "on": true, + "priority": 0, + "unloaned": 0, + "value": 7650 + } + }, + "TinyHardpoint2": { + "module": { + "free": false, + "id": 128668536, + "name": "Hpt_ShieldBooster_Size0_Class5", + "on": true, + "priority": 0, + "unloaned": 0, + "value": 252900 + } + }, + "TinyHardpoint3": { + "module": { + "free": false, + "id": 128668536, + "name": "Hpt_ShieldBooster_Size0_Class5", + "on": true, + "priority": 0, + "unloaned": 0, + "value": 252900 + } + }, + "TinyHardpoint4": { + "module": { + "free": false, + "id": 128668536, + "name": "Hpt_ShieldBooster_Size0_Class5", + "on": true, + "priority": 0, + "unloaned": 0, + "value": 281000 + } + }, + "TinyHardpoint5": { + "module": { + "free": false, + "id": 128668536, + "name": "Hpt_ShieldBooster_Size0_Class5", + "on": true, + "priority": 0, + "unloaned": 0, + "value": 281000 + } + }, + "TinyHardpoint6": { + "module": { + "free": false, + "id": 128668536, + "name": "Hpt_ShieldBooster_Size0_Class5", + "on": true, + "priority": 0, + "unloaned": 0, + "value": 281000 + } + }, + "WeaponColour": { + "module": { + "free": false, + "id": 128732194, + "name": "WeaponCustomisation_Purple", + "on": true, + "priority": 1, + "unloaned": 0, + "value": 0 + } + } + }, + "name": "BelugaLiner", + "value": { + "hull": 71688743, + "modules": 120812762, + "unloaned": 1869489 + } +} diff --git a/__tests__/test-import.js b/__tests__/test-import.js index e3f13dd2..711a8de1 100644 --- a/__tests__/test-import.js +++ b/__tests__/test-import.js @@ -228,6 +228,18 @@ describe('Import Modal', function() { expect(MockRouter.go.mock.calls.length).toBe(1); expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/federal_corvette?code=2putsFklndzsxf50x0x7l28281919040404040402020l06p05sf63c5ifrv66g2f.AwRj4zNaKA%3D%3D.CwRgDBldUExuBiQqA%3D%3D%3D.H4sIAAAAAAAAA02SP0sDQRDFJ4m5%2FLngJucZL4kxak7FRiGFWgiWGtBaC8UqVsEPYGEh2MRW%2FASCFhFEsRC7NKksIqaRoB%2FBQggh0R3fCCfXPGb3%2Febd7s0G9BoR%2FQQgaSNMpOrMHK1gyUGdFisEGW0aREXLJnLugoAmBsz2oma2zmBzSGeFRDtZFxb8wz6zY8eI7Cp6OKxXvaSZiEk0%2B4Ryqglo%2BgAhsatv5vgblmoJ6RzV296ZMkcRonCry2yU0WNdYtPZAs5xveNlhqv4kmE7RPlb9CdXsFes7hKNdQCy6SMbcZDHOZD1IY%2FswVGPOAcnfGTtL1PIhpDLQt6gUiW5JW5FThmHYaXXvcM6GxCzjTIl4oqomgQnfdAAat4LJOKKqBeBUj7oS6BngURcETUMpnASxTctH%2FmOG5uvQhIqVyp1KnEjPmgBVzI78FMirogy5d84eut%2FxnuINq8lSZrcPjaDxR5z7hxxxgcQu4IfwBld9oInu3gIkXn4c20sA00Z37jPf8CoIi3xQ1gHSvJaCjrv%2Bdl9GSpBnE28nsSnTJZ%2FAWD7326UAgAA&bn=Imported%20Federal%20Corvette'); }); + + it('imports a valid v4 build', function() { + const importData = require('./fixtures/companion-api-import-2'); + 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/beluga?code=0pktsFplCdpsnf70t0t2727270004040404043c4fmiml-04mc0iv62i2f.AwRj4yukg%3D%3D%3D.CwRgDBldHi8IUA%3D%3D.H4sIAAAAAAAAA2P8Z8%2FAwPCXEUiIKTMxMPCv%2F%2Ff%2FP8cFIPGf6Z8YTEr0GjMDg%2FJWICERBOTzn%2Fn7%2F7%2FIO5Ai5n9SIEWsQEIoSxAolfbt%2F3%2BJPk4GBhE7YQYGYVmgcuVnf4Aq%2FwMAIrEcGGsAAAA%3D&bn=Imported%20Beluga%20Liner'); + }); }); describe('Import E:D Shipyard Builds', function() { diff --git a/src/app/utils/CompanionApiUtils.js b/src/app/utils/CompanionApiUtils.js index 322c4d43..eba42ff9 100644 --- a/src/app/utils/CompanionApiUtils.js +++ b/src/app/utils/CompanionApiUtils.js @@ -240,7 +240,7 @@ export function shipFromJson(json) { // Add internal compartments let internalSlotNum = 1; for (let i in shipTemplate.slots.internal) { - const internalClassNum = shipTemplate.slots.internal[i]; + const internalClassNum = isNaN(shipTemplate.slots.internal[i]) ? shipTemplate.slots.internal[i].class : shipTemplate.slots.internal[i]; let internalSlot = null; while (internalSlot === null && internalSlotNum < 99) { From 50946eeeb8b15e8a4a122dbeff1caeb2e7bd9f2f Mon Sep 17 00:00:00 2001 From: Cmdr McDonald Date: Thu, 24 Nov 2016 13:18:48 +0000 Subject: [PATCH 5/6] Fix misnamed diamondbacks - issue #36 --- src/app/utils/CompanionApiUtils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/utils/CompanionApiUtils.js b/src/app/utils/CompanionApiUtils.js index eba42ff9..c5293149 100644 --- a/src/app/utils/CompanionApiUtils.js +++ b/src/app/utils/CompanionApiUtils.js @@ -13,8 +13,8 @@ const SHIP_FD_NAME_TO_CORIOLIS_NAME = { 'CobraMkIII': 'cobra_mk_iii', 'CobraMkIV': 'cobra_mk_iv', 'Cutter': 'imperial_cutter', - 'DiamondBack': 'diamondback_explorer', - 'DiamondBackXL': 'diamondback', + 'DiamondBackXL': 'diamondback_explorer', + 'DiamondBack': 'diamondback', 'Eagle': 'eagle', 'Empire_Courier': 'imperial_courier', 'Empire_Eagle': 'imperial_eagle', From e5552d3e1086da49f4bb7d7be8a94dd67cbf0794 Mon Sep 17 00:00:00 2001 From: Cmdr McDonald Date: Thu, 24 Nov 2016 13:49:37 +0000 Subject: [PATCH 6/6] Updates ready for release --- ChangeLog.md | 11 ++++++++++- package.json | 2 +- src/app/pages/OutfittingPage.jsx | 2 -- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index c9c5400e..f5250556 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,14 @@ #2.2.3 - * Fix hull boost calculation + * Fix hull boost calculation - now shows correct % modifier and total armour + * Fix import of DiamondBack - can now be imported + * Fix import of Beluga - can now be imported + * Use coriolis-data 2.2.3: + * Fix mismatch between class 5 and class 7 fighter hangars - now shows correct module + * Add details for concordant sequence special effect - now shows correct damage + * Fix details for thermal shock special effect - now shows correct damage + * Add engineer blueprints + * Modification tooltip now shows name and grade of modifications for imported builds + * Retain import URL unless user changes the build - allows future updates of Coriolis to take advantage of additional build information #2.2.2 * Update DPS/HPS/EPS in real-time as modifiers change diff --git a/package.json b/package.json index 7f54a676..40a09e70 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "coriolis_shipyard", - "version": "2.2.3beta", + "version": "2.2.3", "repository": { "type": "git", "url": "https://github.com/EDCD/coriolis" diff --git a/src/app/pages/OutfittingPage.jsx b/src/app/pages/OutfittingPage.jsx index 6dd3ba3a..e93a5eb9 100644 --- a/src/app/pages/OutfittingPage.jsx +++ b/src/app/pages/OutfittingPage.jsx @@ -289,8 +289,6 @@ export default class OutfittingPage extends Page { sStr = ship.getStandardString() + '.' + ship.getModificationsString(), iStr = ship.getInternalString() + '.' + ship.getModificationsString(); - Router.replace(outfitURL(ship.id, code, buildName)); - return (