Compare commits

..

9 Commits
2.2.2 ... 2.2.3

Author SHA1 Message Date
Cmdr McDonald
fd446b29ba Merge branch 'release/2.2.3' 2016-11-24 14:37:39 +00:00
Cmdr McDonald
e5552d3e10 Updates ready for release 2016-11-24 13:49:37 +00:00
Cmdr McDonald
50946eeeb8 Fix misnamed diamondbacks - issue #36 2016-11-24 13:19:14 +00:00
Cmdr McDonald
0ab59c1f9a Handle import of restricted slots - fix for #35 2016-11-24 11:10:41 +00:00
Cmdr McDonald
9042de422a patch 2016-11-23 01:05:13 +00:00
Cmdr McDonald
f0547feb93 Merge branch 'feature/blueprints' into develop 2016-11-23 00:56:19 +00:00
Cmdr McDonald
f863daa347 Fix hull boost calculation. Partial fix for #29 2016-11-23 00:54:42 +00:00
Cmdr McDonald
fdb202e7d6 Add blueprints 2016-11-22 15:52:31 +00:00
Cmdr McDonald
c6bde19052 Merge branch 'release/2.2.2' into develop 2016-11-21 16:44:19 +00:00
15 changed files with 1001 additions and 49 deletions

View File

@@ -1,4 +1,16 @@
#2.2.x #2.2.3
* 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 * Update DPS/HPS/EPS in real-time as modifiers change
* Use coriolis-data 2.2.2: * Use coriolis-data 2.2.2:
* Add distributor draw modifier to shield generators * Add distributor draw modifier to shield generators

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

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

View File

@@ -1,8 +1,8 @@
{ {
"type_6_transporter": { "type_6_transporter": {
"Cargo": "0p0tdFal8d8s8f4-----04040303430101.Iw1-kA==.Aw1-kA==.", "Cargo": "0p0tdFal8d8s8f4-----04040303430101.Iw1/kA==.Aw1/kA==.",
"Miner": "0p5tdFal8d8s8f42l2l---040403451q0101.Iw1-kA==.Aw1-kA==.", "Miner": "0p5tdFal8d8s8f42l2l---040403451q0101.Iw1/kA==.Aw1/kA==.",
"Hopper": "0p0tdFal8d0s8f41717---030302024300-.Iw1-kA==.Aw1-kA==." "Hopper": "0p0tdFal8d0s8f41717---030302024300-.Iw1/kA==.Aw1/kA==."
}, },
"type_7_transport": { "type_7_transport": {
"Cargo": "0p0tiFfliddsdf5--------0505040403480101.Iw18aQ==.Aw18aQ==.", "Cargo": "0p0tiFfliddsdf5--------0505040403480101.Iw18aQ==.Aw18aQ==.",
@@ -36,7 +36,7 @@
"Test": "4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04--0303326b.Iw18ZlA=.Aw18ZlA=." "Test": "4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04--0303326b.Iw18ZlA=.Aw18ZlA=."
}, },
"diamondback_explorer": { "diamondback_explorer": {
"Explorer": "0p0tdFfldddsdf5---0202--320p432i2f.Iw1-kA==.Aw1-kA==." "Explorer": "0p0tdFfldddsdf5---0202--320p432i2f.Iw1/kA==.Aw1/kA==."
}, },
"vulture": { "vulture": {
"Bounty Hunter": "3patcFalddksff31e1e0404-0l4a5d27662j.Iw19kA==.Aw19kA==." "Bounty Hunter": "3patcFalddksff31e1e0404-0l4a5d27662j.Iw19kA==.Aw19kA==."
@@ -45,6 +45,6 @@
"Attack": "2pfthFalidpsff31r0s0s0s0s000404-04-4a-5d27-.Iw18aQ==.Aw18aQ==." "Attack": "2pfthFalidpsff31r0s0s0s0s000404-04-4a-5d27-.Iw18aQ==.Aw18aQ==."
}, },
"eagle": { "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); expect(modal.state.singleBuild).toBe(true);
clickProceed(); clickProceed();
expect(MockRouter.go.mock.calls.length).toBe(1); 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() { it('catches an invalid build', function() {
@@ -167,7 +167,24 @@ describe('Import Modal', function() {
expect(modal.state.singleBuild).toBe(true); expect(modal.state.singleBuild).toBe(true);
clickProceed(); clickProceed();
expect(MockRouter.go.mock.calls.length).toBe(1); 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,25 @@ describe('Import Modal', function() {
expect(modal.state.singleBuild).toBe(true); expect(modal.state.singleBuild).toBe(true);
clickProceed(); clickProceed();
expect(MockRouter.go.mock.calls.length).toBe(1); 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=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() { 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'); const imports = require('./fixtures/ed-shipyard-import-valid');
for (let i = 0; i < imports.length; i++ ) { for (let i = 0; i < imports.length; i++ ) {
@@ -226,7 +255,7 @@ describe('Import Modal', function() {
expect(modal.state.errorMsg).toEqual(null); expect(modal.state.errorMsg).toEqual(null);
clickProceed(); clickProceed();
expect(MockRouter.go.mock.calls.length).toBe(1); 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", "name": "coriolis_shipyard",
"version": "2.2.2", "version": "2.2.3",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/EDCD/coriolis" "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 validMods = Modifications.validity[m.grp] || [];
let showModuleResistances = Persist.showModuleResistances(); 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}> return <div className='details' draggable='true' onDragStart={drag} onDragEnd={drop}>
<div className={'cb'}> <div className={'cb'}>
<div className={'l'}> <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('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('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> : ''} {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>
<div className={'r'}>{formats.round(m.getMass())}{u.T}</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 validMods = Modifications.validity[m.grp] || [];
let showModuleResistances = Persist.showModuleResistances(); 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; let mass = m.getMass() || m.cargo || m.fuel || 0;
return <div className='details' draggable='true' onDragStart={drag} onDragEnd={drop}> return <div className='details' draggable='true' onDragStart={drag} onDragEnd={drop}>
<div className={'cb'}> <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 className={'r'}>{formats.round(mass)}{u.T}</div>
</div> </div>
<div className={'cb'}> <div className={'cb'}>

View File

@@ -50,6 +50,12 @@ export default class StandardSlot extends TranslatedComponent {
let showModuleResistances = Persist.showModuleResistances(); let showModuleResistances = Persist.showModuleResistances();
let mass = m.getMass() || m.cargo || m.fuel || 0; 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 (!selected) {
// If not selected then sure that modifications flag is unset // If not selected then sure that modifications flag is unset
this._modificationsSelected = false; 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={cn('details-container', { warning: warning && warning(slot.m) })}>
<div className={'sz'}>{slot.maxClass}</div> <div className={'sz'}>{slot.maxClass}</div>
<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 className={'r'}>{formats.round(mass)}{units.T}</div>
<div/> <div/>
<div className={'cb'}> <div className={'cb'}>

View File

@@ -289,8 +289,6 @@ export default class OutfittingPage extends Page {
sStr = ship.getStandardString() + '.' + ship.getModificationsString(), sStr = ship.getStandardString() + '.' + ship.getModificationsString(),
iStr = ship.getInternalString() + '.' + ship.getModificationsString(); iStr = ship.getInternalString() + '.' + ship.getModificationsString();
Router.replace(outfitURL(ship.id, code, buildName));
return ( return (
<div id='outfit' className={'page'} style={{ fontSize: (sizeRatio * 0.9) + 'em' }}> <div id='outfit' className={'page'} style={{ fontSize: (sizeRatio * 0.9) + 'em' }}>
<div id='overview'> <div id='overview'>

View File

@@ -533,7 +533,6 @@ export default class Module {
return this._getModifiedValue('cells'); return this._getModifiedValue('cells');
} }
/** /**
* Get the jitter for this module, taking in to account modifications * Get the jitter for this module, taking in to account modifications
* @return {Number} the jitter for this module * @return {Number} the jitter for this module

View File

@@ -30,6 +30,10 @@ function standardToSchema(standard) {
o.modifications = standard.m.mods; o.modifications = standard.m.mods;
} }
if (standard.m.blueprint && Object.keys(standard.m.blueprint).length > 0) {
o.blueprint = standard.m.blueprint;
}
return o; return o;
} }
return null; return null;
@@ -62,6 +66,10 @@ function slotToSchema(slot) {
if (slot.m.mods && Object.keys(slot.m.mods).length > 0) { if (slot.m.mods && Object.keys(slot.m.mods).length > 0) {
o.modifications = slot.m.mods; o.modifications = slot.m.mods;
} }
if (slot.m.blueprint && Object.keys(slot.m.blueprint).length > 0) {
o.blueprint = slot.m.blueprint;
}
return o; return o;
} }
return null; return null;
@@ -137,6 +145,7 @@ export function fromDetailedBuild(detailedBuild) {
let ship = new Ship(shipId, shipData.properties, shipData.slots); let ship = new Ship(shipId, shipData.properties, shipData.slots);
let bulkheads = ModuleUtils.bulkheadIndex(stn.bulkheads); let bulkheads = ModuleUtils.bulkheadIndex(stn.bulkheads);
let modifications = new Array(stn.bulkheads.modifications); let modifications = new Array(stn.bulkheads.modifications);
let blueprints = new Array(stn.bulkheads.blueprint);
if (bulkheads < 0) { if (bulkheads < 0) {
throw 'Invalid bulkheads: ' + stn.bulkheads; throw 'Invalid bulkheads: ' + stn.bulkheads;
@@ -149,6 +158,7 @@ export function fromDetailedBuild(detailedBuild) {
priorities.push(stn[c].priority === undefined ? 0 : stn[c].priority - 1); priorities.push(stn[c].priority === undefined ? 0 : stn[c].priority - 1);
enabled.push(stn[c].enabled === undefined ? true : stn[c].enabled); enabled.push(stn[c].enabled === undefined ? true : stn[c].enabled);
modifications.push(stn[c].modifications); modifications.push(stn[c].modifications);
blueprints.push(stn[c].blueprint);
return stn[c].class + stn[c].rating; 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.utility.map(c => (c && c.m ? c.m.modifications : null)),
comps.internal.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; return ship;
}; };

View File

@@ -3,12 +3,20 @@ import * as ModuleUtils from './ModuleUtils';
import * as Utils from '../utils/UtilityFunctions'; import * as Utils from '../utils/UtilityFunctions';
import Module from './Module'; import Module from './Module';
import LZString from 'lz-string'; import LZString from 'lz-string';
import * as _ from 'lodash';
import isEqual from 'lodash/lang'; import isEqual from 'lodash/lang';
import { Modifications } from 'coriolis-data/dist'; import { Modifications } from 'coriolis-data/dist';
const zlib = require('zlib'); const zlib = require('zlib');
const UNIQUE_MODULES = ['psg', 'sg', 'bsg', 'rf', 'fs', 'fh']; 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 * Returns the power usage type of a slot and it's particular module
* @param {Object} slot The Slot * @param {Object} slot The Slot
@@ -472,9 +480,10 @@ export default class Ship {
* @param {array} priorities Slot priorities * @param {array} priorities Slot priorities
* @param {Array} enabled Slot active/inactive * @param {Array} enabled Slot active/inactive
* @param {Array} mods Modifications * @param {Array} mods Modifications
* @param {Array} blueprints Blueprints
* @return {this} The current ship instance for chaining * @return {this} The current ship instance for chaining
*/ */
buildWith(comps, priorities, enabled, mods) { buildWith(comps, priorities, enabled, mods, blueprints) {
let internal = this.internal, let internal = this.internal,
standard = this.standard, standard = this.standard,
hps = this.hardpoints, hps = this.hardpoints,
@@ -514,6 +523,7 @@ export default class Ship {
this.bulkheads.m = null; this.bulkheads.m = null;
this.useBulkhead(comps && comps.bulkheads ? comps.bulkheads : 0, true); this.useBulkhead(comps && comps.bulkheads ? comps.bulkheads : 0, true);
this.bulkheads.m.mods = mods && mods[0] ? mods[0] : {}; 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.priority = priorities ? priorities[0] * 1 : 0;
this.cargoHatch.enabled = enabled ? enabled[0] * 1 : true; this.cargoHatch.enabled = enabled ? enabled[0] * 1 : true;
@@ -526,7 +536,10 @@ export default class Ship {
standard[i].discountedCost = 0; standard[i].discountedCost = 0;
if (comps) { if (comps) {
let module = ModuleUtils.standard(i, comps.standard[i]); 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); this.use(standard[i], module, true);
} }
} }
@@ -545,7 +558,10 @@ export default class Ship {
if (comps && comps.hardpoints[i] !== 0) { if (comps && comps.hardpoints[i] !== 0) {
let module = ModuleUtils.hardpoints(comps.hardpoints[i]); 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); this.use(hps[i], module, true);
} }
} }
@@ -562,7 +578,10 @@ export default class Ship {
if (comps && comps.internal[i] !== 0) { if (comps && comps.internal[i] !== 0) {
let module = ModuleUtils.internal(comps.internal[i]); 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); this.use(internal[i], module, true);
} }
} }
@@ -596,6 +615,7 @@ export default class Ship {
hardpoints = new Array(this.hardpoints.length), hardpoints = new Array(this.hardpoints.length),
internal = new Array(this.internal.length), internal = new Array(this.internal.length),
modifications = new Array(1 + this.standard.length + this.hardpoints.length + 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('.'), parts = serializedString.split('.'),
priorities = null, priorities = null,
enabled = null, enabled = null,
@@ -615,7 +635,7 @@ export default class Ship {
this.decodeModificationsString(modstr, modifications); this.decodeModificationsString(modstr, modifications);
} else { } else {
try { 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) { } catch (err) {
// Could be out-of-date URL; ignore // Could be out-of-date URL; ignore
} }
@@ -633,7 +653,8 @@ export default class Ship {
}, },
priorities, priorities,
enabled, enabled,
modifications modifications,
blueprints,
); );
}; };
@@ -1305,8 +1326,11 @@ export default class Ship {
updateModificationsString() { updateModificationsString() {
// Start off by gathering the information that we need // Start off by gathering the information that we need
let slots = new Array(); let slots = new Array();
let blueprints = new Array();
let bulkheadMods = new Array(); let bulkheadMods = new Array();
let bulkheadBlueprint = undefined;
let bulkheadBlueprintGrade = undefined;
if (this.bulkheads.m && this.bulkheads.m.mods) { if (this.bulkheads.m && this.bulkheads.m.mods) {
for (let modKey in this.bulkheads.m.mods) { for (let modKey in this.bulkheads.m.mods) {
// Filter out invalid modifications // 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) }); bulkheadMods.push({ id: Modifications.modifications.indexOf(modKey), value: this.bulkheads.m.getModValue(modKey) });
} }
} }
bulkheadBlueprint = this.bulkheads.m.blueprint;
} }
slots.push(bulkheadMods); slots.push(bulkheadMods);
blueprints.push(bulkheadBlueprint)
for (let slot of this.standard) { for (let slot of this.standard) {
let slotMods = new Array(); let slotMods = new Array();
@@ -1328,6 +1354,7 @@ export default class Ship {
} }
} }
slots.push(slotMods); slots.push(slotMods);
blueprints.push(slot.m ? slot.m.blueprint : undefined);
} }
for (let slot of this.hardpoints) { for (let slot of this.hardpoints) {
@@ -1341,6 +1368,7 @@ export default class Ship {
} }
} }
slots.push(slotMods); slots.push(slotMods);
blueprints.push(slot.m ? slot.m.blueprint : undefined);
} }
for (let slot of this.internal) { for (let slot of this.internal) {
@@ -1354,13 +1382,15 @@ export default class Ship {
} }
} }
slots.push(slotMods); slots.push(slotMods);
blueprints.push(slot.m ? slot.m.blueprint : undefined);
} }
// Now work out the size of the binary buffer from our modifications array // Now work out the size of the binary buffer from our modifications array
let bufsize = 0; let bufsize = 0;
for (let slot of slots) { for (let slot of slots) {
if (slot.length > 0) { 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) { for (let slot of slots) {
if (slot.length > 0) { if (slot.length > 0) {
buffer.writeInt8(i, curpos++); 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) { for (let slotMod of slot) {
buffer.writeInt8(slotMod.id, curpos++); buffer.writeInt8(slotMod.id, curpos++);
buffer.writeInt32LE(slotMod.value, curpos); buffer.writeInt32LE(slotMod.value, curpos);
// console.log('ENCODE Slot ' + i + ': ' + Modifications.modifications[slotMod.id] + ' = ' + slotMod.value); // console.log('ENCODE Slot ' + i + ': ' + Modifications.modifications[slotMod.id] + ' = ' + slotMod.value);
curpos += 4; curpos += 4;
} }
buffer.writeInt8(-1, curpos++); buffer.writeInt8(MODIFICATION_ID_DONE, curpos++);
} }
i++; i++;
} }
if (curpos > 0) { if (curpos > 0) {
buffer.writeInt8(-1, curpos++); buffer.writeInt8(SLOT_ID_DONE, curpos++);
} }
this.serialized.modifications = zlib.gzipSync(buffer).toString('base64'); 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. * Populate the modifications array with modification values from the code.
* See updateModificationsString() for details of the structure. * See updateModificationsString() for details of the structure.
* @param {String} buffer Buffer holding modification info * @param {String} buffer Buffer holding modification info
* @param {Array} arr Modification array * @param {Array} modArr Modification array
* @param {Array} bluprintArr Blueprint array
*/ */
decodeModificationsStruct(buffer, arr) { decodeModificationsStruct(buffer, modArr, blueprintArr) {
let curpos = 0; let curpos = 0;
let slot = buffer.readInt8(curpos++); let slot = buffer.readInt8(curpos++);
while (slot != -1) { while (slot != SLOT_ID_DONE) {
let modifications = {}; let modifications = {};
let blueprint = {};
let modificationId = buffer.readInt8(curpos++); let modificationId = buffer.readInt8(curpos++);
while (modificationId != -1) { while (modificationId != MODIFICATION_ID_DONE) {
let modificationValue = buffer.readInt32LE(curpos); let modificationValue = buffer.readInt32LE(curpos);
curpos += 4; curpos += 4;
// console.log('DECODE Slot ' + slot + ': ' + Modifications.modifications[modificationId] + ' = ' + modificationValue); // There are a number of 'special' modification IDs, check for them here
modifications[Modifications.modifications[modificationId]] = modificationValue; 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++); modificationId = buffer.readInt8(curpos++);
} }
arr[slot] = modifications; modArr[slot] = modifications;
blueprintArr[slot] = blueprint;
slot = buffer.readInt8(curpos++); slot = buffer.readInt8(curpos++);
} }
} }

View File

@@ -13,8 +13,8 @@ const SHIP_FD_NAME_TO_CORIOLIS_NAME = {
'CobraMkIII': 'cobra_mk_iii', 'CobraMkIII': 'cobra_mk_iii',
'CobraMkIV': 'cobra_mk_iv', 'CobraMkIV': 'cobra_mk_iv',
'Cutter': 'imperial_cutter', 'Cutter': 'imperial_cutter',
'DiamondBack': 'diamondback_explorer', 'DiamondBackXL': 'diamondback_explorer',
'DiamondBackXL': 'diamondback', 'DiamondBack': 'diamondback',
'Eagle': 'eagle', 'Eagle': 'eagle',
'Empire_Courier': 'imperial_courier', 'Empire_Courier': 'imperial_courier',
'Empire_Eagle': 'imperial_eagle', 'Empire_Eagle': 'imperial_eagle',
@@ -149,13 +149,13 @@ export function shipFromJson(json) {
throw 'Unknown bulkheads "' + armourJson.name + '"'; throw 'Unknown bulkheads "' + armourJson.name + '"';
} }
ship.bulkheads.enabled = true; 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 // Add the standard modules
// Power plant // Power plant
const powerplantJson = json.modules.PowerPlant.module; const powerplantJson = json.modules.PowerPlant.module;
const powerplant = _moduleFromEdId(powerplantJson.id); 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.use(ship.standard[0], powerplant, true);
ship.standard[0].enabled = powerplantJson.on === true; ship.standard[0].enabled = powerplantJson.on === true;
ship.standard[0].priority = powerplantJson.priority; ship.standard[0].priority = powerplantJson.priority;
@@ -163,7 +163,7 @@ export function shipFromJson(json) {
// Thrusters // Thrusters
const thrustersJson = json.modules.MainEngines.module; const thrustersJson = json.modules.MainEngines.module;
const thrusters = _moduleFromEdId(thrustersJson.id); 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.use(ship.standard[1], thrusters, true);
ship.standard[1].enabled = thrustersJson.on === true; ship.standard[1].enabled = thrustersJson.on === true;
ship.standard[1].priority = thrustersJson.priority; ship.standard[1].priority = thrustersJson.priority;
@@ -171,7 +171,7 @@ export function shipFromJson(json) {
// FSD // FSD
const frameshiftdriveJson = json.modules.FrameShiftDrive.module; const frameshiftdriveJson = json.modules.FrameShiftDrive.module;
const frameshiftdrive = _moduleFromEdId(frameshiftdriveJson.id); 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.use(ship.standard[2], frameshiftdrive, true);
ship.standard[2].enabled = frameshiftdriveJson.on === true; ship.standard[2].enabled = frameshiftdriveJson.on === true;
ship.standard[2].priority = frameshiftdriveJson.priority; ship.standard[2].priority = frameshiftdriveJson.priority;
@@ -179,7 +179,7 @@ export function shipFromJson(json) {
// Life support // Life support
const lifesupportJson = json.modules.LifeSupport.module; const lifesupportJson = json.modules.LifeSupport.module;
const lifesupport = _moduleFromEdId(lifesupportJson.id); 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.use(ship.standard[3], lifesupport, true);
ship.standard[3].enabled = lifesupportJson.on === true; ship.standard[3].enabled = lifesupportJson.on === true;
ship.standard[3].priority = lifesupportJson.priority; ship.standard[3].priority = lifesupportJson.priority;
@@ -187,7 +187,7 @@ export function shipFromJson(json) {
// Power distributor // Power distributor
const powerdistributorJson = json.modules.PowerDistributor.module; const powerdistributorJson = json.modules.PowerDistributor.module;
const powerdistributor = _moduleFromEdId(powerdistributorJson.id); 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.use(ship.standard[4], powerdistributor, true);
ship.standard[4].enabled = powerdistributorJson.on === true; ship.standard[4].enabled = powerdistributorJson.on === true;
ship.standard[4].priority = powerdistributorJson.priority; ship.standard[4].priority = powerdistributorJson.priority;
@@ -195,7 +195,7 @@ export function shipFromJson(json) {
// Sensors // Sensors
const sensorsJson = json.modules.Radar.module; const sensorsJson = json.modules.Radar.module;
const sensors = _moduleFromEdId(sensorsJson.id); 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.use(ship.standard[5], sensors, true);
ship.standard[5].enabled = sensorsJson.on === true; ship.standard[5].enabled = sensorsJson.on === true;
ship.standard[5].priority = sensorsJson.priority; ship.standard[5].priority = sensorsJson.priority;
@@ -229,7 +229,7 @@ export function shipFromJson(json) {
} else { } else {
const hardpointJson = hardpointSlot.module; const hardpointJson = hardpointSlot.module;
const hardpoint = _moduleFromEdId(hardpointJson.id); 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.use(ship.hardpoints[hardpointArrayNum], hardpoint, true);
ship.hardpoints[hardpointArrayNum].enabled = hardpointJson.on === true; ship.hardpoints[hardpointArrayNum].enabled = hardpointJson.on === true;
ship.hardpoints[hardpointArrayNum].priority = hardpointJson.priority; ship.hardpoints[hardpointArrayNum].priority = hardpointJson.priority;
@@ -240,7 +240,7 @@ export function shipFromJson(json) {
// Add internal compartments // Add internal compartments
let internalSlotNum = 1; let internalSlotNum = 1;
for (let i in shipTemplate.slots.internal) { 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; let internalSlot = null;
while (internalSlot === null && internalSlotNum < 99) { while (internalSlot === null && internalSlotNum < 99) {
@@ -256,7 +256,7 @@ export function shipFromJson(json) {
} else { } else {
const internalJson = internalSlot.module; const internalJson = internalSlot.module;
const internal = _moduleFromEdId(internalJson.id); 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.use(ship.internal[i], internal, true);
ship.internal[i].enabled = internalJson.on === true; ship.internal[i].enabled = internalJson.on === true;
ship.internal[i].priority = internalJson.priority; ship.internal[i].priority = internalJson.priority;
@@ -271,8 +271,10 @@ export function shipFromJson(json) {
* Add the modifications for a module * Add the modifications for a module
* @param {Module} module the module * @param {Module} module the module
* @param {Object} modifiers the modifiers * @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; if (!modifiers || !modifiers.modifiers) return;
for (const i in modifiers.modifiers) { 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 // Need to fix up a few items
// Shield boosters are treated internally as straight modifiers, so rather than (for example) // Shield boosters are treated internally as straight modifiers, so rather than (for example)
@@ -355,6 +365,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 // Jitter is an absolute number, so we need to divide it by 100
if (module.getModValue('jitter')) { if (module.getModValue('jitter')) {
module.setModValue('jitter', module.getModValue('jitter') / 100); module.setModValue('jitter', module.getModValue('jitter') / 100);

View File

@@ -68,6 +68,7 @@
"rating": { "$ref": "#/definitions/standardRatings" }, "rating": { "$ref": "#/definitions/standardRatings" },
"enabled": { "type": "boolean" }, "enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 }, "priority": { "type": "integer", "minimum": 1, "maximum": 5 },
"blueprint": { "type": "object" },
"modifications": { "type": "object" } "modifications": { "type": "object" }
} }
}, },
@@ -82,6 +83,7 @@
"description": "The name identifing the thrusters (if applicable), e.g. 'Enhanced Performance'", "description": "The name identifing the thrusters (if applicable), e.g. 'Enhanced Performance'",
"type": "string" "type": "string"
}, },
"blueprint": { "type": "object" },
"modifications": { "type": "object" } "modifications": { "type": "object" }
} }
}, },
@@ -92,6 +94,7 @@
"rating": { "$ref": "#/definitions/standardRatings" }, "rating": { "$ref": "#/definitions/standardRatings" },
"enabled": { "type": "boolean" }, "enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 }, "priority": { "type": "integer", "minimum": 1, "maximum": 5 },
"blueprint": { "type": "object" },
"modifications": { "type": "object" } "modifications": { "type": "object" }
} }
}, },
@@ -102,6 +105,7 @@
"rating": { "$ref": "#/definitions/standardRatings" }, "rating": { "$ref": "#/definitions/standardRatings" },
"enabled": { "type": "boolean" }, "enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 }, "priority": { "type": "integer", "minimum": 1, "maximum": 5 },
"blueprint": { "type": "object" },
"modifications": { "type": "object" } "modifications": { "type": "object" }
} }
}, },
@@ -112,6 +116,7 @@
"rating": { "$ref": "#/definitions/standardRatings" }, "rating": { "$ref": "#/definitions/standardRatings" },
"enabled": { "type": "boolean" }, "enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 }, "priority": { "type": "integer", "minimum": 1, "maximum": 5 },
"blueprint": { "type": "object" },
"modifications": { "type": "object" } "modifications": { "type": "object" }
} }
}, },
@@ -122,6 +127,7 @@
"rating": { "$ref": "#/definitions/standardRatings" }, "rating": { "$ref": "#/definitions/standardRatings" },
"enabled": { "type": "boolean" }, "enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 }, "priority": { "type": "integer", "minimum": 1, "maximum": 5 },
"blueprint": { "type": "object" },
"modifications": { "type": "object" } "modifications": { "type": "object" }
} }
}, },
@@ -132,6 +138,7 @@
"rating": { "$ref": "#/definitions/standardRatings" }, "rating": { "$ref": "#/definitions/standardRatings" },
"enabled": { "type": "boolean" }, "enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 }, "priority": { "type": "integer", "minimum": 1, "maximum": 5 },
"blueprint": { "type": "object" },
"modifications": { "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'", "description": "The name identifying the component (if applicable), e.g. 'Advance Discovery Scanner', or 'Detailed Surface Scanner'",
"type": "string" "type": "string"
}, },
"blueprint": { "type": "object" },
"modifications": { "type": "object" } "modifications": { "type": "object" }
} }
}, },
@@ -179,6 +187,7 @@
"description": "The name identifing the component (if applicable), e.g. 'Retributor', or 'Mining Lance'", "description": "The name identifing the component (if applicable), e.g. 'Retributor', or 'Mining Lance'",
"type": "string" "type": "string"
}, },
"blueprint": { "type": "object" },
"modifications": { "type": "object" } "modifications": { "type": "object" }
} }
}, },
@@ -202,6 +211,7 @@
"description": "The name identifing the component (if applicable), e.g. 'Point Defence', or 'Electronic Countermeasure'", "description": "The name identifing the component (if applicable), e.g. 'Point Defence', or 'Electronic Countermeasure'",
"type": "string" "type": "string"
}, },
"blueprint": { "type": "object" },
"modifications": { "type": "object" } "modifications": { "type": "object" }
} }
}, },