Merge branch 'feature/blueprints' into develop

This commit is contained in:
Cmdr McDonald
2016-11-23 00:56:19 +00:00
12 changed files with 415 additions and 43 deletions

View File

@@ -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
}
}

View File

@@ -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==."
}
}

View File

@@ -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));
}
});

View File

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

View File

@@ -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 <div className='details' draggable='true' onDragStart={drag} onDragEnd={drop}>
<div className={'cb'}>
<div className={'l'}>
@@ -53,7 +59,7 @@ export default class HardpointSlot extends Slot {
{m.type && m.type.match('K') ? <span onMouseOver={termtip.bind(null, 'kinetic')} onMouseOut={tooltip.bind(null, null)}><DamageKinetic /></span> : ''}
{m.type && m.type.match('T') ? <span onMouseOver={termtip.bind(null, 'thermal')} onMouseOut={tooltip.bind(null, null)}><DamageThermal /></span> : ''}
{m.type && m.type.match('E') ? <span onMouseOver={termtip.bind(null, 'explosive')} onMouseOut={tooltip.bind(null, null)}><DamageExplosive /></span> : ''}
{classRating} {translate(m.name || m.grp)}{ m.mods && Object.keys(m.mods).length > 0 ? <span className='r' onMouseOver={termtip.bind(null, 'modified')} onMouseOut={tooltip.bind(null, null)}><Modified /></span> : null }
{classRating} {translate(m.name || m.grp)}{ m.mods && Object.keys(m.mods).length > 0 ? <span className='r' onMouseOver={termtip.bind(null, modTT)} onMouseOut={tooltip.bind(null, null)}><Modified /></span> : null }
</div>
<div className={'r'}>{formats.round(m.getMass())}{u.T}</div>

View File

@@ -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 <div className='details' draggable='true' onDragStart={drag} onDragEnd={drop}>
<div className={'cb'}>
<div className={'l'}>{classRating} {translate(m.name || m.grp)}{m.mods && Object.keys(m.mods).length > 0 ? <span onMouseOver={termtip.bind(null, 'modified')} onMouseOut={tooltip.bind(null, null)}><Modified /></span> : ''}</div>
<div className={'l'}>{classRating} {translate(m.name || m.grp)}{m.mods && Object.keys(m.mods).length > 0 ? <span onMouseOver={termtip.bind(null, modTT)} onMouseOut={tooltip.bind(null, null)}><Modified /></span> : ''}</div>
<div className={'r'}>{formats.round(mass)}{u.T}</div>
</div>
<div className={'cb'}>

View File

@@ -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 {
<div className={cn('details-container', { warning: warning && warning(slot.m) })}>
<div className={'sz'}>{slot.maxClass}</div>
<div>
<div className={'l'}>{classRating} {translate(m.name || m.grp)}{m.mods && Object.keys(m.mods).length > 0 ? <span className='r' onMouseOver={termtip.bind(null, 'modified')} onMouseOut={tooltip.bind(null, null)}><Modified /></span> : null }</div>
<div className={'l'}>{classRating} {translate(m.name || m.grp)}{m.mods && Object.keys(m.mods).length > 0 ? <span className='r' onMouseOver={termtip.bind(null, modTT)} onMouseOut={tooltip.bind(null, null)}><Modified /></span> : null }</div>
<div className={'r'}>{formats.round(mass)}{units.T}</div>
<div/>
<div className={'cb'}>

View File

@@ -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

View File

@@ -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;
};

View File

@@ -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++);
}
}

View File

@@ -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)

View File

@@ -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" }
}
},