Compare commits

..

24 Commits
1.3.0 ... 1.4.0

Author SHA1 Message Date
Colin McLeod
6630ff8fee Adding another E:D import test case 2015-08-14 11:41:53 -07:00
Colin McLeod
14f303c581 Merge pull request #74 from sf302/master
Adding powerplant capacity warnings
2015-08-14 00:42:50 -07:00
Colin McLeod
0728af14dd Support import of E:D shipyard text exports 2015-08-13 23:22:13 -07:00
Colin McLeod
1edacf3eba Corrected thurster selection and warnings 2015-08-13 23:21:40 -07:00
Colin McLeod
3d6d210563 updating linting params 2015-08-13 23:18:35 -07:00
Colin McLeod
df09da4b0a Remove redundant statements 2015-08-13 23:14:48 -07:00
Colin McLeod
b02de43b50 Updating dependencies 2015-08-13 23:14:33 -07:00
Kevin Chang
1b3ca2f697 Fix lint error 2015-08-13 22:22:46 -07:00
Colin McLeod
886614527f Improved low weight build logic 2015-08-10 15:12:59 -07:00
Colin McLeod
5f05bf0dc5 Lint fix 2015-08-10 15:12:18 -07:00
Colin McLeod
59710ce2cf Adding button for class A oufit 2015-08-10 10:50:46 -07:00
Colin McLeod
b533191bc9 Adding loader for later use 2015-08-10 10:50:16 -07:00
Kevin Chang
4fa1115e8f Extend PD Boost warning to PP Retracted power (TODO: extend to two-stage warning for DEP/RET) 2015-08-06 20:58:11 -07:00
Colin McLeod
be5a069b23 Merge pull request #71 from sf302/master
Add build preset button and correct/improve SCB info
2015-07-30 20:48:17 -07:00
Kevin Chang
80da41c866 Another fix to lint errors 2015-07-30 20:18:33 -07:00
Kevin Chang
d278a7c1fd Correcting CI errors 2015-07-30 20:14:46 -07:00
Kevin Chang
69de209aba A-rated uses largest eligible shield slot; dirty hacks rewritten 2015-07-30 19:50:08 -07:00
Kevin Chang
15616d112f Add per-slot total SCB capacity in MJ 2015-07-30 19:04:52 -07:00
Kevin Chang
95adca5cde Incremented all shield cell bank counts -- "Munitions" tab shows actual cell counts 2015-07-30 18:54:57 -07:00
kchang
82c5460936 Shortcut to A-rated common components and shield generator 2015-07-28 23:21:46 -07:00
Colin McLeod
b850695715 Bumping version to 1.3.1 2015-07-26 22:42:06 -07:00
Colin McLeod
d5af972272 Add 8A pristmatic shield generator 2015-07-26 22:39:13 -07:00
Colin McLeod
8946f9b97c Add component group filtering for Orca special case internal slots 2015-07-21 12:34:35 -07:00
Colin McLeod
348339520d Improve comparison import validation 2015-07-21 12:34:07 -07:00
26 changed files with 609 additions and 492 deletions

View File

@@ -6,7 +6,7 @@
The Coriolis project was inspired by [E:D Shipyard](http://www.edshipyard.com/) and, of course, [Elite Dangerous](http://www.elitedangerous.com). The ultimate goal of Coriolis is to provide rich features to support in-game play and planning while engaging the E:D community to support its development. The Coriolis project was inspired by [E:D Shipyard](http://www.edshipyard.com/) and, of course, [Elite Dangerous](http://www.elitedangerous.com). The ultimate goal of Coriolis is to provide rich features to support in-game play and planning while engaging the E:D community to support its development.
Coriolis was created for non-commercial purposes. Coriolis was created using assets and imagery from Elite: Dangerous, with the permission of Frontier Developments plc, for non-commercial purposes. It is not endorsed by nor reflects the views or opinions of Frontier Developments and no employee of Frontier Developments was involved in the making of it. Coriolis was created using assets and imagery from Elite: Dangerous, with the permission of Frontier Developments plc, for non-commercial purposes. It is not endorsed by nor reflects the views or opinions of Frontier Developments and no employee of Frontier Developments was involved in the making of it.
## Contributing ## Contributing

3
app/icons/a.svg Executable file
View File

@@ -0,0 +1,3 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<path d="M10.063 26l1.8-6h8.274l1.8 6h3.551l-6-20h-6.976l-6 20h3.551zM14.863 10h2.274l1.8 6h-5.874l1.8-6z"></path>
</svg>

After

Width:  |  Height:  |  Size: 265 B

View File

@@ -1,11 +1,25 @@
angular.module('app').controller('ImportController', ['lodash', '$rootScope', '$scope', '$stateParams', 'ShipsDB', 'Ship', 'Persist', 'Serializer', function(_, $rootScope, $scope, $stateParams, Ships, Ship, Persist, Serializer) { angular.module('app').controller('ImportController', ['lodash', '$rootScope', '$scope', '$stateParams', 'ShipsDB', 'Ship', 'Components', 'GroupMap', 'Persist', 'Serializer', function(_, $rootScope, $scope, $stateParams, Ships, Ship, Components, GroupMap, Persist, Serializer) {
$scope.jsonValid = false; $scope.importValid = false;
$scope.importJSON = null; $scope.importString = null;
$scope.errorMsg = null; $scope.errorMsg = null;
$scope.canEdit = true; $scope.canEdit = true;
$scope.builds = $stateParams.obj || null; $scope.builds = $stateParams.obj || null;
$scope.ships = Ships; $scope.ships = Ships;
var textBuildRegex = new RegExp('^\\[([\\w \\-]+)\\]\n');
var lineRegex = new RegExp('^([\\dA-Z]{1,2}): (\\d)([A-I])[/]?([FGT])?([SD])? ([\\w\\- ]+)');
var mountMap = { 'H': 4, 'L': 3, 'M': 2, 'S': 1, 'U': 0 };
var commonMap = { 'RB': 0, 'TM': 1, 'FH': 2, 'EC': 3, 'PC': 4, 'SS': 5, 'FS': 6 };
var bhMap = { 'lightweight alloy': 0, 'reinforced alloy': 1, 'military grade composite': 2, 'mirrored surface composite': 3, 'reactive surface composite': 4 };
function isEmptySlot(slot) {
return slot.maxClass == this && slot.c === null;
}
function equalsIgnoreCase(str) {
return str.toLowerCase() == this.toLowerCase();
}
function validateBuild(shipId, code, name) { function validateBuild(shipId, code, name) {
var shipData = Ships[shipId]; var shipData = Ships[shipId];
@@ -52,7 +66,15 @@ angular.module('app').controller('ImportController', ['lodash', '$rootScope', '$
throw 'builds must be an object!'; throw 'builds must be an object!';
} }
if (importData.comparisons) { if (importData.comparisons) {
// TODO: check ship/builds exist for comparison for (var compName in importData.comparisons) {
var comparison = importData.comparisons[compName];
for (var i = 0, l = comparison.builds.length; i < l; i++) {
var build = comparison.builds[i];
if (!importData.builds[build.shipId] || !importData.builds[build.shipId][build.buildName]) {
throw build.shipId + ' build "' + build.buildName + '" data is missing!';
}
}
}
$scope.comparisons = importData.comparisons; $scope.comparisons = importData.comparisons;
} }
if (importData.discounts instanceof Array && importData.discounts.length == 2) { if (importData.discounts instanceof Array && importData.discounts.length == 2) {
@@ -75,40 +97,134 @@ angular.module('app').controller('ImportController', ['lodash', '$rootScope', '$
$scope.builds = builds; $scope.builds = builds;
} }
$scope.validateJson = function() { function importTextBuild(buildStr) {
var buildName = textBuildRegex.exec(buildStr)[1].trim();
var shipName = buildName.toLowerCase();
var shipId = null;
for (var sId in Ships) {
if (Ships[sId].properties.name.toLowerCase() == shipName) {
shipId = sId;
break;
}
}
if (!shipId) { throw 'No such ship found: "' + buildName + '"'; }
var lines = buildStr.split('\n');
var ship = new Ship(shipId, Ships[shipId].properties, Ships[shipId].slots);
ship.buildWith(null);
for (var i = 1; i < lines.length; i++) {
var line = lines[i].trim();
if (!line) { continue; }
if (line.substring(0, 3) == '---') { break; }
var parts = lineRegex.exec(line);
if (!parts) { throw 'Error parsing: "' + line + '"'; }
var typeSize = parts[1];
var cl = parts[2];
var rating = parts[3];
var mount = parts[4];
var missile = parts[5];
var name = parts[6].trim();
var slot, group;
if (isNaN(typeSize)) { // Common or Hardpoint
if (typeSize.length == 1) { // Hardpoint
var slotClass = mountMap[typeSize];
if (cl > slotClass) { throw cl + rating + ' ' + name + ' exceeds slot size: "' + line + '"'; }
slot = _.find(ship.hardpoints, isEmptySlot, slotClass);
if (!slot) { throw 'No hardpoint slot available for: "' + line + '"'; }
group = _.find(GroupMap, equalsIgnoreCase, name);
var hpid = Components.findHardpointId(group, cl, rating, group ? null : name, mount, missile);
if (!hpid) { throw 'Unknown component: "' + line + '"'; }
ship.use(slot, hpid, Components.hardpoints(hpid), true);
} else if (typeSize == 'BH') {
var bhId = bhMap[name.toLowerCase()];
if (bhId === undefined) { throw 'Unknown bulkhead: "' + line + '"'; }
ship.useBulkhead(bhId, true);
} else if (commonMap[typeSize] != undefined) {
var commonIndex = commonMap[typeSize];
if (ship.common[commonIndex].maxClass < cl) { throw name + ' exceeds max class for the ' + ship.name; }
ship.use(ship.common[commonIndex], cl + rating, Components.common(commonIndex, cl + rating), true);
} else {
throw 'Unknown component: "' + line + '"';
}
} else {
if (cl > typeSize) { throw cl + rating + ' ' + name + ' exceeds slot size: "' + line + '"'; }
slot = _.find(ship.internal, isEmptySlot, typeSize);
if (!slot) { throw 'No internal slot available for: "' + line + '"'; }
group = _.find(GroupMap, equalsIgnoreCase, name);
var intId = Components.findInternalId(group, cl, rating, group ? null : name);
if (!intId) { throw 'Unknown component: "' + line + '"'; }
ship.use(slot, intId, Components.internal(intId));
}
}
var builds = {};
builds[shipId] = {};
builds[shipId]['Imported ' + buildName] = Serializer.fromShip(ship);
$scope.builds = builds;
}
$scope.validateImport = function() {
var importData = null; var importData = null;
$scope.jsonValid = false; var importString = $scope.importString.trim();
$scope.importValid = false;
$scope.errorMsg = null; $scope.errorMsg = null;
$scope.builds = $scope.discounts = $scope.comparisons = $scope.insurance = null; $scope.builds = $scope.discounts = $scope.comparisons = $scope.insurance = null;
if (!$scope.importJSON) { return; } if (!importString) { return; }
try { try {
importData = angular.fromJson($scope.importJSON); if (textBuildRegex.test(importString)) { // E:D Shipyard build text
} catch (e) { importTextBuild(importString);
$scope.errorMsg = 'Cannot Parse JSON!'; } else { // JSON Build data
return; importData = angular.fromJson($scope.importString);
}
if (!importData || typeof importData != 'object') { if (!importData || typeof importData != 'object') {
$scope.errorMsg = 'Must be an object or array!'; throw 'Must be an object or array!';
return; }
}
try { if (importData instanceof Array) { // Must be detailed export json
if (importData instanceof Array) { // Must be detailed export json importDetailedArray(importData);
importDetailedArray(importData); } else if (importData.ship && importData.name) { // Using JSON from a single ship build export
} else if (importData.ship && importData.name) { // Using JSON from a single ship build export importDetailedArray([importData]); // Convert to array with singleobject
importDetailedArray([importData]); // Convert to array with singleobject } else { // Using Backup JSON
} else { // Using Backup JSON importBackup(importData);
importBackup(importData); }
} }
} catch (e) { } catch (e) {
$scope.errorMsg = e; $scope.errorMsg = (typeof e == 'string') ? e : 'Cannot Parse the data!';
return; return;
} }
$scope.jsonValid = true; $scope.importValid = true;
}; };
$scope.hasBuild = function(shipId, name) { $scope.hasBuild = function(shipId, name) {

View File

@@ -145,7 +145,14 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
*/ */
$scope.select = function(type, slot, e, id) { $scope.select = function(type, slot, e, id) {
e.stopPropagation(); e.stopPropagation();
id = id || angular.element(e.target).attr('cpid'); // Get component ID
if (!id) { // Find component id if not passed
var elem = e.target;
while (elem && elem !== e.currentTarget && !elem.getAttribute('cpid')) {
elem = elem.parentElement;
}
id = elem.getAttribute('cpid');
}
if (id) { if (id) {
if (id == 'empty') { if (id == 'empty') {
@@ -175,16 +182,45 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
}; };
/** /**
* Strip ship to D-class and no other components. * Strip ship to A-class and biggest A-class shield generator with military bulkheads
*/ */
$scope.stripBuild = function() { $scope.aRatedBuild = function() {
for (var i = 0, l = ship.common.length - 1; i < l; i++) { // All except Fuel Tank for (var i = 0, l = ship.common.length - 1; i < l; i++) { // All except Fuel Tank
var id = ship.common[i].maxClass + 'D'; var id = ship.common[i].maxClass + 'A';
ship.use(ship.common[i], id, Components.common(i, id)); ship.use(ship.common[i], id, Components.common(i, id));
} }
ship.hardpoints.forEach(function(slot) { ship.use(slot, null, null); }); ship.hardpoints.forEach(function(slot) { ship.use(slot, null, null); });
ship.internal.forEach(function(slot) { ship.use(slot, null, null); }); ship.internal.forEach(function(slot) { ship.use(slot, null, null); });
ship.internal.some(function(slot) {
if (typeof slot.eligible === 'undefined') { // Assuming largest slot can hold an eligible shield
id = Components.findInternalId('Shield Generator', slot.maxClass, 'A');
ship.use(slot, id, Components.internal(id));
return true;
}
});
ship.useBulkhead(2);
updateState(Serializer.fromShip(ship));
};
/**
* Optimize for the lower mass build that can still boost and power the ship
* without power management.
*/
$scope.optimizeMassBuild = function() {
var common = ship.common;
ship.hardpoints.forEach(function(slot) { ship.use(slot, null, null); });
ship.internal.forEach(function(slot) { ship.use(slot, null, null); });
ship.useBulkhead(0); ship.useBulkhead(0);
ship.use(common[1], common[1].maxClass + 'D', Components.common(1, common[1].maxClass + 'D')); // Thrusters
ship.use(common[2], common[2].maxClass + 'A', Components.common(2, common[2].maxClass + 'A')); // FSD
ship.use(common[3], common[3].maxClass + 'D', Components.common(3, common[3].maxClass + 'D')); // Life Support
ship.use(common[5], common[5].maxClass + 'D', Components.common(5, common[5].maxClass + 'D')); // Sensors
var pd = $scope.availCS.lightestPowerDist(ship.boostEnergy); // Find lightest Power Distributor that can still boost
ship.use(ship.common[4], pd, Components.common(4, pd));
var pp = $scope.availCS.lightestPowerPlant(ship.powerRetracted); // Find lightest Power plant that can power the ship
ship.use(ship.common[0], pp, Components.common(0, pp));
updateState(Serializer.fromShip(ship)); updateState(Serializer.fromShip(ship));
}; };
@@ -371,6 +407,10 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
$scope.costTab = tab; $scope.costTab = tab;
}; };
$scope.ppWarning = function(pp) {
return pp.pGen < ship.powerRetracted;
};
$scope.pdWarning = function(pd) { $scope.pdWarning = function(pd) {
return pd.enginecapacity < ship.boostEnergy; return pd.enginecapacity < ship.boostEnergy;
}; };

View File

@@ -22,13 +22,13 @@ angular.module('app').directive('componentSelect', function() {
list.push(' warning'); list.push(' warning');
} }
list.push((o.maxmass && mass > o.maxmass) ? ' disabled"' : '" cpid="', id, '">'); list.push((o.maxmass && (mass + (o.mass ? o.mass : 0)) > o.maxmass) ? ' disabled"' : '" cpid="', id, '">');
if (o.mode) { if (o.mode) {
list.push('<svg cpid="', id, '" class="icon lg"><use cpid="', id, '" xlink:href="#mount-', o.mode, '"></use></svg> '); list.push('<svg class="icon lg"><use xlink:href="#mount-', o.mode, '"></use></svg> ');
} }
list.push('<span cpid="', id, '">', o.class, o.rating); list.push('<span>', o.class, o.rating);
if (o.missile) { if (o.missile) {
list.push('/' + o.missile); list.push('/' + o.missile);
@@ -50,7 +50,7 @@ angular.module('app').directive('componentSelect', function() {
scope: { scope: {
opts: '=', // Component Options object opts: '=', // Component Options object
groups: '=', // Groups of Component Options groups: '=', // Groups of Component Options
mass: '=', // Current ship unladen mass mass: '=', // Current ship mass
s: '=', // Current Slot s: '=', // Current Slot
warning: '=' // Check warning function warning: '=' // Check warning function
}, },
@@ -60,7 +60,7 @@ angular.module('app').directive('componentSelect', function() {
var component = scope.s.c; // Slot's Current Component (may be null/undefined) var component = scope.s.c; // Slot's Current Component (may be null/undefined)
var opts = scope.opts; var opts = scope.opts;
var groups = scope.groups; var groups = scope.groups;
var mass = scope.mass || 0; var mass = (scope.mass ? scope.mass : 0) - (component && component.mass ? component.mass : 0); // Mass minus the currently selected component
if (groups) { if (groups) {
// At present time slots with grouped options (Hardpoints and Internal) can be empty // At present time slots with grouped options (Hardpoints and Internal) can be empty

View File

@@ -0,0 +1,9 @@
angular.module('app').directive('loader', function() {
return {
restrict: 'A',
link: function(scope, element) {
element.addClass('loader');
element.html('<svg viewbox="0 0 40 40" width="100%" height="100%"><path d="m5,8l5,8l5,-8z" class="l1 d1" /><path d="m5,8l5,-8l5,8z" class="l1 d2" /><path d="m10,0l5,8l5,-8z" class="l1 d3" /><path d="m15,8l5,-8l5,8z" class="l1 d4" /><path d="m20,0l5,8l5,-8z" class="l1 d5" /><path d="m25,8l5,-8l5,8z" class="l1 d6" /><path d="m25,8l5,8l5,-8z" class="l1 d7" /><path d="m30,16l5,-8l5,8z" class="l1 d8" /><path d="m30,16l5,8l5,-8z" class="l1 d9" /><path d="m25,24l5,-8l5,8z" class="l1 d10" /><path d="m25,24l5,8l5,-8z" class="l1 d11" /><path d="m20,32l5,-8l5,8z" class="l1 d13" /><path d="m15,24l5,8l5,-8z" class="l1 d14" /><path d="m10,32l5,-8l5,8z" class="l1 d15" /><path d="m5,24l5,8l5,-8z" class="l1 d16" /><path d="m5,24l5,-8l5,8z" class="l1 d17" /><path d="m0,16l5,8l5,-8z" class="l1 d18" /><path d="m0,16l5,-8l5,8z" class="l1 d20" /><path d="m10,16l5,-8l5,8z" class="l2 d0" /><path d="m15,8l5,8l5,-8z" class="l2 d3" /><path d="m20,16l5,-8l5,8z" class="l2 d6" /><path d="m20,16l5,8l5,-8z" class="l2 d9" /><path d="m15,24l5,-8l5,8z" class="l2 d12" /><path d="m10,16l5,8l5,-8z" class="l2 d15" /></svg>');
}
};
});

View File

@@ -6,6 +6,13 @@ angular.module('shipyard').factory('ComponentSet', ['lodash', function(_) {
}); });
} }
function getKey(maxClass, eligible) {
if (eligible) {
return maxClass + Object.keys(eligible).join('-');
}
return maxClass;
}
function ComponentSet(components, mass, maxCommonArr, maxInternal, maxHardPoint) { function ComponentSet(components, mass, maxCommonArr, maxInternal, maxHardPoint) {
this.mass = mass; this.mass = mass;
this.common = {}; this.common = {};
@@ -36,32 +43,78 @@ angular.module('shipyard').factory('ComponentSet', ['lodash', function(_) {
for (var g in components.internal) { for (var g in components.internal) {
this.internal[g] = filter(components.internal[g], maxInternal, 0, mass); this.internal[g] = filter(components.internal[g], maxInternal, 0, mass);
} }
/**
* Create a memoized function for determining the components that are
* eligible for an internal slot
* @param {integer} c The max class component that can be mounted in the slot
* @param {Object} eligible) The map of eligible internal groups
* @return {object} A map of all eligible components by group
*/
this.getInts = _.memoize(
function(c, eligible) {
var o = {};
for (var key in this.internal) {
if (eligible && !eligible[key]) {
continue;
}
var data = filter(this.internal[key], c, 0, this.mass);
if (data.length) { // If group is not empty
o[key] = data;
}
}
return o;
},
getKey
);
/**
* Create a memoized function for determining the components that are
* eligible for an hardpoint slot
* @param {integer} c The max class component that can be mounted in the slot
* @param {Object} eligible) The map of eligible hardpoint groups
* @return {object} A map of all eligible components by group
*/
this.getHps = _.memoize(
function(c, eligible) {
var o = {};
for (var key in this.hardpoints) {
if (eligible && !eligible[key]) {
continue;
}
var data = filter(this.hardpoints[key], c, c ? 1 : 0, this.mass);
if (data.length) { // If group is not empty
o[key] = data;
}
}
return o;
},
getKey
);
} }
ComponentSet.prototype.getHps = function(c) { ComponentSet.prototype.lightestPowerDist = function(boostEnergy) {
if (!this.hpClass[c]) { var pds = this.common[4];
var o = this.hpClass[c] = {}; var pd = pds[0];
for (var key in this.hardpoints) {
var data = filter(this.hardpoints[key], c, c ? 1 : 0, this.mass); for (var i = 1; i < pds.length; i++) {
if (data.length) { // If group is not empty if (pds[i].mass < pd.mass && pds[i].enginecapacity >= boostEnergy) {
o[key] = data; pd = pds[i];
}
} }
} }
return this.hpClass[c]; return pd.class + pd.rating;
}; };
ComponentSet.prototype.getInts = function(c) { ComponentSet.prototype.lightestPowerPlant = function(powerUsed) {
if (!this.intClass[c]) { var pps = this.common[0];
var o = this.intClass[c] = {}; var pp = null;
for (var key in this.internal) {
var data = filter(this.internal[key], c, 0, this.mass); for (var i = 0; i < pps.length; i++) {
if (data.length) { // If group is not empty if (pp == null || (pps[i].mass < pp.mass && pps[i].pGen >= powerUsed)) {
o[key] = data; pp = pps[i];
}
} }
} }
return this.intClass[c]; return pp.class + (pp.rating != 'D' ? 'A' : 'D'); // Use A rated if C,E
}; };
return ComponentSet; return ComponentSet;

View File

@@ -36,7 +36,11 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
var slotGroup = slots[slotType]; var slotGroup = slots[slotType];
var group = this[slotType] = []; // Initialize Slot group (Common, Hardpoints, Internal) var group = this[slotType] = []; // Initialize Slot group (Common, Hardpoints, Internal)
for (var i = 0; i < slotGroup.length; i++) { for (var i = 0; i < slotGroup.length; i++) {
group.push({ id: null, c: null, incCost: true, maxClass: slotGroup[i] }); if (typeof slotGroup[i] == 'object') {
group.push({ id: null, c: null, incCost: true, maxClass: slotGroup[i].class, eligible: slotGroup[i].eligible });
} else {
group.push({ id: null, c: null, incCost: true, maxClass: slotGroup[i] });
}
} }
} }
// Make a Ship 'slot'/item similar to other slots // Make a Ship 'slot'/item similar to other slots
@@ -91,7 +95,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
this.totalDps = 0; this.totalDps = 0;
this.bulkheads.c = null; this.bulkheads.c = null;
this.useBulkhead(comps.bulkheads || 0, true); this.useBulkhead(comps && comps.bulkheads ? comps.bulkheads : 0, true);
this.cargoScoop.priority = priorities ? priorities[0] * 1 : 0; this.cargoScoop.priority = priorities ? priorities[0] * 1 : 0;
this.cargoScoop.enabled = enabled ? enabled[0] * 1 : true; this.cargoScoop.enabled = enabled ? enabled[0] * 1 : true;
@@ -112,7 +116,10 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
common[i].type = 'SYS'; common[i].type = 'SYS';
common[i].c = common[i].id = null; // Resetting 'old' component if there was one common[i].c = common[i].id = null; // Resetting 'old' component if there was one
common[i].discountedCost = 0; common[i].discountedCost = 0;
this.use(common[i], comps.common[i], Components.common(i, comps.common[i]), true);
if (comps) {
this.use(common[i], comps.common[i], Components.common(i, comps.common[i]), true);
}
} }
common[1].type = 'ENG'; // Thrusters common[1].type = 'ENG'; // Thrusters
@@ -127,7 +134,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
hps[i].c = hps[i].id = null; // Resetting 'old' component if there was one hps[i].c = hps[i].id = null; // Resetting 'old' component if there was one
hps[i].discountedCost = 0; hps[i].discountedCost = 0;
if (comps.hardpoints[i] !== 0) { if (comps && comps.hardpoints[i] !== 0) {
this.use(hps[i], comps.hardpoints[i], Components.hardpoints(comps.hardpoints[i]), true); this.use(hps[i], comps.hardpoints[i], Components.hardpoints(comps.hardpoints[i]), true);
} }
} }
@@ -142,15 +149,17 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
internal[i].id = internal[i].c = null; // Resetting 'old' component if there was one internal[i].id = internal[i].c = null; // Resetting 'old' component if there was one
internal[i].discountedCost = 0; internal[i].discountedCost = 0;
if (comps.internal[i] !== 0) { if (comps && comps.internal[i] !== 0) {
this.use(internal[i], comps.internal[i], Components.internal(comps.internal[i]), true); this.use(internal[i], comps.internal[i], Components.internal(comps.internal[i]), true);
} }
} }
// Update aggragated stats // Update aggragated stats
this.updatePower(); if (comps) {
this.updateJumpStats(); this.updatePower();
this.updateShieldStrength(); this.updateJumpStats();
this.updateShieldStrength();
}
}; };
Ship.prototype.useBulkhead = function(index, preventUpdate) { Ship.prototype.useBulkhead = function(index, preventUpdate) {

View File

@@ -33,15 +33,25 @@ angular.module('shipyard').service('Components', ['lodash', 'ComponentsDB', 'Shi
}; };
this.findInternalId = function(groupName, clss, rating, name) { this.findInternalId = function(groupName, clss, rating, name) {
var group = C.internal[groupName]; var groups = {};
if (!group) { if (groupName) {
throw 'Invalid internal group: ' + groupName; if (!C.internal[groupName]) {
throw 'Invalid internal group: ' + groupName;
}
groups[groupName] = C.internal[groupName];
} else if (name) {
groups = C.internal;
} else {
throw 'Invalid group or name not provided';
} }
for (var i = 0, l = group.length; i < l; i++) { for (var g in groups) {
if (group[i].class == clss && group[i].rating == rating && ((!name && !group[i].name) || group[i].name == name)) { var group = groups[g];
return group[i].id; for (var i = 0, l = group.length; i < l; i++) {
if (group[i].class == clss && group[i].rating == rating && ((!name && !group[i].name) || group[i].name == name)) {
return group[i].id;
}
} }
} }
@@ -49,18 +59,28 @@ angular.module('shipyard').service('Components', ['lodash', 'ComponentsDB', 'Shi
}; };
this.findHardpointId = function(groupName, clss, rating, name, mode, missile) { this.findHardpointId = function(groupName, clss, rating, name, mode, missile) {
var group = C.hardpoints[groupName]; var groups = {};
if (!group) { if (groupName) {
throw 'Invalid hardpoint group: ' + groupName; if (!C.hardpoints[groupName]) {
throw 'Invalid internal group: ' + groupName;
}
groups[groupName] = C.hardpoints[groupName];
} else if (name) {
groups = C.hardpoints;
} else {
throw 'Invalid group or name not provided';
} }
for (var i = 0, l = group.length; i < l; i++) { for (var g in groups) {
if (group[i].class == clss && group[i].rating == rating && group[i].mode == mode var group = groups[g];
&& ((!name && !group[i].name) || group[i].name == name) for (var i = 0, l = group.length; i < l; i++) {
&& ((!missile && !group[i].missile) || group[i].missile == missile) if (group[i].class == clss && group[i].rating == rating && group[i].mode == mode
) { && ((!name && !group[i].name) || group[i].name == name)
return group[i].id; && ((!missile && !group[i].missile) || group[i].missile == missile)
) {
return group[i].id;
}
} }
} }
@@ -90,7 +110,8 @@ angular.module('shipyard').service('Components', ['lodash', 'ComponentsDB', 'Shi
*/ */
this.forShip = function(shipId) { this.forShip = function(shipId) {
var ship = Ships[shipId]; var ship = Ships[shipId];
return new ComponentSet(C, ship.minMassFilter || ship.properties.hullMass + 5, ship.slots.common, ship.slots.internal[0], ship.slots.hardpoints[0]); var maxInternal = isNaN(ship.slots.internal[0]) ? ship.slots.internal[0].class : ship.slots.internal[0];
return new ComponentSet(C, ship.minMassFilter || ship.properties.hullMass + 5, ship.slots.common, maxInternal, ship.slots.hardpoints[0]);
}; };
}]); }]);

View File

@@ -19,6 +19,7 @@
@import 'buttons'; @import 'buttons';
@import 'error'; @import 'error';
@import 'sortable'; @import 'sortable';
@import 'loader';
html, body { html, body {
height: 100%; height: 100%;

37
app/less/loader.less Normal file
View File

@@ -0,0 +1,37 @@
@keyframes hideshow {
0% { opacity: 0; }
10% { opacity: 1; }
100% { opacity: 0; }
}
@keyframes inner {
0% { opacity: 0; }
10% { opacity: 1; }
100% { opacity: 0; }
}
@animationTime: 750ms;
@outerTriangles: 19;
@animationDelay: @animationTime / @outerTriangles;
.loader {
path {
stroke: #000;
stroke-width: 0;
opacity: 0;
}
}
.l1 { animation: hideshow @animationTime linear infinite; }
.l2 { animation: inner @animationTime linear infinite; }
.mixin-loop (@i) when (@i > 0) {
.d@{i} {
animation-delay: @i * @animationDelay;
}
.mixin-loop(@i - 1);
}
.mixin-loop(@outerTriangles);

View File

@@ -71,16 +71,17 @@
color: @primary; color: @primary;
} }
.largePhone({ .smallTablet({
width: 60%; width: 60%;
}); });
.medPhone({ .largePhone({
width: 100%; width: 100%;
}); });
} }
.largePhone({ .smallTablet({
float: left; float: left;
clear: left; clear: left;
width: 100%; width: 100%;

View File

@@ -101,6 +101,7 @@ select {
} }
&.disabled { &.disabled {
cursor: not-allowed;
border-color: @disabled; border-color: @disabled;
color: @disabled; color: @disabled;
stroke: @disabled; stroke: @disabled;

View File

@@ -10,7 +10,7 @@
<div class="l" ng-if="c.c.rate">Rate: {{c.c.rate}} <u>Kg/s</u>&nbsp;&nbsp;&nbsp;Refuel Time: {{$r.fTime(fuel * 1000 / c.c.rate)}}</div> <div class="l" ng-if="c.c.rate">Rate: {{c.c.rate}} <u>Kg/s</u>&nbsp;&nbsp;&nbsp;Refuel Time: {{$r.fTime(fuel * 1000 / c.c.rate)}}</div>
<div class="l" ng-if="c.c.ammo">Ammo: {{c.c.ammo}}</div> <div class="l" ng-if="c.c.ammo">Ammo: {{c.c.ammo}}</div>
<div class="l" ng-if="c.c.cells">Cells: {{c.c.cells}}</div> <div class="l" ng-if="c.c.cells">Cells: {{c.c.cells}}</div>
<div class="l" ng-if="c.c.recharge">Recharge: {{c.c.recharge}} <u>MJ</u></div> <div class="l" ng-if="c.c.recharge">Recharge: {{c.c.recharge}} <u>MJ</u>&nbsp;&nbsp;&nbsp;Total: {{c.c.cells * c.c.recharge}} <u>MJ</u></div>
<div class="l" ng-if="c.c.repair">Repair: {{c.c.repair}}</div> <div class="l" ng-if="c.c.repair">Repair: {{c.c.repair}}</div>
<div class="l" ng-if="c.c.range">Range {{c.c.range}} <u>km</u></div> <div class="l" ng-if="c.c.range">Range {{c.c.range}} <u>km</u></div>
<div class="l" ng-if="c.c.time">Time: {{$r.fTime(c.c.time)}}</div> <div class="l" ng-if="c.c.time">Time: {{$r.fTime(c.c.time)}}</div>

View File

@@ -1,7 +1,7 @@
<h2>Import</h2> <h2>Import</h2>
<div ng-show="!processed"> <div ng-show="!processed">
<textarea class="cb json" ng-model="importJSON" ng-change="validateJson()" placeholder="Paste JSON Here"></textarea> <textarea class="cb json" ng-model="importString" ng-change="validateImport()" placeholder="Paste JSON or Build text Here"></textarea>
<button class="l" ng-click="process()" ng-disabled="!jsonValid">Proceed</button> <button class="l" ng-click="process()" ng-disabled="!importValid">Proceed</button>
<div class="l warning" style="margin-left:3em;">{{errorMsg}}</div> <div class="l warning" style="margin-left:3em;">{{errorMsg}}</div>
</div> </div>
@@ -34,7 +34,7 @@
</table> </table>
<button class="cl l" ng-click="import()"><svg class="icon"><use xlink:href="#download"></use></svg> Import</button> <button class="cl l" ng-click="import()"><svg class="icon"><use xlink:href="#download"></use></svg> Import</button>
<button class="l" style="margin-left: 2em;" ng-click="processed = false" ng-show="canEdit">Edit JSON</button> <button class="l" style="margin-left: 2em;" ng-click="processed = false" ng-show="canEdit">Edit Data</button>
</div> </div>
<button class="r dismiss" ng-click="dismiss()">Cancel</button> <button class="r dismiss" ng-click="dismiss()">Cancel</button>

View File

@@ -16,8 +16,11 @@
<button ui-sref="outfit({shipId: ship.id,code:null, bn: buildName})" ng-disabled="!code"> <button ui-sref="outfit({shipId: ship.id,code:null, bn: buildName})" ng-disabled="!code">
<svg class="icon lg"><use xlink:href="#switch"></use></svg><span class="button-lbl">Reset</span> <svg class="icon lg"><use xlink:href="#switch"></use></svg><span class="button-lbl">Reset</span>
</button> </button>
<button ng-click="stripBuild()"> <button ng-click="aRatedBuild()">
<svg class="icon lg"><use xlink:href="#feather"></use></svg><span class="button-lbl">Low-Weight</span> <svg class="icon lg"><use xlink:href="#a"></use></svg><span class="button-lbl">A-Rated</span>
</button>
<button ng-click="optimizeMassBuild()">
<svg class="icon lg"><use xlink:href="#feather"></use></svg><span class="button-lbl">Optimize Mass</span>
</button> </button>
<button ng-click="exportBuild($event)" ng-disabled="!buildName"> <button ng-click="exportBuild($event)" ng-disabled="!buildName">
<svg class="icon lg"><use xlink:href="#download"></use></svg><span class="button-lbl">Export</span> <svg class="icon lg"><use xlink:href="#download"></use></svg><span class="button-lbl">Export</span>
@@ -31,8 +34,8 @@
<tr class="main"> <tr class="main">
<th rowspan="2">Size</th> <th rowspan="2">Size</th>
<th rowspan="2">Agility</th> <th rowspan="2">Agility</th>
<th rowspan="2">Speed</th> <th rowspan="2" ng-class="{'bg-warning-disabled': th.c.maxmass < ship.ladenMass}">Speed</th>
<th rowspan="2" ng-class="{'bg-warning-disabled': pd.c.enginecapacity < ship.boostEnergy}">Boost</th> <th rowspan="2" ng-class="{'bg-warning-disabled': (pd.c.enginecapacity < ship.boostEnergy || th.c.maxmass < ship.ladenMass)}">Boost</th>
<th rowspan="2">DPS</th> <th rowspan="2">DPS</th>
<th rowspan="2">Armour</th> <th rowspan="2">Armour</th>
<th rowspan="2">Shields</th> <th rowspan="2">Shields</th>
@@ -59,10 +62,15 @@
<tr> <tr>
<td ng-bind="SZ[ship.class]"></td> <td ng-bind="SZ[ship.class]"></td>
<td>{{ship.agility}}/10</td> <td>{{ship.agility}}/10</td>
<td>{{fRound(ship.speed)}} <u>m/s</u></td>
<td> <td>
<span ng-if="pd.c.enginecapacity >= ship.boostEnergy">{{fRound(ship.boost)}} <u>m/s</u></span> <span ng-if="th.c.maxmass >= ship.ladenMass">{{fRound(ship.speed)}} <u>m/s</u></span>
<span class="warning" ng-if="pd.c.enginecapacity < ship.boostEnergy">0 <svg class="icon"><use xlink:href="#warning"></use></svg></span> <span class="warning" ng-if="th.c.maxmass < ship.ladenMass">0 <svg class="icon"><use xlink:href="#warning"></use></svg></span>
</td>
<td>
<span ng-if="pd.c.enginecapacity >= ship.boostEnergy && th.c.maxmass >= ship.ladenMass">{{fRound(ship.boost)}} <u>m/s</u></span>
<span class="warning" ng-if="pd.c.enginecapacity < ship.boostEnergy || th.c.maxmass < ship.ladenMass">0
<svg class="icon"><use xlink:href="#warning"></use></svg>
</span>
</td> </td>
<td>{{fRound(ship.totalDps)}}</td> <td>{{fRound(ship.totalDps)}}</td>
<td> <td>
@@ -108,7 +116,7 @@
</div> </div>
</div> </div>
<div class="slot" ng-click="selectSlot($event, pp)" ng-class="{selected: selectedSlot==pp}"> <div class="slot" ng-click="selectSlot($event, pp)" ng-class="{selected: selectedSlot==pp}">
<div class="details"> <div class="details" ng-class="{warning: pp.c.pGen < ship.powerRetracted}">
<div class="sz">{{::pp.maxClass}}</div> <div class="sz">{{::pp.maxClass}}</div>
<div class="l">{{pp.id}} Power Plant</div> <div class="l">{{pp.id}} Power Plant</div>
<div class="r">{{pp.c.mass}} <u>T</u></div> <div class="r">{{pp.c.mass}} <u>T</u></div>
@@ -116,10 +124,10 @@
<div class="l">Efficiency: {{pp.c.eff}}</div> <div class="l">Efficiency: {{pp.c.eff}}</div>
<div class="l">Power: {{pp.c.pGen}} <u>MW</u></div> <div class="l">Power: {{pp.c.pGen}} <u>MW</u></div>
</div> </div>
<div component-select class="select" s="pp" opts="availCS.common[0]" ng-if="selectedSlot==pp" ng-click="select('c',pp,$event)"></div> <div component-select class="select" s="pp" warning="ppWarning" opts="availCS.common[0]" ng-if="selectedSlot==pp" ng-click="select('c',pp,$event)"></div>
</div> </div>
<div class="slot" ng-click="selectSlot($event, th)" ng-class="{selected: selectedSlot==th}"> <div class="slot" ng-click="selectSlot($event, th)" ng-class="{selected: selectedSlot==th}">
<div class="details"> <div class="details" ng-class="{'warning': th.c.maxmass < ship.ladenMass}">
<div class="sz">{{::th.maxClass}}</div> <div class="sz">{{::th.maxClass}}</div>
<div class="l">{{th.id}} Thrusters</div> <div class="l">{{th.id}} Thrusters</div>
<div class="r">{{th.c.mass}} <u>T</u></div> <div class="r">{{th.c.mass}} <u>T</u></div>
@@ -187,7 +195,7 @@
<div class="slot" ng-repeat="i in ship.internal" ng-click="selectSlot($event, i)" context-menu="select('i', i, $event, 'empty')" ng-class="{selected: selectedSlot==i}"> <div class="slot" ng-repeat="i in ship.internal" ng-click="selectSlot($event, i)" context-menu="select('i', i, $event, 'empty')" ng-class="{selected: selectedSlot==i}">
<div slot-internal class="details" slot="i" lbl="GMAP[i.c.grp]" fuel="ship.fuelCapacity"></div> <div slot-internal class="details" slot="i" lbl="GMAP[i.c.grp]" fuel="ship.fuelCapacity"></div>
<div class="select" ng-if="selectedSlot==i" ng-click="select('i',i,$event)"> <div class="select" ng-if="selectedSlot==i" ng-click="select('i',i,$event)">
<div component-select s="i" groups="availCS.getInts(i.maxClass)"></div> <div component-select s="i" groups="availCS.getInts(i.maxClass, i.eligible)"></div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -25,7 +25,7 @@
"angular-ui-router": "^0.2.15", "angular-ui-router": "^0.2.15",
"d3-tip": "~0.6.7", "d3-tip": "~0.6.7",
"ng-sortable": "~1.2.1", "ng-sortable": "~1.2.1",
"lz-string": "~1.4.3", "lz-string": "~1.4.4",
"angular": "~1.4.0" "angular": "~1.4.0"
}, },
"overrides": { "overrides": {

View File

@@ -1,317 +1,37 @@
{ {
"8E": { "8E":{ "grp": "pp", "class": 8, "rating": "E", "cost": 2007241, "mass": 160, "pGen": 24, "eff": "F" },
"grp": "pp", "8D":{ "grp": "pp", "class": 8, "rating": "D", "cost": 6021722, "mass": 64, "pGen": 27, "eff": "D" },
"class": 8, "8C":{ "grp": "pp", "class": 8, "rating": "C", "cost": 18065165, "mass": 80, "pGen": 30, "eff": "C" },
"rating": "E", "8B":{ "grp": "pp", "class": 8, "rating": "B", "cost": 54195495, "mass": 128, "pGen": 33, "eff": "C" },
"cost": 2007241, "8A":{ "grp": "pp", "class": 8, "rating": "A", "cost": 162586486, "mass": 80, "pGen": 36, "eff": "B" },
"mass": 160, "7E":{ "grp": "pp", "class": 7, "rating": "E", "cost": 633199, "mass": 80, "pGen": 20, "eff": "F" },
"pGen": 24, "7D":{ "grp": "pp", "class": 7, "rating": "D", "cost": 1899597, "mass": 32, "pGen": 22.5, "eff": "D" },
"eff": "F" "7C":{ "grp": "pp", "class": 7, "rating": "C", "cost": 5698790, "mass": 40, "pGen": 25, "eff": "C" },
}, "7B":{ "grp": "pp", "class": 7, "rating": "B", "cost": 17096371, "mass": 64, "pGen": 27.5, "eff": "C" },
"8D": { "7A":{ "grp": "pp", "class": 7, "rating": "A", "cost": 51289112, "mass": 40, "pGen": 30, "eff": "B" },
"grp": "pp", "6E":{ "grp": "pp", "class": 6, "rating": "E", "cost": 199747, "mass": 40, "pGen": 16.8, "eff": "F" },
"class": 8, "6D":{ "grp": "pp", "class": 6, "rating": "D", "cost": 599242, "mass": 16, "pGen": 18.9, "eff": "D" },
"rating": "D", "6C":{ "grp": "pp", "class": 6, "rating": "C", "cost": 1797726, "mass": 20, "pGen": 21, "eff": "C" },
"cost": 6021722, "6B":{ "grp": "pp", "class": 6, "rating": "B", "cost": 5393177, "mass": 32, "pGen": 23.1, "eff": "C" },
"mass": 64, "6A":{ "grp": "pp", "class": 6, "rating": "A", "cost": 16179531, "mass": 20, "pGen": 25.2, "eff": "B" },
"pGen": 27, "5E":{ "grp": "pp", "class": 5, "rating": "E", "cost": 63012, "mass": 20, "pGen": 13.6, "eff": "F" },
"eff": "D" "5D":{ "grp": "pp", "class": 5, "rating": "D", "cost": 189035, "mass": 8, "pGen": 15.3, "eff": "D" },
}, "5C":{ "grp": "pp", "class": 5, "rating": "C", "cost": 567106, "mass": 10, "pGen": 17, "eff": "C" },
"8C": { "5B":{ "grp": "pp", "class": 5, "rating": "B", "cost": 1701318, "mass": 16, "pGen": 18.7, "eff": "C" },
"grp": "pp", "5A":{ "grp": "pp", "class": 5, "rating": "A", "cost": 5103953, "mass": 10, "pGen": 20.4, "eff": "B" },
"class": 8, "4E":{ "grp": "pp", "class": 4, "rating": "E", "cost": 19878, "mass": 10, "pGen": 10.4, "eff": "F" },
"rating": "C", "4D":{ "grp": "pp", "class": 4, "rating": "D", "cost": 59633, "mass": 4, "pGen": 11.7, "eff": "D" },
"cost": 18065165, "4C":{ "grp": "pp", "class": 4, "rating": "C", "cost": 178898, "mass": 5, "pGen": 13, "eff": "C" },
"mass": 80, "4B":{ "grp": "pp", "class": 4, "rating": "B", "cost": 536693, "mass": 8, "pGen": 14.3, "eff": "C" },
"pGen": 30, "4A":{ "grp": "pp", "class": 4, "rating": "A", "cost": 1610080, "mass": 5, "pGen": 15.6, "eff": "B" },
"eff": "C" "3E":{ "grp": "pp", "class": 3, "rating": "E", "cost": 6271, "mass": 5, "pGen": 8, "eff": "F" },
}, "3D":{ "grp": "pp", "class": 3, "rating": "D", "cost": 18812, "mass": 2, "pGen": 9, "eff": "D" },
"8B": { "3C":{ "grp": "pp", "class": 3, "rating": "C", "cost": 56435, "mass": 2.5, "pGen": 10, "eff": "C" },
"grp": "pp", "3B":{ "grp": "pp", "class": 3, "rating": "B", "cost": 169304, "mass": 4, "pGen": 11, "eff": "C" },
"class": 8, "3A":{ "grp": "pp", "class": 3, "rating": "A", "cost": 507912, "mass": 2.5, "pGen": 12, "eff": "B" },
"rating": "B", "2E":{ "grp": "pp", "class": 2, "rating": "E", "cost": 1978, "mass": 2.5, "pGen": 6.4, "eff": "F" },
"cost": 54195495, "2D":{ "grp": "pp", "class": 2, "rating": "D", "cost": 5934, "mass": 1, "pGen": 7.2, "eff": "D" },
"mass": 128, "2C":{ "grp": "pp", "class": 2, "rating": "C", "cost": 17803, "mass": 1.3, "pGen": 8, "eff": "C" },
"pGen": 33, "2B":{ "grp": "pp", "class": 2, "rating": "B", "cost": 53408, "mass": 2, "pGen": 8.8, "eff": "C" },
"eff": "C" "2A":{ "grp": "pp", "class": 2, "rating": "A", "cost": 160224, "mass": 1.3, "pGen": 9.6, "eff": "B" }
},
"8A": {
"grp": "pp",
"class": 8,
"rating": "A",
"cost": 162586486,
"mass": 80,
"pGen": 36,
"eff": "B"
},
"7E": {
"grp": "pp",
"class": 7,
"rating": "E",
"cost": 633199,
"mass": 80,
"pGen": 20,
"eff": "F"
},
"7D": {
"grp": "pp",
"class": 7,
"rating": "D",
"cost": 1899597,
"mass": 32,
"pGen": 22.5,
"eff": "D"
},
"7C": {
"grp": "pp",
"class": 7,
"rating": "C",
"cost": 5698790,
"mass": 40,
"pGen": 25,
"eff": "C"
},
"7B": {
"grp": "pp",
"class": 7,
"rating": "B",
"cost": 17096371,
"mass": 64,
"pGen": 27.5,
"eff": "C"
},
"7A": {
"grp": "pp",
"class": 7,
"rating": "A",
"cost": 51289112,
"mass": 40,
"pGen": 30,
"eff": "B"
},
"6E": {
"grp": "pp",
"class": 6,
"rating": "E",
"cost": 199747,
"mass": 40,
"pGen": 16.8,
"eff": "F"
},
"6D": {
"grp": "pp",
"class": 6,
"rating": "D",
"cost": 599242,
"mass": 16,
"pGen": 18.9,
"eff": "D"
},
"6C": {
"grp": "pp",
"class": 6,
"rating": "C",
"cost": 1797726,
"mass": 20,
"pGen": 21,
"eff": "C"
},
"6B": {
"grp": "pp",
"class": 6,
"rating": "B",
"cost": 5393177,
"mass": 32,
"pGen": 23.1,
"eff": "C"
},
"6A": {
"grp": "pp",
"class": 6,
"rating": "A",
"cost": 16179531,
"mass": 20,
"pGen": 25.2,
"eff": "B"
},
"5E": {
"grp": "pp",
"class": 5,
"rating": "E",
"cost": 63012,
"mass": 20,
"pGen": 13.6,
"eff": "F"
},
"5D": {
"grp": "pp",
"class": 5,
"rating": "D",
"cost": 189035,
"mass": 8,
"pGen": 15.3,
"eff": "D"
},
"5C": {
"grp": "pp",
"class": 5,
"rating": "C",
"cost": 567106,
"mass": 10,
"pGen": 17,
"eff": "C"
},
"5B": {
"grp": "pp",
"class": 5,
"rating": "B",
"cost": 1701318,
"mass": 16,
"pGen": 18.7,
"eff": "C"
},
"5A": {
"grp": "pp",
"class": 5,
"rating": "A",
"cost": 5103953,
"mass": 10,
"pGen": 20.4,
"eff": "B"
},
"4E": {
"grp": "pp",
"class": 4,
"rating": "E",
"cost": 19878,
"mass": 10,
"pGen": 10.4,
"eff": "F"
},
"4D": {
"grp": "pp",
"class": 4,
"rating": "D",
"cost": 59633,
"mass": 4,
"pGen": 11.7,
"eff": "D"
},
"4C": {
"grp": "pp",
"class": 4,
"rating": "C",
"cost": 178898,
"mass": 5,
"pGen": 13,
"eff": "C"
},
"4B": {
"grp": "pp",
"class": 4,
"rating": "B",
"cost": 536693,
"mass": 8,
"pGen": 14.3,
"eff": "C"
},
"4A": {
"grp": "pp",
"class": 4,
"rating": "A",
"cost": 1610080,
"mass": 5,
"pGen": 15.6,
"eff": "B"
},
"3E": {
"grp": "pp",
"class": 3,
"rating": "E",
"cost": 6271,
"mass": 5,
"pGen": 8,
"eff": "F"
},
"3D": {
"grp": "pp",
"class": 3,
"rating": "D",
"cost": 18812,
"mass": 2,
"pGen": 9,
"eff": "D"
},
"3C": {
"grp": "pp",
"class": 3,
"rating": "C",
"cost": 56435,
"mass": 2.5,
"pGen": 10,
"eff": "C"
},
"3B": {
"grp": "pp",
"class": 3,
"rating": "B",
"cost": 169304,
"mass": 4,
"pGen": 11,
"eff": "C"
},
"3A": {
"grp": "pp",
"class": 3,
"rating": "A",
"cost": 507912,
"mass": 2.5,
"pGen": 12,
"eff": "B"
},
"2E": {
"grp": "pp",
"class": 2,
"rating": "E",
"cost": 1978,
"mass": 2.5,
"pGen": 6.4,
"eff": "F"
},
"2D": {
"grp": "pp",
"class": 2,
"rating": "D",
"cost": 5934,
"mass": 1,
"pGen": 7.2,
"eff": "D"
},
"2C": {
"grp": "pp",
"class": 2,
"rating": "C",
"cost": 17803,
"mass": 1.3,
"pGen": 8,
"eff": "C"
},
"2B": {
"grp": "pp",
"class": 2,
"rating": "B",
"cost": 53408,
"mass": 2,
"pGen": 8.8,
"eff": "C"
},
"2A": {
"grp": "pp",
"class": 2,
"rating": "A",
"cost": 160224,
"mass": 1.3,
"pGen": 9.6,
"eff": "B"
}
} }

View File

@@ -1,11 +1,12 @@
{ {
"Prismatic Shield Generator": [ "Prismatic Shield Generator": [
{ "id": "p6", "grp": "psg", "class": 1, "rating": "A", "cost": 132195, "mass": 2.5, "power": 2.52, "minmass": 13, "optmass": 25, "maxmass": 63, "minmul": 2.04, "optmul": 1.44, "maxmul": 0.84 }, { "id": "p6", "grp": "psg", "class": 1, "rating": "A", "cost": 132195, "mass": 2.5, "power": 2.52, "minmass": 13, "optmass": 25, "maxmass": 63, "minmul": 2.04, "optmul": 1.44, "maxmul": 0.84 },
{ "id": "p5", "grp": "psg", "class": 2, "rating": "A", "cost": 240336, "mass": 5, "power": 3.15, "minmass": 23, "optmass": 55, "maxmass": 138, "minmul": 2.04, "optmul": 1.44, "maxmul": 0.84 }, { "id": "p5", "grp": "psg", "class": 2, "rating": "A", "cost": 240336, "mass": 5, "power": 3.15, "minmass": 23, "optmass": 55, "maxmass": 138, "minmul": 2.04, "optmul": 1.44, "maxmul": 0.84 },
{ "id": "p4", "grp": "psg", "class": 3, "rating": "A", "cost": 761868, "mass": 10, "power": 3.78, "minmass": 83, "optmass": 165, "maxmass": 413, "minmul": 2.04, "optmul": 1.44, "maxmul": 0.84 }, { "id": "p4", "grp": "psg", "class": 3, "rating": "A", "cost": 761868, "mass": 10, "power": 3.78, "minmass": 83, "optmass": 165, "maxmass": 413, "minmul": 2.04, "optmul": 1.44, "maxmul": 0.84 },
{ "id": "p3", "grp": "psg", "class": 4, "rating": "A", "cost": 2415120, "mass": 20, "power": 4.62, "minmass": 143, "optmass": 285, "maxmass": 713, "minmul": 2.04, "optmul": 1.44, "maxmul": 0.84 }, { "id": "p3", "grp": "psg", "class": 4, "rating": "A", "cost": 2415120, "mass": 20, "power": 4.62, "minmass": 143, "optmass": 285, "maxmass": 713, "minmul": 2.04, "optmul": 1.44, "maxmul": 0.84 },
{ "id": "p2", "grp": "psg", "class": 5, "rating": "A", "cost": 7655930, "mass": 40, "power": 5.46, "minmass": 203, "optmass": 405, "maxmass": 1013, "minmul": 2.04, "optmul": 1.44, "maxmul": 0.84 }, { "id": "p2", "grp": "psg", "class": 5, "rating": "A", "cost": 7655930, "mass": 40, "power": 5.46, "minmass": 203, "optmass": 405, "maxmass": 1013, "minmul": 2.04, "optmul": 1.44, "maxmul": 0.84 },
{ "id": "p1", "grp": "psg", "class": 6, "rating": "A", "cost": 24269297, "mass": 80, "power": 6.51, "minmass": 270, "optmass": 540, "maxmass": 1350, "minmul": 2.04, "optmul": 1.44, "maxmul": 0.84 }, { "id": "p1", "grp": "psg", "class": 6, "rating": "A", "cost": 24269297, "mass": 80, "power": 6.51, "minmass": 270, "optmass": 540, "maxmass": 1350, "minmul": 2.04, "optmul": 1.44, "maxmul": 0.84 },
{ "id": "p0", "grp": "psg", "class": 7, "rating": "A", "cost": 76933668, "mass": 160, "power": 7.35, "minmass": 530, "optmass": 1060, "maxmass": 2650, "minmul": 2.04, "optmul": 1.44, "maxmul": 0.84 } { "id": "p0", "grp": "psg", "class": 7, "rating": "A", "cost": 76933668, "mass": 160, "power": 7.35, "minmass": 530, "optmass": 1060, "maxmass": 2650, "minmul": 2.04, "optmul": 1.44, "maxmul": 0.84 },
{ "id": "p7", "grp": "psg", "class": 8, "rating": "A", "cost": 243879729, "mass": 320, "power": 8.4, "minmass": 900, "optmass": 1800, "maxmass": 4500, "minmul": 2.04, "optmul": 1.44, "maxmul": 0.84 }
] ]
} }

View File

@@ -1,44 +1,44 @@
{ {
"Shield Cell Bank": [ "Shield Cell Bank": [
{ "id": "65", "grp": "scb", "class": 8, "rating": "E", "cost": 697584, "mass": 160, "power": 1.44, "cells": 5, "rechargeRating": "C", "recharge": 0 }, { "id": "65", "grp": "scb", "class": 8, "rating": "E", "cost": 697584, "mass": 160, "power": 1.44, "cells": 6, "rechargeRating": "C", "recharge": 0 },
{ "id": "64", "grp": "scb", "class": 8, "rating": "D", "cost": 1743961, "mass": 64, "power": 1.92, "cells": 3, "rechargeRating": "C", "recharge": 0 }, { "id": "64", "grp": "scb", "class": 8, "rating": "D", "cost": 1743961, "mass": 64, "power": 1.92, "cells": 4, "rechargeRating": "C", "recharge": 0 },
{ "id": "63", "grp": "scb", "class": 8, "rating": "C", "cost": 4359903, "mass": 160, "power": 2.4, "cells": 4, "rechargeRating": "B", "recharge": 0 }, { "id": "63", "grp": "scb", "class": 8, "rating": "C", "cost": 4359903, "mass": 160, "power": 2.4, "cells": 5, "rechargeRating": "B", "recharge": 0 },
{ "id": "62", "grp": "scb", "class": 8, "rating": "B", "cost": 10899756, "mass": 256, "power": 2.88, "cells": 5, "rechargeRating": "A", "recharge": 0 }, { "id": "62", "grp": "scb", "class": 8, "rating": "B", "cost": 10899756, "mass": 256, "power": 2.88, "cells": 6, "rechargeRating": "A", "recharge": 0 },
{ "id": "61", "grp": "scb", "class": 8, "rating": "A", "cost": 27249391, "mass": 160, "power": 3.36, "cells": 4, "rechargeRating": "A", "recharge": 0 }, { "id": "61", "grp": "scb", "class": 8, "rating": "A", "cost": 27249391, "mass": 160, "power": 3.36, "cells": 5, "rechargeRating": "A", "recharge": 0 },
{ "id": "60", "grp": "scb", "class": 7, "rating": "E", "cost": 249137, "mass": 80, "power": 1.24, "cells": 5, "rechargeRating": "D", "recharge": 97 }, { "id": "60", "grp": "scb", "class": 7, "rating": "E", "cost": 249137, "mass": 80, "power": 1.24, "cells": 6, "rechargeRating": "D", "recharge": 97 },
{ "id": "5v", "grp": "scb", "class": 7, "rating": "D", "cost": 622843, "mass": 32, "power": 1.66, "cells": 3, "rechargeRating": "C", "recharge": 130 }, { "id": "5v", "grp": "scb", "class": 7, "rating": "D", "cost": 622843, "mass": 32, "power": 1.66, "cells": 4, "rechargeRating": "C", "recharge": 130 },
{ "id": "5u", "grp": "scb", "class": 7, "rating": "C", "cost": 1557108, "mass": 80, "power": 2.07, "cells": 4, "rechargeRating": "B", "recharge": 163 }, { "id": "5u", "grp": "scb", "class": 7, "rating": "C", "cost": 1557108, "mass": 80, "power": 2.07, "cells": 5, "rechargeRating": "B", "recharge": 163 },
{ "id": "5t", "grp": "scb", "class": 7, "rating": "B", "cost": 3892770, "mass": 128, "power": 2.48, "cells": 5, "rechargeRating": "B", "recharge": 197 }, { "id": "5t", "grp": "scb", "class": 7, "rating": "B", "cost": 3892770, "mass": 128, "power": 2.48, "cells": 6, "rechargeRating": "B", "recharge": 197 },
{ "id": "5s", "grp": "scb", "class": 7, "rating": "A", "cost": 9731925, "mass": 80, "power": 2.9, "cells": 4, "rechargeRating": "A", "recharge": 230 }, { "id": "5s", "grp": "scb", "class": 7, "rating": "A", "cost": 9731925, "mass": 80, "power": 2.9, "cells": 5, "rechargeRating": "A", "recharge": 230 },
{ "id": "5r", "grp": "scb", "class": 6, "rating": "E", "cost": 88978, "mass": 40, "power": 1.06, "cells": 5, "rechargeRating": "D", "recharge": 92 }, { "id": "5r", "grp": "scb", "class": 6, "rating": "E", "cost": 88978, "mass": 40, "power": 1.06, "cells": 6, "rechargeRating": "D", "recharge": 92 },
{ "id": "5q", "grp": "scb", "class": 6, "rating": "D", "cost": 222444, "mass": 16, "power": 1.42, "cells": 3, "rechargeRating": "C", "recharge": 120 }, { "id": "5q", "grp": "scb", "class": 6, "rating": "D", "cost": 222444, "mass": 16, "power": 1.42, "cells": 4, "rechargeRating": "C", "recharge": 120 },
{ "id": "5p", "grp": "scb", "class": 6, "rating": "C", "cost": 556110, "mass": 40, "power": 1.77, "cells": 4, "rechargeRating": "C", "recharge": 148 }, { "id": "5p", "grp": "scb", "class": 6, "rating": "C", "cost": 556110, "mass": 40, "power": 1.77, "cells": 5, "rechargeRating": "C", "recharge": 148 },
{ "id": "5o", "grp": "scb", "class": 6, "rating": "B", "cost": 1390275, "mass": 64, "power": 2.12, "cells": 5, "rechargeRating": "B", "recharge": 176 }, { "id": "5o", "grp": "scb", "class": 6, "rating": "B", "cost": 1390275, "mass": 64, "power": 2.12, "cells": 6, "rechargeRating": "B", "recharge": 176 },
{ "id": "5n", "grp": "scb", "class": 6, "rating": "A", "cost": 3475688, "mass": 40, "power": 2.48, "cells": 4, "rechargeRating": "A", "recharge": 204 }, { "id": "5n", "grp": "scb", "class": 6, "rating": "A", "cost": 3475688, "mass": 40, "power": 2.48, "cells": 5, "rechargeRating": "A", "recharge": 204 },
{ "id": "5m", "grp": "scb", "class": 5, "rating": "E", "cost": 31778, "mass": 20, "power": 0.9, "cells": 4, "rechargeRating": "D", "recharge": 82 }, { "id": "5m", "grp": "scb", "class": 5, "rating": "E", "cost": 31778, "mass": 20, "power": 0.9, "cells": 5, "rechargeRating": "D", "recharge": 82 },
{ "id": "5l", "grp": "scb", "class": 5, "rating": "D", "cost": 79444, "mass": 8, "power": 1.2, "cells": 2, "rechargeRating": "C", "recharge": 109 }, { "id": "5l", "grp": "scb", "class": 5, "rating": "D", "cost": 79444, "mass": 8, "power": 1.2, "cells": 3, "rechargeRating": "C", "recharge": 109 },
{ "id": "5k", "grp": "scb", "class": 5, "rating": "C", "cost": 198611, "mass": 20, "power": 1.5, "cells": 3, "rechargeRating": "C", "recharge": 135 }, { "id": "5k", "grp": "scb", "class": 5, "rating": "C", "cost": 198611, "mass": 20, "power": 1.5, "cells": 4, "rechargeRating": "C", "recharge": 135 },
{ "id": "5j", "grp": "scb", "class": 5, "rating": "B", "cost": 496527, "mass": 32, "power": 1.8, "cells": 4, "rechargeRating": "B", "recharge": 162 }, { "id": "5j", "grp": "scb", "class": 5, "rating": "B", "cost": 496527, "mass": 32, "power": 1.8, "cells": 5, "rechargeRating": "B", "recharge": 162 },
{ "id": "5i", "grp": "scb", "class": 5, "rating": "A", "cost": 1241317, "mass": 20, "power": 2.1, "cells": 3, "rechargeRating": "B", "recharge": 189 }, { "id": "5i", "grp": "scb", "class": 5, "rating": "A", "cost": 1241317, "mass": 20, "power": 2.1, "cells": 4, "rechargeRating": "B", "recharge": 189 },
{ "id": "5h", "grp": "scb", "class": 4, "rating": "E", "cost": 11349, "mass": 10, "power": 0.74, "cells": 4, "rechargeRating": "D", "recharge": 72 }, { "id": "5h", "grp": "scb", "class": 4, "rating": "E", "cost": 11349, "mass": 10, "power": 0.74, "cells": 5, "rechargeRating": "D", "recharge": 72 },
{ "id": "5g", "grp": "scb", "class": 4, "rating": "D", "cost": 28373, "mass": 4, "power": 0.98, "cells": 2, "rechargeRating": "D", "recharge": 94 }, { "id": "5g", "grp": "scb", "class": 4, "rating": "D", "cost": 28373, "mass": 4, "power": 0.98, "cells": 3, "rechargeRating": "D", "recharge": 94 },
{ "id": "5f", "grp": "scb", "class": 4, "rating": "C", "cost": 70932, "mass": 10, "power": 1.23, "cells": 3, "rechargeRating": "C", "recharge": 117 }, { "id": "5f", "grp": "scb", "class": 4, "rating": "C", "cost": 70932, "mass": 10, "power": 1.23, "cells": 4, "rechargeRating": "C", "recharge": 117 },
{ "id": "5e", "grp": "scb", "class": 4, "rating": "B", "cost": 177331, "mass": 16, "power": 1.48, "cells": 4, "rechargeRating": "C", "recharge": 140 }, { "id": "5e", "grp": "scb", "class": 4, "rating": "B", "cost": 177331, "mass": 16, "power": 1.48, "cells": 5, "rechargeRating": "C", "recharge": 140 },
{ "id": "5d", "grp": "scb", "class": 4, "rating": "A", "cost": 443328, "mass": 10, "power": 1.72, "cells": 3, "rechargeRating": "B", "recharge": 163 }, { "id": "5d", "grp": "scb", "class": 4, "rating": "A", "cost": 443328, "mass": 10, "power": 1.72, "cells": 4, "rechargeRating": "B", "recharge": 163 },
{ "id": "5c", "grp": "scb", "class": 3, "rating": "E", "cost": 4053, "mass": 5, "power": 0.61, "cells": 4, "rechargeRating": "D", "recharge": 61 }, { "id": "5c", "grp": "scb", "class": 3, "rating": "E", "cost": 4053, "mass": 5, "power": 0.61, "cells": 5, "rechargeRating": "D", "recharge": 61 },
{ "id": "5b", "grp": "scb", "class": 3, "rating": "D", "cost": 10133, "mass": 2, "power": 0.82, "cells": 2, "rechargeRating": "D", "recharge": 80 }, { "id": "5b", "grp": "scb", "class": 3, "rating": "D", "cost": 10133, "mass": 2, "power": 0.82, "cells": 3, "rechargeRating": "D", "recharge": 80 },
{ "id": "5a", "grp": "scb", "class": 3, "rating": "C", "cost": 25333, "mass": 5, "power": 1.02, "cells": 3, "rechargeRating": "D", "recharge": 100 }, { "id": "5a", "grp": "scb", "class": 3, "rating": "C", "cost": 25333, "mass": 5, "power": 1.02, "cells": 4, "rechargeRating": "D", "recharge": 100 },
{ "id": "59", "grp": "scb", "class": 3, "rating": "B", "cost": 63333, "mass": 8, "power": 1.22, "cells": 4, "rechargeRating": "C", "recharge": 119 }, { "id": "59", "grp": "scb", "class": 3, "rating": "B", "cost": 63333, "mass": 8, "power": 1.22, "cells": 5, "rechargeRating": "C", "recharge": 119 },
{ "id": "58", "grp": "scb", "class": 3, "rating": "A", "cost": 158331, "mass": 5, "power": 1.43, "cells": 3, "rechargeRating": "C", "recharge": 138 }, { "id": "58", "grp": "scb", "class": 3, "rating": "A", "cost": 158331, "mass": 5, "power": 1.43, "cells": 4, "rechargeRating": "C", "recharge": 138 },
{ "id": "57", "grp": "scb", "class": 2, "rating": "E", "cost": 1448, "mass": 2.5, "power": 0.5, "cells": 4, "rechargeRating": "E", "recharge": 46 }, { "id": "57", "grp": "scb", "class": 2, "rating": "E", "cost": 1448, "mass": 2.5, "power": 0.5, "cells": 5, "rechargeRating": "E", "recharge": 46 },
{ "id": "56", "grp": "scb", "class": 2, "rating": "D", "cost": 3619, "mass": 1, "power": 0.67, "cells": 2, "rechargeRating": "D", "recharge": 61 }, { "id": "56", "grp": "scb", "class": 2, "rating": "D", "cost": 3619, "mass": 1, "power": 0.67, "cells": 3, "rechargeRating": "D", "recharge": 61 },
{ "id": "55", "grp": "scb", "class": 2, "rating": "C", "cost": 9048, "mass": 2.5, "power": 0.84, "cells": 3, "rechargeRating": "D", "recharge": 77 }, { "id": "55", "grp": "scb", "class": 2, "rating": "C", "cost": 9048, "mass": 2.5, "power": 0.84, "cells": 4, "rechargeRating": "D", "recharge": 77 },
{ "id": "54", "grp": "scb", "class": 2, "rating": "B", "cost": 22619, "mass": 4, "power": 1.01, "cells": 4, "rechargeRating": "D", "recharge": 92 }, { "id": "54", "grp": "scb", "class": 2, "rating": "B", "cost": 22619, "mass": 4, "power": 1.01, "cells": 5, "rechargeRating": "D", "recharge": 92 },
{ "id": "53", "grp": "scb", "class": 2, "rating": "A", "cost": 56547, "mass": 2.5, "power": 1.18, "cells": 3, "rechargeRating": "C", "recharge": 107 }, { "id": "53", "grp": "scb", "class": 2, "rating": "A", "cost": 56547, "mass": 2.5, "power": 1.18, "cells": 4, "rechargeRating": "C", "recharge": 107 },
{ "id": "52", "grp": "scb", "class": 1, "rating": "E", "cost": 517, "mass": 1.3, "power": 0.41, "cells": 3, "rechargeRating": "E", "recharge": 31 }, { "id": "52", "grp": "scb", "class": 1, "rating": "E", "cost": 517, "mass": 1.3, "power": 0.41, "cells": 4, "rechargeRating": "E", "recharge": 31 },
{ "id": "51", "grp": "scb", "class": 1, "rating": "D", "cost": 1293, "mass": 0.5, "power": 0.55, "cells": 1, "rechargeRating": "E", "recharge": 41 }, { "id": "51", "grp": "scb", "class": 1, "rating": "D", "cost": 1293, "mass": 0.5, "power": 0.55, "cells": 2, "rechargeRating": "E", "recharge": 41 },
{ "id": "50", "grp": "scb", "class": 1, "rating": "C", "cost": 3231, "mass": 1.3, "power": 0.69, "cells": 2, "rechargeRating": "D", "recharge": 51 }, { "id": "50", "grp": "scb", "class": 1, "rating": "C", "cost": 3231, "mass": 1.3, "power": 0.69, "cells": 3, "rechargeRating": "D", "recharge": 51 },
{ "id": "4v", "grp": "scb", "class": 1, "rating": "B", "cost": 8078, "mass": 2, "power": 0.83, "cells": 3, "rechargeRating": "D", "recharge": 61 }, { "id": "4v", "grp": "scb", "class": 1, "rating": "B", "cost": 8078, "mass": 2, "power": 0.83, "cells": 4, "rechargeRating": "D", "recharge": 61 },
{ "id": "4u", "grp": "scb", "class": 1, "rating": "A", "cost": 20195, "mass": 1.3, "power": 0.97, "cells": 2, "rechargeRating": "D", "recharge": 72 } { "id": "4u", "grp": "scb", "class": 1, "rating": "A", "cost": 20195, "mass": 1.3, "power": 0.97, "cells": 3, "rechargeRating": "D", "recharge": 72 }
] ]
} }

View File

@@ -35,8 +35,8 @@
0 0
], ],
"internal": [ "internal": [
6, { "class": 6, "eligible": { "Cargo Rack": 1, "Hull Reinforcement Package": 1 } },
5, { "class": 5, "eligible": { "Cargo Rack": 1, "Hull Reinforcement Package": 1 } },
5, 5,
5, 5,
4, 4,

View File

@@ -51,7 +51,8 @@ gulp.task('js-lint', function() {
'space-before-function-paren': [2, 'never'], 'space-before-function-paren': [2, 'never'],
'space-before-blocks': [2, 'always'], 'space-before-blocks': [2, 'always'],
'object-curly-spacing': [2, "always"], 'object-curly-spacing': [2, "always"],
'brace-style': [2, '1tbs', { allowSingleLine: true }] 'brace-style': [2, '1tbs', { allowSingleLine: true }],
'no-control-regex': false
}, },
envs: ['browser'] envs: ['browser']
})) }))

View File

@@ -1,6 +1,6 @@
{ {
"name": "coriolis_shipyard", "name": "coriolis_shipyard",
"version": "1.3.0", "version": "1.4.0",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/cmmcleod/coriolis" "url": "https://github.com/cmmcleod/coriolis"
@@ -8,7 +8,7 @@
"private": true, "private": true,
"engine": "node >= 0.12.2", "engine": "node >= 0.12.2",
"devDependencies": { "devDependencies": {
"angular-mocks": "1.3.x", "angular-mocks": "1.4.x",
"async": "0.9.x", "async": "0.9.x",
"del": "1.2.x", "del": "1.2.x",
"gulp": "3.9.x", "gulp": "3.9.x",

View File

@@ -0,0 +1,22 @@
[
{
"buildText": "[Imaginary Ship]\nbla bla",
"errorMsg": "No such ship found: \"Imaginary Ship\""
},
{
"buildText": "[Viper]\nS: 1F/F Pulse Laser\nsome un-parseable nonsense\nS: 1F/F Pulse Laser\n",
"errorMsg": "Error parsing: \"some un-parseable nonsense\""
},
{
"buildText": "[Sidewinder]\nS: 2F/F Pulse Laser\nS: 1F/F Pulse Laser\n",
"errorMsg": "2F Pulse Laser exceeds slot size: \"S: 2F/F Pulse Laser\""
},
{
"buildText": "[Sidewinder]\nL: 2F/F Pulse Laser\nS: 1F/F Pulse Laser\n",
"errorMsg": "No hardpoint slot available for: \"L: 2F/F Pulse Laser\""
},
{
"buildText": "[Sidewinder]\nS: 1F/F Magic Thing\nS: 1F/F Pulse Laser\n",
"errorMsg": "Unknown component: \"S: 1F/F Magic Thing\""
}
]

View File

@@ -0,0 +1,32 @@
[
{
"shipId": "anaconda",
"buildName": "Imported Anaconda",
"buildCode": "08E7E6E5E8E8E5C------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"
},
{
"shipId": "anaconda",
"buildName": "Imported Anaconda",
"buildCode": "08E7E6E5E8E8E5C------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"
},
{
"shipId": "cobra_mk_iii",
"buildName": "Imported Cobra Mk III",
"buildCode": "04A4C4E3D2A3D4C1712222503040202490f242h.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"
},
{
"shipId": "type_9_heavy",
"buildName": "Imported Type-9 Heavy",
"buildCode": "35A7D6A5A4D4D5C7e2k2f2h110001020306054j03022f01242i.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"
},
{
"shipId": "vulture",
"buildName": "Imported Vulture",
"buildCode": "44A5A4A3D5A4D3C1e1e0e0j04044a0n532jf1.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)"
}
]

View File

@@ -37,9 +37,9 @@ describe('Import Controller', function() {
it('imports a valid backup', function() { it('imports a valid backup', function() {
var importData = __json__['fixtures/valid-backup']; var importData = __json__['fixtures/valid-backup'];
scope.importJSON = angular.toJson(importData); scope.importString = angular.toJson(importData);
scope.validateJson(); scope.validateImport();
expect(scope.jsonValid).toBeTruthy(); expect(scope.importValid).toBeTruthy();
expect(scope.errorMsg).toEqual(null); expect(scope.errorMsg).toEqual(null);
scope.process(); scope.process();
expect(scope.processed).toBeTruthy(); expect(scope.processed).toBeTruthy();
@@ -52,9 +52,9 @@ describe('Import Controller', function() {
it('imports an old valid backup', function() { it('imports an old valid backup', function() {
var importData = __json__['fixtures/old-valid-export']; var importData = __json__['fixtures/old-valid-export'];
scope.importJSON = angular.toJson(importData); scope.importString = angular.toJson(importData);
scope.validateJson(); scope.validateImport();
expect(scope.jsonValid).toBeTruthy(); expect(scope.importValid).toBeTruthy();
expect(scope.errorMsg).toEqual(null); expect(scope.errorMsg).toEqual(null);
scope.process(); scope.process();
expect(scope.processed).toBeTruthy(); expect(scope.processed).toBeTruthy();
@@ -65,26 +65,33 @@ describe('Import Controller', function() {
it('catches an invalid backup', function() { it('catches an invalid backup', function() {
var importData = __json__['fixtures/valid-backup']; var importData = __json__['fixtures/valid-backup'];
scope.importJSON = 'null'; scope.importString = 'null';
scope.validateJson(); scope.validateImport();
expect(scope.jsonValid).toBeFalsy(); expect(scope.importValid).toBeFalsy();
expect(scope.errorMsg).toEqual('Must be an object or array!'); expect(scope.errorMsg).toEqual('Must be an object or array!');
scope.importJSON = '{ "builds": "Should not be a string" }'; scope.importString = '{ "builds": "Should not be a string" }';
scope.validateJson(); scope.validateImport();
expect(scope.jsonValid).toBeFalsy(); expect(scope.importValid).toBeFalsy();
expect(scope.errorMsg).toEqual('builds must be an object!'); expect(scope.errorMsg).toEqual('builds must be an object!');
scope.importJSON = angular.toJson(importData).replace('anaconda', 'invalid_ship'); scope.importString = angular.toJson(importData).replace('anaconda', 'invalid_ship');
scope.validateJson(); scope.validateImport();
expect(scope.jsonValid).toBeFalsy(); expect(scope.importValid).toBeFalsy();
expect(scope.errorMsg).toEqual('"invalid_ship" is not a valid Ship Id!'); expect(scope.errorMsg).toEqual('"invalid_ship" is not a valid Ship Id!');
scope.importJSON = angular.toJson(importData).replace('Dream', ''); scope.importString = angular.toJson(importData).replace('Dream', '');
scope.validateJson(); scope.validateImport();
expect(scope.jsonValid).toBeFalsy(); expect(scope.importValid).toBeFalsy();
expect(scope.errorMsg).toEqual('Imperial Clipper build "" must be a string at least 3 characters long!'); expect(scope.errorMsg).toEqual('Imperial Clipper build "" must be a string at least 3 characters long!');
invalidImportData = angular.copy(importData);
invalidImportData.builds.asp = null; // Remove Asp Miner build used in comparison
scope.importString = angular.toJson(invalidImportData);
scope.validateImport();
expect(scope.importValid).toBeFalsy();
expect(scope.errorMsg).toEqual('asp build "Miner" data is missing!');
}); });
}); });
@@ -93,9 +100,9 @@ describe('Import Controller', function() {
it('imports a valid build', function() { it('imports a valid build', function() {
var importData = __json__['fixtures/anaconda-test-detailed-export']; var importData = __json__['fixtures/anaconda-test-detailed-export'];
scope.importJSON = angular.toJson(importData); scope.importString = angular.toJson(importData);
scope.validateJson(); scope.validateImport();
expect(scope.jsonValid).toBeTruthy(); expect(scope.importValid).toBeTruthy();
expect(scope.errorMsg).toEqual(null); expect(scope.errorMsg).toEqual(null);
scope.process(); scope.process();
expect(scope.processed).toBeTruthy(); expect(scope.processed).toBeTruthy();
@@ -107,9 +114,9 @@ describe('Import Controller', function() {
it('catches an invalid build', function() { it('catches an invalid build', function() {
var importData = __json__['fixtures/anaconda-test-detailed-export']; var importData = __json__['fixtures/anaconda-test-detailed-export'];
scope.importJSON = angular.toJson(importData).replace('components', 'comps'); scope.importString = angular.toJson(importData).replace('components', 'comps');
scope.validateJson(); scope.validateImport();
expect(scope.jsonValid).toBeFalsy(); expect(scope.importValid).toBeFalsy();
expect(scope.errorMsg).toEqual('Anaconda Build "Test": Invalid data'); expect(scope.errorMsg).toEqual('Anaconda Build "Test": Invalid data');
}); });
@@ -120,9 +127,9 @@ describe('Import Controller', function() {
it('imports all builds', function() { it('imports all builds', function() {
var importData = __json__['fixtures/valid-detailed-export']; var importData = __json__['fixtures/valid-detailed-export'];
var expectedBuilds = __json__['fixtures/expected-builds']; var expectedBuilds = __json__['fixtures/expected-builds'];
scope.importJSON = angular.toJson(importData); scope.importString = angular.toJson(importData);
scope.validateJson(); scope.validateImport();
expect(scope.jsonValid).toBeTruthy(); expect(scope.importValid).toBeTruthy();
expect(scope.errorMsg).toEqual(null); expect(scope.errorMsg).toEqual(null);
scope.process(); scope.process();
expect(scope.processed).toBeTruthy(); expect(scope.processed).toBeTruthy();
@@ -137,4 +144,39 @@ describe('Import Controller', function() {
}); });
describe('Import E:D Shipyard Builds', function() {
it('imports a valid builds', function() {
var imports = __json__['fixtures/ed-shipyard-import-valid'];
for (var i = 0; i < imports.length; i++ ) {
scope.importString = imports[i].buildText;
scope.validateImport();
expect(scope.importValid).toBeTruthy();
expect(scope.errorMsg).toEqual(null, 'Build #' + i + ': ' + imports[i].buildName);
if (scope.importValid) { // No point in carrying out other assertions
scope.process();
expect(scope.processed).toBeTruthy();
scope.import();
var allBuilds = angular.fromJson(localStorage.getItem('builds'));
var shipBuilds = allBuilds ? allBuilds[imports[i].shipId] : null;
var build = shipBuilds ? shipBuilds[imports[i].buildName] : null;
expect(build).toEqual(imports[i].buildCode, 'Build #' + i + ': ' + imports[i].buildName);
}
}
});
it('catches invalid builds', function() {
var imports = __json__['fixtures/ed-shipyard-import-invalid'];
for (var i = 0; i < imports.length; i++ ) {
scope.importString = imports[i].buildText;
scope.validateImport();
expect(scope.importValid).toBeFalsy();
expect(scope.errorMsg).toEqual(imports[i].errorMsg);
}
});
});
}); });