Merge branch 'feature/fixes' into develop

This commit is contained in:
Cmdr McDonald
2016-11-09 19:05:43 +00:00
24 changed files with 1003 additions and 162 deletions

13
ChangeLog.md Normal file
View File

@@ -0,0 +1,13 @@
#2.2.x
* Update DPS/HPS/EPS in real-time as modifiers change
* Use coriolis-data 2.2.2:
* Add distributor draw modifier to shield generators
* Remove modifiers for sensors
* Add initial loadout passenger cabins for Beluga
* Add initial loadout passenger cabins for Orca
* Update costs and initial loadouts for Keelback and Type-7
* Show modification icon for modified modules
* Take modifications in to account when deciding whether to issue a warning on a standard module
* Fix hardpoint comparison DPS number when selecting an alternate module
* Ensure that retrofit tab only shows changed modules
* Fix import and export of ships with modifications, bump schema version to 4

View File

@@ -0,0 +1,300 @@
{
"$schema": "http://cdn.coriolis.io/schemas/ship-loadout/4.json#",
"name": "Test My Ship",
"ship": "Anaconda",
"references": [
{
"name": "Coriolis.io",
"url": "http://localhost:3300/outfit/anaconda/48A6A6A5A8A8A5C2c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04--0303326b.AwRj4zNKqA==.CwBhCYzBGW9qCTSqs5xA.H4sIAAAAAAAAA2MUe8HMwPD-PwDDhxeuCAAAAA==?bn=Test%20My%20Ship",
"old-code": "48A6A6A5A8A8A5C2c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04--0303326b.AwRj4zNKqA==.CwBhCYzBGW9qCTSqs5xA.H4sIAAAAAAAAA2MUe8HMwPD-PwDDhxeuCAAAAA==",
"code": "4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04--0303326b.AwRj4zNKqA==.CwBhCYzBGW9qCTSqs5xA.H4sIAAAAAAAAA2MUe8HMwPD-PwDDhxeuCAAAAA==",
"shipId": "anaconda"
}
],
"components": {
"standard": {
"bulkheads": "Reactive Surface Composite",
"cargoHatch": {
"enabled": false,
"priority": 5
},
"powerPlant": {
"class": 8,
"rating": "A",
"enabled": true,
"priority": 1,
"modifications": {
"pgen": 1000
}
},
"thrusters": {
"class": 6,
"rating": "A",
"enabled": true,
"priority": 1
},
"frameShiftDrive": {
"class": 6,
"rating": "A",
"enabled": true,
"priority": 3
},
"lifeSupport": {
"class": 5,
"rating": "A",
"enabled": true,
"priority": 1
},
"powerDistributor": {
"class": 8,
"rating": "A",
"enabled": true,
"priority": 1
},
"sensors": {
"class": 8,
"rating": "A",
"enabled": true,
"priority": 1
},
"fuelTank": {
"class": 5,
"rating": "C",
"enabled": true,
"priority": 1
}
},
"hardpoints": [
{
"class": 4,
"rating": "A",
"enabled": true,
"priority": 2,
"group": "Plasma Accelerator",
"mount": "Fixed"
},
{
"class": 3,
"rating": "D",
"enabled": true,
"priority": 2,
"group": "Beam Laser",
"mount": "Turret"
},
{
"class": 3,
"rating": "D",
"enabled": true,
"priority": 2,
"group": "Beam Laser",
"mount": "Turret"
},
{
"class": 3,
"rating": "D",
"enabled": true,
"priority": 2,
"group": "Beam Laser",
"mount": "Turret"
},
{
"class": 2,
"rating": "E",
"enabled": true,
"priority": 2,
"group": "Cannon",
"mount": "Turret"
},
{
"class": 2,
"rating": "E",
"enabled": true,
"priority": 2,
"group": "Cannon",
"mount": "Turret"
},
{
"class": 1,
"rating": "F",
"enabled": true,
"priority": 2,
"group": "Beam Laser",
"mount": "Turret"
},
{
"class": 1,
"rating": "F",
"enabled": true,
"priority": 2,
"group": "Beam Laser",
"mount": "Turret"
}
],
"utility": [
{
"class": 0,
"rating": "A",
"enabled": true,
"priority": 1,
"group": "Shield Booster"
},
{
"class": 0,
"rating": "A",
"enabled": true,
"priority": 1,
"group": "Shield Booster"
},
null,
{
"class": 0,
"rating": "C",
"enabled": true,
"priority": 2,
"group": "Kill Warrant Scanner"
},
{
"class": 0,
"rating": "C",
"enabled": true,
"priority": 2,
"group": "Cargo Scanner"
},
{
"class": 0,
"rating": "F",
"enabled": false,
"priority": 1,
"group": "Electronic Countermeasure",
"name": "Electronic Countermeasure"
},
{
"class": 0,
"rating": "I",
"enabled": true,
"priority": 1,
"group": "Chaff Launcher",
"name": "Chaff Launcher"
},
{
"class": 0,
"rating": "I",
"enabled": true,
"priority": 2,
"group": "Point Defence",
"name": "Point Defence"
}
],
"internal": [
{
"class": 7,
"rating": "A",
"enabled": true,
"priority": 1,
"group": "Shield Generator"
},
{
"class": 6,
"rating": "A",
"enabled": true,
"priority": 1,
"group": "Shield Cell Bank"
},
{
"class": 6,
"rating": "E",
"enabled": true,
"priority": 1,
"group": "Cargo Rack"
},
{
"class": 5,
"rating": "D",
"enabled": true,
"priority": 1,
"group": "Hull Reinforcement Package"
},
{
"class": 5,
"rating": "E",
"enabled": true,
"priority": 1,
"group": "Cargo Rack"
},
null,
null,
{
"class": 4,
"rating": "E",
"enabled": true,
"priority": 1,
"group": "Cargo Rack"
},
{
"class": 4,
"rating": "E",
"enabled": true,
"priority": 1,
"group": "Cargo Rack"
},
{
"class": 4,
"rating": "A",
"enabled": true,
"priority": 3,
"group": "Fuel Scoop"
},
{
"class": 2,
"rating": "A",
"enabled": true,
"priority": 3,
"group": "Frame Shift Drive Interdictor"
}
]
},
"stats": {
"class": 3,
"fighterHangars": 1,
"hullCost": 141889930,
"speed": 180,
"topSpeed": 186.5,
"boost": 240,
"boostEnergy": 27,
"topBoost": 248.62,
"topSpeed": 186.46,
"totalCost": 882362058,
"totalDps": 97.74,
"totalEps": 22.71,
"totalHps": 677.29,
"agility": 2,
"baseShieldStrength": 350,
"baseArmour": 945,
"hullExplRes": 0,
"hullKinRes": 0,
"hullMass": 400,
"hullThermRes": 0,
"masslock": 23,
"pipSpeed": 0.14,
"moduleCostMultiplier": 1,
"fuelCapacity": 32,
"cargoCapacity": 128,
"ladenMass": 1339.2,
"armour": 2227.5,
"baseArmour": 525,
"unladenMass": 1179.2,
"powerAvailable": 39.6,
"powerRetracted": 23.33,
"powerDeployed": 34.76,
"unladenRange": 18.49,
"fullTankRange": 18.12,
"ladenRange": 16.39,
"unladenFastestRange": 73.21,
"ladenFastestRange": 66.15,
"maxJumpCount": 4,
"shield": 833,
"shieldExplRes": 0,
"shieldKinRes": 0,
"shieldThermRes": 0
}
}

View File

@@ -2,31 +2,31 @@
{ {
"shipId": "anaconda", "shipId": "anaconda",
"buildName": "Imported Anaconda", "buildName": "Imported Anaconda",
"buildCode": "0pyttFolodDsyf5------1717--------05044j-03--2h--00.Iw18ZlA=.Aw18ZlA=", "buildCode": "0pyttFolodDsyf5------1717--------05044j-03--2h--00.Iw18ZlA=.Aw18ZlA=.",
"buildText": "[Anaconda]\nS: 1F/F Pulse Laser\nS: 1F/F Pulse Laser\n\nBH: 1I Lightweight Alloy\nRB: 8E Power Plant\nTM: 7E Thrusters\nFH: 6E Frame Shift Drive\nEC: 5E Life Support\nPC: 8E Power Distributor\nSS: 8E Sensors\nFS: 5C Fuel Tank (Capacity: 32)\n\n7: 6E Cargo Rack (Capacity: 64)\n6: 5E Cargo Rack (Capacity: 32)\n6: 6E Shield Generator\n5: 4E Cargo Rack (Capacity: 16)\n4: 1E Basic Discovery Scanner\n2: 1E Cargo Rack (Capacity: 2)\n" "buildText": "[Anaconda]\nS: 1F/F Pulse Laser\nS: 1F/F Pulse Laser\n\nBH: 1I Lightweight Alloy\nRB: 8E Power Plant\nTM: 7E Thrusters\nFH: 6E Frame Shift Drive\nEC: 5E Life Support\nPC: 8E Power Distributor\nSS: 8E Sensors\nFS: 5C Fuel Tank (Capacity: 32)\n\n7: 6E Cargo Rack (Capacity: 64)\n6: 5E Cargo Rack (Capacity: 32)\n6: 6E Shield Generator\n5: 4E Cargo Rack (Capacity: 16)\n4: 1E Basic Discovery Scanner\n2: 1E Cargo Rack (Capacity: 2)\n"
}, },
{ {
"shipId": "anaconda", "shipId": "anaconda",
"buildName": "Imported Anaconda", "buildName": "Imported Anaconda",
"buildCode": "0pyttFolodDsyf5------1717--------05044j-03--2h--00.Iw18ZlA=.Aw18ZlA=", "buildCode": "0pyttFolodDsyf5------1717--------05044j-03--2h--00.Iw18ZlA=.Aw18ZlA=.",
"buildText": "\n\n \t[Anaconda]\nS: 1F/F Pulse Laser\nS: 1F/F Pulse Laser\n\nBH: 1I Lightweight Alloy\nRB: 8E Power Plant\nTM: 7E Thrusters\nFH: 6E Frame Shift Drive\nEC: 5E Life Support\nPC: 8E Power Distributor\nSS: 8E Sensors\nFS: 5C Fuel Tank (Capacity: 32)\n\n7: 6E Cargo Rack (Capacity: 64)\n6: 5E Cargo Rack (Capacity: 32)\n6: 6E Shield Generator\n5: 4E Cargo Rack (Capacity: 16)\n4: 1E Basic Discovery Scanner\n2: 1E Cargo Rack (Capacity: 2)\n" "buildText": "\n\n \t[Anaconda]\nS: 1F/F Pulse Laser\nS: 1F/F Pulse Laser\n\nBH: 1I Lightweight Alloy\nRB: 8E Power Plant\nTM: 7E Thrusters\nFH: 6E Frame Shift Drive\nEC: 5E Life Support\nPC: 8E Power Distributor\nSS: 8E Sensors\nFS: 5C Fuel Tank (Capacity: 32)\n\n7: 6E Cargo Rack (Capacity: 64)\n6: 5E Cargo Rack (Capacity: 32)\n6: 6E Shield Generator\n5: 4E Cargo Rack (Capacity: 16)\n4: 1E Basic Discovery Scanner\n2: 1E Cargo Rack (Capacity: 2)\n"
}, },
{ {
"shipId": "cobra_mk_iii", "shipId": "cobra_mk_iii",
"buildName": "Imported Cobra Mk III", "buildName": "Imported Cobra Mk III",
"buildCode": "0patcFeldd5sdf41712222503040202490f242h.Iw1-kA==.Aw1-kA==", "buildCode": "0patcFeldd5sdf41712222503040202490f242h.Iw1-kA==.Aw1-kA==.",
"buildText": "[Cobra Mk III]\nM: 1F/F Pulse Laser\nM: 1G/G Burst Laser\nS: 1E/T Fragment Cannon\nS: 1G/T Multi-cannon\nU: 0I Point Defence\nU: 0A Shield Booster\n\nBH: 1I Lightweight Alloy\nRB: 4A Power Plant\nTM: 4C Thrusters\nFH: 4E Frame Shift Drive\nEC: 3D Life Support\nPC: 2A Power Distributor\nSS: 3D Sensors\nFS: 4C Fuel Tank (Capacity: 16)\n\n4: 3E Cargo Rack (Capacity: 8)\n4: 3E Cargo Rack (Capacity: 8)\n4: 4E Shield Generator\n2: 2C Auto Field-Maintenance Unit\n2: 1E Standard Docking Computer\n2: 1E Basic Discovery Scanner\n---\nShield: 112.29 MJ\nPower : 10.45 MW retracted (67%)\n 12.16 MW deployed (78%)\n 15.60 MW available\nCargo : 16 T\nFuel : 16 T\nMass : 235.5 T empty\n 267.5 T full\nRange : 10.69 LY unladen\n 10.05 LY laden\nPrice : 2,929,040 CR\nRe-Buy: 146,452 CR @ 95% insurance\n" "buildText": "[Cobra Mk III]\nM: 1F/F Pulse Laser\nM: 1G/G Burst Laser\nS: 1E/T Fragment Cannon\nS: 1G/T Multi-cannon\nU: 0I Point Defence\nU: 0A Shield Booster\n\nBH: 1I Lightweight Alloy\nRB: 4A Power Plant\nTM: 4C Thrusters\nFH: 4E Frame Shift Drive\nEC: 3D Life Support\nPC: 2A Power Distributor\nSS: 3D Sensors\nFS: 4C Fuel Tank (Capacity: 16)\n\n4: 3E Cargo Rack (Capacity: 8)\n4: 3E Cargo Rack (Capacity: 8)\n4: 4E Shield Generator\n2: 2C Auto Field-Maintenance Unit\n2: 1E Standard Docking Computer\n2: 1E Basic Discovery Scanner\n---\nShield: 112.29 MJ\nPower : 10.45 MW retracted (67%)\n 12.16 MW deployed (78%)\n 15.60 MW available\nCargo : 16 T\nFuel : 16 T\nMass : 235.5 T empty\n 267.5 T full\nRange : 10.69 LY unladen\n 10.05 LY laden\nPrice : 2,929,040 CR\nRe-Buy: 146,452 CR @ 95% insurance\n"
}, },
{ {
"shipId": "type_9_heavy", "shipId": "type_9_heavy",
"buildName": "Imported Type-9 Heavy", "buildName": "Imported Type-9 Heavy",
"buildCode": "3pftsFklkdisif57e2k2f2h110001020306054j03022f01242i.Iw18eQ==.Aw18eQ==", "buildCode": "3pftsFklkdisif57e2k2f2h110001020306054j03022f01242i.Iw18eQ==.Aw18eQ==.",
"buildText": "[Type-9 Heavy]\nM: 2D/G Fragment Cannon\nM: 2I/F Mine Launcher\nM: 2B/FD Missile Rack\nS: 1I/FS Torpedo Pylon\nS: 1F/F Burst Laser\nU: 0I Chaff Launcher\nU: 0F Electronic Countermeasure\nU: 0I Heat Sink Launcher\nU: 0I Point Defence\n\nBH: 1I Mirrored Surface Composite\nRB: 5A Power Plant\nTM: 7D Thrusters\nFH: 6A Frame Shift Drive\nEC: 5A Life Support\nPC: 4D Power Distributor\nSS: 4D Sensors\nFS: 5C Fuel Tank (Capacity: 32)\n\n8: 7E Cargo Rack (Capacity: 128)\n7: 6E Cargo Rack (Capacity: 64)\n6: 6E Shield Generator\n5: 4E Cargo Rack (Capacity: 16)\n4: 3E Cargo Rack (Capacity: 8)\n4: 1C Advanced Discovery Scanner\n3: 2E Cargo Rack (Capacity: 4)\n3: 1E Standard Docking Computer\n2: 1C Detailed Surface Scanner\n" "buildText": "[Type-9 Heavy]\nM: 2D/G Fragment Cannon\nM: 2I/F Mine Launcher\nM: 2B/FD Missile Rack\nS: 1I/FS Torpedo Pylon\nS: 1F/F Burst Laser\nU: 0I Chaff Launcher\nU: 0F Electronic Countermeasure\nU: 0I Heat Sink Launcher\nU: 0I Point Defence\n\nBH: 1I Mirrored Surface Composite\nRB: 5A Power Plant\nTM: 7D Thrusters\nFH: 6A Frame Shift Drive\nEC: 5A Life Support\nPC: 4D Power Distributor\nSS: 4D Sensors\nFS: 5C Fuel Tank (Capacity: 32)\n\n8: 7E Cargo Rack (Capacity: 128)\n7: 6E Cargo Rack (Capacity: 64)\n6: 6E Shield Generator\n5: 4E Cargo Rack (Capacity: 16)\n4: 3E Cargo Rack (Capacity: 8)\n4: 1C Advanced Discovery Scanner\n3: 2E Cargo Rack (Capacity: 4)\n3: 1E Standard Docking Computer\n2: 1C Detailed Surface Scanner\n"
}, },
{ {
"shipId": "vulture", "shipId": "vulture",
"buildName": "Imported Vulture", "buildName": "Imported Vulture",
"buildCode": "4patfFalddksif31e1e0e0j04044a0n532jf1.Iw19kA==.Aw19kA==", "buildCode": "4patfFalddksif31e1e0e0j04044a0n532jf1.Iw19kA==.Aw19kA==.",
"buildText": "[Vulture]\nL: 3E/G Pulse Laser\nL: 3E/G Pulse Laser\nU: 0A Frame Shift Wake Scanner\nU: 0A Kill Warrant Scanner\nU: 0A Shield Booster\nU: 0A Shield Booster\n\nBH: 1I Reactive Surface Composite\nRB: 4A Power Plant\nTM: 5A Thrusters\nFH: 4A Frame Shift Drive\nEC: 3D Life Support\nPC: 5A Power Distributor\nSS: 4D Sensors\nFS: 3C Fuel Tank (Capacity: 8)\n\n5: 5A Shield Generator\n4: 4A Auto Field-Maintenance Unit\n2: 2A Shield Cell Bank\n1: 1A Fuel Scoop\n1: 1C Fuel Tank (Capacity: 2)" "buildText": "[Vulture]\nL: 3E/G Pulse Laser\nL: 3E/G Pulse Laser\nU: 0A Frame Shift Wake Scanner\nU: 0A Kill Warrant Scanner\nU: 0A Shield Booster\nU: 0A Shield Booster\n\nBH: 1I Reactive Surface Composite\nRB: 4A Power Plant\nTM: 5A Thrusters\nFH: 4A Frame Shift Drive\nEC: 3D Life Support\nPC: 5A Power Distributor\nSS: 4D Sensors\nFS: 3C Fuel Tank (Capacity: 8)\n\n5: 5A Shield Generator\n4: 4A Auto Field-Maintenance Unit\n2: 2A Shield Cell Bank\n1: 1A Fuel Scoop\n1: 1C Fuel Tank (Capacity: 2)"
} }
] ]

View File

@@ -1,50 +1,50 @@
{ {
"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==.",
"Miner": "0pdtiFflid8sdf5--2l2l----0505041v03450000.Iw18aQ==.Aw18aQ==" "Miner": "0pdtiFflid8sdf5--2l2l----0505041v03450000.Iw18aQ==.Aw18aQ==."
}, },
"federal_dropship": { "federal_dropship": {
"Cargo": "0pdtiFflnddsif4-1717------05040448020201.Iw18aQ==.Aw18aQ==" "Cargo": "0pdtiFflnddsif4-1717------05040448020201.Iw18aQ==.Aw18aQ==."
}, },
"asp": { "asp": {
"Miner": "2pftfFflidfskf50s0s24242l2l---04054a1q02022o27.Iw18WQ==.Aw18WQ==" "Miner": "2pftfFflidfskf50s0s24242l2l---04054a1q02022o27.Iw18WQ==.Aw18WQ==."
}, },
"imperial_clipper": { "imperial_clipper": {
"Cargo": "0p5tiFflndisnf4--0s0s----0605450302020101.Iw18aQ==.Aw18aQ==", "Cargo": "0p5tiFflndisnf4--0s0s----0605450302020101.Iw18aQ==.Aw18aQ==.",
"Dream": "2pktkFflndpskf40v0v0s0s0404040n4k5n5d2b29292o-.Iw18aQ==.Aw18aQ==", "Dream": "2pktkFflndpskf40v0v0s0s0404040n4k5n5d2b29292o-.Iw18aQ==.Aw18aQ==.",
"Current": "0patkFflndfskf4----------------.Iw18aQ==.Aw18aQ==" "Current": "0patkFflndfskf4----------------.Iw18aQ==.Aw18aQ==."
}, },
"type_9_heavy": { "type_9_heavy": {
"Current": "0patsFklndnsif6---------0706054a0303020224.Iw18eQ==.Aw18eQ==" "Current": "0patsFklndnsif6---------0706054a0303020224.Iw18eQ==.Aw18eQ==."
}, },
"python": { "python": {
"Cargo": "0patnFflidsssf5---------050505040448020201.Iw18eQ==.Aw18eQ==", "Cargo": "0patnFflidsssf5---------050505040448020201.Iw18eQ==.Aw18eQ==.",
"Miner": "0pktkFflidpspf50v0v0v2m2m0404--050505Ce4a1v02022o.Iw18eQ==.Aw18eQ==", "Miner": "0pktkFflidpspf50v0v0v2m2m0404--050505Ce4a1v02022o.Iw18eQ==.Aw18eQ==.",
"Dream": "2pptkFfliduspf50v0v0v27270404040m5n5n4f2d2d032t0201.Iw18eQ==.Aw18eQ==", "Dream": "2pptkFfliduspf50v0v0v27270404040m5n5n4f2d2d032t0201.Iw18eQ==.Aw18eQ==.",
"Missile": "0pttoFjljdystf52f2g2d2ePh----04044j03---002h.Iw18eQ==.Aw18eQ==" "Missile": "0pttoFjljdystf52f2g2d2ePh----04044j03---002h.Iw18eQ==.Aw18eQ==."
}, },
"anaconda": { "anaconda": {
"Dream": "4putpFklndzsuf52c0o0o0o1m1m0q0q0404040l0b0100004k5n5n112d2d040303326b.Iw18ZlA=.Aw18ZlA=", "Dream": "4putpFklndzsuf52c0o0o0o1m1m0q0q0404040l0b0100004k5n5n112d2d040303326b.Iw18ZlA=.Aw18ZlA=.",
"Cargo": "0patnFklndnsxf5----------------0605050504040445030301.Iw18ZlA=.Aw18ZlA=", "Cargo": "0patnFklndnsxf5----------------0605050504040445030301.Iw18ZlA=.Aw18ZlA=.",
"Current": "0patnFklndksxf5----------------0605050504040403034524.Iw18ZlA=.Aw18ZlA=", "Current": "0patnFklndksxf5----------------0605050504040403034524.Iw18ZlA=.Aw18ZlA=.",
"Explorer": "0patnFklndksxf5--------0202------f7050505040s372f2i4524.Iw18ZlA=.Aw18ZlA=", "Explorer": "0patnFklndksxf5--------0202------f7050505040s372f2i4524.Iw18ZlA=.Aw18ZlA=.",
"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==."
}, },
"fer_de_lance": { "fer_de_lance": {
"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

@@ -33,7 +33,8 @@
}, },
"anaconda": { "anaconda": {
"Dream": "48A6A6A5A8A8A5C2c0o0o0o1m1m0q0q0404040l0b0100034k5n05050404040303326b.AwRj4yo5dig=.MwBhEYy6duwEziA=", "Dream": "48A6A6A5A8A8A5C2c0o0o0o1m1m0q0q0404040l0b0100034k5n05050404040303326b.AwRj4yo5dig=.MwBhEYy6duwEziA=",
"Cargo": "03A7D6A5D4D8D5C----------------060505054d040403030301.AwRj4yuqg===.Aw18ZlA=" "Cargo": "03A7D6A5D4D8D5C----------------060505054d040403030301.AwRj4yuqg===.Aw18ZlA=",
"Modified": "0pyttFolodDsyf5------1717--------05044j-03----2h00.Iw18ZlA=.Aw18ZlA=.H4sIAAAAAAAAA2MUe8HMwPD-PwDDhxeuCAAAAA=="
}, },
"diamondback_explorer": { "diamondback_explorer": {
"Explorer": "02A4D5A3D3D3D5C-------320p432i2f.AwRj4zTI.AwiMIypI" "Explorer": "02A4D5A3D3D3D5C-------320p432i2f.AwRj4zTI.AwiMIypI"
@@ -63,4 +64,4 @@
1, 1,
1 1
] ]
} }

View File

@@ -129,7 +129,7 @@ describe('Import Modal', function() {
}); });
}); });
describe('Import Detailed Build', function() { describe('Import Detailed V3 Build', function() {
beforeEach(reset); beforeEach(reset);
@@ -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/4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04--0303326b.AwRj4zNKqA==.CwBhCYzBGW9qCTSqs5xA.?bn=Test%20My%20Ship');
}); });
it('catches an invalid build', function() { it('catches an invalid build', function() {
@@ -154,6 +154,23 @@ describe('Import Modal', function() {
}); });
}); });
describe('Import Detailed V4 Build', function() {
beforeEach(reset);
it('imports a valid v4 build', function() {
const importData = require('./fixtures/anaconda-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/anaconda/4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04--0303326b.AwRj4zNKqA==.CwBhCYzBGW9qCTSqs5xA.H4sIAAAAAAAAA2MUe8HMwPD-PwDDhxeuCAAAAA==?bn=Test%20My%20Ship');
});
});
describe('Import Detaild Builds Array', function() { describe('Import Detaild Builds Array', function() {
beforeEach(reset); beforeEach(reset);

View File

@@ -4,16 +4,16 @@ import * as Serializer from '../src/app/shipyard/Serializer';
import jsen from 'jsen'; import jsen from 'jsen';
describe("Serializer", function() { describe("Serializer", function() {
const anacondaTestExport = require.requireActual('./fixtures/anaconda-test-detailed-export-v3'); const anacondaTestExport = require.requireActual('./fixtures/anaconda-test-detailed-export-v4');
const code = anacondaTestExport.references[0].code; const code = anacondaTestExport.references[0].code;
const anaconda = Ships.anaconda; const anaconda = Ships.anaconda;
const validate = jsen(require('../src/schemas/ship-loadout/3')); const validate = jsen(require('../src/schemas/ship-loadout/4'));
describe("To Detailed Build", function() { describe("To Detailed Build", function() {
let testBuild = new Ship('anaconda', anaconda.properties, anaconda.slots).buildFrom(code); let testBuild = new Ship('anaconda', anaconda.properties, anaconda.slots).buildFrom(code);
let exportData = Serializer.toDetailedBuild('Test My Ship', testBuild); let exportData = Serializer.toDetailedBuild('Test My Ship', testBuild);
it("conforms to the v3 ship-loadout schema", function() { it("conforms to the v4 ship-loadout schema", function() {
expect(validate(exportData)).toBe(true); expect(validate(exportData)).toBe(true);
}); });
@@ -31,7 +31,7 @@ describe("Serializer", function() {
const builds = require('./fixtures/expected-builds'); const builds = require('./fixtures/expected-builds');
const exportData = Serializer.toDetailedExport(builds); const exportData = Serializer.toDetailedExport(builds);
it("conforms to the v3 ship-loadout schema", function() { it("conforms to the v4 ship-loadout schema", function() {
expect(exportData instanceof Array).toBe(true); expect(exportData instanceof Array).toBe(true);
for (let detailedBuild of exportData) { for (let detailedBuild of exportData) {

View File

@@ -24,7 +24,7 @@ describe("Ship", function() {
expect(ship.fuelCapacity).toBeGreaterThan(0, s + ' fuelCapacity'); expect(ship.fuelCapacity).toBeGreaterThan(0, s + ' fuelCapacity');
expect(ship.unladenFastestRange).toBeGreaterThan(0, s + ' unladenFastestRange'); expect(ship.unladenFastestRange).toBeGreaterThan(0, s + ' unladenFastestRange');
expect(ship.ladenFastestRange).toBeGreaterThan(0, s + ' ladenFastestRange'); expect(ship.ladenFastestRange).toBeGreaterThan(0, s + ' ladenFastestRange');
expect(ship.shieldStrength).toBeGreaterThan(0, s + ' shieldStrength'); expect(ship.shield).toBeGreaterThan(0, s + ' shield');
expect(ship.armour).toBeGreaterThan(0, s + ' armour'); expect(ship.armour).toBeGreaterThan(0, s + ' armour');
expect(ship.topSpeed).toBeGreaterThan(0, s + ' topSpeed'); expect(ship.topSpeed).toBeGreaterThan(0, s + ' topSpeed');
} }

View File

@@ -379,7 +379,7 @@ export default class CostSection extends TranslatedComponent {
<td colSpan='4' className='lbl cap' >{translate('retrofit from')}</td> <td colSpan='4' className='lbl cap' >{translate('retrofit from')}</td>
<td className='val cen' style={{ borderRight: 'none', width: '1em' }}><u className='primary-disabled'>&#9662;</u></td> <td className='val cen' style={{ borderRight: 'none', width: '1em' }}><u className='primary-disabled'>&#9662;</u></td>
<td className='val' style={{ borderLeft:'none', padding: 0 }}> <td className='val' style={{ borderLeft:'none', padding: 0 }}>
<select style={{ width: '100%', padding: 0 }} value={retrofitName} onChange={this._onBaseRetrofitChange}> <select style={{ width: '100%', padding: 0 }} value={retrofitName || translate('Stock')} onChange={this._onBaseRetrofitChange}>
{options} {options}
</select> </select>
</td> </td>
@@ -419,7 +419,9 @@ export default class CostSection extends TranslatedComponent {
let retroSlotGroup = retrofitShip[g]; let retroSlotGroup = retrofitShip[g];
let slotGroup = ship[g]; let slotGroup = ship[g];
for (i = 0, l = slotGroup.length; i < l; i++) { for (i = 0, l = slotGroup.length; i < l; i++) {
if (slotGroup[i].m != retroSlotGroup[i].m) { const modId = slotGroup[i].m ? slotGroup[i].m.eddbID : null;
const retroModId = retroSlotGroup[i].m ? retroSlotGroup[i].m.eddbID : null;
if (modId != retroModId) {
item = { netCost: 0, retroItem: retroSlotGroup[i] }; item = { netCost: 0, retroItem: retroSlotGroup[i] };
if (slotGroup[i].m) { if (slotGroup[i].m) {
item.buyName = slotGroup[i].m.name || slotGroup[i].m.grp; item.buyName = slotGroup[i].m.name || slotGroup[i].m.grp;

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import Slot from './Slot'; import Slot from './Slot';
import { DamageKinetic, DamageThermal, DamageExplosive, MountFixed, MountGimballed, MountTurret, ListModifications } from './SvgIcons'; import { DamageKinetic, DamageThermal, DamageExplosive, MountFixed, MountGimballed, MountTurret, ListModifications, Modified } from './SvgIcons';
import { Modifications } from 'coriolis-data/dist'; import { Modifications } from 'coriolis-data/dist';
import { stopCtxPropagation } from '../utils/UtilityFunctions'; import { stopCtxPropagation } from '../utils/UtilityFunctions';
@@ -51,7 +51,9 @@ 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)}</div> {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={'r'}>{formats.round(m.getMass())}{u.T}</div> <div className={'r'}>{formats.round(m.getMass())}{u.T}</div>
</div> </div>
<div className={'cb'}> <div className={'cb'}>

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import Slot from './Slot'; import Slot from './Slot';
import { ListModifications } from './SvgIcons'; import { ListModifications, Modified } from './SvgIcons';
import { Modifications } from 'coriolis-data/dist'; import { Modifications } from 'coriolis-data/dist';
import { stopCtxPropagation } from '../utils/UtilityFunctions'; import { stopCtxPropagation } from '../utils/UtilityFunctions';
@@ -27,7 +27,7 @@ export default class InternalSlot extends Slot {
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)}</div> <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={'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

@@ -5,7 +5,7 @@ import { jumpRange } from '../shipyard/Calculations';
import { diffDetails } from '../utils/SlotFunctions'; import { diffDetails } from '../utils/SlotFunctions';
import AvailableModulesMenu from './AvailableModulesMenu'; import AvailableModulesMenu from './AvailableModulesMenu';
import ModificationsMenu from './ModificationsMenu'; import ModificationsMenu from './ModificationsMenu';
import { ListModifications } from './SvgIcons'; import { ListModifications, Modified } from './SvgIcons';
import { Modifications } from 'coriolis-data/dist'; import { Modifications } from 'coriolis-data/dist';
import { stopCtxPropagation } from '../utils/UtilityFunctions'; import { stopCtxPropagation } from '../utils/UtilityFunctions';
@@ -79,7 +79,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.grp == 'bh' ? m.grp : m.name || m.grp)}</div> <div className={'l'}>{classRating} {translate(m.grp == 'bh' ? m.grp : 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={'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

@@ -2,6 +2,7 @@ import React from 'react';
import cn from 'classnames'; import cn from 'classnames';
import SlotSection from './SlotSection'; import SlotSection from './SlotSection';
import StandardSlot from './StandardSlot'; import StandardSlot from './StandardSlot';
import Module from '../shipyard/Module';
import { diffDetails } from '../utils/SlotFunctions'; import { diffDetails } from '../utils/SlotFunctions';
import * as ModuleUtils from '../shipyard/ModuleUtils'; import * as ModuleUtils from '../shipyard/ModuleUtils';
import * as ShipRoles from '../shipyard/ShipRoles'; import * as ShipRoles from '../shipyard/ShipRoles';
@@ -114,7 +115,7 @@ export default class StandardSlotSection extends SlotSection {
selected={currentMenu == st[0]} selected={currentMenu == st[0]}
onChange={this.props.onChange} onChange={this.props.onChange}
ship={ship} ship={ship}
warning={m => m.pgen < ship.powerRetracted} warning={m => m instanceof Module ? m.getPowerGeneration() < ship.powerRetracted : m.pgen < ship.powerRetracted}
/>; />;
slots[2] = <StandardSlot slots[2] = <StandardSlot
@@ -126,7 +127,7 @@ export default class StandardSlotSection extends SlotSection {
selected={currentMenu == st[1]} selected={currentMenu == st[1]}
onChange={this.props.onChange} onChange={this.props.onChange}
ship={ship} ship={ship}
warning={m => m.maxmass < (ship.ladenMass - st[1].mass + m.mass)} warning={m => m instanceof Module ? m.getMaxMass() < (ship.ladenMass - st[1].mass + m.mass) : m.maxmass < (ship.ladenMass - st[1].mass + m.mass)}
/>; />;
@@ -161,7 +162,7 @@ export default class StandardSlotSection extends SlotSection {
selected={currentMenu == st[4]} selected={currentMenu == st[4]}
onChange={this.props.onChange} onChange={this.props.onChange}
ship={ship} ship={ship}
warning= {m => m.engcap < ship.boostEnergy} warning={m => m instanceof Module ? m.getEnginesCapacity() < ship.boostEnergy : m.engcap < ship.boostEnergy}
/>; />;
slots[6] = <StandardSlot slots[6] = <StandardSlot

View File

@@ -497,7 +497,19 @@ export class ListModifications extends SvgIcon {
* @return {String} view box * @return {String} view box
*/ */
viewBox() { return '0 0 200 200'; } viewBox() { return '0 0 200 200'; }
/** /**
* Render the Icon
* @return {React.Component} SVG Icon
*/
render() {
return (
<svg className={cn('modicon', this.props.className)} style={this.props.style} viewBox={this.viewBox()}>
{this.svg()}
</svg>
);
}
/** /**
* Generate the SVG * Generate the SVG
* @return {React.Component} SVG Contents * @return {React.Component} SVG Contents
@@ -507,6 +519,40 @@ export class ListModifications extends SvgIcon {
} }
} }
/**
* Modified (engineers)
*/
export class Modified extends SvgIcon {
/**
* Overriden view box
* @return {String} view box
*/
viewBox() { return '0 0 200 200'; }
/**
* Render the Icon
* @return {React.Component} SVG Icon
*/
render() {
return (
<svg className={cn('modicon', this.props.className)} style={this.props.style} viewBox={this.viewBox()}>
{this.svg()}
</svg>
);
}
/**
* Generate the SVG
* @return {React.Component} SVG Contents
*/
svg() {
return <g>
<path d="M100,5L18,52.5L18,147.5L100,195L182,147.5L182,52.5L100,5Z"/>
<path d="M100,70L74,85L74,115L100,130L126,115L126,85L100,70Z"/>
</g>;
}
}
/** /**
* Hammer * Hammer
*/ */

View File

@@ -5,6 +5,7 @@ import * as ES from './es';
import * as FR from './fr'; import * as FR from './fr';
import * as IT from './it'; import * as IT from './it';
import * as RU from './ru'; import * as RU from './ru';
import * as PL from './pl';
import d3 from 'd3'; import d3 from 'd3';
let fallbackTerms = EN.terms; let fallbackTerms = EN.terms;
@@ -23,6 +24,7 @@ export function getLanguage(langCode) {
case 'fr': lang = FR; break; case 'fr': lang = FR; break;
case 'it': lang = IT; break; case 'it': lang = IT; break;
case 'ru': lang = RU; break; case 'ru': lang = RU; break;
case 'pl': lang = PL; break;
default: default:
lang = EN; lang = EN;
} }
@@ -82,5 +84,6 @@ export const Languages = {
it: 'Italiano', it: 'Italiano',
es: 'Español', es: 'Español',
fr: 'Français', fr: 'Français',
ru: 'ру́сский' ru: 'ру́сский',
pl: 'polski'
}; };

77
src/app/i18n/pl.js Normal file
View File

@@ -0,0 +1,77 @@
export const formats = {
decimal: '.',
thousands: ',',
grouping: [3],
currency: ['$', ''],
dateTime: '%a %b %e %X %Y',
date: '%m/%d/%Y',
time: '%H:%M:%S',
periods: ['AM', 'PM'],
days: ['Niedziela', 'Poniedziałek', 'Wtorek', 'Środa', 'Czwartek', 'Piątek', 'Sobota'],
shortDays: ['Nie', 'Pon', 'Wt', 'Śr', 'Czw', 'Pt', 'Sob'],
months: ['Styczeń', 'Luty', 'Marzec', 'Kwiecień', 'Maj', 'Czerwiec', 'Lipiec', 'Sierpień', 'Wrzesień', 'Październik', 'Listopad', 'Grudzień'],
shortMonths: ['Sty', 'Lut', 'Mar', 'Kwi', 'Maj', 'Cze', 'Lip', 'Sie', 'Wrz', 'Paź', 'Lis', 'Gru']
};
export const terms = {
PHRASE_ALT_ALL: 'Alt + kliknięcie by wypełnić wszystkie sloty',
PHRASE_BACKUP_DESC: 'Kopia zapasowa wszystkich danych Coriolis w celu zapisu lub przeniesienia na inne urządzenie/przeglądarkę',
PHRASE_CONFIRMATION: 'Czy jesteś pewien?',
PHRASE_EXPORT_DESC: 'Szczegółowy eksport schematu w formacie JSON w celu użycia na innych stronach i narzędziach',
PHRASE_FASTEST_RANGE: 'Maksymalna ilość skoków na najwyższym zasięgu',
PHRASE_IMPORT: 'Wklej tu JSON lub importuj',
PHRASE_LADEN: 'Masa statku + paliwo + ładunek',
PHRASE_NO_BUILDS: 'Nie dodano schematu do porównania!',
PHRASE_NO_RETROCH: 'Brak zmian retrofit',
PHRASE_SELECT_BUILDS: 'Wybierz schematy do porównania',
PHRASE_SG_RECHARGE: 'Czas od 50% do 100% naładowania',
PHRASE_SG_RECOVER: 'Odnowienie (do 50%) po upadku',
PHRASE_UNLADEN: 'Masa statku z wyłączeniem paliwa i ładunku',
PHRASE_UPDATE_RDY: 'Dostępna aktualizacja! Naciśnij by odświeżyć',
// Other languages fallback to these values
// Only Translate to other languages if the name is different in-game
am: 'Auto Field-Maintenance Unit',
bh: 'Bulkheads',
bl: 'Beam Laser',
bsg: 'Bi-Weave Shield Generator',
c: 'Cannon',
cc: 'Collector Limpet Controller',
cm: 'Countermeasure',
cr: 'Cargo Rack',
cs: 'Cargo Scanner',
dc: 'Docking Computer',
fc: 'Fragment Cannon',
fi: 'FSD Interdictor',
fs: 'Fuel Scoop',
fsd: 'Frame Shift Drive',
ft: 'Fuel Tank',
fx: 'Fuel Transfer Limpet Controller',
hb: 'Hatch Breaker Limpet Controller',
hr: 'Hull Reinforcement Package',
kw: 'Kill Warrant Scanner',
ls: 'Life Support',
mc: 'Multi-cannon',
ml: 'Mining Laser',
mr: 'Missile Rack',
nl: 'Mine Launcher',
pa: 'Plasma Accelerator',
pas: 'Planetary Approach Suite',
pc: 'Prospector Limpet Controller',
pd: 'power distributor',
pl: 'Pulse Laser',
pp: 'Power Plant',
psg: 'Prismatic Shield Generator',
pv: 'Planetary Vehicle Hangar',
rf: 'Refinery',
rg: 'Rail Gun',
s: 'Sensors',
sb: 'Shield Booster',
sc: 'Scanner',
scb: 'Shield Cell Bank',
sg: 'Shield Generator',
t: 'thrusters',
tp: 'Torpedo Pylon',
ul: 'Burst Laser',
ws: 'Frame Shift Wake Scanner'
};

View File

@@ -51,15 +51,19 @@ export const ModuleGroupToName = {
bl: 'Beam Laser', bl: 'Beam Laser',
ul: 'Burst Laser', ul: 'Burst Laser',
c: 'Cannon', c: 'Cannon',
ch: 'Chaff Launcher',
cs: 'Cargo Scanner', cs: 'Cargo Scanner',
cm: 'Countermeasure', cm: 'Countermeasure',
ec: 'Electronic Countermeasure',
fc: 'Fragment Cannon', fc: 'Fragment Cannon',
hs: 'Heat Sink Launcher',
ws: 'Frame Shift Wake Scanner', ws: 'Frame Shift Wake Scanner',
kw: 'Kill Warrant Scanner', kw: 'Kill Warrant Scanner',
nl: 'Mine Launcher', nl: 'Mine Launcher',
ml: 'Mining Laser', ml: 'Mining Laser',
mr: 'Missile Rack', mr: 'Missile Rack',
pa: 'Plasma Accelerator', pa: 'Plasma Accelerator',
po: 'Point Defence',
mc: 'Multi-cannon', mc: 'Multi-cannon',
pl: 'Pulse Laser', pl: 'Pulse Laser',
rg: 'Rail Gun', rg: 'Rail Gun',

View File

@@ -11,7 +11,7 @@ export default class Module {
* @param {Object} params Module parameters. Either grp/id or template * @param {Object} params Module parameters. Either grp/id or template
*/ */
constructor(params) { constructor(params) {
let properties = Object.assign({ grp: null, id: null, template: null }, params); let properties = Object.assign({ grp: null, id: null, template: null, }, params);
let template; let template;
if (properties.template == undefined) { if (properties.template == undefined) {
@@ -23,7 +23,6 @@ export default class Module {
for (let p in template) { this[p] = template[p]; } for (let p in template) { this[p] = template[p]; }
} }
} }
this.mods = {};
} }
/** /**
@@ -41,6 +40,10 @@ export default class Module {
* @param {Number} value The value of the modification, as a decimal value where 1 is 100% * @param {Number} value The value of the modification, as a decimal value where 1 is 100%
*/ */
setModValue(name, value) { setModValue(name, value) {
if (!this.mods) {
this.mods = {};
}
if (value == null || value == 0) { if (value == null || value == 0) {
delete this.mods[name]; delete this.mods[name];
} else { } else {

View File

@@ -212,6 +212,16 @@ export function findHardpoint(groupName, clss, rating, name, mount, missile) {
*/ */
export function findHardpointId(groupName, clss, rating, name, mount, missile) { export function findHardpointId(groupName, clss, rating, name, mount, missile) {
let h = this.findHardpoint(groupName, clss, rating, name, mount, missile); let h = this.findHardpoint(groupName, clss, rating, name, mount, missile);
if (h) {
return h.id;
}
// Countermeasures used to be lumped in a single group but have been broken, out. If we have been given a groupName of 'Countermeasure' then
// rely on the unique name to find it
if (groupName === 'cm' || groupName === 'Countermeasure') {
h = this.findHardpoint(null, clss, rating, name, mount, missile);
}
return h ? h.id : 0; return h ? h.id : 0;
} }

View File

@@ -115,32 +115,12 @@ export function toDetailedBuild(buildName, ship) {
return data; return data;
}; };
/**
* Instantiates a ship from a ship-loadout object, using the code
* @param {Object} detailedBuild ship-loadout object
* @return {Ship} Ship instance
*/
export function fromDetailedBuild(detailedBuild) {
let shipId = Object.keys(Ships).find((shipId) => Ships[shipId].properties.name.toLowerCase() == detailedBuild.ship.toLowerCase());
if (!shipId) {
throw 'No such ship: ' + detailedBuild.ship;
}
let comps = detailedBuild.components;
let stn = comps.standard;
let shipData = Ships[shipId];
let ship = new Ship(shipId, shipData.properties, shipData.slots);
return ship.buildFrom(detailedBuild.references[0].code);
};
/** /**
* Instantiates a ship from a ship-loadout object * Instantiates a ship from a ship-loadout object
* @param {Object} detailedBuild ship-loadout object * @param {Object} detailedBuild ship-loadout object
* @return {Ship} Ship instance * @return {Ship} Ship instance
*/ */
export function oldfromDetailedBuild(detailedBuild) { export function fromDetailedBuild(detailedBuild) {
let shipId = Object.keys(Ships).find((shipId) => Ships[shipId].properties.name.toLowerCase() == detailedBuild.ship.toLowerCase()); let shipId = Object.keys(Ships).find((shipId) => Ships[shipId].properties.name.toLowerCase() == detailedBuild.ship.toLowerCase());
if (!shipId) { if (!shipId) {
@@ -154,6 +134,7 @@ export function oldfromDetailedBuild(detailedBuild) {
let shipData = Ships[shipId]; let shipData = Ships[shipId];
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);
if (bulkheads < 0) { if (bulkheads < 0) {
throw 'Invalid bulkheads: ' + stn.bulkheads; throw 'Invalid bulkheads: ' + stn.bulkheads;
@@ -165,6 +146,7 @@ export function oldfromDetailedBuild(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);
return stn[c].class + stn[c].rating; return stn[c].class + stn[c].rating;
}); });
@@ -185,8 +167,13 @@ export function oldfromDetailedBuild(detailedBuild) {
comps.utility.map(c => (!c || c.enabled === undefined) ? true : c.enabled * 1), comps.utility.map(c => (!c || c.enabled === undefined) ? true : c.enabled * 1),
comps.internal.map(c => (!c || c.enabled === undefined) ? true : c.enabled * 1) comps.internal.map(c => (!c || c.enabled === undefined) ? true : c.enabled * 1)
); );
modifications = modifications.concat(
comps.hardpoints.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))
);
ship.buildWith({ bulkheads, standard, hardpoints, internal }, priorities, enabled); ship.buildWith({ bulkheads, standard, hardpoints, internal }, priorities, enabled, modifications);
return ship; return ship;
}; };

View File

@@ -423,20 +423,27 @@ export default class Ship {
this.updateJumpStats(); this.updateJumpStats();
} else if (name == 'optmass') { } else if (name == 'optmass') {
m.setModValue(name, value); m.setModValue(name, value);
// Could be for either thrusters or FSD // Could be for any of thrusters, FSD or shield
this.updateTopSpeed(); this.updateTopSpeed();
this.updateJumpStats(); this.updateJumpStats();
this.updateShield();
} else if (name == 'optmul') { } else if (name == 'optmul') {
m.setModValue(name, value); m.setModValue(name, value);
// Could be for either thrusters or FSD // Could be for any of thrusters, FSD or shield
this.updateTopSpeed(); this.updateTopSpeed();
this.updateJumpStats(); this.updateJumpStats();
this.updateShield();
} else if (name == 'shieldboost') { } else if (name == 'shieldboost') {
m.setModValue(name, value); m.setModValue(name, value);
this.updateShield(); this.updateShield();
} else if (name == 'hullboost') { } else if (name == 'hullboost') {
m.setModValue(name, value); m.setModValue(name, value);
this.updateArmour(); this.updateArmour();
} else if (name == 'burst' || name == 'clip' || name == 'damage' || name == 'distdraw' || name == 'jitter' || name == 'piercing' || name == 'range' || name == 'reload' || name == 'rof' || name == 'thermload') {
m.setModValue(name, value);
this.recalculateDps();
this.recalculateHps();
this.recalculateEps();
} else { } else {
// Generic // Generic
m.setModValue(name, value); m.setModValue(name, value);
@@ -481,7 +488,6 @@ export default class Ship {
this.bulkheads.m.mods = mods && mods[0] ? mods[0] : {}; this.bulkheads.m.mods = mods && mods[0] ? mods[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;
this.cargoHatch.mods = mods ? mods[0] : {};
for (i = 0; i < cl; i++) { for (i = 0; i < cl; i++) {
standard[i].cat = 0; standard[i].cat = 0;
@@ -557,7 +563,7 @@ export default class Ship {
let standard = new Array(this.standard.length), let standard = new Array(this.standard.length),
hardpoints = new Array(this.hardpoints.length), hardpoints = new Array(this.hardpoints.length),
internal = new Array(this.internal.length), internal = new Array(this.internal.length),
mods = 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),
parts = serializedString.split('.'), parts = serializedString.split('.'),
priorities = null, priorities = null,
enabled = null, enabled = null,
@@ -574,10 +580,10 @@ export default class Ship {
if (parts[3]) { if (parts[3]) {
const modstr = parts[3].replace(/-/g, '/'); const modstr = parts[3].replace(/-/g, '/');
if (modstr.match(':')) { if (modstr.match(':')) {
this.decodeModificationsString(modstr, mods); this.decodeModificationsString(modstr, modifications);
} else { } else {
try { try {
this.decodeModificationsStruct(zlib.gunzipSync(new Buffer(modstr, 'base64')), mods); this.decodeModificationsStruct(zlib.gunzipSync(new Buffer(modstr, 'base64')), modifications);
} catch (err) { } catch (err) {
// Could be out-of-date URL; ignore // Could be out-of-date URL; ignore
} }
@@ -595,7 +601,7 @@ export default class Ship {
}, },
priorities, priorities,
enabled, enabled,
mods modifications
); );
}; };
@@ -820,6 +826,60 @@ export default class Ship {
return this; return this;
} }
/**
* Calculate damage per second for weapons
* @return {this} The ship instance (for chaining operations)
*/
recalculateDps() {
let totalDps = 0;
for (let slotNum in this.hardpoints) {
const slot = this.hardpoints[slotNum];
if (slot.m && slot.enabled && slot.m.getDps()) {
totalDps += slot.m.getDps();
}
}
this.totalDps = totalDps;
return this;
}
/**
* Calculate heat per second for weapons
* @return {this} The ship instance (for chaining operations)
*/
recalculateHps() {
let totalHps = 0;
for (let slotNum in this.hardpoints) {
const slot = this.hardpoints[slotNum];
if (slot.m && slot.enabled && slot.m.getHps()) {
totalHps += slot.m.getHps();
}
}
this.totalHps = totalHps;
return this;
}
/**
* Calculate energy per second for weapons
* @return {this} The ship instance (for chaining operations)
*/
recalculateEps() {
let totalEps = 0;
for (let slotNum in this.hardpoints) {
const slot = this.hardpoints[slotNum];
if (slot.m && slot.enabled && slot.m.getEps()) {
totalEps += slot.m.getEps();
}
}
this.totalEps = totalEps;
return this;
}
/** /**
* Update power calculations when amount generated changes * Update power calculations when amount generated changes
* @return {this} The ship instance (for chaining operations) * @return {this} The ship instance (for chaining operations)
@@ -998,10 +1058,10 @@ export default class Ship {
} }
/** /**
* Update the modifications string * Update the modifications string in a human-readable format
* @return {this} The ship instance (for chaining operations) * @return {this} The ship instance (for chaining operations)
*/ */
oldupdateModificationsString() { debugupdateModificationsString() {
let allMods = new Array(); let allMods = new Array();
let bulkheadMods = new Array(); let bulkheadMods = new Array();
@@ -1219,7 +1279,6 @@ export default class Ship {
case 1: this.serialized.hardpoints = null; break; case 1: this.serialized.hardpoints = null; break;
case 2: this.serialized.internal = null; case 2: this.serialized.internal = null;
} }
this.serialized.modifications = null;
} }
return this; return this;
} }

View File

@@ -93,69 +93,6 @@ export function slotComparator(translate, propComparator, desc) {
}; };
} }
const PROP_BLACKLIST = {
eddbID: 1,
edID: 1,
id: 1,
index: 1,
'class': 1,
rating: 1,
maxfuel: 1,
fuelmul: 1,
fuelpower: 1,
optmass: 1,
maxmass: 1,
minmass: 1,
passive: 1,
thermload: 1,
ammocost: 1,
activepower: 1,
cooldown: 1,
chargeup: 1,
optmul: 1,
minmul: 1,
maxmul: 1,
ssdam: 1,
mjdps: 1,
mjeps: 1,
mass: 1,
cost: 1,
recover: 1,
wepcap: 1,
weprate: 1,
engcap: 1,
engrate: 1,
syscap: 1,
sysrate: 1,
breachdps: 1,
breachmin: 1,
breachmax: 1,
integrity: 1
};
const TERM_LOOKUP = {
pgen: 'power',
armouradd: 'armour',
rof: 'ROF',
dps: 'DPS'
};
const FORMAT_LOOKUP = {
time: 'time'
};
const UNIT_LOOKUP = {
fuel: 'T',
cargo: 'T',
rate: 'kgs',
range: 'km',
recharge: 'MJ',
rangeLS: 'Ls',
power: 'MJ',
pgen: 'MJ',
rof: 'ps'
};
/** /**
* Determine the appropriate class based on diff value * Determine the appropriate class based on diff value
* @param {Number} a Potential Module (cannot be null) * @param {Number} a Potential Module (cannot be null)
@@ -214,23 +151,15 @@ export function diffDetails(language, m, mm) {
let mmMass = mm ? mm.getMass() : 0; let mmMass = mm ? mm.getMass() : 0;
if (mMass != mmMass) propDiffs.push(<div key='mass'>{translate('mass')}: <span className={diffClass(mMass, mmMass, true)}>{diff(formats.round, mMass, mmMass)}{units.T}</span></div>); if (mMass != mmMass) propDiffs.push(<div key='mass'>{translate('mass')}: <span className={diffClass(mMass, mmMass, true)}>{diff(formats.round, mMass, mmMass)}{units.T}</span></div>);
let mPowerGeneration = m.pgen || 0;
let mmPowerGeneration = mm ? mm.getPowerGeneration() : 0;
if (mPowerGeneration != mmPowerGeneration) propDiffs.push(<div key='pgen'>{translate('pgen')}: <span className={diffClass(mPowerGeneration, mmPowerGeneration, true)}>{diff(formats.round, mPowerGeneration, mmPowerGeneration)}{units.MJ}</span></div>);
let mPowerUsage = m.power || 0; let mPowerUsage = m.power || 0;
let mmPowerUsage = mm ? mm.getPowerUsage() : 0; let mmPowerUsage = mm ? mm.getPowerUsage() : 0;
if (mPowerUsage != mmPowerUsage) propDiffs.push(<div key='power'>{translate('power')}: <span className={diffClass(mPowerUsage, mmPowerUsage, true)}>{diff(formats.round, mPowerUsage, mmPowerUsage)}{units.MJ}</span></div>); if (mPowerUsage != mmPowerUsage) propDiffs.push(<div key='power'>{translate('power')}: <span className={diffClass(mPowerUsage, mmPowerUsage, true)}>{diff(formats.round, mPowerUsage, mmPowerUsage)}{units.MJ}</span></div>);
// for (let p in m) { let mDps = m.damage * (m.rpshot || 1) * (m.rof || 1) || 0;
// if (!PROP_BLACKLIST[p] && !isNaN(m[p])) {
// let mVal = m[p] === null ? Infinity : m[p];
// let mmVal = mm[p] === null ? Infinity : mm[p];
// let format = formats[FORMAT_LOOKUP[p]] || formats.round;
// propDiffs.push(<div key={p}>
// {`${translate(TERM_LOOKUP[p] || p)}: `}
// <span className={diffClass(mVal, mmVal, p == 'power')}>{diff(format, mVal, mmVal)}{units[UNIT_LOOKUP[p]]}</span>
// </div>);
// }
// }
let mDps = m.damage * (m.rpshot || 1) * m.rof || 0;
let mmDps = mm ? mm.getDps() || 0 : 0; let mmDps = mm ? mm.getDps() || 0 : 0;
if (mDps != mmDps) propDiffs.push(<div key='dps'>{translate('dps')}: <span className={diffClass(mmDps, mDps, true)}>{diff(formats.round, mDps, mmDps)}</span></div>); if (mDps != mmDps) propDiffs.push(<div key='dps'>{translate('dps')}: <span className={diffClass(mmDps, mDps, true)}>{diff(formats.round, mDps, mmDps)}</span></div>);

View File

@@ -1,4 +1,5 @@
// Standard icons
.icon { .icon {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
@@ -25,3 +26,33 @@
height: 2em; height: 2em;
} }
} }
// Modifiction icons - hard-code stroke/fill
.modicon {
display: inline-block;
vertical-align: middle;
width: 1.1em;
height: 1em;
stoke: @fg;
fill: transparent;
&.sm {
width: 0.8em;
height: 0.75em;
}
&.tn {
width: 0.6em;
height: 0.5em;
}
&.lg {
width: 1.6em;
height: 1.5em;
}
&.xl {
width: 2.1em;
height: 2em;
}
}

View File

@@ -0,0 +1,356 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://cdn.coriolis.io/schemas/ship-loadout/4.json#",
"title": "Ship Loadout",
"type": "object",
"description": "The details for a specific ship build/loadout",
"required": ["name", "ship", "components"],
"properties": {
"name": {
"description": "The name of the build/loadout",
"type": "string",
"minLength": 1
},
"ship": {
"description": "The full display name of the ship",
"type": "string",
"minimum": 3
},
"manufacturer": {
"description": "The ship manufacturer",
"type": "string"
},
"references" : {
"description": "3rd Party references and/or links to this build/loadout",
"type": "array",
"items": {
"type": "object",
"required": ["name","url"],
"additionalProperties": true,
"properties": {
"name": {
"description": "The name of the 3rd party, .e.g 'Coriolis.io' or 'E:D Shipyard'",
"type": "string"
},
"url": {
"description": "The link/url to the 3rd party referencing this build/loadout",
"type": "string"
}
}
}
},
"components": {
"description": "The components used by this build",
"type": "object",
"additionalProperties": false,
"required": ["standard", "internal", "hardpoints", "utility"],
"properties": {
"standard": {
"description": "The set of standard components across all ships",
"type": "object",
"additionalProperties": false,
"required": ["bulkheads", "powerPlant", "thrusters", "frameShiftDrive", "lifeSupport", "powerDistributor", "sensors", "fuelTank", "cargoHatch"],
"properties": {
"bulkheads": {
"enum": ["Lightweight Alloy", "Reinforced Alloy", "Military Grade Composite", "Mirrored Surface Composite", "Reactive Surface Composite"]
},
"cargoHatch": {
"required": ["enabled", "priority"],
"properties": {
"enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 }
}
},
"powerPlant": {
"required": ["class", "rating", "enabled", "priority"],
"properties": {
"class": { "type": "integer", "minimum": 2, "maximum": 8 },
"rating": { "$ref": "#/definitions/standardRatings" },
"enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 },
"modifications": { "type": "object" }
}
},
"thrusters": {
"required": ["class", "rating", "enabled", "priority"],
"properties": {
"class": { "type": "integer", "minimum": 2, "maximum": 8 },
"rating": { "$ref": "#/definitions/standardRatings" },
"enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 },
"name": {
"description": "The name identifing the thrusters (if applicable), e.g. 'Enhanced Performance'",
"type": "string"
},
"modifications": { "type": "object" }
}
},
"frameShiftDrive": {
"required": ["class", "rating", "enabled", "priority"],
"properties": {
"class": { "type": "integer", "minimum": 2, "maximum": 8 },
"rating": { "$ref": "#/definitions/standardRatings" },
"enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 },
"modifications": { "type": "object" }
}
},
"lifeSupport": {
"required": ["class", "rating", "enabled", "priority"],
"properties": {
"class": { "type": "integer", "minimum": 1, "maximum": 6 },
"rating": { "$ref": "#/definitions/standardRatings" },
"enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 },
"modifications": { "type": "object" }
}
},
"powerDistributor": {
"required": ["class", "rating", "enabled", "priority"],
"properties": {
"class": { "type": "integer", "minimum": 1, "maximum": 8 },
"rating": { "$ref": "#/definitions/standardRatings" },
"enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 },
"modifications": { "type": "object" }
}
},
"sensors": {
"required": ["class", "rating", "enabled", "priority"],
"properties": {
"class": { "type": "integer", "minimum": 1, "maximum": 8 },
"rating": { "$ref": "#/definitions/standardRatings" },
"enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 },
"modifications": { "type": "object" }
}
},
"fuelTank": {
"required": ["class", "rating", "enabled", "priority"],
"properties": {
"class": { "type": "integer", "minimum": 1, "maximum": 6 },
"rating": { "$ref": "#/definitions/standardRatings" },
"enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 },
"modifications": { "type": "object" }
}
}
}
},
"internal": {
"type": "array",
"items": {
"type": ["object", "null"],
"required": ["class", "rating", "enabled", "priority", "group"],
"properties" : {
"class": { "type": "integer", "minimum": 1, "maximum": 8 },
"rating": { "$ref": "#/definitions/standardRatings" },
"enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 },
"group": {
"description": "The group of the component, e.g. 'Shield Generator', or 'Cargo Rack'",
"type": "string"
},
"name": {
"description": "The name identifying the component (if applicable), e.g. 'Advance Discovery Scanner', or 'Detailed Surface Scanner'",
"type": "string"
},
"modifications": { "type": "object" }
}
},
"minItems": 3
},
"hardpoints": {
"type": "array",
"items": {
"type": ["object", "null"],
"required": ["class", "rating", "enabled", "priority", "group", "mount"],
"properties" : {
"class": { "type": "integer", "minimum": 1, "maximum": 4 },
"rating": { "$ref": "#/definitions/allRatings" },
"enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 },
"mount": { "type": "string", "enum": ["Fixed", "Gimballed", "Turret"] },
"group": {
"description": "The group of the component, e.g. 'Beam Laser', or 'Missile Rack'",
"type": "string"
},
"name": {
"description": "The name identifing the component (if applicable), e.g. 'Retributor', or 'Mining Lance'",
"type": "string"
},
"modifications": { "type": "object" }
}
},
"minItems": 1
},
"utility": {
"type": "array",
"items": {
"type": ["object", "null"],
"required": ["class", "rating", "enabled", "priority", "group"],
"properties" : {
"class": { "type": "integer", "minimum": 0, "maximum": 0 },
"rating": { "$ref": "#/definitions/allRatings" },
"enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 },
"group": {
"description": "The group of the component, e.g. 'Shield Booster', or 'Kill Warrant Scanner'",
"type": "string"
},
"name": {
"description": "The name identifing the component (if applicable), e.g. 'Point Defence', or 'Electronic Countermeasure'",
"type": "string"
},
"modifications": { "type": "object" }
}
},
"minItems": 1
}
}
},
"stats": {
"description": "Optional statistics from the build",
"type": "object",
"additionalProperties": true,
"properties": {
"agility": {
"type": "integer",
"minimum": 0
},
"armour": {
"description": "Sum of base armour + any hull reinforcements",
"type": "integer",
"minimum": 1
},
"armourAdded":{
"description": "Armour added through Hull reinforcement",
"type": "integer",
"minimum": 0
},
"baseShieldStrength": {
"type": "integer",
"minimum": 1
},
"baseArmour": {
"type": "integer",
"minimum": 1
},
"boost": {
"description": "Maximum boost speed of the ships (4 pips, straight-line)",
"type": "number",
"minimum": 0
},
"cargoCapacity": {
"type": "integer",
"minimum": 0
},
"class": {
"description": "Ship Class/Size [Small, Medium, Large]",
"enum": [1,2,3]
},
"totalDps": {
"description": "Total damage dealt per second of all weapons",
"type": "number",
"minimum": 0
},
"totalEps": {
"description": "Total energy consumed per second of all weapons",
"type": "number",
"minimum": 0
},
"totalHps": {
"description": "Total heat generated per second of all weapons",
"type": "number",
"minimum": 0
},
"hullCost": {
"description": "Cost of the ship's hull",
"type": "integer",
"minimum": 1
},
"hullMass": {
"description": "Mass of the Ship hull only",
"type": "number",
"minimum": 1
},
"hullExplRes": {
"description": "Resistance of the hull to explosive attacks",
"type": "number"
},
"hullKinRes": {
"description": "Resistance of the hull to kinetic attacks",
"type": "number"
},
"hullThermRes": {
"description": "Resistance of the hull to thermal attacks",
"type": "number"
},
"fuelCapacity": {
"type": "integer",
"minimum": 1
},
"fullTankRange": {
"description": "Single Jump range with a full tank (unladenMass + fuel)",
"type": "number",
"minimum": 0
},
"ladenMass": {
"description": "Mass of the Ship + fuel + cargo (hull + all components + fuel tank + cargo capacity)",
"type": "number",
"minimum": 1
},
"ladenRange": {
"description": "Single Jump range with full cargo load, see ladenMass",
"type": "number",
"minimum": 0
},
"masslock": {
"description": "Mass Lock Factor of the Ship",
"type": "integer",
"minimum": 1
},
"shield": {
"description": "Shield strengh in Mega Joules (Mj)",
"type": "number",
"minimum": 0
},
"shieldExplRes": {
"description": "Resistance of the shield to explosive attacks",
"type": "number"
},
"shieldKinRes": {
"description": "Resistance of the shield to kinetic attacks",
"type": "number"
},
"shieldThermRes": {
"description": "Resistance of the shield to thermal attacks",
"type": "number"
},
"speed": {
"description": "Maximum speed of the ships (4 pips, straight-line)",
"type": "number",
"minimum": 1
},
"totalCost": {
"type": "integer",
"minimum": 1
},
"unladenRange": {
"description": "Single Jump range when unladen, see unladenMass",
"type": "number",
"minimum": 0
},
"unladenMass": {
"description": "Mass of the Ship (hull + all components)",
"type": "number",
"minimum": 1
}
}
}
},
"definitions": {
"standardRatings": { "enum": ["A", "B", "C", "D", "E", "F", "G", "H"] },
"allRatings": { "enum": ["A", "B", "C", "D", "E", "F", "G", "H", "I" ] }
}
}