Compare commits

...

31 Commits
1.2.0 ... 1.4.1

Author SHA1 Message Date
Colin McLeod
c98a73c6a8 Bumping version to 1.4.1 2015-08-15 16:35:30 -07:00
Colin McLeod
0116523c63 Merge pull request #75 from sf302/master
Additional refinement to "Optimize Mass" preset
2015-08-14 22:36:17 -07:00
Kevin Chang
c1afa7c385 Additional refinement to "Optimize Mass" preset 2015-08-14 19:16:49 -07:00
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
Colin McLeod
f0bdcd5557 Bumping version to 1.3.0 2015-07-20 13:42:38 -07:00
Colin McLeod
b1ee0e44f3 Linting fixes, update unit test 2015-07-20 13:42:21 -07:00
Colin McLeod
c96e6afbd7 Power Distributor required for Boost. Resolves #17 2015-07-20 13:37:03 -07:00
Colin McLeod
77334341ea Armour value improved by bulkhead 2015-07-20 00:55:51 -07:00
48 changed files with 701 additions and 517 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.
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

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) {
$scope.jsonValid = false;
$scope.importJSON = null;
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.importValid = false;
$scope.importString = null;
$scope.errorMsg = null;
$scope.canEdit = true;
$scope.builds = $stateParams.obj || null;
$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) {
var shipData = Ships[shipId];
@@ -52,7 +66,15 @@ angular.module('app').controller('ImportController', ['lodash', '$rootScope', '$
throw 'builds must be an object!';
}
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;
}
if (importData.discounts instanceof Array && importData.discounts.length == 2) {
@@ -75,40 +97,134 @@ angular.module('app').controller('ImportController', ['lodash', '$rootScope', '$
$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;
$scope.jsonValid = false;
var importString = $scope.importString.trim();
$scope.importValid = false;
$scope.errorMsg = null;
$scope.builds = $scope.discounts = $scope.comparisons = $scope.insurance = null;
if (!$scope.importJSON) { return; }
if (!importString) { return; }
try {
importData = angular.fromJson($scope.importJSON);
} catch (e) {
$scope.errorMsg = 'Cannot Parse JSON!';
return;
}
if (textBuildRegex.test(importString)) { // E:D Shipyard build text
importTextBuild(importString);
} else { // JSON Build data
importData = angular.fromJson($scope.importString);
if (!importData || typeof importData != 'object') {
$scope.errorMsg = 'Must be an object or array!';
return;
}
if (!importData || typeof importData != 'object') {
throw 'Must be an object or array!';
}
try {
if (importData instanceof Array) { // Must be detailed export json
importDetailedArray(importData);
} else if (importData.ship && importData.name) { // Using JSON from a single ship build export
importDetailedArray([importData]); // Convert to array with singleobject
} else { // Using Backup JSON
importBackup(importData);
if (importData instanceof Array) { // Must be detailed export json
importDetailedArray(importData);
} else if (importData.ship && importData.name) { // Using JSON from a single ship build export
importDetailedArray([importData]); // Convert to array with singleobject
} else { // Using Backup JSON
importBackup(importData);
}
}
} catch (e) {
$scope.errorMsg = e;
$scope.errorMsg = (typeof e == 'string') ? e : 'Cannot Parse the data!';
return;
}
$scope.jsonValid = true;
$scope.importValid = true;
};
$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) {
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 == 'empty') {
@@ -175,16 +182,46 @@ 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
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.hardpoints.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.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 th = $scope.availCS.lightestThruster(ship.ladenMass); // Find lightest Thruster that still works for the ship at max mass
ship.use(ship.common[1], th, Components.common(1, th));
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));
};
@@ -371,6 +408,14 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
$scope.costTab = tab;
};
$scope.ppWarning = function(pp) {
return pp.pGen < ship.powerRetracted;
};
$scope.pdWarning = function(pd) {
return pd.enginecapacity < ship.boostEnergy;
};
// Hide any open menu/slot/etc if the background is clicked
$scope.$on('close', function() {
$scope.selectedSlot = null;

View File

@@ -2,7 +2,7 @@ angular.module('app').directive('componentSelect', function() {
// Generting the HTML in this manner is MUCH faster than using an angular template.
function appendGroup(list, opts, cid, mass) {
function appendGroup(list, opts, cid, mass, checkWarning) {
var prevClass = null, prevRating = null;
for (var i = 0; i < opts.length; i++) {
var o = opts[i];
@@ -18,13 +18,17 @@ angular.module('app').directive('componentSelect', function() {
list.push(' active');
}
list.push((o.maxmass && mass > o.maxmass) ? ' disabled"' : '" cpid="', id, '">');
if (o.mode) {
list.push('<svg cpid="', id, '" class="icon lg"><use cpid="', id, '" xlink:href="#mount-', o.mode, '"></use></svg> ');
if (checkWarning && checkWarning(opts[i])) {
list.push(' warning');
}
list.push('<span cpid="', id, '">', o.class, o.rating);
list.push((o.maxmass && (mass + (o.mass ? o.mass : 0)) > o.maxmass) ? ' disabled"' : '" cpid="', id, '">');
if (o.mode) {
list.push('<svg class="icon lg"><use xlink:href="#mount-', o.mode, '"></use></svg> ');
}
list.push('<span>', o.class, o.rating);
if (o.missile) {
list.push('/' + o.missile);
@@ -46,8 +50,9 @@ angular.module('app').directive('componentSelect', function() {
scope: {
opts: '=', // Component Options object
groups: '=', // Groups of Component Options
mass: '=', // Current ship unladen mass
s: '=' // Current Slot
mass: '=', // Current ship mass
s: '=', // Current Slot
warning: '=' // Check warning function
},
link: function(scope, element) {
var list = [];
@@ -55,7 +60,7 @@ angular.module('app').directive('componentSelect', function() {
var component = scope.s.c; // Slot's Current Component (may be null/undefined)
var opts = scope.opts;
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) {
// At present time slots with grouped options (Hardpoints and Internal) can be empty
@@ -64,12 +69,12 @@ angular.module('app').directive('componentSelect', function() {
var grp = groups[g];
var grpCode = grp[Object.keys(grp)[0]].grp; // Nasty operation to get the grp property of the first/any single component
list.push('<div id="', grpCode, '" class="select-group">', g, '</div><ul>');
appendGroup(list, grp, cid, mass);
appendGroup(list, grp, cid, mass, scope.warning);
list.push('</ul>');
}
} else {
list.push('<ul>');
appendGroup(list, opts, cid, mass);
appendGroup(list, opts, cid, mass, scope.warning);
list.push('</ul>');
}

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) {
this.mass = mass;
this.common = {};
@@ -36,32 +43,90 @@ angular.module('shipyard').factory('ComponentSet', ['lodash', function(_) {
for (var g in components.internal) {
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) {
if (!this.hpClass[c]) {
var o = this.hpClass[c] = {};
for (var key in this.hardpoints) {
var data = filter(this.hardpoints[key], c, c ? 1 : 0, this.mass);
if (data.length) { // If group is not empty
o[key] = data;
}
ComponentSet.prototype.lightestPowerDist = function(boostEnergy) {
var pds = this.common[4];
var pd = pds[0];
for (var i = 1; i < pds.length; i++) {
if (pds[i].mass < pd.mass && pds[i].enginecapacity >= boostEnergy) {
pd = pds[i];
}
}
return this.hpClass[c];
return pd.class + pd.rating;
};
ComponentSet.prototype.getInts = function(c) {
if (!this.intClass[c]) {
var o = this.intClass[c] = {};
for (var key in this.internal) {
var data = filter(this.internal[key], c, 0, this.mass);
if (data.length) { // If group is not empty
o[key] = data;
}
ComponentSet.prototype.lightestThruster = function(ladenMass) {
var ths = this.common[1];
var th = ths[0];
for (var i = 1; i < ths.length; i++) {
if (ths[i].mass < th.mass && ths[i].maxmass >= ladenMass) {
th = ths[i];
}
}
return this.intClass[c];
return th.class + th.rating;
};
ComponentSet.prototype.lightestPowerPlant = function(powerUsed) {
var pps = this.common[0];
var pp = null;
for (var i = 0; i < pps.length; i++) {
if (pp == null || (pps[i].mass < pp.mass && pps[i].pGen >= powerUsed)) {
pp = pps[i];
}
}
return pp.class + (pp.rating != 'D' ? 'A' : 'D'); // Use A rated if C,E
};
return ComponentSet;

View File

@@ -1,4 +1,4 @@
angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', 'calcJumpRange', 'calcTotalRange', 'lodash', function(Components, calcShieldStrength, calcJumpRange, calcTotalRange, _) {
angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', 'calcJumpRange', 'calcTotalRange', 'lodash', 'ArmourMultiplier', function(Components, calcShieldStrength, calcJumpRange, calcTotalRange, _, ArmourMultiplier) {
/**
* Returns the power usage type of a slot and it's particular component
@@ -36,7 +36,11 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
var slotGroup = slots[slotType];
var group = this[slotType] = []; // Initialize Slot group (Common, Hardpoints, Internal)
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
@@ -84,14 +88,14 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
this.cargoCapacity = 0;
this.ladenMass = 0;
this.armourAdded = 0;
this.armourMultiplier = 1;
this.shieldMultiplier = 1;
this.totalCost = this.c.incCost ? this.c.discountedCost : 0;
this.unladenMass = this.hullMass;
this.armour = this.baseArmour;
this.totalDps = 0;
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.enabled = enabled ? enabled[0] * 1 : true;
@@ -112,7 +116,10 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
common[i].type = 'SYS';
common[i].c = common[i].id = null; // Resetting 'old' component if there was one
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
@@ -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].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);
}
}
@@ -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].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);
}
}
// Update aggragated stats
this.updatePower();
this.updateJumpStats();
this.updateShieldStrength();
if (comps) {
this.updatePower();
this.updateJumpStats();
this.updateShieldStrength();
}
};
Ship.prototype.useBulkhead = function(index, preventUpdate) {
@@ -158,6 +167,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
this.bulkheads.id = index;
this.bulkheads.c = Components.bulkheads(this.id, index);
this.bulkheads.discountedCost = this.bulkheads.c.cost * this.componentCostMultiplier;
this.armourMultiplier = ArmourMultiplier[index];
this.updateStats(this.bulkheads, this.bulkheads.c, oldBulkhead, preventUpdate);
};
@@ -359,7 +369,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
}
this.ladenMass = this.unladenMass + this.cargoCapacity + this.fuelCapacity;
this.armour = this.armourAdded + this.baseArmour;
this.armour = this.armourAdded + Math.round(this.baseArmour * this.armourMultiplier);
if (!preventUpdate) {
if (powerChange) {

View File

@@ -10,6 +10,13 @@ angular.module('shipyard', ['ngLodash'])
// Create 'angularized' references to DB.This will aid testing
.constant('ShipsDB', DB.ships)
.constant('ComponentsDB', DB.components)
.value('ArmourMultiplier', [
1, // Lightweight
1.4, // Reinforced
1.945, // Military
1.945, // Mirrored
1.945 // Reactive
])
.value('commonArray', [
'Power Plant',
'Thrusters',

View File

@@ -33,15 +33,25 @@ angular.module('shipyard').service('Components', ['lodash', 'ComponentsDB', 'Shi
};
this.findInternalId = function(groupName, clss, rating, name) {
var group = C.internal[groupName];
var groups = {};
if (!group) {
throw 'Invalid internal group: ' + groupName;
if (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++) {
if (group[i].class == clss && group[i].rating == rating && ((!name && !group[i].name) || group[i].name == name)) {
return group[i].id;
for (var g in groups) {
var group = groups[g];
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) {
var group = C.hardpoints[groupName];
var groups = {};
if (!group) {
throw 'Invalid hardpoint group: ' + groupName;
if (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++) {
if (group[i].class == clss && group[i].rating == rating && group[i].mode == mode
&& ((!name && !group[i].name) || group[i].name == name)
&& ((!missile && !group[i].missile) || group[i].missile == missile)
) {
return group[i].id;
for (var g in groups) {
var group = groups[g];
for (var i = 0, l = group.length; i < l; i++) {
if (group[i].class == clss && group[i].rating == rating && group[i].mode == mode
&& ((!name && !group[i].name) || group[i].name == name)
&& ((!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) {
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 'error';
@import 'sortable';
@import 'loader';
html, body {
height: 100%;

View File

@@ -66,3 +66,7 @@
color: @warning-disabled;
fill: @warning-disabled;
}
.bg-warning-disabled {
background-color: @warning-disabled;
}

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;
}
.largePhone({
.smallTablet({
width: 60%;
});
.medPhone({
.largePhone({
width: 100%;
});
}
.largePhone({
.smallTablet({
float: left;
clear: left;
width: 100%;

View File

@@ -77,18 +77,10 @@ select {
stroke: @primary-disabled;
&:hover {
border-color: @primary;
color: @primary;
stroke: @primary;
}
&.disabled {
cursor: not-allowed;
color: @disabled;
stroke: @disabled;
}
&.active {
color: @secondary;
stroke: @secondary;
}
}
.lc, .c {
@@ -96,15 +88,28 @@ select {
padding: 0.1em 0.2em;
margin: 0.3em;
&:hover {
border:1px solid @primary;
&.warning {
border-color: @warning-disabled;
color: @warning-disabled;
stroke: @warning-disabled;
&:hover {
border-color: @warning;
color: @warning;
stroke: @warning;
}
}
&.disabled {
border:1px solid @disabled;
cursor: not-allowed;
border-color: @disabled;
color: @disabled;
stroke: @disabled;
}
&.active {
border:1px solid @secondary;
border-color: @secondary;
color: @secondary;
stroke: @secondary;
}
}

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.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.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.range">Range {{c.c.range}} <u>km</u></div>
<div class="l" ng-if="c.c.time">Time: {{$r.fTime(c.c.time)}}</div>
@@ -19,4 +19,4 @@
<div class="l" ng-if="c.c.rangeLS === null"><svg class="icon"><use xlink:href="#infinite"></use></svg> <u>LS</u></div>
<div class="l" ng-if="c.c.rangeRating">Range: {{c.c.rangeRating}}</div>
<div class="l" ng-if="c.c.armouradd">+{{c.c.armouradd}} <u>Armour</u></div>
</div>
</div>

View File

@@ -1,7 +1,7 @@
<h2>Import</h2>
<div ng-show="!processed">
<textarea class="cb json" ng-model="importJSON" ng-change="validateJson()" placeholder="Paste JSON Here"></textarea>
<button class="l" ng-click="process()" ng-disabled="!jsonValid">Proceed</button>
<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="!importValid">Proceed</button>
<div class="l warning" style="margin-left:3em;">{{errorMsg}}</div>
</div>
@@ -34,7 +34,7 @@
</table>
<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>
<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">
<svg class="icon lg"><use xlink:href="#switch"></use></svg><span class="button-lbl">Reset</span>
</button>
<button ng-click="stripBuild()">
<svg class="icon lg"><use xlink:href="#feather"></use></svg><span class="button-lbl">Low-Weight</span>
<button ng-click="aRatedBuild()">
<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 ng-click="exportBuild($event)" ng-disabled="!buildName">
<svg class="icon lg"><use xlink:href="#download"></use></svg><span class="button-lbl">Export</span>
@@ -31,8 +34,8 @@
<tr class="main">
<th rowspan="2">Size</th>
<th rowspan="2">Agility</th>
<th rowspan="2">Speed</th>
<th rowspan="2">Boost</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 || th.c.maxmass < ship.ladenMass)}">Boost</th>
<th rowspan="2">DPS</th>
<th rowspan="2">Armour</th>
<th rowspan="2">Shields</th>
@@ -59,10 +62,22 @@
<tr>
<td ng-bind="SZ[ship.class]"></td>
<td>{{ship.agility}}/10</td>
<td>{{fRound(ship.speed)}} <u>m/s</u></td>
<td>{{fRound(ship.boost)}} <u>m/s</u></td>
<td>
<span ng-if="th.c.maxmass >= ship.ladenMass">{{fRound(ship.speed)}} <u>m/s</u></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>{{fRound(ship.totalDps)}}</td>
<td>{{ship.armour}} <span ng-if="ship.armourAdded">({{ship.baseArmour}} + {{ship.armourAdded}})</span></td>
<td>
{{ship.armour}}
<span ng-if="ship.armourAdded || ship.armourMultiplier > 1">(<span ng-if="ship.armourMultiplier > 1">{{fRPct(ship.armourMultiplier)}}</span>
<span ng-if="ship.armourAdded">+ {{ship.armourAdded}}</span>)</span>
</td>
<td>{{fRound(ship.shieldStrength)}} <u>MJ</u> <span ng-if="ship.shieldMultiplier > 1 && ship.shieldStrength > 0">({{fRPct(ship.shieldMultiplier)}})</span></td>
<td>{{ship.hullMass}} <u>T</u></td>
<td>{{fRound(ship.unladenMass)}} <u>T</u></td>
@@ -101,7 +116,7 @@
</div>
</div>
<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="l">{{pp.id}} Power Plant</div>
<div class="r">{{pp.c.mass}} <u>T</u></div>
@@ -109,10 +124,10 @@
<div class="l">Efficiency: {{pp.c.eff}}</div>
<div class="l">Power: {{pp.c.pGen}} <u>MW</u></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 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="l">{{th.id}} Thrusters</div>
<div class="r">{{th.c.mass}} <u>T</u></div>
@@ -144,7 +159,7 @@
<div component-select class="select" s="ls" opts="availCS.common[3]" ng-if="selectedSlot==ls" ng-click="select('c',ls,$event)"></div>
</div>
<div class="slot" ng-click="selectSlot($event, pd)" ng-class="{selected: selectedSlot==pd}">
<div class="details">
<div class="details" ng-class="{warning: pd.c.enginecapacity < ship.boostEnergy}">
<div class="sz">{{::pd.maxClass}}</div>
<div class="l">{{pd.id}} Power Distributor</div>
<div class="r">{{pd.c.mass}} <u>T</u></div>
@@ -153,7 +168,7 @@
<div class="l">SYS: {{pd.c.systemcapacity}} <u>MJ</u> / {{pd.c.systemrecharge}} <u>MW</u></div>
<div class="l">ENG: {{pd.c.enginecapacity}} <u>MJ</u> / {{pd.c.enginerecharge}} <u>MW</u></div>
</div>
<div component-select class="select" s="pd" opts="availCS.common[4]" ng-if="selectedSlot==pd" ng-click="select('c',pd,$event)"></div>
<div component-select class="select" s="pd" warning="pdWarning" opts="availCS.common[4]" ng-if="selectedSlot==pd" ng-click="select('c',pd,$event)"></div>
</div>
<div class="slot" ng-click="selectSlot($event, ss)" ng-class="{selected: selectedSlot==ss}">
<div class="details">
@@ -180,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 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 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>

View File

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

View File

@@ -1,317 +1,37 @@
{
"8E": {
"grp": "pp",
"class": 8,
"rating": "E",
"cost": 2007241,
"mass": 160,
"pGen": 24,
"eff": "F"
},
"8D": {
"grp": "pp",
"class": 8,
"rating": "D",
"cost": 6021722,
"mass": 64,
"pGen": 27,
"eff": "D"
},
"8C": {
"grp": "pp",
"class": 8,
"rating": "C",
"cost": 18065165,
"mass": 80,
"pGen": 30,
"eff": "C"
},
"8B": {
"grp": "pp",
"class": 8,
"rating": "B",
"cost": 54195495,
"mass": 128,
"pGen": 33,
"eff": "C"
},
"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"
}
"8E":{ "grp": "pp", "class": 8, "rating": "E", "cost": 2007241, "mass": 160, "pGen": 24, "eff": "F" },
"8D":{ "grp": "pp", "class": 8, "rating": "D", "cost": 6021722, "mass": 64, "pGen": 27, "eff": "D" },
"8C":{ "grp": "pp", "class": 8, "rating": "C", "cost": 18065165, "mass": 80, "pGen": 30, "eff": "C" },
"8B":{ "grp": "pp", "class": 8, "rating": "B", "cost": 54195495, "mass": 128, "pGen": 33, "eff": "C" },
"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": [
{ "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": "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": "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": "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": "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": "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": "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": "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": [
{ "id": "65", "grp": "scb", "class": 8, "rating": "E", "cost": 697584, "mass": 160, "power": 1.44, "cells": 5, "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": "63", "grp": "scb", "class": 8, "rating": "C", "cost": 4359903, "mass": 160, "power": 2.4, "cells": 4, "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": "61", "grp": "scb", "class": 8, "rating": "A", "cost": 27249391, "mass": 160, "power": 3.36, "cells": 4, "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": "5v", "grp": "scb", "class": 7, "rating": "D", "cost": 622843, "mass": 32, "power": 1.66, "cells": 3, "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": "5t", "grp": "scb", "class": 7, "rating": "B", "cost": 3892770, "mass": 128, "power": 2.48, "cells": 5, "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": "5r", "grp": "scb", "class": 6, "rating": "E", "cost": 88978, "mass": 40, "power": 1.06, "cells": 5, "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": "5p", "grp": "scb", "class": 6, "rating": "C", "cost": 556110, "mass": 40, "power": 1.77, "cells": 4, "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": "5n", "grp": "scb", "class": 6, "rating": "A", "cost": 3475688, "mass": 40, "power": 2.48, "cells": 4, "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": "5l", "grp": "scb", "class": 5, "rating": "D", "cost": 79444, "mass": 8, "power": 1.2, "cells": 2, "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": "5j", "grp": "scb", "class": 5, "rating": "B", "cost": 496527, "mass": 32, "power": 1.8, "cells": 4, "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": "5h", "grp": "scb", "class": 4, "rating": "E", "cost": 11349, "mass": 10, "power": 0.74, "cells": 4, "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": "5f", "grp": "scb", "class": 4, "rating": "C", "cost": 70932, "mass": 10, "power": 1.23, "cells": 3, "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": "5d", "grp": "scb", "class": 4, "rating": "A", "cost": 443328, "mass": 10, "power": 1.72, "cells": 3, "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": "5b", "grp": "scb", "class": 3, "rating": "D", "cost": 10133, "mass": 2, "power": 0.82, "cells": 2, "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": "59", "grp": "scb", "class": 3, "rating": "B", "cost": 63333, "mass": 8, "power": 1.22, "cells": 4, "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": "57", "grp": "scb", "class": 2, "rating": "E", "cost": 1448, "mass": 2.5, "power": 0.5, "cells": 4, "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": "55", "grp": "scb", "class": 2, "rating": "C", "cost": 9048, "mass": 2.5, "power": 0.84, "cells": 3, "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": "53", "grp": "scb", "class": 2, "rating": "A", "cost": 56547, "mass": 2.5, "power": 1.18, "cells": 3, "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": "51", "grp": "scb", "class": 1, "rating": "D", "cost": 1293, "mass": 0.5, "power": 0.55, "cells": 1, "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": "4v", "grp": "scb", "class": 1, "rating": "B", "cost": 8078, "mass": 2, "power": 0.83, "cells": 3, "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": "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": 4, "rechargeRating": "C", "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": 6, "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": 6, "rechargeRating": "D", "recharge": 97 },
{ "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": 5, "rechargeRating": "B", "recharge": 163 },
{ "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": 5, "rechargeRating": "A", "recharge": 230 },
{ "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": 4, "rechargeRating": "C", "recharge": 120 },
{ "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": 6, "rechargeRating": "B", "recharge": 176 },
{ "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": 5, "rechargeRating": "D", "recharge": 82 },
{ "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": 4, "rechargeRating": "C", "recharge": 135 },
{ "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": 4, "rechargeRating": "B", "recharge": 189 },
{ "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": 3, "rechargeRating": "D", "recharge": 94 },
{ "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": 5, "rechargeRating": "C", "recharge": 140 },
{ "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": 5, "rechargeRating": "D", "recharge": 61 },
{ "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": 4, "rechargeRating": "D", "recharge": 100 },
{ "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": 4, "rechargeRating": "C", "recharge": 138 },
{ "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": 3, "rechargeRating": "D", "recharge": 61 },
{ "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": 5, "rechargeRating": "D", "recharge": 92 },
{ "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": 4, "rechargeRating": "E", "recharge": 31 },
{ "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": 3, "rechargeRating": "D", "recharge": 51 },
{ "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": 3, "rechargeRating": "D", "recharge": 72 }
]
}
}

View File

@@ -7,6 +7,7 @@
"hullCost": 39993,
"speed": 220,
"boost": 320,
"boostEnergy": 9,
"agility": 8,
"baseShieldStrength": 60,
"baseArmour": 162,

View File

@@ -7,6 +7,7 @@
"hullCost": 141889932,
"speed": 180,
"boost": 240,
"boostEnergy": 29,
"agility": 2,
"baseShieldStrength": 350,
"baseArmour": 945,

View File

@@ -7,6 +7,7 @@
"hullCost": 6135658,
"speed": 250,
"boost": 340,
"boostEnergy": 14,
"agility": 6,
"baseShieldStrength": 140,
"baseArmour": 378,

View File

@@ -7,6 +7,7 @@
"hullCost": 235787,
"speed": 280,
"boost": 400,
"boostEnergy": 11,
"agility": 6,
"baseShieldStrength": 80,
"baseArmour": 216,

View File

@@ -7,6 +7,7 @@
"hullCost": 461341,
"speed": 283,
"boost": 384,
"boostEnergy": 11,
"agility": 8,
"baseShieldStrength": 118,
"baseArmour": 216,

View File

@@ -7,6 +7,7 @@
"hullCost": 1635691,
"speed": 242,
"boost": 316,
"boostEnergy": 14,
"agility": 5,
"baseShieldStrength": 146,
"baseArmour": 270,

View File

@@ -7,6 +7,7 @@
"hullCost": 10446,
"speed": 240,
"boost": 350,
"boostEnergy": 9,
"agility": 10,
"baseShieldStrength": 60,
"baseArmour": 72,

View File

@@ -7,6 +7,7 @@
"hullCost": 18969990,
"speed": 180,
"boost": 300,
"boostEnergy": 21,
"agility": 2,
"baseShieldStrength": 200,
"baseArmour": 540,

View File

@@ -7,6 +7,7 @@
"hullCost": 51232230,
"speed": 260,
"boost": 350,
"boostEnergy": 21,
"agility": 6,
"baseShieldStrength": 300,
"baseArmour": 405,

View File

@@ -8,6 +8,7 @@
"speed": 200,
"boost": 300,
"agility": 6,
"boostEnergy": 7,
"baseShieldStrength": 50,
"baseArmour": 90,
"hullMass": 14,

View File

@@ -7,6 +7,7 @@
"hullCost": 21077784,
"speed": 300,
"boost": 380,
"boostEnergy": 21,
"agility": 2,
"baseShieldStrength": 180,
"baseArmour": 486,

View File

@@ -7,6 +7,7 @@
"hullCost": 2481552,
"speed": 277,
"boost": 380,
"boostEnergy": 11,
"agility": 6,
"baseShieldStrength": 197,
"baseArmour": 144,

View File

@@ -7,6 +7,7 @@
"hullCost": 47798079,
"speed": 300,
"boost": 380,
"boostEnergy": 17,
"agility": 2,
"baseShieldStrength": 220,
"baseArmour": 396,
@@ -34,8 +35,8 @@
0
],
"internal": [
6,
5,
{ "class": 6, "eligible": { "Cargo Rack": 1, "Hull Reinforcement Package": 1 } },
{ "class": 5, "eligible": { "Cargo Rack": 1, "Hull Reinforcement Package": 1 } },
5,
5,
4,

View File

@@ -7,6 +7,7 @@
"hullCost": 55171395,
"speed": 230,
"boost": 280,
"boostEnergy": 24,
"agility": 6,
"baseShieldStrength": 260,
"baseArmour": 468,

View File

@@ -7,6 +7,7 @@
"hullCost": 12887,
"speed": 220,
"boost": 320,
"boostEnergy": 7,
"agility": 8,
"baseShieldStrength": 40,
"baseArmour": 108,

View File

@@ -7,6 +7,7 @@
"hullCost": 865782,
"speed": 220,
"boost": 350,
"boostEnergy": 11,
"agility": 3,
"baseShieldStrength": 90,
"baseArmour": 162,

View File

@@ -7,6 +7,7 @@
"hullCost": 16881511,
"speed": 180,
"boost": 300,
"boostEnergy": 11,
"agility": 2,
"baseShieldStrength": 120,
"baseArmour": 216,

View File

@@ -7,6 +7,7 @@
"hullCost": 73255168,
"speed": 130,
"boost": 200,
"boostEnergy": 21,
"agility": 0,
"baseShieldStrength": 240,
"baseArmour": 432,

View File

@@ -7,6 +7,7 @@
"hullCost": 95893,
"speed": 320,
"boost": 400,
"boostEnergy": 11,
"agility": 6,
"baseShieldStrength": 105,
"baseArmour": 126,

View File

@@ -7,6 +7,7 @@
"hullCost": 4689629,
"speed": 210,
"boost": 340,
"boostEnergy": 17,
"agility": 9,
"baseShieldStrength": 240,
"baseArmour": 288,

View File

@@ -51,7 +51,8 @@ gulp.task('js-lint', function() {
'space-before-function-paren': [2, 'never'],
'space-before-blocks': [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']
}))

View File

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

View File

@@ -188,6 +188,7 @@
"hullCost": 141889932,
"speed": 180,
"boost": 240,
"boostEnergy": 29,
"agility": 2,
"baseShieldStrength": 350,
"baseArmour": 945,
@@ -198,11 +199,12 @@
"fuelCapacity": 32,
"cargoCapacity": 128,
"ladenMass": 1339.2,
"armour": 2078,
"armourAdded": 240,
"armourMultiplier": 1.95,
"shieldMultiplier": 1.4,
"totalCost": 882362049,
"unladenMass": 1179.2,
"armour": 1185,
"totalDps": 29,
"powerAvailable": 36,
"powerRetracted": 23.93,

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() {
var importData = __json__['fixtures/valid-backup'];
scope.importJSON = angular.toJson(importData);
scope.validateJson();
expect(scope.jsonValid).toBeTruthy();
scope.importString = angular.toJson(importData);
scope.validateImport();
expect(scope.importValid).toBeTruthy();
expect(scope.errorMsg).toEqual(null);
scope.process();
expect(scope.processed).toBeTruthy();
@@ -52,9 +52,9 @@ describe('Import Controller', function() {
it('imports an old valid backup', function() {
var importData = __json__['fixtures/old-valid-export'];
scope.importJSON = angular.toJson(importData);
scope.validateJson();
expect(scope.jsonValid).toBeTruthy();
scope.importString = angular.toJson(importData);
scope.validateImport();
expect(scope.importValid).toBeTruthy();
expect(scope.errorMsg).toEqual(null);
scope.process();
expect(scope.processed).toBeTruthy();
@@ -65,26 +65,33 @@ describe('Import Controller', function() {
it('catches an invalid backup', function() {
var importData = __json__['fixtures/valid-backup'];
scope.importJSON = 'null';
scope.validateJson();
expect(scope.jsonValid).toBeFalsy();
scope.importString = 'null';
scope.validateImport();
expect(scope.importValid).toBeFalsy();
expect(scope.errorMsg).toEqual('Must be an object or array!');
scope.importJSON = '{ "builds": "Should not be a string" }';
scope.validateJson();
expect(scope.jsonValid).toBeFalsy();
scope.importString = '{ "builds": "Should not be a string" }';
scope.validateImport();
expect(scope.importValid).toBeFalsy();
expect(scope.errorMsg).toEqual('builds must be an object!');
scope.importJSON = angular.toJson(importData).replace('anaconda', 'invalid_ship');
scope.validateJson();
expect(scope.jsonValid).toBeFalsy();
scope.importString = angular.toJson(importData).replace('anaconda', 'invalid_ship');
scope.validateImport();
expect(scope.importValid).toBeFalsy();
expect(scope.errorMsg).toEqual('"invalid_ship" is not a valid Ship Id!');
scope.importJSON = angular.toJson(importData).replace('Dream', '');
scope.validateJson();
expect(scope.jsonValid).toBeFalsy();
scope.importString = angular.toJson(importData).replace('Dream', '');
scope.validateImport();
expect(scope.importValid).toBeFalsy();
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() {
var importData = __json__['fixtures/anaconda-test-detailed-export'];
scope.importJSON = angular.toJson(importData);
scope.validateJson();
expect(scope.jsonValid).toBeTruthy();
scope.importString = angular.toJson(importData);
scope.validateImport();
expect(scope.importValid).toBeTruthy();
expect(scope.errorMsg).toEqual(null);
scope.process();
expect(scope.processed).toBeTruthy();
@@ -107,9 +114,9 @@ describe('Import Controller', function() {
it('catches an invalid build', function() {
var importData = __json__['fixtures/anaconda-test-detailed-export'];
scope.importJSON = angular.toJson(importData).replace('components', 'comps');
scope.validateJson();
expect(scope.jsonValid).toBeFalsy();
scope.importString = angular.toJson(importData).replace('components', 'comps');
scope.validateImport();
expect(scope.importValid).toBeFalsy();
expect(scope.errorMsg).toEqual('Anaconda Build "Test": Invalid data');
});
@@ -120,9 +127,9 @@ describe('Import Controller', function() {
it('imports all builds', function() {
var importData = __json__['fixtures/valid-detailed-export'];
var expectedBuilds = __json__['fixtures/expected-builds'];
scope.importJSON = angular.toJson(importData);
scope.validateJson();
expect(scope.jsonValid).toBeTruthy();
scope.importString = angular.toJson(importData);
scope.validateImport();
expect(scope.importValid).toBeTruthy();
expect(scope.errorMsg).toEqual(null);
scope.process();
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);
}
});
});
});