Compare commits

...

45 Commits
1.4.1 ... 1.5.5

Author SHA1 Message Date
Colin McLeod
6e65d67f14 Bumping version to 1.5.5 2015-09-05 23:01:19 -07:00
Colin McLeod
a127e2f5a5 Merge pull request #85 from gbiobob/master
Corrections for French localisation
2015-09-05 11:01:13 -07:00
gbiobob
9154b7f38c Corrections for French localisation 2015-09-05 11:13:26 +02:00
Colin McLeod
c2d8cad249 Bumping version to 1.5.4 2015-09-04 17:31:08 -07:00
Colin McLeod
e9ffe5baec Fix to Russian language name 2015-09-04 17:30:41 -07:00
Colin McLeod
fffa325e83 Corrections to French translation 2015-09-04 12:45:14 -07:00
Colin McLeod
ed14ed2bb7 Bumping version to 1.5.2 2015-09-03 12:19:59 -07:00
Colin McLeod
7c9e020b88 Minor french translation correction 2015-09-03 12:10:21 -07:00
Colin McLeod
d711d1519b Correct base shield strength on fed assault and gun ship 2015-09-03 12:07:50 -07:00
Colin McLeod
3361f7e435 Another russian translation correction 2015-09-03 12:01:13 -07:00
Colin McLeod
3a79f99f77 Correct Russian translations 2015-09-03 11:58:29 -07:00
Colin McLeod
ff25b55c1f Lint fix 2015-09-03 00:22:50 -07:00
Colin McLeod
ae6f6b0da1 Bumping version to 1.5.1 2015-09-03 00:21:23 -07:00
Colin McLeod
6dc714371d Update Shield Strength calculation 2015-09-03 00:19:58 -07:00
Colin McLeod
5762b133e5 Fix Orca first interal compartment restrictions 2015-09-03 00:19:30 -07:00
Colin McLeod
50741657a5 Merge pull request #82 from michaelhue/beta-ships
Include v1.4-beta ships
2015-09-02 16:31:23 -07:00
michaelhue
ff9a38f23f Include v1.4-beta ships.
Adds the Federal Assault Ship, Federal Gunship and Imperial Eagle to the ship selection.

Note: Values for `boostEnergy` and `masslock` attributes are currently based on their parent ships. Should be updated as soon as data is available.
2015-09-02 17:48:42 +02:00
Colin McLeod
3b11b31e7c Add all english terms due to angular translate workaround 2015-09-02 01:50:49 -07:00
Colin McLeod
44e5dfb4d4 Lint fix 2015-09-01 20:55:07 -07:00
Colin McLeod
30ea10830c Fix to slider reset event 2015-09-01 20:47:43 -07:00
Colin McLeod
eb0f611d78 Fix slider event 2015-09-01 20:38:28 -07:00
Colin McLeod
96ef192738 Fix max fuel label 2015-09-01 20:38:13 -07:00
Colin McLeod
1970616443 Add cargo hatch priority and status to be included in detailed export 2015-09-01 18:36:57 -07:00
Colin McLeod
aac4c9a872 Fix to slider events 2015-09-01 18:05:35 -07:00
Colin McLeod
aebfb62ac4 Correct Select DOM generation 2015-09-01 18:02:17 -07:00
Colin McLeod
9748043466 Update sensors 2015-09-01 17:59:33 -07:00
Colin McLeod
b6f98e741b UI tweak 2015-09-01 02:53:15 -07:00
Colin McLeod
b513cca4b5 Minor code clean up 2015-09-01 02:49:03 -07:00
Colin McLeod
65f53a3fa4 Fixes for language and scaling 2015-09-01 02:20:05 -07:00
Colin McLeod
bf217e7fdd Updating DE, FR and RU 2015-08-31 17:41:45 -07:00
Colin McLeod
09e646ee95 Power warning when at 100% 2015-08-31 17:39:04 -07:00
Colin McLeod
ab18228131 Further improvement to size ratio 2015-08-31 17:39:04 -07:00
Colin McLeod
164e9f5c8a Another improvement to font-size adjustments 2015-08-31 17:37:04 -07:00
Colin McLeod
faa8759851 More changes for font size adjustment 2015-08-31 17:35:14 -07:00
Colin McLeod
c2a84606a1 Inital commit for font size adjust slider 2015-08-31 17:34:28 -07:00
Colin McLeod
42d51b7612 Merge pull request #81 from Marginal/priorities
Include module status and priority in JSON import and export.
2015-08-31 17:29:54 -07:00
Jonathan Harris
38dc4319c0 Test import/export of module state and priority. 2015-08-30 06:52:44 +01:00
Jonathan Harris
fda966be02 Pass tests. 2015-08-30 06:05:12 +01:00
Jonathan Harris
bf47a81dc1 More cosmetic issues. 2015-08-30 05:29:25 +01:00
Jonathan Harris
eef4e06f29 Fix cosmetic issues. 2015-08-30 05:26:22 +01:00
Jonathan Harris
2d2c2b75e3 Include module status and priority in JSON import and export. 2015-08-30 05:02:59 +01:00
Colin McLeod
0066e7fd40 Bumping version to 1.5.0 2015-08-23 12:40:34 -07:00
Colin McLeod
d596723b7b Major refactor for language support, EN, DE, ES, FR, RU 2015-08-23 12:38:17 -07:00
Colin McLeod
c7269423ed Handle select edge-case 2015-08-20 14:09:07 -07:00
Colin McLeod
ee60e4d043 Fix Diamondback Explorer MLF 2015-08-20 14:08:46 -07:00
95 changed files with 3040 additions and 916 deletions

View File

@@ -57,13 +57,13 @@
<body style="background-color:#000;">
<div style="height: 0; width: 0; overflow:hidden"><%= svgContent %></div>
<shipyard-header></shipyard-header>
<div id="main" ui-view ng-click="bgClicked($event)"></div>
<div id="main" ui-view ng-click="bgClicked($event)" ng-style="{'font-size': sizeRatio + 'em'}"></div>
<div ui-view="modal" ng-click="bgClicked($event)"></div>
<footer>
<div class="right">
<a href="https://github.com/cmmcleod/coriolis/releases/" target="_blank" title="Coriolis Github Project">Version <%= version %> - <%= date %></a>
<div class="right cap">
<a href="https://github.com/cmmcleod/coriolis/releases/" target="_blank" title="Coriolis Github Project"><span translate="version"></span> <%= version %> - <%= date %></a>
</div>
<div style="max-width:50%" class="l">
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.

View File

@@ -1,6 +1,6 @@
angular.module('app', ['ui.router', 'ct.ui.router.extras.sticky', 'ui.sortable', 'shipyard', 'ngLodash', 'app.templates'])
.run(['$rootScope', '$location', '$window', '$document', '$state', 'commonArray', 'shipSize', 'hardPointClass', 'GroupMap', 'Persist', 'Discounts',
function($rootScope, $location, $window, $doc, $state, CArr, sz, hpc, GroupMap, Persist, Discounts) {
angular.module('app', ['ui.router', 'ct.ui.router.extras.sticky', 'ui.sortable', 'shipyard', 'ngLodash', 'app.templates', 'pascalprecht.translate'])
.run(['$rootScope', '$location', '$window', '$document', '$state', '$translate', 'localeFormat', 'Persist', 'Discounts', 'Languages',
function($rootScope, $location, $window, $doc, $state, $translate, localeFormat, Persist, Discounts, Languages) {
// App is running as a standalone web app on tablet/mobile
var isStandAlone;
// This was causing issues on Windows phones ($window.external was causing Angular js to throw an exception). Backup is to try this and set isStandAlone to false if this fails.
@@ -21,7 +21,6 @@ function($rootScope, $location, $window, $doc, $state, CArr, sz, hpc, GroupMap,
$rootScope.prevState = { name: from.name, params: fromParams };
if (to.url) { // Only track states that have a URL
if ($window.ga) {
ga('send', 'pageview', { page: $location.path() });
}
@@ -33,46 +32,51 @@ function($rootScope, $location, $window, $doc, $state, CArr, sz, hpc, GroupMap,
}
});
$rootScope.language = {
opts: Languages,
current: Languages[Persist.getLangCode()] ? Persist.getLangCode() : 'en'
};
$rootScope.localeFormat = d3.locale(localeFormat.get($rootScope.language.current));
updateNumberFormat();
// Global Reference variables
$rootScope.CArr = CArr;
$rootScope.SZ = sz;
$rootScope.HPC = hpc;
$rootScope.GMAP = GroupMap;
$rootScope.insurance = { opts: [{ name: 'Standard', pct: 0.05 }, { name: 'Alpha', pct: 0.025 }, { name: 'Beta', pct: 0.0375 }] };
$rootScope. discounts = { opts: Discounts };
$rootScope.STATUS = ['', 'DISABLED', 'OFF', 'ON'];
$rootScope.insurance = { opts: [{ name: 'standard', pct: 0.05 }, { name: 'alpha', pct: 0.025 }, { name: 'beta', pct: 0.0375 }] };
$rootScope.discounts = { opts: Discounts };
$rootScope.STATUS = ['', 'disabled', 'off', 'on'];
$rootScope.STATUS_CLASS = ['', 'disabled', 'warning', 'secondary-disabled'];
$rootScope.sizeRatio = Persist.getSizeRatio();
$rootScope.title = 'Coriolis';
$rootScope.changeLanguage = function() {
$translate.use($rootScope.language.current);
$rootScope.localeFormat = d3.locale(localeFormat.get($rootScope.language.current));
updateNumberFormat();
$rootScope.$broadcast('languageChanged', $rootScope.language.current);
};
// Formatters
$rootScope.fRPct = d3.format('%');
$rootScope.fTime = function(d) { return Math.floor(d / 60) + ':' + ('00' + Math.floor(d % 60)).substr(-2, 2); };
function updateNumberFormat() {
var locale = $rootScope.localeFormat;
var fGen = $rootScope.fGen = locale.numberFormat('n');
$rootScope.fCrd = locale.numberFormat(',.0f');
$rootScope.fPwr = locale.numberFormat(',.2f');
$rootScope.fRound = function(d) { return fGen(d3.round(d, 2)); };
$rootScope.fPct = locale.numberFormat('.2%');
$rootScope.f1Pct = locale.numberFormat('.1%');
}
/**
* Returns the name of the component mounted in the specified slot
* @param {Object} slot The slot object
* @return {String} The component name
*/
$rootScope.cName = function(slot) {
return slot.c ? slot.c.name ? slot.c.name : GroupMap[slot.c.grp] : null;
return $translate.instant(slot.c ? slot.c.name ? slot.c.name : slot.c.grp : null);
};
// Formatters
$rootScope.fCrd = d3.format(',.0f');
$rootScope.fPwr = d3.format(',.2f');
$rootScope.fRound = function(d) { return d3.round(d, 2); };
$rootScope.fRound4 = function(d) { return d3.round(d, 4); };
$rootScope.fPct = d3.format('.2%');
$rootScope.f1Pct = d3.format('.1%');
$rootScope.fRPct = d3.format('%');
$rootScope.fTime = function(d) { return Math.floor(d / 60) + ':' + ('00' + Math.floor(d % 60)).substr(-2, 2); };
if (isStandAlone) {
var state = Persist.getState();
// If a previous state has been stored, load that state
if (state && state.name && state.params) {
$state.go(state.name, state.params, { location: 'replace' });
} else {
$state.go('shipyard', null, { location: 'replace' }); // Default to home page
}
}
// Global Event Listeners
$doc.bind('keyup', function(e) {
if (e.keyCode == 27) { // Escape Key
@@ -98,4 +102,14 @@ function($rootScope, $location, $window, $doc, $state, CArr, sz, hpc, GroupMap,
}, false);
}
if (isStandAlone) {
var state = Persist.getState();
// If a previous state has been stored, load that state
if (state && state.name && state.params) {
$state.go(state.name, state.params, { location: 'replace' });
} else {
$state.go('shipyard', null, { location: 'replace' }); // Default to home page
}
}
}]);

View File

@@ -4,6 +4,7 @@
angular.module('app').config(['$provide', '$stateProvider', '$urlRouterProvider', '$locationProvider', 'ShipsDB', function($provide, $stateProvider, $urlRouterProvider, $locationProvider, ships) {
// Use HTML5 push and replace state if possible
$locationProvider.html5Mode({ enabled: true, requireBase: false });
/**
* Set up all states and their routes.
*/

View File

@@ -1,4 +1,4 @@
angular.module('app').controller('ComparisonController', ['lodash', '$rootScope', '$filter', '$scope', '$state', '$stateParams', 'Utils', 'ShipFacets', 'ShipsDB', 'Ship', 'Persist', 'Serializer', function(_, $rootScope, $filter, $scope, $state, $stateParams, Utils, ShipFacets, Ships, Ship, Persist, Serializer) {
angular.module('app').controller('ComparisonController', ['lodash', '$rootScope', '$filter', '$scope', '$state', '$stateParams', '$translate', 'Utils', 'ShipFacets', 'ShipsDB', 'Ship', 'Persist', 'Serializer', function(_, $rootScope, $filter, $scope, $state, $stateParams, $translate, Utils, ShipFacets, Ships, Ship, Persist, Serializer) {
$rootScope.title = 'Coriolis - Compare';
$scope.predicate = 'name'; // Sort by ship name as default
$scope.desc = false;
@@ -155,7 +155,7 @@ angular.module('app').controller('ComparisonController', ['lodash', '$rootScope'
return 'Error - ' + err.statusText;
}
);
$state.go('modal.export', { promise: promise, title: 'Forum BBCode' });
$state.go('modal.export', { promise: promise, title: $translate.instant('FORUM') + ' BBCode' });
};
/**
@@ -184,6 +184,10 @@ angular.module('app').controller('ComparisonController', ['lodash', '$rootScope'
$scope.showBuilds = false;
});
$scope.$on('languageChanged', function() {
$scope.tblUpdate = !$scope.tblUpdate; // Simple switch to trigger the table to update
});
/* Initialization */
if ($scope.compareMode) {
if ($scope.name == 'all') {
@@ -226,7 +230,7 @@ angular.module('app').controller('ComparisonController', ['lodash', '$rootScope'
}
}
// Replace fmt with actual format function as defined in rootScope and retain original index
facets.forEach(function(f, i) { f.fmt = $rootScope[f.fmt]; f.index = i; });
facets.forEach(function(f, i) { f.index = i; });
// Remove default facets, mark as active, and add them back in selected order
_.pullAt(facets, defaultFacets).forEach(function(f) { f.active = true; facets.unshift(f); });
$scope.builds = $filter('orderBy')($scope.builds, $scope.predicate, $scope.desc);

View File

@@ -1,4 +1,4 @@
angular.module('app').controller('OutfitController', ['$window', '$rootScope', '$scope', '$state', '$stateParams', 'ShipsDB', 'Ship', 'Components', 'Serializer', 'Persist', 'calcTotalRange', 'calcSpeed', function($window, $rootScope, $scope, $state, $p, Ships, Ship, Components, Serializer, Persist, calcTotalRange, calcSpeed) {
angular.module('app').controller('OutfitController', ['$window', '$rootScope', '$scope', '$state', '$stateParams', '$translate', 'ShipsDB', 'Ship', 'Components', 'Serializer', 'Persist', 'calcTotalRange', 'calcSpeed', function($window, $rootScope, $scope, $state, $p, $translate, Ships, Ship, Components, Serializer, Persist, calcTotalRange, calcSpeed) {
var win = angular.element($window); // Angularized window object for event triggering
var data = Ships[$p.shipId]; // Retrieve the basic ship properties, slots and defaults
var ship = new Ship($p.shipId, data.properties, data.slots); // Create a new Ship instance
@@ -65,11 +65,11 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
$scope.jrChart = {
labels: {
xAxis: {
title: 'Cargo',
title: 'cargo',
unit: 'T'
},
yAxis: {
title: 'Jump Range',
title: 'jump range',
unit: 'LY'
}
}
@@ -87,11 +87,11 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
$scope.trChart = {
labels: {
xAxis: {
title: 'Cargo',
title: 'cargo',
unit: 'T'
},
yAxis: {
title: 'Total Range',
title: 'total range',
unit: 'LY'
}
}
@@ -110,11 +110,11 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
$scope.speedChart = {
labels: {
xAxis: {
title: 'Cargo',
title: 'cargo',
unit: 'T'
},
yAxis: {
title: 'Speed',
title: 'speed',
unit: 'm/s'
}
}
@@ -151,7 +151,9 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
while (elem && elem !== e.currentTarget && !elem.getAttribute('cpid')) {
elem = elem.parentElement;
}
id = elem.getAttribute('cpid');
if (elem) {
id = elem.getAttribute('cpid');
}
}
if (id) {
@@ -256,8 +258,8 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
if ($scope.buildName) {
$state.go('modal.export', {
title: $scope.buildName + ' Export',
description: 'A detailed JSON export of your build for use in other sites and tools',
title: $scope.buildName + ' ' + $translate.instant('export'),
description: $translate.instant('PHRASE_EXPORT_DESC'),
data: Serializer.toDetailedBuild($scope.buildName, ship, $scope.code || Serializer.fromShip(ship))
});
}
@@ -364,15 +366,14 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
function updateRetrofitCosts() {
var costs = $scope.retrofitList = [];
var cName = $rootScope.cName;
var total = 0, i, l, item;
if (ship.bulkheads.id != retrofitShip.bulkheads.id) {
item = {
buyClassRating: ship.bulkheads.c.class + ship.bulkheads.c.rating,
buyName: cName(ship.bulkheads),
buyName: ship.bulkheads.c.name,
sellClassRating: retrofitShip.bulkheads.c.class + retrofitShip.bulkheads.c.rating,
sellName: cName(retrofitShip.bulkheads),
sellName: retrofitShip.bulkheads.c.name,
netCost: ship.bulkheads.discountedCost - retrofitShip.bulkheads.discountedCost
};
costs.push(item);
@@ -386,12 +387,12 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
if (slotGroup[i].id != retroSlotGroup[i].id) {
item = { netCost: 0 };
if (slotGroup[i].id) {
item.buyName = cName(slotGroup[i]);
item.buyName = slotGroup[i].c.name || slotGroup[i].c.grp;
item.buyClassRating = slotGroup[i].c.class + slotGroup[i].c.rating;
item.netCost = slotGroup[i].discountedCost;
}
if (retroSlotGroup[i].id) {
item.sellName = cName(retroSlotGroup[i]);
item.sellName = retroSlotGroup[i].c.name || retroSlotGroup[i].c.grp;
item.sellClassRating = retroSlotGroup[i].c.class + retroSlotGroup[i].c.rating;
item.netCost -= retroSlotGroup[i].discountedCost;
}
@@ -421,6 +422,11 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
$scope.selectedSlot = null;
});
// Hide any open menu/slot/etc if the background is clicked
$scope.$on('languageChanged', function() {
$scope.selectedSlot = null;
});
// Hide any open menu/slot/etc if the background is clicked
$scope.$on('discountChange', function() {
ship.applyDiscounts($rootScope.discounts.ship, $rootScope.discounts.components);

View File

@@ -1,4 +1,4 @@
angular.module('app').directive('areaChart', ['$window', function($window) {
angular.module('app').directive('areaChart', ['$window', '$translate', function($window, $translate) {
return {
restrict: 'A',
scope: {
@@ -47,18 +47,19 @@ angular.module('app').directive('areaChart', ['$window', function($window) {
// Create Y Axis SVG Elements
var yTxt = vis.append('g').attr('class', 'y axis')
.append('text')
.attr('class', 'cap')
.attr('transform', 'rotate(-90)')
.attr('y', -50)
.attr('dy', '.1em')
.style('text-anchor', 'middle')
.text(labels.yAxis.title + ' (' + labels.yAxis.unit + ')');
.text($translate.instant(labels.yAxis.title) + ' (' + $translate.instant(labels.yAxis.unit) + ')');
// Create X Axis SVG Elements
var xLbl = vis.append('g').attr('class', 'x axis');
var xTxt = xLbl.append('text')
.attr('y', 30)
.attr('dy', '.1em')
.style('text-anchor', 'middle')
.text(labels.xAxis.title + ' (' + labels.xAxis.unit + ')');
.text($translate.instant(labels.xAxis.title) + ' (' + $translate.instant(labels.xAxis.unit) + ')');
// Create and Add tooltip
var tip = vis.append('g').style('display', 'none');
@@ -150,8 +151,8 @@ angular.module('app').directive('areaChart', ['$window', function($window) {
tip.attr('transform', 'translate(' + x(x0) + ',' + y(y0) + ')');
tip.selectAll('rect').attr('x', flip ? '-5.75em' : '0.5em').style('text-anchor', flip ? 'end' : 'start');
tip.selectAll('text.label').attr('x', flip ? '-2em' : '1em').style('text-anchor', flip ? 'end' : 'start');
tip.select('text.label.x').text(fmtLong(x0) + ' ' + labels.xAxis.unit);
tip.select('text.label.y').text(fmtLong(y0) + ' ' + labels.yAxis.unit);
tip.select('text.label.x').text(fmtLong(x0) + ' ' + $translate.instant(labels.xAxis.unit));
tip.select('text.label.y').text(fmtLong(y0) + ' ' + $translate.instant(labels.yAxis.unit));
}
scope.$on('$destroy', function() {

View File

@@ -1,4 +1,4 @@
angular.module('app').directive('barChart', ['$window', function($window) {
angular.module('app').directive('barChart', ['$window', '$translate', '$rootScope', function($window, $translate, $rootScope) {
function bName(build) {
return build.buildName + '\n' + build.name;
@@ -11,7 +11,7 @@ angular.module('app').directive('barChart', ['$window', function($window) {
for (var i = 0; i < words.length; i++) {
var tspan = el.append('tspan').text(words[i]);
if (i > 0) {
tspan.attr('x', -9).attr('dy', 12);
tspan.attr('x', -9).attr('dy', '1em');
}
}
}
@@ -25,15 +25,15 @@ angular.module('app').directive('barChart', ['$window', function($window) {
link: function(scope, element) {
var color = d3.scale.ordinal().range([ '#7b6888', '#6b486b', '#3182bd', '#a05d56', '#d0743c']),
labels = scope.facet.lbls,
fmt = scope.facet.fmt,
fmt = null,
unit = null,
properties = scope.facet.props,
unit = scope.facet.unit,
margin = { top: 10, right: 20, bottom: 35, left: 150 },
margin = { top: 10, right: 20, bottom: 40, left: 150 },
y0 = d3.scale.ordinal(),
y1 = d3.scale.ordinal(),
x = d3.scale.linear(),
yAxis = d3.svg.axis().scale(y0).outerTickSize(0).orient('left'),
xAxis = d3.svg.axis().scale(x).ticks(5).outerTickSize(0).orient('bottom').tickFormat(d3.format('.2s'));
xAxis = d3.svg.axis().scale(x).ticks(5).outerTickSize(0).orient('bottom');
// Create chart
var svg = d3.select(element[0]).append('svg');
@@ -43,7 +43,7 @@ angular.module('app').directive('barChart', ['$window', function($window) {
var tip = d3.tip()
.attr('class', 'd3-tip')
.html(function(property, propertyIndex) {
return (labels ? (labels[propertyIndex] + ': ') : '') + fmt(property.value) + ' ' + unit;
return (labels ? ($translate.instant(labels[propertyIndex]) + ': ') : '') + fmt(property.value) + ' ' + unit;
});
vis.call(tip);
@@ -53,25 +53,19 @@ angular.module('app').directive('barChart', ['$window', function($window) {
vis.selectAll('g.y.axis g text').each(insertLinebreaks);
// Create X Axis SVG Elements
var xAxisLbl = vis.append('g')
.attr('class', 'x axis')
.attr('class', 'x axis cap')
.append('text')
.attr('y', 30)
.attr('y', 33)
.attr('dy', '.1em')
.style('text-anchor', 'middle')
.text(scope.facet.title + (unit ? (' (' + unit + ')') : ''));
.style('text-anchor', 'middle');
/**
* Watch for changes in the comparison array (ships added/removed, sorting)
*/
scope.$watchCollection('data', render);
angular.element($window).bind('orientationchange resize render', render);
updateFormats();
function render() {
var data = scope.data,
width = element[0].offsetWidth,
w = width - margin.left - margin.right,
height = 45 + (30 * data.length),
height = 45 + (30 * data.length * $rootScope.sizeRatio),
h = height - margin.top - margin.bottom,
maxVal = d3.max(data, function(d) { return d3.max(properties, function(p) {return d[p]; }); });
@@ -117,6 +111,17 @@ angular.module('app').directive('barChart', ['$window', function($window) {
}
function updateFormats() {
fmt = $rootScope[scope.facet.fmt];
unit = $translate.instant(scope.facet.unit);
xAxisLbl.text($translate.instant(scope.facet.title) + (unit ? (' (' + $translate.instant(unit) + ')') : ''));
xAxis.tickFormat($rootScope.localeFormat.numberFormat('.2s'));
render();
}
angular.element($window).bind('orientationchange resize render', render);
scope.$watchCollection('data', render); // Watch for changes in the comparison array
scope.$on('languageChanged', updateFormats);
scope.$on('$destroy', function() {
angular.element($window).unbind('orientationchange resize render', render);
tip.destroy(); // Remove the tooltip from the DOM

View File

@@ -1,7 +1,7 @@
angular.module('app').directive('comparisonTable', ['$state', function($state) {
angular.module('app').directive('comparisonTable', ['$state', '$translate', '$rootScope', function($state, $translate, $rootScope) {
function tblHeader(facets) {
var r1 = ['<tr class="main"><th rowspan="2" class="prop" prop="name">Ship</th><th rowspan="2" class="prop" prop="buildName">Build</th>'];
var r1 = ['<tr class="main"><th rowspan="2" class="prop" prop="name">', $translate.instant('SHIP'), '</th><th rowspan="2" class="prop" prop="buildName">', $translate.instant('BUILD'), '</th>'];
var r2 = [];
for (var i = 0, l = facets.length; i < l; i++) {
if (facets[i].active) {
@@ -14,11 +14,11 @@ angular.module('app').directive('comparisonTable', ['$state', function($state) {
r1.push(' prop="', p[0], '" class="prop"');
} else {
for (var j = 0; j < pl; j++) {
r2.push('<th prop="', p[j], '" class="prop ', j === 0 ? 'lft' : '', '">', f.lbls[j], '</th>');
r2.push('<th prop="', p[j], '" class="prop ', j === 0 ? 'lft' : '', '">', $translate.instant(f.lbls[j]), '</th>');
}
}
r1.push('>', f.title, '</th>');
r1.push('>', $translate.instant(f.title), '</th>');
}
}
r1.push('</tr><tr>');
@@ -46,7 +46,7 @@ angular.module('app').directive('comparisonTable', ['$state', function($state) {
var f = facets[j];
var p = f.props;
for (var k = 0, pl = p.length; k < pl; k++) {
body.push('<td>', f.fmt(b[p[k]]), '<u> ', f.unit, '</u></td>');
body.push('<td>', $rootScope[f.fmt](b[p[k]]), '<u> ', $translate.instant(f.unit), '</u></td>');
}
}
}

View File

@@ -1,4 +1,4 @@
angular.module('app').directive('componentSelect', function() {
angular.module('app').directive('componentSelect', ['$translate', function($translate) {
// Generting the HTML in this manner is MUCH faster than using an angular template.
@@ -22,7 +22,7 @@ angular.module('app').directive('componentSelect', function() {
list.push(' warning');
}
list.push((o.maxmass && (mass + (o.mass ? o.mass : 0)) > o.maxmass) ? ' disabled"' : '" cpid="', id, '">');
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> ');
@@ -36,7 +36,7 @@ angular.module('app').directive('componentSelect', function() {
if (o.name) {
list.push(' ' + o.name);
list.push(' ' + $translate.instant(o.name));
}
list.push('</span></li>');
@@ -64,11 +64,11 @@ angular.module('app').directive('componentSelect', function() {
if (groups) {
// At present time slots with grouped options (Hardpoints and Internal) can be empty
list.push('<div class="empty-c" cpid="empty">EMPTY</div>');
list.push('<div class="empty-c upp" cpid="empty">', $translate.instant('empty'), '</div>');
for (var g in groups) {
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>');
list.push('<div id="', grpCode, '" class="select-group cap">', $translate.instant(g), '</div><ul>');
appendGroup(list, grp, cid, mass, scope.warning);
list.push('</ul>');
}
@@ -87,4 +87,4 @@ angular.module('app').directive('componentSelect', function() {
}
}
};
});
}]);

View File

@@ -1,4 +1,5 @@
angular.module('app').directive('shipyardHeader', ['lodash', '$rootScope', '$state', 'Persist', 'Serializer', 'ShipsDB', function(_, $rootScope, $state, Persist, Serializer, ships) {
angular.module('app').directive('shipyardHeader', ['lodash', '$window', '$rootScope', '$state', 'Persist', 'Serializer', 'ShipsDB', function(_, $window, $rootScope, $state, Persist, Serializer, ships) {
return {
restrict: 'E',
@@ -12,6 +13,7 @@ angular.module('app').directive('shipyardHeader', ['lodash', '$rootScope', '$sta
scope.allComparisons = Persist.comparisons;
scope.bs = Persist.state;
var win = angular.element($window); // Angularized window object for event triggering
var insIndex = _.findIndex($rootScope.insurance.opts, 'name', Persist.getInsurance());
var savedDiscounts = Persist.getDiscount() || [1, 1];
$rootScope.insurance.current = $rootScope.insurance.opts[insIndex != -1 ? insIndex : 0];
@@ -38,9 +40,9 @@ angular.module('app').directive('shipyardHeader', ['lodash', '$rootScope', '$sta
e.stopPropagation();
scope.openedMenu = null;
$state.go('modal.export', {
title: 'Backup',
title: 'backup',
data: Persist.getAll(),
description: 'Backup of all Coriolis data to save or transfer to another browser/device'
description: 'PHRASE_BACKUP_DESC'
});
};
@@ -49,9 +51,9 @@ angular.module('app').directive('shipyardHeader', ['lodash', '$rootScope', '$sta
e.stopPropagation();
scope.openedMenu = null;
$state.go('modal.export', {
title: 'Detailed Export',
title: 'detailed export',
data: Serializer.toDetailedExport(scope.allBuilds),
description: 'Detailed export of all builds for use with other tools and sites'
description: 'PHRASE_EXPORT_DESC'
});
};
@@ -79,6 +81,22 @@ angular.module('app').directive('shipyardHeader', ['lodash', '$rootScope', '$sta
scope.openedMenu = null;
});
scope.textSizeChange = function(size) {
if (size != $rootScope.sizeRatio) {
$rootScope.sizeRatio = size;
document.getElementById('main').style.fontSize = size + 'em';
Persist.setSizeRatio(size);
win.triggerHandler('resize');
}
};
scope.resetTextSize = function() {
if ($rootScope.sizeRatio != 1) {
scope.textSizeChange(1);
scope.$broadcast('reset', 1);
}
};
scope.$watchCollection('allBuilds', function() {
scope.buildsList = Object.keys(scope.allBuilds).sort();
});

View File

@@ -1,4 +1,4 @@
angular.module('app').directive('lineChart', ['$window', function($window) {
angular.module('app').directive('lineChart', ['$window', '$translate', '$rootScope', function($window, $translate, $rootScope) {
return {
restrict: 'A',
scope: {
@@ -12,8 +12,7 @@ angular.module('app').directive('lineChart', ['$window', function($window) {
config = scope.config,
labels = config.labels,
margin = { top: 15, right: 15, bottom: 35, left: 60 },
fmt = d3.format('.3r'),
fmtLong = d3.format('.2f'),
fmtLong = null,
func = seriesConfig.func,
drag = d3.behavior.drag(),
dragging = false,
@@ -21,8 +20,8 @@ angular.module('app').directive('lineChart', ['$window', function($window) {
x = d3.scale.linear(),
y = d3.scale.linear(),
// Define Axes
xAxis = d3.svg.axis().scale(x).outerTickSize(0).orient('bottom').tickFormat(d3.format('.2r')),
yAxis = d3.svg.axis().scale(y).ticks(6).outerTickSize(0).orient('left').tickFormat(fmt),
xAxis = d3.svg.axis().scale(x).outerTickSize(0).orient('bottom'),
yAxis = d3.svg.axis().scale(y).ticks(6).outerTickSize(0).orient('left'),
data = [];
// Create chart
@@ -36,21 +35,23 @@ angular.module('app').directive('lineChart', ['$window', function($window) {
// Create Y Axis SVG Elements
var yTxt = vis.append('g').attr('class', 'y axis')
.append('text')
.attr('class', 'cap')
.attr('transform', 'rotate(-90)')
.attr('y', -50)
.attr('dy', '.1em')
.style('text-anchor', 'middle')
.text(labels.yAxis.title + ' (' + labels.yAxis.unit + ')');
.text($translate.instant(labels.yAxis.title) + ' (' + $translate.instant(labels.yAxis.unit) + ')');
// Create X Axis SVG Elements
var xLbl = vis.append('g').attr('class', 'x axis');
var xTxt = xLbl.append('text')
.attr('class', 'cap')
.attr('y', 30)
.attr('dy', '.1em')
.style('text-anchor', 'middle')
.text(labels.xAxis.title + ' (' + labels.xAxis.unit + ')');
.text($translate.instant(labels.xAxis.title) + ' (' + $translate.instant(labels.xAxis.unit) + ')');
// Create and Add tooltip
var tipWidth = (Math.max(labels.yAxis.unit.length, labels.xAxis.unit.length) * 1.25) + 2;
var tipWidth = (Math.max(labels.yAxis.unit.length, labels.xAxis.unit.length) * 1.25) + 2.5;
var tips = vis.append('g').style('display', 'none');
var background = vis.append('rect') // Background to capture hover/drag
@@ -72,15 +73,11 @@ angular.module('app').directive('lineChart', ['$window', function($window) {
})
.on('drag', moveTip);
/**
* Watch for changes in the series data (mass changes, etc)
*/
scope.$watchCollection('series', render);
angular.element($window).bind('orientationchange resize render', render);
updateFormats();
function render() {
var width = element[0].parentElement.offsetWidth,
height = width * 0.5,
height = width * 0.5 * $rootScope.sizeRatio,
xMax = seriesConfig.xMax,
xMin = seriesConfig.xMin,
yMax = seriesConfig.yMax,
@@ -177,10 +174,22 @@ angular.module('app').directive('lineChart', ['$window', function($window) {
var tip = tips.selectAll('g.tooltip').attr('transform', function(d, i) { return 'translate(' + x(x0) + ',' + y(series ? y0[series[i]] : y0) + ')'; });
tip.selectAll('rect').attr('x', flip ? (-tipWidth - 0.5) + 'em' : '0.5em').style('text-anchor', flip ? 'end' : 'start');
tip.selectAll('text.label').attr('x', flip ? '-1em' : '1em').style('text-anchor', flip ? 'end' : 'start');
tip.selectAll('text.label.x').text(fmtLong(x0) + ' ' + labels.xAxis.unit);
tips.selectAll('text.label.y').text(function(d, i) { return fmtLong(series ? y0[series[i]] : y0) + ' ' + labels.yAxis.unit; });
tip.selectAll('text.label.x').text(fmtLong(x0) + ' ' + $translate.instant(labels.xAxis.unit));
tips.selectAll('text.label.y').text(function(d, i) { return fmtLong(series ? y0[series[i]] : y0) + ' ' + $translate.instant(labels.yAxis.unit); });
}
function updateFormats() {
xTxt.text($translate.instant(labels.xAxis.title) + ' (' + $translate.instant(labels.xAxis.unit) + ')');
yTxt.text($translate.instant(labels.yAxis.title) + ' (' + $translate.instant(labels.yAxis.unit) + ')');
fmtLong = $rootScope.localeFormat.numberFormat('.2f');
xAxis.tickFormat($rootScope.localeFormat.numberFormat('.2r'));
yAxis.tickFormat($rootScope.localeFormat.numberFormat('.3r'));
render();
}
angular.element($window).bind('orientationchange resize render', render);
scope.$watchCollection('series', render); // Watch for changes in the series data
scope.$on('languageChanged', updateFormats);
scope.$on('$destroy', function() {
angular.element($window).unbind('orientationchange resize render', render);
});

View File

@@ -1,4 +1,4 @@
angular.module('app').directive('powerBands', ['$window', function($window) {
angular.module('app').directive('powerBands', ['$window', '$translate', '$rootScope', function($window, $translate, $rootScope) {
return {
restrict: 'A',
scope: {
@@ -6,60 +6,88 @@ angular.module('app').directive('powerBands', ['$window', function($window) {
available: '='
},
link: function(scope, element) {
var margin = { top: 20, right: 130, bottom: 20, left: 40 },
barHeight = 20,
bands = null,
innerHeight = (barHeight * 2) + 3,
height = innerHeight + margin.top + margin.bottom + 1,
var bands = null,
available = 0,
maxBand,
maxPwr,
deployedSum = 0,
retractedSum = 0,
retBandsSelected = false,
depBandsSelected = false,
wattScale = d3.scale.linear(),
pctScale = d3.scale.linear().domain([0, 1]),
wattFmt = d3.format('.2f'),
pctFmt = d3.format('.1%'),
wattAxis = d3.svg.axis().scale(wattScale).outerTickSize(0).orient('top').tickFormat(d3.format('.2r')),
pctAxis = d3.svg.axis().scale(pctScale).outerTickSize(0).orient('bottom').tickFormat(d3.format('%')),
wattFmt,
pctFmt,
wattAxis = d3.svg.axis().scale(wattScale).outerTickSize(0).orient('top'),
pctAxis = d3.svg.axis().scale(pctScale).outerTickSize(0).orient('bottom'),
// Create chart
svg = d3.select(element[0]).append('svg'),
vis = svg.append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'),
vis = svg.append('g'),
deployed = vis.append('g').attr('class', 'power-band'),
retracted = vis.append('g').attr('class', 'power-band');
svg.on('contextmenu', function() {
if (!d3.event.shiftKey) {
d3.event.preventDefault();
for (var i = 0, l = bands.length; i < l; i++) {
bands[i].retSelected = false;
bands[i].depSelected = false;
}
render();
});
dataChange();
}
});
// Create Y Axis SVG Elements
vis.append('g').attr('class', 'watt axis');
vis.append('g').attr('class', 'pct axis');
vis.append('text').attr('x', -35).attr('y', 16).attr('class', 'primary').text('RET');
vis.append('text').attr('x', -35).attr('y', barHeight + 18).attr('class', 'primary').text('DEP');
var retText = vis.append('text').attr('x', -3).style('text-anchor', 'end').attr('dy', '0.5em').attr('class', 'primary upp');
var depText = vis.append('text').attr('x', -3).style('text-anchor', 'end').attr('dy', '0.5em').attr('class', 'primary upp');
var retLbl = vis.append('text').attr('dy', '0.5em');
var depLbl = vis.append('text').attr('dy', '0.5em');
var retLbl = vis.append('text').attr('y', 16);
var depLbl = vis.append('text').attr('y', barHeight + 18);
updateFormats(true);
// Watch for changes to data and events
scope.$watchCollection('available', render);
angular.element($window).bind('orientationchange resize pwrchange', render);
function dataChange() {
bands = scope.bands;
available = scope.available;
maxBand = bands[bands.length - 1];
deployedSum = 0;
retractedSum = 0;
retBandsSelected = false;
depBandsSelected = false;
maxPwr = Math.max(available, maxBand.retractedSum, maxBand.deployedSum);
for (var b = 0, l = bands.length; b < l; b++) {
if (bands[b].retSelected) {
retractedSum += bands[b].retracted + bands[b].retOnly;
retBandsSelected = true;
}
if (bands[b].depSelected) {
deployedSum += bands[b].deployed + bands[b].retracted;
depBandsSelected = true;
}
}
render();
}
function render() {
bands = scope.bands;
var available = scope.available,
var size = $rootScope.sizeRatio,
mTop = Math.round(25 * size),
mRight = Math.round(130 * size),
mBottom = Math.round(25 * size),
mLeft = Math.round(45 * size),
barHeight = Math.round(20 * size),
width = element[0].offsetWidth,
w = width - margin.left - margin.right,
maxBand = bands[bands.length - 1],
deployedSum = 0,
retractedSum = 0,
retBandsSelected = false,
depBandsSelected = false,
maxPwr = Math.max(available, maxBand.retractedSum, maxBand.deployedSum);
innerHeight = (barHeight * 2) + 2,
height = innerHeight + mTop + mBottom,
w = width - mLeft - mRight,
repY = (barHeight / 2),
depY = (barHeight * 1.5) - 1;
// Update chart size
svg.attr('width', width).attr('height', height);
vis.attr('transform', 'translate(' + mLeft + ',' + mTop + ')');
// Remove existing elements
retracted.selectAll('rect').remove();
@@ -73,75 +101,68 @@ angular.module('app').directive('powerBands', ['$window', function($window) {
vis.selectAll('.watt.axis').call(wattAxis);
vis.selectAll('.pct.axis').attr('transform', 'translate(0,' + innerHeight + ')').call(pctAxis);
for (var b = 0, l = bands.length; b < l; b++) {
if (bands[b].retSelected) {
retractedSum += bands[b].retracted + bands[b].retOnly;
retBandsSelected = true;
}
if (bands[b].depSelected) {
deployedSum += bands[b].deployed + bands[b].retracted;
depBandsSelected = true;
}
}
updateLabel(retLbl, w, retBandsSelected, retBandsSelected ? retractedSum : maxBand.retractedSum, available);
updateLabel(depLbl, w, depBandsSelected, depBandsSelected ? deployedSum : maxBand.deployedSum, available);
retText.attr('y', repY);
depText.attr('y', depY);
updateLabel(retLbl, w, repY, retBandsSelected, retBandsSelected ? retractedSum : maxBand.retractedSum, available);
updateLabel(depLbl, w, depY, depBandsSelected, depBandsSelected ? deployedSum : maxBand.deployedSum, available);
retracted.selectAll('rect').data(bands).enter().append('rect')
.attr('height', barHeight)
.attr('width', function(d) { return Math.max(wattScale(d.retracted + d.retOnly) - 1, 0); })
.attr('x', function(d) { return wattScale(d.retractedSum) - wattScale(d.retracted + d.retOnly); })
.attr('width', function(d) { return Math.ceil(Math.max(wattScale(d.retracted + d.retOnly), 0)); })
.attr('x', function(d) { return Math.floor(Math.max(wattScale(d.retractedSum) - wattScale(d.retracted + d.retOnly), 0)); })
.attr('y', 1)
.on('click', function(d) {
d.retSelected = !d.retSelected;
render();
dataChange();
})
.attr('class', function(d) { return getClass(d.retSelected, d.retractedSum, available); });
retracted.selectAll('text').data(bands).enter().append('text')
.attr('x', function(d) { return wattScale(d.retractedSum) - (wattScale(d.retracted + d.retOnly) / 2); })
.attr('y', 15)
.attr('y', repY)
.attr('dy', '0.5em')
.style('text-anchor', 'middle')
.attr('class', 'primary-bg')
.on('click', function(d) {
d.retSelected = !d.retSelected;
render();
dataChange();
})
.text(function(d, i) { return bandText(d.retracted + d.retOnly, i); });
deployed.selectAll('rect').data(bands).enter().append('rect')
.attr('height', barHeight)
.attr('width', function(d) { return Math.max(wattScale(d.deployed + d.retracted) - 1, 0); })
.attr('x', function(d) { return wattScale(d.deployedSum) - wattScale(d.retracted) - wattScale(d.deployed); })
.attr('y', barHeight + 2)
.attr('width', function(d) { return Math.ceil(Math.max(wattScale(d.deployed + d.retracted), 0)); })
.attr('x', function(d) { return Math.floor(Math.max(wattScale(d.deployedSum) - wattScale(d.retracted) - wattScale(d.deployed), 0)); })
.attr('y', barHeight + 1)
.on('click', function(d) {
d.depSelected = !d.depSelected;
render();
dataChange();
})
.attr('class', function(d) { return getClass(d.depSelected, d.deployedSum, available); });
deployed.selectAll('text').data(bands).enter().append('text')
.attr('x', function(d) { return wattScale(d.deployedSum) - ((wattScale(d.retracted) + wattScale(d.deployed)) / 2); })
.attr('y', barHeight + 17)
.attr('y', depY)
.attr('dy', '0.5em')
.style('text-anchor', 'middle')
.attr('class', 'primary-bg')
.on('click', function(d) {
d.depSelected = !d.depSelected;
render();
dataChange();
})
.text(function(d, i) { return bandText(d.deployed + d.retracted, i); });
}
function updateLabel(lbl, width, selected, sum, available) {
function updateLabel(lbl, width, y, selected, sum, avail) {
lbl
.attr('x', width + 5 )
.attr('class', getClass(selected, sum, available))
.text(wattFmt(Math.max(0, sum)) + ' (' + pctFmt(Math.max(0, sum / available)) + ')');
.attr('y', y)
.attr('class', getClass(selected, sum, avail))
.text(wattFmt(Math.max(0, sum)) + ' (' + pctFmt(Math.max(0, sum / avail)) + ')');
}
function getClass(selected, sum, available) {
return selected ? 'secondary' : (sum > available) ? 'warning' : 'primary';
function getClass(selected, sum, avail) {
return selected ? 'secondary' : (sum >= avail) ? 'warning' : 'primary';
}
function bandText(val, index) {
@@ -151,6 +172,23 @@ angular.module('app').directive('powerBands', ['$window', function($window) {
return '';
}
function updateFormats(preventRender) {
retText.text($translate.instant('ret'));
depText.text($translate.instant('dep'));
wattFmt = $rootScope.localeFormat.numberFormat('.2f');
pctFmt = $rootScope.localeFormat.numberFormat('.1%');
wattAxis.tickFormat($rootScope.localeFormat.numberFormat('.2r'));
pctAxis.tickFormat($rootScope.localeFormat.numberFormat('%'));
if (!preventRender) {
render();
}
}
// Watch for changes to data and events
angular.element($window).bind('pwrchange', dataChange);
angular.element($window).bind('orientationchange resize', render);
scope.$watchCollection('available', dataChange);
scope.$on('languageChanged', updateFormats);
scope.$on('$destroy', function() {
angular.element($window).unbind('orientationchange resize pwrchange', render);
});

View File

@@ -3,73 +3,83 @@ angular.module('app').directive('slider', ['$window', function($window) {
return {
restrict: 'A',
scope: {
min: '=',
def: '=',
max: '=',
unit: '=',
change: '&onChange'
change: '&onChange',
ignoreResize: '='
},
link: function(scope, element) {
var margin = { top: -10, right: 145, bottom: 0, left: 50 },
height = 40, // Height is fixed
h = height - margin.top - margin.bottom,
var unit = scope.unit,
margin = unit ? { top: -10, right: 145, left: 50 } : { top: 0, right: 10, left: 10 },
height = unit ? 40 : 20, // Height is fixed
h = height - margin.top,
fmt = d3.format('.2f'),
pct = d3.format('.1%'),
unit = scope.unit,
val = scope.max,
def = scope.def !== undefined ? scope.def : scope.max,
val = def,
svg = d3.select(element[0]).append('svg'),
vis = svg.append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'),
xAxis = vis.append('g').attr('class', 'x slider-axis').attr('transform', 'translate(0,' + h / 2 + ')'),
xAxisContainer = vis.append('g').attr('class', 'x slider-axis').attr('transform', 'translate(0,' + h / 2 + ')'),
x = d3.scale.linear(),
xAxis = d3.svg.axis().scale(x).orient('bottom').tickFormat(function(d) { return d + unit; }).tickSize(0).tickPadding(12),
slider = vis.append('g').attr('class', 'slider'),
filled = slider.append('path').attr('class', 'filled').attr('transform', 'translate(0,' + h / 2 + ')'),
brush = d3.svg.brush().x(x).extent([scope.max, scope.max]).on('brush', brushed),
handle = slider.append('circle').attr('class', 'handle').attr('r', '0.6em'),
lbl = slider.append('g').append('text').attr('y', h / 2);
lbl = unit ? slider.append('g').append('text').attr('y', h / 2) : null;
slider.call(brush);
slider.select('.background').attr('height', h);
handle.attr('transform', 'translate(0,' + h / 2 + ')');
function render() {
var width = element[0].offsetWidth, w = width - margin.left - margin.right;
svg.attr('width', width).attr('height', height);
x.domain([scope.min || 0, scope.max]).range([0, w]).clamp(true);
handle.attr('cx', x(val));
if (unit) {
xAxisContainer.call(xAxis.tickValues([0, scope.max / 4, scope.max / 2, (3 * scope.max) / 4, scope.max]));
lbl.attr('x', w + 20);
}
slider.call(brush.extent([val, val]));
drawBrush();
slider.selectAll('.extent,.resize').remove();
}
function brushed() {
val = x.invert(d3.mouse(this)[0]);
brush.extent([val, val]);
scope.change({ val: val });
drawBrush();
}
function drawBrush() {
if (unit) {
lbl.text(fmt(val) + ' ' + unit + ' ' + pct(val / scope.max));
}
handle.attr('cx', x(val));
filled.attr('d', 'M0,0V0H' + x(val) + 'V0');
}
/**
* Watch for changes in the max, window size
*/
scope.$watch('max', function(newMax, oldMax) {
val = newMax * (val / oldMax); // Retain percentage filled
scope.change({ val: val });
render();
});
angular.element($window).bind('orientationchange resize', render);
function render() {
var width = element[0].offsetWidth, w = width - margin.left - margin.right;
svg.attr('width', width).attr('height', height);
x.domain([0, scope.max]).range([0, w]).clamp(true);
handle.attr('cx', x(val));
xAxis
.call(d3.svg.axis()
.scale(x)
.orient('bottom')
.tickFormat(function(d) { return d + unit; })
.tickValues([0, scope.max / 4, scope.max / 2, (3 * scope.max) / 4, scope.max])
.tickSize(0)
.tickPadding(12))
.select('.domain');
lbl.attr('x', w + 20);
slider.call(brush.extent([val, val])).call(brush.event);
slider.selectAll('.extent,.resize').remove();
if (!scope.ignoreResize) {
angular.element($window).bind('orientationchange resize', render);
}
function brushed() {
val = brush.extent()[0];
if (d3.event.sourceEvent) { // not a programmatic event
val = x.invert(d3.mouse(this)[0]);
brush.extent([val, val]);
}
lbl.text(fmt(val) + ' ' + unit + ' ' + pct(val / scope.max));
scope.change({ val: val });
handle.attr('cx', x(val));
filled.attr('d', 'M0,0V0H' + x(val) + 'V0');
}
scope.$on('reset', function(e, resetVal) {
val = resetVal;
drawBrush();
});
scope.$on('$destroy', function() {
angular.element($window).unbind('orientationchange resize render', render);

View File

@@ -3,8 +3,7 @@ angular.module('app').directive('slotHardpoint', ['$rootScope', function($r) {
restrict: 'A',
scope: {
hp: '=',
size: '=',
lbl: '='
size: '='
},
templateUrl: 'views/_slot-hardpoint.html',
link: function(scope) {

View File

@@ -3,7 +3,6 @@ angular.module('app').directive('slotInternal', ['$rootScope', function($r) {
restrict: 'A',
scope: {
c: '=slot',
lbl: '=',
fuel: '='
},
templateUrl: 'views/_slot-internal.html',

View File

@@ -1,7 +1,7 @@
/**
* BBCode Generator functions for embedding in the Elite Dangerous Forums
*/
angular.module('app').factory('Utils', ['$window', '$state', '$http', '$q', function($window, $state, $http, $q) {
angular.module('app').factory('Utils', ['$window', '$state', '$http', '$q', '$translate', '$rootScope', function($window, $state, $http, $q, $translate, $rootScope) {
var shortenAPI = 'https://www.googleapis.com/urlshortener/v1/url?key=';
@@ -24,11 +24,11 @@ angular.module('app').factory('Utils', ['$window', '$state', '$http', '$q', func
p = f.props;
if (p.length == 1) {
l.push('[th][B][COLOR=#FF8C0D]', f.title, '[/COLOR][/B][/th]');
l.push('[th][B][COLOR=#FF8C0D]', $translate.instant(f.title).toUpperCase(), '[/COLOR][/B][/th]');
colCount++;
} else {
for (j = 0; j < p.length; j++) {
l.push('[th][B][COLOR=#FF8C0D]', f.title, '\n', f.lbls[j], '[/COLOR][/B][/th]');
l.push('[th][B][COLOR=#FF8C0D]', $translate.instant(f.title).toUpperCase(), '\n', $translate.instant(f.lbls[j]).toUpperCase(), '[/COLOR][/B][/th]');
colCount++;
}
}
@@ -46,7 +46,7 @@ angular.module('app').factory('Utils', ['$window', '$state', '$http', '$q', func
f = facets[j];
p = f.props;
for (k = 0, pl = p.length; k < pl; k++) {
l.push('[td="align: right"]', f.fmt(b[p[k]]), ' [size=-2]', f.unit, '[/size][/td]');
l.push('[td="align: right"]', $rootScope[f.fmt](b[p[k]]), ' [size=-2]', $translate.instant(f.unit), '[/size][/td]');
}
}
}

219
app/js/i18n/de.js Normal file
View File

@@ -0,0 +1,219 @@
angular.module('app').config(['$translateProvider', 'localeFormatProvider', function($translateProvider, localeFormatProvider) {
// Declare number format settings
localeFormatProvider.addFormat('de', {
decimal: ',',
thousands: '.',
grouping: [3],
currency: ['', ' €'],
dateTime: '%A, der %e. %B %Y, %X',
date: '%d.%m.%Y',
time: '%H:%M:%S',
periods: ['AM', 'PM'], // unused
days: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
shortDays: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'],
months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
shortMonths: ['Jan', 'Feb', 'Mrz', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez']
});
$translateProvider.translations('de', {
PHRASE_EXPORT_DESC: 'Ein detaillierter JSON-Export Ihrer Konfiguration für die Verwendung in anderen Websites und Tools',
'A-Rated': 'A-Klasse',
about: 'Über',
action: 'Aktion',
added: 'Hinzugefügt',
Advanced: 'Verbessert',
'Advanced Discovery Scanner': 'Fortgeschrittener Aufklärungsscanner',
agility: 'Manövrierbarkeit',
ammo: 'Munition',
PHRASE_CONFIRMATION: 'Sind Sie sicher?',
armour: 'Panzerung',
am: 'Automatische Feldwartungs-Einheit',
available: 'Verfügbar',
backup: 'Sicherungsdatei',
'Basic Discovery Scanner': 'Einfacher Aufklärungsscanner',
bl: 'Strahlenlaser',
beta: 'Beta',
bins: 'Behälter',
boost: 'Boost',
build: 'Ausstattung',
'build name': 'Ausstattungsname',
builds: 'Ausstattungen',
bh: 'Rumpfhüllenverstärkung',
ul: 'Salvenlaser',
buy: 'Kaufen',
cancel: 'Abbrechen',
c: 'Kanone',
capital: 'Kapital',
cargo: 'Fracht',
'Cargo Hatch': 'Frachtluke',
cr: 'Frachtgestell',
cs: 'Frachtscanner',
cells: 'Zellen',
'Chaff Launcher': 'Düppel-Werfer',
close: 'Schließen',
cc: 'Krallensteuerung: Sammler',
compare: 'Vergleichen',
'compare all': 'Alles Vergleichen',
comparison: 'Vergleich',
comparisons: 'Vergleiche',
component: 'Komponente',
cost: 'Preis',
costs: 'Kosten',
cm: 'Gegenmaßnahme',
create: 'Erstellen',
'create new': 'Neu Erstellen',
Cytoscrambler: 'Zytostreuer',
damage: 'Schaden',
delete: 'Löschen',
'delete all': 'Alles Löschen',
dep: 'Ausg',
deployed: 'Ausgefahren',
'detailed export': 'Detailierter Export',
'Detailed Surface Scanner': 'Detailoberflächenscanner',
disabled: 'Deaktiviert',
discount: 'Rabatt',
Distruptor: 'Disruptor',
dc: 'Standard-Landecomputer',
done: 'Fertig',
'edit data': 'Bearbeiten',
efficiency: 'Effizienz',
'Electronic Countermeasure': 'Elektronische Gegenmaßnahme',
empty: 'leer',
Enforcer: 'Vollstrecker',
ENG: 'ANT',
'enter name': 'Namen eingeben',
export: 'Export',
fixed: 'Fixiert',
forum: 'Forum',
fc: 'Splitterkanone',
fd: 'Frameshiftantrieb',
ws: 'Frameshift-Sogwolkenscanner',
FSD: 'FSA',
fi: 'FSA-Unterbrecher',
fuel: 'Treibstoff',
fs: 'Treibstoffsammler',
ft: 'Treibstofftank',
fx: 'Krallensteuerung Treibstoffstransfer',
'full tank': 'Tank voll',
Gimballed: 'Kardanisch',
H: 'R',
hardpoints: 'Waffenaufhängungen',
hb: 'Krallen-Steuereinheit (Ladelukenöffner)',
'Heat Sink Launcher': 'Kühlkörperwerfer',
huge: 'Riesig',
hull: 'Hülle',
hr: 'Rumpfhüllenverstärkung (Paket)',
'Imperial Hammer': 'Imperialer Hammer',
import: 'Importieren',
'import all': 'Alles Importieren',
insurance: 'Versicherung',
'Intermediate Discovery Scanner': 'Mittlerer Aufklärungsscanner',
'internal compartments': 'Innenbereichskabine',
'jump range': 'Sprungreichweite',
jumps: 'Sprünge',
kw: 'Tötungsbefehl-Scanner',
L: 'G',
laden: 'Beladen',
language: 'Sprache',
large: 'Groß',
ls: 'Lebenserhaltung',
'Lightweight Alloy': 'Leichte Legierung',
'lock factor': 'Massensperrefaktor',
LS: 'Ls',
LY: 'Lj',
mass: 'Masse',
'max mass': 'maximale Masse',
medium: 'Mittel',
'Military Grade Composite': 'Militär-Komposit',
nl: 'Minenwerfer',
'Mining Lance': 'Lanzenabbaulaser',
ml: 'Abbaulaser',
'Mirrored Surface Composite': 'Gespiegelte-Oberfläche-Komposit',
mr: 'Raketenbatterie',
mc: 'Mehrfachgeschütz',
'net cost': 'Nettokosten',
no: 'Nein',
PHRASE_NO_BUILDS: 'Keine Konfigurationen zum Vergleich ausgewählt!',
PHRASE_NO_RETROCH: 'Keine Umrüständerungen',
none: 'Nichts',
'none created': 'Leer',
off: 'Aus',
on: 'An',
'optimal mass': 'optimale Masse',
'optimize mass': 'Masse optimieren',
overwrite: 'Überschreiben',
Pacifier: 'Friedensstifter',
'Pack-Hound': 'Schwarmwerfer',
PHRASE_IMPORT: 'JSON hier einfügen oder importieren',
pen: 'Durchdr.',
penetration: 'Durchdringung',
permalink: 'Permalink',
pa: 'Plasmabeschleuniger',
'Point Defence': 'Punktverteidigung',
power: 'Energie',
pd: 'Energieverteiler',
pp: 'Kraftwerk',
pri: 'Prio',
priority: 'Priorität',
psg: 'Prismaschildgenerator',
proceed: 'Fortfahren',
pc: 'Krallensteuerung: Erzsucher',
pl: 'Impulslaser',
PWR: 'En',
rg: 'Schienenkanone',
range: 'Reichweite',
rate: 'Rate',
'Reactive Surface Composite': 'Reaktive-Oberfläche-Komposit',
recharge: 'Aufladen',
rf: 'Raffinerie',
'refuel time': 'Auftankzeit',
'Reinforced Alloy': 'Verstärkte Legierung',
reload: 'Aktualisieren',
rename: 'Umbenennen',
repair: 'Reparieren',
reset: 'Zurücksetzen',
ret: 'Eing',
retracted: 'Eingefahren',
'retrofit costs': 'Änderungskosten',
'retrofit from': 'Nachrüsten von',
ROF: 'Kad',
S: 'K',
save: 'Speichern',
sc: 'Scanner',
PHRASE_SELECT_BUILDS: 'Ausstattung zum Vergleich auswählen',
sell: 'Verkaufen',
s: 'Sensoren',
settings: 'Einstellungen',
sb: 'Schild-Booster',
scb: 'Schildzellenbank',
sg: 'Schildgenerator',
shields: 'Schilde',
ship: 'Schiff',
ships: 'Schiffe',
shortened: 'Gekürzt',
size: 'Größe',
skip: 'Überspringen',
small: 'Klein',
speed: 'Geschwindigkeit',
standard: 'Standard',
'Standard Docking Computer': 'Standard-Landecomputer',
Stock: 'Standard',
T: 't',
T_LOAD: 'T-Lad',
'The Retributor': 'Retributor',
t: 'Schubdüsen',
time: 'Dauer',
tp: 'Torpedoaufhängung',
total: 'Gesamt',
'total range': 'Maximale Reichweite',
turret: 'Geschützturm',
type: 'Typ',
U: 'W',
unladen: 'Unbeladen',
PHRASE_UPDATE_RDY: 'Update verfügbar! Klicken zum Aktualisieren',
utility: 'Werkzeug',
'utility mounts': 'Werkzeug-Steckplätze',
WEP: 'WAF',
yes: 'Ja',
PHRASE_BACKUP_DESC: 'Export aller Coriolis-Daten, um sie zu sichern oder oder um sie zu einem anderen Browser/Gerät zu übertragen.'
});
}]);

218
app/js/i18n/en.js Normal file
View File

@@ -0,0 +1,218 @@
angular.module('app').config(['$translateProvider', function($translateProvider) {
$translateProvider
.translations('en', {
PHRASE_EXPORT_DESC: 'A detailed JSON export of your build for use in other sites and tools',
'A-Rated': 'A-Rated',
about: 'about',
action: 'action',
added: 'added',
Advanced: 'Advanced',
'Advanced Discovery Scanner': 'Advanced Discovery Scanner',
agility: 'agility',
alpha: 'alpha',
ammo: 'ammo',
PHRASE_CONFIRMATION: 'Are You Sure?',
armour: 'armour',
am: 'Auto Field-Maintenance Unit',
available: 'available',
backup: 'backup',
'Basic Discovery Scanner': 'Basic Discovery Scanner',
bl: 'Beam Laser',
beta: 'beta',
bins: 'bins',
boost: 'boost',
build: 'build',
'build name': 'Build Name',
builds: 'builds',
bh: 'bulkheads',
ul: 'Burst Laser',
buy: 'buy',
cancel: 'cancel',
c: 'Cannon',
capital: 'capital',
cargo: 'cargo',
'Cargo Hatch': 'Cargo Hatch',
cr: 'Cargo Rack',
cs: 'Cargo Scanner',
cells: 'cells',
'Chaff Launcher': 'Chaff Launcher',
close: 'close',
cc: 'Collector Limpet Controller',
compare: 'compare',
'compare all': 'compare all',
comparison: 'comparison',
comparisons: 'comparisons',
component: 'component',
cost: 'cost',
costs: 'costs',
cm: 'Countermeasure',
CR: 'CR',
create: 'create',
'create new': 'create new',
credits: 'credits',
Cytoscrambler: 'Cytoscrambler',
damage: 'damage',
delete: 'delete',
'delete all': 'delete all',
dep: 'dep',
deployed: 'deployed',
'detailed export': 'detailed export',
'Detailed Surface Scanner': 'Detailed Surface Scanner',
disabled: 'disabled',
discount: 'discount',
Distruptor: 'Distruptor',
dc: 'Docking Computer',
done: 'done',
DPS: 'DPS',
'edit data': 'edit data',
efficiency: 'efficiency',
'Electronic Countermeasure': 'Electronic Countermeasure',
empty: 'empty',
Enforcer: 'Enforcer',
ENG: 'ENG',
'enter name': 'Enter Name',
EPS: 'EPS',
export: 'export',
fixed: 'fixed',
forum: 'forum',
fc: 'Fragment Cannon',
fd: 'Frame Shift Drive',
ws: 'Frame Shift Wake Scanner',
FSD: 'FSD',
fi: 'FSD Interdictor',
fuel: 'fuel',
fs: 'Fuel Scoop',
ft: 'Fuel Tank',
fx: 'Fuel Transfer Limpet Controller',
'full tank': 'full tank',
Gimballed: 'Gimballed',
H: 'H',
hardpoints: 'hardpoints',
hb: 'Hatch Breaker Limpet Controller',
'Heat Sink Launcher': 'Heat Sink Launcher',
huge: 'huge',
hull: 'hull',
hr: 'Hull Reinforcement Package',
'Imperial Hammer': 'Imperial Hammer',
import: 'import',
'import all': 'import all',
insurance: 'insurance',
'Intermediate Discovery Scanner': 'Intermediate Discovery Scanner',
'internal compartments': 'internal compartments',
'jump range': 'jump range',
jumps: 'jumps',
kw: 'Kill Warrant Scanner',
L: 'L',
laden: 'laden',
language: 'language',
large: 'large',
ls: 'life support',
'Lightweight Alloy': 'Lightweight Alloy',
'lock factor': 'lock factor',
LS: 'Ls',
LY: 'LY',
M: 'M',
'm/s': 'm/s',
mass: 'mass',
max: 'max',
'max mass': 'max mass',
medium: 'medium',
'Military Grade Composite': 'Military Grade Composite',
nl: 'Mine Launcher',
'Mining Lance': 'Mining Lance',
ml: 'Mining Laser',
'Mirrored Surface Composite': 'Mirrored Surface Composite',
mr: 'Missile Rack',
mc: 'Multi-cannon',
'net cost': 'net cost',
no: 'no',
PHRASE_NO_BUILDS: 'No builds added to comparison!',
PHRASE_NO_RETROCH: 'No Retrofitting changes',
none: 'none',
'none created': 'none created',
off: 'off',
on: 'on',
optimal: 'optimal',
'optimal mass': 'optimal mass',
'optimize mass': 'optimize mass',
overwrite: 'overwrite',
Pacifier: 'Pacifier',
'Pack-Hound': 'Pack-Hound',
PHRASE_IMPORT: 'Paste JSON or import here',
pen: 'pen',
penetration: 'penetration',
permalink: 'permalink',
pa: 'Plasma Accelerator',
'Point Defence': 'Point Defence',
power: 'power',
pd: 'power distributor',
pp: 'power plant',
pri: 'pri',
priority: 'priority',
psg: 'Prismatic Shield Generator',
proceed: 'proceed',
pc: 'Prospector Limpet Controller',
pl: 'Pulse Laser',
PWR: 'PWR',
rg: 'Rail Gun',
range: 'range',
rate: 'rate',
'Reactive Surface Composite': 'Reactive Surface Composite',
recharge: 'recharge',
rf: 'Refinery',
'refuel time': 'refuel time',
'Reinforced Alloy': 'Reinforced Alloy',
reload: 'reload',
rename: 'rename',
repair: 'repair',
reset: 'reset',
ret: 'ret',
retracted: 'retracted',
'retrofit costs': 'retrofit costs',
'retrofit from': 'retrofit from',
ROF: 'ROF',
S: 'S',
save: 'save',
sc: 'scanner',
PHRASE_SELECT_BUILDS: 'Select Builds to Compare',
sell: 'sell',
s: 'sensors',
settings: 'settings',
sb: 'Shield Booster',
scb: 'Shield Cell Bank',
sg: 'Shield Generator',
shields: 'shields',
ship: 'ship',
ships: 'ships',
shortened: 'shortened',
size: 'size',
skip: 'skip',
small: 'small',
speed: 'speed',
standard: 'standard',
'Standard Docking Computer': 'Standard Docking Computer',
Stock: 'Stock',
SYS: 'SYS',
T: 'T',
T_LOAD: 't-load',
'The Retributor': 'The Retributor',
t: 'thrusters',
time: 'time',
tp: 'Torpedo Pylon',
total: 'total',
'total range': 'total range',
turret: 'turret',
type: 'type',
U: 'U',
unladen: 'unladen',
PHRASE_UPDATE_RDY: 'Update Available! Click to Refresh',
URL: 'URL',
utility: 'utility',
'utility mounts': 'utility mounts',
version: 'version',
WEP: 'WEP',
yes: 'yes',
PHRASE_BACKUP_DESC: 'Backup of all Coriolis data to save or transfer to another browser/device'
});
}]);

263
app/js/i18n/es.js Normal file
View File

@@ -0,0 +1,263 @@
angular.module('app').config(['$translateProvider', 'localeFormatProvider', function($translateProvider, localeFormatProvider) {
// Declare number format settings
localeFormatProvider.addFormat('es', {
decimal: ',',
thousands: '.',
grouping: [3],
currency: ['', ' €'],
dateTime: '%A, %e de %B de %Y, %X',
date: '%d/%m/%Y',
time: '%H:%M:%S',
periods: ['AM', 'PM'],
days: ['domingo', 'lunes', 'martes', 'miércoles', 'jueves', 'viernes', 'sábado'],
shortDays: ['dom', 'lun', 'mar', 'mié', 'jue', 'vie', 'sáb'],
months: ['enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio', 'julio', 'agosto', 'septiembre', 'octubre', 'noviembre', 'diciembre'],
shortMonths: ['ene', 'feb', 'mar', 'abr', 'may', 'jun', 'jul', 'ago', 'sep', 'oct', 'nov', 'dic']
});
$translateProvider.translations('es', {
PHRASE_EXPORT_DESC: 'Ein detaillierter JSON-Export Ihrer Konfiguration für die Verwendung in anderen Websites und Tools',
A_RATED: 'A-Klasse',
ABOUT: 'Über',
ACTION: 'Aktion',
ADDED: 'Hinzugefügt',
ADDER: 'Adder',
ADVANCED: 'Fortgeschritten',
'Advanced Discovery Scanner': 'Fortgeschrittener Aufklärungsscanner',
'Advanced Plasma Laser': 'Fortgeschrittener Plasma-Laser',
AGILITY: 'Beweglichkeit',
ALPHA: 'Alpha',
AMMO: 'Munition',
ANACONDA: 'Anaconda',
PHRASE_CONFIRMATION: 'Sind Sie sicher?',
ARMOUR: 'Panzerung',
ASP_EXPLORER: 'Asp Explorer',
am: 'Automatische Feldwartungseinheit',
AVAILABLE: 'Verfügbar',
BACKUP: 'Sicherungsdatei',
'Basic Discovery Scanner': 'Einfacher Aufklärungsscanner',
bl: 'Strahlenlaser',
BELUGA_LINER: 'Beluga Liner',
BETA: 'beta',
BINS: 'Behälter',
BOOST: 'Boost',
BUILD: 'Konfiguration',
BUILD_NAME: 'Konfigurationsname',
BUILDS: 'Konfigurationen',
BULKHEADS: 'Rumpfhüllenverstärkung',
ul: 'Salvenlaser',
BUY: 'Kaufen',
CANCEL: 'Abbrechen',
c: 'Kanone',
CAPITAL: 'kapital',
CARGO: 'Fracht',
CARGO_HATCH: 'Frachtluke',
cr: 'Frachtgestell',
cs: 'Frachtscanner',
CELLS: 'Zellen',
CHAFF_LAUNCHER: 'Düppel-Werfer',
CLOSE: 'Schließen',
COBRA_MK_III: 'Cobra MK III',
COBRA_MK_IV: 'Cobra MK IV',
cc: 'Krallensteuerung: Sammler',
COMPARE: 'Vergleichen',
COMPARE_ALL: 'Alles Vergleichen',
COMPARISON: 'Vergleich',
COMPARISONS: 'Vergleiche',
COMPONENT: 'Komponente',
COST: 'Kostet',
COSTS: 'Kosten',
cm: 'Gegenmaßnahme',
CR: 'CR',
CREATE: 'Erstellen',
CREATE_NEW: 'Neu Erstellen',
CREDITS: 'Credits',
Cytoscrambler: 'Zytostreuer',
DAMAGE: 'Schaden',
DELETE: 'Löschen',
DELETE_ALL: 'Alles Löschen',
DEP: 'Ausg',
DEPLOYED: 'Ausgefahren',
DETAILED_EXPORT: 'Detailiertes Exportieren',
'Detailed Surface Scanner': 'Detailoberflächenscanner',
DIAMONDBACK_EXPLORER: 'Diamondback-Erkunder',
DIAMONDBACK_SCOUT: 'Diamondback-Aufklärer',
DISABLED: 'Deaktiviert',
DISCOUNT: 'Rabatt',
Distruptor: 'Disruptor',
dc: 'Standard-Landecomputer',
DOLPHIN: 'Dolphin',
DONE: 'Fertig',
DPS: 'DPS',
EAGLE: 'Eagle',
EDIT_DATA: 'Bearbeiten',
EFFICIENCY: 'Effizienz',
'Electronic Countermeasure': 'Elektronische Gegenmaßnahme',
EMPTY: 'leer',
ENFORCER: 'Vollstrecker',
ENG: 'FAH',
PHRASE_ENTER_BUILD_NAME: '',
EPS: 'en/s',
EXPORT: 'Exportieren',
FEDERAL_CORVETTE: 'Föderale Korvette',
FEDERAL_DROPSHIP: 'Föderales Abwurfschiff',
FEDERAL_DROPSHIP_MK_II: 'Föderales Abwurfschiff Mk II',
FEDERAL_GUNSHIP: 'Föderales Kanonenschiff',
FER_DE_LANCE: 'Fer-de-Lance',
FIXED: '',
FORUM: 'Forum',
fc: 'Splitterkanone',
fd: 'Frameshift-Antrieb',
ws: 'Sogwolkenscanner',
FSD: 'FSA',
fi: 'FSA-Unterbrecher',
FUEL: 'Treibstoff',
fs: 'Treibstoffsammler',
ft: 'Treibstofftank',
fx: 'Krallensteuerung Treibstoffstransfer',
FULL_TANK: 'Tank voll',
GIMBALLED: 'Kardianisch',
H: 'H',
HARDPOINTS: 'Waffenaufhängungen',
hb: 'Krallen-Steuereinheit (Ladelukenöffner)',
HAULER: 'Hauler',
'Heat Sink Launcher': 'Kühlkörperwerfer',
HUGE: 'Riesig',
HULL: 'Hülle',
hr: 'Rumpfhüllenverstärkung (Paket)',
IMPERIAL_CLIPPER: 'Imperialer Clipper',
IMPERIAL_COURIER: 'Imperialer Kurier',
IMPERIAL_CUTTER: 'Imperialer Cutter',
IMPERIAL_EAGLE: 'Imperialer Eagle',
IMPERIAL_HAMMER: 'Imperialer Hammer',
IMPORT: 'Importieren',
IMPORT_ALL: 'Alles Importieren',
INSURANCE: 'Versicherung',
'Intermediate Discover Scanner': 'Mittlerer Aufklärungsscanner',
INTERNAL_COMPARTMENTS: 'Innenbereichkabine',
JUMP_RANGE: 'Sprungreichweite',
JUMPS: 'Sprünge',
kw: 'Tötungsbefehlscanner',
KRAIT: 'Krait',
L: 'L',
LADEN: 'Beladen',
LANGUAGE: 'Sprache',
LARGE: 'Groß',
ls: 'Lebenserhaltung',
'Lightweight Alloy': 'Leichte Legierung',
LOCK_FACTOR: 'Massensperrefaktor',
LS: 'LS',
LY: 'LJ',
M: 'M',
'm/s': 'M/Sec.',
MASS: 'Masse',
MAX: 'max',
MAX_MASS: 'maximale Masse',
MEDIUM: 'Mittel',
'Military Grade Composite': 'Militär-Komposit',
nl: 'Minenwerfer',
'Mining Lance': 'Lanzenabbaulaser',
ml: 'Abbaulaser',
'Mirrored Surface Composite': 'Gespiegelte-Oberfläche-Komposit',
mr: 'Raketenbatterie',
mc: 'Mehrfachgeschütz',
NET_COST: 'Nettokosten',
NO: 'Nein',
NO_RETROFITTING_CHANGES: 'Keine Umrüständerungen',
NONE: 'Nichts',
NONE_CREATED: 'Nichts erstellt',
OFF: 'Aus',
ON: 'An',
OPTIMAL: 'optimal',
OPTIMAL_MASS: 'optimale Masse',
OPTIMIZE_MASS: 'Masse optimieren',
ORCA: 'Orca',
OVERWRITE: 'Überschreiben',
Pacifier: 'Friedensstifter',
'Pack-Hound': 'Schwarmwerfer',
PANTHER_CLIPPER: 'Panter Clipper',
PHRASE_IMPORT: 'JSON hier einfügen oder hier importieren',
PEN: 'Durchdr',
PENETRATION: 'Durchdringung',
PERMALINK: 'Permalink',
pa: 'Plasmabeschleuniger',
POINT_DEFENCE: 'Punktverteidigung',
POWER: 'Energie',
pd: 'Energieverteiler',
pp: 'Kraftwerk',
PRI: 'Prio',
PRIORITY: 'Priorität',
psg: 'Prismaschildgenerator',
PROCEED: 'Fortfahren',
pc: 'Krallensteuerung: Erzsucher',
pl: 'Impulslaser',
PWR: 'En',
PYTHON: 'Python',
rg: 'Schienenkanone',
RANGE: 'Reichweite',
RATE: 'Rate',
'Reactive Surface Composite': 'Reaktive-Oberfläche-Komposit',
RECHARGE: 'Aufladen',
rf: 'Raffinerie',
REFUEL_TIME: 'Auftankzeit',
'Reinforced Alloy': 'Verstärkte Legierungen',
RELOAD: 'Aktualisieren',
RENAME: 'Umbenennen',
REPAIR: 'Reparieren',
RESET: 'Zurücksetzen',
RET: 'eing',
RETRACTED: 'Eingefahren',
RETROFIT_COSTS: 'Nachrüstkosten',
RETROFIT_FROM: 'Nachrüsten von',
ROF: 'Kad',
S: 'S',
SAVE: 'Speichern',
sc: 'Scanner',
PHRASE_SELECT_BUILDS: 'Wähle Konfigurationen zum Vergleichen',
SELL: 'Verkaufen',
s: 'Sensoren',
SETTINGS: 'Konfiguration',
sb: 'Schildverstärker',
scb: 'Schildzellenbank',
sg: 'Schildgenerator',
SHIELDS: 'Schilde',
SHIP: 'Schiff',
SHIPS: 'Schiffe',
SHORTENED: 'Gekürzt',
SIDEWINDER: 'Sidewinder',
SIZE: 'Größe',
SKIP: 'Überspringen',
SMALL: 'S',
SPEED: 'Geschwindigkeit',
STANDARD: 'Standard',
STANDARD_DOCKING_COMPUTER: 'Landecomputer',
STOCK: 'Standard',
SYS: 'SYS',
T: 'T',
T_LOAD: 'T-Lad',
THE_HUNTER: 'The Hunter',
'The Retributor': 'Retributor',
t: 'Schubdüsen',
TIME: 'Dauer',
tp: 'Torpedoaufhängung',
TOTAL: 'Gesamt',
TOTAL_RANGE: 'Maximale Reichweite',
TURRET: 'Geschützturm',
TYPE: 'Typ',
TYPE_6_TRANSPORTER: 'Typ-6 Transporter',
TYPE_7_TRANSPORTER: 'Typ-7 Transporter',
TYPE_9_HEAVY: 'Typ-9 Transporter (schwer)',
U: 'U',
UNLADEN: 'Unbeladen',
UPDATE_NOTIFICATION: 'Update verfügbar! Klicken zum Aktualisieren',
URL: 'URL',
UTILITY: 'Werkzeug',
UTILITY_MOUNTS: 'Werkzeug-Steckplatz',
VERSION: 'Version',
VIPER: 'Viper',
VULTURE: 'Vulture',
WEP: 'WAF',
YES: 'Ja'
});
}]);

199
app/js/i18n/fr.js Normal file
View File

@@ -0,0 +1,199 @@
angular.module('app').config(['$translateProvider', 'localeFormatProvider', function($translateProvider, localeFormatProvider) {
// Declare number format settings
localeFormatProvider.addFormat('fr', {
decimal: ',',
thousands: '.',
grouping: [3],
currency: ['', ' €'],
dateTime: '%A, le %e %B %Y, %X',
date: '%d/%m/%Y',
time: '%H:%M:%S',
periods: ['AM', 'PM'], // unused
days: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'],
shortDays: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'],
months: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'],
shortMonths: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.']
});
$translateProvider.translations('fr', {
PHRASE_EXPORT_DESC: 'Export détaillé en JSON de votre configuration pour utilisation sur d\'autres sites et outils',
'A-Rated': 'Classe-A ',
about: 'à propos',
added: 'ajouté',
Advanced: 'Avancé',
'Advanced Discovery Scanner': 'Scanner de découverte avancé',
agility: 'manœuvrabilité',
ammo: 'munitions',
PHRASE_CONFIRMATION: 'Êtes-vous sûr ?',
armour: 'Armure',
am: 'Unité de réparation automatique',
available: 'Disponibilité',
backup: 'sauvegarde',
'Basic Discovery Scanner': 'Scanner de découverte simple',
bl: 'Rayon Laser',
bins: 'bacs',
build: 'Configuration',
'build name': 'Nom de la configuration',
builds: 'Configurations',
bh: 'Coque',
ul: 'Laser à rafale',
buy: 'Acheter',
cancel: 'Annuler',
c: 'Canon',
cargo: 'Soute',
'Cargo Hatch': 'Ecoutille de soute',
cr: 'Compartiment de soute',
cs: 'Scanner de soute',
cells: 'Cellules',
'Chaff Launcher': 'Lanceur de paillettes',
close: 'fermer',
cc: 'Contrôleur de prospecteur',
compare: 'comparer',
'compare all': 'tout comparer',
comparison: 'comparaison',
comparisons: 'comparaisons',
component: 'composant',
cost: 'coût',
costs: 'coûts',
cm: 'Contre-mesure',
create: 'Créer',
'create new': 'Créer nouveau',
credits: 'crédits',
damage: 'Dégâts',
delete: 'supprimer',
'delete all': 'tout supprimer',
dep: 'depl',
deployed: 'déployé',
'detailed export': 'export détaillé',
'Detailed Surface Scanner': 'Scanner de surface détaillé',
disabled: 'désactivé',
discount: 'réduction',
Distruptor: 'Disrupteur',
dc: 'Ordinateur d\'appontage',
done: 'Valider',
'edit data': 'Editer donnée',
efficiency: 'efficience',
'Electronic Countermeasure': 'Contre mesure électronique',
empty: 'Vide',
'enter name': 'Entrer un nom',
fixed: 'fixé',
fc: 'Canon à fragmentation',
fd: 'Réacteur FSD',
ws: 'Détecteur de sillage FSD',
fi: 'Intercepteur de réacteur FSD',
fuel: 'carburant',
fs: 'Récupérateur de carburant',
ft: 'Réservoir de carburant',
fx: 'Drone de ravitaillement',
'full tank': 'Réservoir plein',
Gimballed: 'Point',
hardpoints: 'Points d\'emport',
hb: 'Contrôle de patelle perce-soute',
'Heat Sink Launcher': 'Ejecteur de dissipateur thermique',
huge: 'Très grand',
hull: 'Coque',
hr: 'Renfort de soute',
'Imperial Hammer': 'Marteau impérial',
import: 'Importer',
'import all': 'Importer tout',
insurance: 'Assurance',
'Intermediate Discovery Scanner': 'Scanner de découverte intermédiaire',
'internal compartments': 'compartiments internes',
'jump range': 'Distance de saut',
jumps: 'Sauts',
kw: 'Détecteur d\'avis de recherche',
laden: 'chargé',
language: 'Langage',
large: 'large',
ls: 'Support vital',
'Lightweight Alloy': 'alliage léger',
'lock factor': 'facteur inhibition de masse',
LS: 'SL',
LY: 'AL',
mass: 'Masse',
'max mass': 'masse max',
'Military Grade Composite': 'Composite militaire',
nl: 'Lance-mines',
'Mining Lance': 'Lance de minage',
ml: 'Laser minier',
'Mirrored Surface Composite': 'Composite à surface mirroir',
mr: 'Lance missiles',
mc: 'Canon multiple',
'net cost': 'coûts nets',
no: 'non',
PHRASE_NO_BUILDS: 'Aucune configuration ajoutée pour comparaison',
PHRASE_NO_RETROCH: 'Configuration non modifiée',
none: 'aucun',
'none created': 'Rien de créé',
off: 'éteint',
on: 'allumé',
'optimal mass': 'masse optimale',
'optimize mass': 'optimiser masse',
overwrite: 'remplacer',
Pacifier: 'Pacificateur',
PHRASE_IMPORT: 'Coller ici votre JSON à importer',
pen: 'pén.',
penetration: 'pénétration',
permalink: 'lien durable',
pa: 'accélérateur plasma',
'Point Defence': 'Défense ponctuelle',
power: 'énergie',
pd: 'distributeur d\'énérgie',
pp: 'centrale d\'énergie',
priority: 'priorité',
psg: 'générateur de bouclier prisme',
proceed: 'continuer',
pc: 'Drône de minage',
pl: 'Laser à impulsion',
PWR: 'P',
rg: 'Canon électromagnétique',
range: 'portée',
rate: 'cadence',
'Reactive Surface Composite': 'Composite à surface réactive',
recharge: 'recharger',
rf: 'Raffinerie',
'refuel time': 'Temps de remplissage',
'Reinforced Alloy': 'alliage renforcé',
reload: 'recharger',
rename: 'renommer',
repair: 'réparer',
reset: 'Réinitialisation',
ret: 'esc',
retracted: 'escamoté',
'retrofit costs': 'Valeur de rachat',
'retrofit from': 'Racheter de',
ROF: 'cadence',
save: 'sauvegarder',
sc: 'scanner',
PHRASE_SELECT_BUILDS: 'Sélectionner les configurations à comparer',
sell: 'vendre',
s: 'détecteurs',
settings: 'paramètres',
sb: 'Survolteur de bouclier',
scb: 'Réserve de cellules d\'énergie',
sg: 'Générateur de bouclier',
shields: 'boucliers',
ship: 'vaisseau',
ships: 'vaisseaux',
shortened: 'raccourci',
size: 'taille',
skip: 'Suivant',
small: 'petit',
speed: 'vitesse',
'Standard Docking Computer': 'ordinateur amarrage standard',
Stock: 'de base',
T_LOAD: 'degrés',
'The Retributor': 'Le Rétributeur',
t: 'propulseurs',
time: 'temps',
tp: 'Tube lance-torpille',
'total range': 'Distance maximale',
turret: 'tourelle',
unladen: 'Non chargé',
PHRASE_UPDATE_RDY: 'Mise à jour disponible ! Cliquez pour rafraichir',
utility: 'utilitaire',
'utility mounts': 'Support utilitaire',
WEP: 'ARM',
yes: 'oui',
PHRASE_BACKUP_DESC: 'Exportation détaillée des données de Coriolis pour l\'utilisation dans d\'autres sites et outils'
});
}]);

21
app/js/i18n/languages.js Normal file
View File

@@ -0,0 +1,21 @@
angular.module('app').config(['$translateProvider', function($translateProvider) {
$translateProvider
.useSanitizeValueStrategy('escapeParameters')
.useStorage('Persist')
.fallbackLanguage('en') // Use English as default/fallback language
.registerAvailableLanguageKeys(['en', 'de', 'fr', 'ru'], { // TODO: add 'es' to the array when ready
'en*': 'en',
'de*': 'de',
//'es*': 'es',
'fr*': 'fr',
'ru*': 'ru'
})
.determinePreferredLanguage();
}])
.value('Languages', {
en: 'English',
de: 'Deutsh',
//es: 'Español',
fr: 'Français',
ru: 'ру́сский'
});

233
app/js/i18n/ru.js Normal file
View File

@@ -0,0 +1,233 @@
angular.module('app').config(['$translateProvider', 'localeFormatProvider', function($translateProvider, localeFormatProvider) {
// Declare number format settings
localeFormatProvider.addFormat('ru', {
decimal: ',',
thousands: '\xa0',
grouping: [3],
currency: ['', ' руб.'],
dateTime: '%A, %e %B %Y г. %X',
date: '%d.%m.%Y',
time: '%H:%M:%S',
periods: ['AM', 'PM'],
days: ['воскресенье', 'понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота'],
shortDays: ['вс', 'пн', 'вт', 'ср', 'чт', 'пт', 'сб'],
months: ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря'],
shortMonths: ['янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек']
});
$translateProvider.translations('ru', {
PHRASE_EXPORT_DESC: 'Подробный экспорта JSON вашего телосложения для использования в других местах и инструментов',
'A-Rated': 'А-Класса',
about: 'О сайте',
action: 'Действие',
added: 'Добавлено',
Advanced: 'Продвинутый',
'Advanced Discovery Scanner': 'Продвинутый астросканер',
agility: 'Маневренность',
alpha: 'Альфа',
ammo: 'Боекомплект',
PHRASE_CONFIRMATION: 'Вы уверены?',
armour: 'Броня',
am: 'Ремонтный модуль',
available: 'доступно',
backup: 'Резервная копия',
'Basic Discovery Scanner': 'Стандартный исследовательский сканер',
bl: 'Лучевой лазер',
beta: 'Бета',
bins: 'контейнеры',
boost: 'форсаж',
build: 'cборка',
'build name': 'название сборки',
builds: 'cборки',
bh: 'Корпус',
ul: 'Мультиимпульсный лазер',
buy: 'купить',
cancel: 'отменить',
c: 'Пушка',
capital: 'Крупный',
cargo: 'Груз',
'Cargo Hatch': 'Грузовой люк',
cr: 'Грузовой отсек',
cs: 'Сканер груза',
cells: 'Ячейки',
'Chaff Launcher': 'Постановщик помех',
close: 'закрыть',
cc: 'Контроллер "дрон-сборщик"',
compare: 'сравнить ',
'compare all': 'сравнить все',
comparison: 'сравнение',
comparisons: 'сравнения',
component: 'Компонент',
cost: 'Стоимость',
costs: 'Расходы',
cm: 'Контрмеры',
CR: 'кр.',
create: 'создать',
'create new': 'Создать новый',
credits: 'Кредиты',
Cytoscrambler: 'сайтоскрамблер',
damage: 'Урон',
delete: 'Удалить',
'delete all': 'Удалить все',
dep: 'Вып',
deployed: 'Открыты',
'detailed export': 'Подробный экспорт',
'Detailed Surface Scanner': 'Подробный сканер поверхности',
disabled: 'Отключено',
discount: 'Скидка',
Distruptor: 'Дисраптор',
dc: 'Стыковочный компьютер',
done: 'готово',
DPS: 'УВС',
'edit data': 'Редактирование',
efficiency: 'Эффективность',
'Electronic Countermeasure': 'Электронная противомера',
empty: 'пусто',
Enforcer: 'Энфорсер',
ENG: 'ДВГ',
'enter name': 'Введите имя',
EPS: 'ЭВС',
export: 'Экспорт',
fixed: 'Фиксированое',
forum: 'Форум',
fc: 'Осколочное Орудие',
fd: 'Двигатель FSD',
ws: 'FSD Сканнер',
fi: 'Перехватчик FSD',
fuel: 'Топливо',
fs: 'Топливосборщик',
ft: 'Топливный бак',
fx: 'Контроллер Дрона-заправщика',
'full tank': 'Полный бак',
Gimballed: 'Шарнирное',
H: 'O',
hardpoints: 'Орудийные порты',
hb: 'Контроллер "дрон-взломщик"',
'Heat Sink Launcher': 'Теплоотводная ПУ',
huge: 'огромный',
hull: 'Корпус',
hr: 'Набор усиления корпуса',
'Imperial Hammer': 'Имперский Молот',
import: 'импортировать ',
'import all': 'импортировать все',
insurance: 'Страховка',
'Intermediate Discovery Scanner': 'Средний исследовательский сканер',
'internal compartments': 'внутренние отсеки',
'jump range': 'Дальность прыжка',
jumps: 'Прыжков',
kw: 'Полицейский сканер',
L: 'б',
laden: 'Груженый',
language: 'Язык',
large: 'большой',
ls: 'Система жизнеобеспечения',
'Lightweight Alloy': 'Легкий сплав',
'lock factor': 'Масс. блок',
LS: 'Св.сек',
LY: 'Св.лет',
M: 'С',
'm/s': 'м/с',
mass: 'Масса',
max: 'Макс',
'max mass': 'Максимальная масса',
medium: 'Средний',
'Military Grade Composite': 'Военный композит',
nl: 'Минноукладчик',
'Mining Lance': 'Бурильная сулица',
ml: 'Бурильный лазер',
'Mirrored Surface Composite': 'Зеркальный композит',
mr: 'Ракетная установка',
mc: 'Многоствольное орудие',
'net cost': 'разница в цене',
no: 'Нет',
PHRASE_NO_BUILDS: 'Нечего сравнивать',
PHRASE_NO_RETROCH: 'нет ранних версий сборки\конфигурации',
none: 'ни один',
'none created': 'не создано',
off: 'выкл',
on: 'вкл',
optimal: 'Оптимальный',
'optimal mass': 'Оптимальная масса',
'optimize mass': 'Оптимизировать массу',
overwrite: 'перезаписать',
Pacifier: 'Миротворец',
'Pack-Hound': 'Ракета "Гончая"',
PHRASE_IMPORT: 'Для импорта вставьте код в эту форму',
pen: 'ПБ',
penetration: 'Пробитие',
permalink: 'Постоянная ссылка',
pa: 'Ускоритель плазмы',
'Point Defence': 'Противоракетная защита',
power: 'Мощность',
pd: 'Распределитель энергии',
pp: 'Реактор',
pri: 'Осн',
priority: 'Приоритет',
psg: 'Генератор призматического щита',
proceed: 'продолжить',
pc: 'Контроллер "Дрон-исследователь"',
pl: 'Импульсный лазер',
PWR: 'Эн',
rg: 'Рельсотрон',
range: 'Дальность',
rate: 'скорость',
'Reactive Surface Composite': 'Динамическая защита',
recharge: 'Перезарядка',
rf: 'Переработка',
'refuel time': 'Время дозаправки',
'Reinforced Alloy': 'Усиленный сплав',
reload: 'Перезарядить',
rename: 'Переименовать',
repair: 'Починка',
reset: 'Сброс',
ret: 'Убр.',
retracted: 'Убрано',
'retrofit costs': 'цена модификации',
'retrofit from': 'модификация от',
ROF: 'В/сек',
S: 'М',
save: 'Сохранить',
sc: 'Сканер',
PHRASE_SELECT_BUILDS: 'Выберите конфигурацию для сравнения',
sell: 'Продать',
s: 'Сенсоры',
settings: 'Настройки',
sb: 'Усилитель щита',
scb: 'Батареи перезарядки щита',
sg: 'Генератор щита',
shields: 'Щиты',
ship: 'Корабль',
ships: 'Корабли',
shortened: 'Укороченный',
size: 'размер',
skip: 'пропустить',
small: 'Малый',
speed: 'скорость',
standard: 'Стандартный',
'Standard Docking Computer': 'Стандартный стыковочный компьютер',
Stock: 'Стандартная комплектация',
SYS: 'СИС',
T: 'Т',
T_LOAD: 'Тепл.',
'The Retributor': '"Возмездие"',
t: 'Двигатели',
time: 'Время',
tp: 'Торпедный аппарат',
total: 'Всего',
'total range': 'Общий радиус',
turret: 'Туррель',
type: 'Тип',
U: 'В',
unladen: 'Пустой',
PHRASE_UPDATE_RDY: 'Доступно обновление. Нажмите для обновления.',
URL: 'Ссылка',
utility: 'Вспомогательное',
'utility mounts': 'Вспомогательное оборудование',
version: 'Версия',
WEP: 'ОРУ',
yes: 'Да',
PHRASE_BACKUP_DESC: 'Сохраните все данные перед переносом в другой браузер или устройство'
});
}]);

View File

@@ -0,0 +1,36 @@
angular.module('app').provider('localeFormat', function localeFormatProvider() {
var formats = {
en: {
decimal: '.',
thousands: ',',
grouping: [3],
currency: ['$', ''],
dateTime: '%a %b %e %X %Y',
date: '%m/%d/%Y',
time: '%H:%M:%S',
periods: ['AM', 'PM'],
days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
shortDays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
shortMonths: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
}
};
function LocaleFormat(formatMap) {
this.formatMap = formatMap;
this.get = function(lang) {
return this.formatMap[lang] ? this.formatMap[lang] : this.formatMap.en;
};
}
this.addFormat = function(langCode, formatDetails) {
formats[langCode] = formatDetails;
};
this.$get = [function() {
return new LocaleFormat(formats);
}];
});

View File

@@ -4,6 +4,7 @@
angular.module('app').service('Persist', ['$window', 'lodash', function($window, _) {
var LS_KEY_BUILDS = 'builds';
var LS_KEY_COMPARISONS = 'comparisons';
var LS_KEY_LANG = 'NG_TRANSLATE_LANG_KEY';
var LS_KEY_COST_TAB = 'costTab';
var LS_KEY_INSURANCE = 'insurance';
var LS_KEY_DISCOUNTS = 'discounts';
@@ -31,6 +32,22 @@ angular.module('app').service('Persist', ['$window', 'lodash', function($window,
hasBuilds: buildCount > 0,
hasComparisons: Object.keys(this.comparisons).length > 0
};
this.put = function(name, value) {
if (!this.lsEnabled) {
return;
}
localStorage.setItem(name, value);
};
this.get = function(name) {
return this.lsEnabled ? localStorage.getItem(name) : null;
};
this.getLangCode = function() {
return this.lsEnabled ? localStorage.getItem(LS_KEY_LANG) : null;
};
/**
* Persist a ship build in local storage.
*
@@ -240,7 +257,7 @@ angular.module('app').service('Persist', ['$window', 'lodash', function($window,
/**
* Retrieve the last router state from local storage
* @param {object} state State object containing state name and params
* @return {object} state State object containing state name and params
*/
this.getState = function() {
if (this.lsEnabled) {
@@ -262,6 +279,30 @@ angular.module('app').service('Persist', ['$window', 'lodash', function($window,
}
};
/**
* Retrieve the last router state from local storage
* @return {number} size Ratio
*/
this.getSizeRatio = function() {
if (this.lsEnabled) {
var ratio = localStorage.getItem('sizeRatio');
if (!isNaN(ratio) && ratio > 0.6) {
return ratio;
}
}
return 1;
};
/**
* Save the current size ratio to localstorage
* @param {number} sizeRatio
*/
this.setSizeRatio = function(sizeRatio) {
if (this.lsEnabled) {
localStorage.setItem('sizeRatio', sizeRatio);
}
};
/**
* Check if localStorage is enabled/active
* @return {Boolean} True if localStorage is enabled

View File

@@ -10,8 +10,8 @@ angular.module('app').service('Serializer', ['lodash', 'GroupMap', 'MountMap', '
*/
this.fromShip = function(ship) {
var power = {
enabled: [ship.cargoScoop.enabled ? 1 : 0],
priorities: [ship.cargoScoop.priority]
enabled: [ship.cargoHatch.enabled ? 1 : 0],
priorities: [ship.cargoHatch.priority]
};
var data = [
@@ -72,7 +72,7 @@ angular.module('app').service('Serializer', ['lodash', 'GroupMap', 'MountMap', '
internal = ship.internal;
var data = {
$schema: 'http://cdn.coriolis.io/schemas/ship-loadout/1.json#',
$schema: 'http://cdn.coriolis.io/schemas/ship-loadout/2.json#',
name: buildName,
ship: ship.name,
references: [{
@@ -84,13 +84,14 @@ angular.module('app').service('Serializer', ['lodash', 'GroupMap', 'MountMap', '
components: {
standard: {
bulkheads: ship.bulkheads.c.name,
powerPlant: { class: standard[0].c.class, rating: standard[0].c.rating },
thrusters: { class: standard[1].c.class, rating: standard[1].c.rating },
frameShiftDrive: { class: standard[2].c.class, rating: standard[2].c.rating },
lifeSupport: { class: standard[3].c.class, rating: standard[3].c.rating },
powerDistributor: { class: standard[4].c.class, rating: standard[4].c.rating },
sensors: { class: standard[5].c.class, rating: standard[5].c.rating },
fuelTank: { class: standard[6].c.class, rating: standard[6].c.rating }
cargoHatch: { enabled: Boolean(ship.cargoHatch.enabled), priority: ship.cargoHatch.priority + 1 },
powerPlant: { class: standard[0].c.class, rating: standard[0].c.rating, enabled: Boolean(standard[0].enabled), priority: standard[0].priority + 1 },
thrusters: { class: standard[1].c.class, rating: standard[1].c.rating, enabled: Boolean(standard[1].enabled), priority: standard[1].priority + 1 },
frameShiftDrive: { class: standard[2].c.class, rating: standard[2].c.rating, enabled: Boolean(standard[2].enabled), priority: standard[2].priority + 1 },
lifeSupport: { class: standard[3].c.class, rating: standard[3].c.rating, enabled: Boolean(standard[3].enabled), priority: standard[3].priority + 1 },
powerDistributor: { class: standard[4].c.class, rating: standard[4].c.rating, enabled: Boolean(standard[4].enabled), priority: standard[4].priority + 1 },
sensors: { class: standard[5].c.class, rating: standard[5].c.rating, enabled: Boolean(standard[5].enabled), priority: standard[5].priority + 1 },
fuelTank: { class: standard[6].c.class, rating: standard[6].c.rating, enabled: Boolean(standard[6].enabled), priority: standard[6].priority + 1 }
},
hardpoints: _.map(_.filter(hardpoints, function(slot) { return slot.maxClass > 0; }), slotToSchema),
utility: _.map(_.filter(hardpoints, function(slot) { return slot.maxClass === 0; }), slotToSchema),
@@ -116,21 +117,26 @@ angular.module('app').service('Serializer', ['lodash', 'GroupMap', 'MountMap', '
}
var comps = detailedBuild.components;
var standard = comps.standard;
var priorities = [ standard.cargoHatch && standard.cargoHatch.priority !== undefined ? standard.cargoHatch.priority - 1 : 0 ];
var enabled = [ standard.cargoHatch && standard.cargoHatch.enabled !== undefined ? standard.cargoHatch.enabled : true ];
var shipData = ShipsDB[shipId];
var ship = new Ship(shipId, shipData.properties, shipData.slots);
var bulkheads = Components.bulkheadIndex(comps.standard.bulkheads);
var bulkheads = Components.bulkheadIndex(standard.bulkheads);
if (bulkheads < 0) {
throw 'Invalid bulkheads: ' + comps.standard.bulkheads;
throw 'Invalid bulkheads: ' + standard.bulkheads;
}
var common = _.map(
['powerPlant', 'thrusters', 'frameShiftDrive', 'lifeSupport', 'powerDistributor', 'sensors', 'fuelTank'],
function(c) {
if (!comps.standard[c].class || !comps.standard[c].rating) {
if (!standard[c].class || !standard[c].rating) {
throw 'Invalid value for ' + c;
}
return comps.standard[c].class + comps.standard[c].rating;
priorities.push(standard[c].priority === undefined ? 0 : standard[c].priority - 1);
enabled.push(standard[c].enabled === undefined ? true : standard[c].enabled);
return standard[c].class + standard[c].rating;
}
);
@@ -143,7 +149,15 @@ angular.module('app').service('Serializer', ['lodash', 'GroupMap', 'MountMap', '
return c ? Components.findHardpointId(c.group, c.class, c.rating, c.name, MountMap[c.mount]) : 0;
}));
ship.buildWith({ bulkheads: bulkheads, common: common, hardpoints: hardpoints, internal: internal });
// The ordering of these arrays must match the order in which they are read in Ship.buildWith
priorities = priorities.concat(_.map(comps.hardpoints, function(c) { return (!c || c.priority === undefined) ? 0 : c.priority - 1; }),
_.map(comps.utility, function(c) { return (!c || c.priority === undefined) ? 0 : c.priority - 1; }),
_.map(comps.internal, function(c) { return (!c || c.priority === undefined) ? 0 : c.priority - 1; }));
enabled = enabled.concat(_.map(comps.hardpoints, function(c) { return (!c || c.enabled === undefined) ? true : c.enabled * 1; }),
_.map(comps.utility, function(c) { return (!c || c.enabled === undefined) ? true : c.enabled * 1; }),
_.map(comps.internal, function(c) { return (!c || c.enabled === undefined) ? true : c.enabled * 1; }));
ship.buildWith({ bulkheads: bulkheads, common: common, hardpoints: hardpoints, internal: internal }, priorities, enabled);
return ship;
};
@@ -213,7 +227,7 @@ angular.module('app').service('Serializer', ['lodash', 'GroupMap', 'MountMap', '
function slotToSchema(slot) {
if (slot.c) {
var o = { class: slot.c.class, rating: slot.c.rating, group: GroupMap[slot.c.grp] };
var o = { class: slot.c.class, rating: slot.c.rating, enabled: Boolean(slot.enabled), priority: slot.priority + 1, group: GroupMap[slot.c.grp] };
if (slot.c.name) {
o.name = slot.c.name;
}

View File

@@ -27,7 +27,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
*/
function Ship(id, properties, slots) {
this.id = id;
this.cargoScoop = { c: Components.cargoScoop(), type: 'SYS' };
this.cargoHatch = { c: Components.cargoHatch(), type: 'SYS' };
this.bulkheads = { incCost: true, maxClass: 8 };
for (var p in properties) { this[p] = properties[p]; } // Copy all base properties from shipData
@@ -51,7 +51,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
this.costList.unshift(this.c); // Add the ship itself to the list
this.powerList = _.union(this.internal, this.hardpoints);
this.powerList.unshift(this.cargoScoop);
this.powerList.unshift(this.cargoHatch);
this.powerList.unshift(this.common[1]); // Add Thrusters
this.powerList.unshift(this.common[5]); // Add Sensors
this.powerList.unshift(this.common[4]); // Add Power Distributor
@@ -96,8 +96,8 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
this.bulkheads.c = null;
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;
this.cargoHatch.priority = priorities ? priorities[0] * 1 : 0;
this.cargoHatch.enabled = enabled ? enabled[0] * 1 : true;
for (i = 0, l = this.priorityBands.length; i < l; i++) {
this.priorityBands[i].deployed = 0;
@@ -105,8 +105,8 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
this.priorityBands[i].retOnly = 0;
}
if (this.cargoScoop.enabled) {
bands[this.cargoScoop.priority].retracted += this.cargoScoop.c.power;
if (this.cargoHatch.enabled) {
bands[this.cargoHatch.priority].retracted += this.cargoHatch.c.power;
}
for (i = 0; i < cl; i++) {
@@ -292,12 +292,12 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
} else if (!slot.enabled) {
return 1; // Disabled
} else if (deployed && !slot.c.retractedOnly) { // Certain component (e.g. Detaild Surface scanner) are power only while retracted
return this.priorityBands[slot.priority].deployedSum > this.powerAvailable ? 2 : 3; // Offline : Online
return this.priorityBands[slot.priority].deployedSum >= this.powerAvailable ? 2 : 3; // Offline : Online
// Active hardpoints have no retracted status
} else if ((deployed && slot.c.retractedOnly) || (slot.cat === 1 && !slot.c.passive)) {
return 0; // No Status (Not possible)
}
return this.priorityBands[slot.priority].retractedSum > this.powerAvailable ? 2 : 3; // Offline : Online
return this.priorityBands[slot.priority].retractedSum >= this.powerAvailable ? 2 : 3; // Offline : Online
};
/**

View File

@@ -7,7 +7,7 @@
* @requires ngLodash
*/
angular.module('shipyard', ['ngLodash'])
// Create 'angularized' references to DB.This will aid testing
// Create 'angularized' references to DB. This will aid testing
.constant('ShipsDB', DB.ships)
.constant('ComponentsDB', DB.components)
.value('ArmourMultiplier', [
@@ -17,16 +17,7 @@ angular.module('shipyard', ['ngLodash'])
1.945, // Mirrored
1.945 // Reactive
])
.value('commonArray', [
'Power Plant',
'Thrusters',
'Frame Shift Drive',
'Life Support',
'Power Distributor',
'Sensors',
'Fuel Tank'
])
// Map to lookup group labels/names for component grp
// Map to lookup group labels/names for component grp, used for JSON Serialization
.value('GroupMap', {
// Common
pp: 'Power Plant',
@@ -81,20 +72,6 @@ angular.module('shipyard', ['ngLodash'])
'Gimballed': 'G',
'Turret': 'T'
})
.value('shipSize', [
'N/A',
'Small',
'Medium',
'Large',
'Capital'
])
.value('hardPointClass', [
'Utility',
'Small',
'Medium',
'Large',
'Huge'
])
/**
* Array of all Ship properties (facets) organized into groups
* used for ship comparisons.
@@ -103,91 +80,89 @@ angular.module('shipyard', ['ngLodash'])
*/
.value('ShipFacets', [
{ // 0
title: 'Agility',
title: 'agility',
props: ['agility'],
unit: '',
fmt: 'fCrd'
},
{ // 1
title: 'Speed',
title: 'speed',
props: ['speed', 'boost'],
lbls: ['Thrusters', 'Boost'],
lbls: ['thrusters', 'boost'],
unit: 'm/s',
fmt: 'fRound'
},
{ // 2
title: 'Armour',
title: 'armour',
props: ['armour'],
unit: '',
fmt: 'fCrd'
},
{ // 3
title: 'Shields',
title: 'shields',
props: ['shieldStrength'],
unit: 'MJ',
fmt: 'fRound'
},
{ // 4
title: 'Jump Range',
title: 'jump range',
props: ['unladenRange', 'fullTankRange', 'ladenRange'],
lbls: ['Max', 'Full Tank', 'Laden'],
lbls: ['max', 'full tank', 'laden'],
unit: 'LY',
fmt: 'fRound'
},
{ // 5
title: 'Mass',
title: 'mass',
props: ['unladenMass', 'ladenMass'],
lbls: ['Unladen', 'Laden'],
lbls: ['unladen', 'laden'],
unit: 'T',
fmt: 'fRound'
},
{ // 6
title: 'Cargo',
title: 'cargo',
props: ['cargoCapacity'],
unit: 'T',
fmt: 'fRound'
},
{ // 7
title: 'Fuel',
title: 'fuel',
props: ['fuelCapacity'],
unit: 'T',
fmt: 'fRound'
},
{ // 8
title: 'Power',
title: 'power',
props: ['powerRetracted', 'powerDeployed', 'powerAvailable'],
lbls: ['Retracted', 'Deployed', 'Available'],
lbls: ['retracted', 'deployed', 'available'],
unit: 'MW',
fmt: 'fPwr'
},
{ // 9
title: 'Cost',
title: 'cost',
props: ['totalCost'],
unit: 'CR',
fmt: 'fCrd'
},
{ // 10
title: 'Total Range',
title: 'total range',
props: ['unladenTotalRange', 'ladenTotalRange'],
lbls: ['Unladen', 'Laden'],
lbls: ['unladen', 'laden'],
unit: 'LY',
fmt: 'fRound'
},
{ // 11
title: 'DPS',
props: ['totalDps'],
lbls: ['Dps'],
lbls: ['DPS'],
unit: '',
fmt: 'fRound'
}
])
/**
* Set of all available / theoretical discounts
*
* @type {Object}
*/
.value('Discounts', {
'None': 1,
'0%': 1,
'5%': 0.95,
'10%': 0.90,
'15%': 0.85,
@@ -237,16 +212,22 @@ angular.module('shipyard', ['ngLodash'])
* @return {number} Approximate shield strengh in MJ
*/
.value('calcShieldStrength', function(mass, shields, sg, multiplier) {
if (mass <= sg.minmass) {
var opt;
if (mass < sg.minmass) {
return shields * multiplier * sg.minmul;
}
if (mass > sg.maxmass) {
return shields * multiplier * sg.maxmul;
}
if (mass < sg.optmass) {
return shields * multiplier * (sg.minmul + (mass - sg.minmass) / (sg.optmass - sg.minmass) * (sg.optmul - sg.minmul));
opt = (sg.optmass - mass) / (sg.optmass - sg.minmass);
opt = 1 - Math.pow(1 - opt, 0.87);
return shields * multiplier * ((opt * sg.minmul) + ((1 - opt) * sg.optmul));
} else {
opt = (sg.optmass - mass) / (sg.maxmass - sg.optmass);
opt = -1 + Math.pow(1 + opt, 2.425);
return shields * multiplier * ( (-1 * opt * sg.maxmul) + ((1 + opt) * sg.optmul) );
}
if (mass < sg.maxmass) {
return shields * multiplier * (sg.optmul + (mass - sg.optmass) / (sg.maxmass - sg.optmass) * (sg.maxmul - sg.optmul));
}
return shields * multiplier * sg.maxmul;
})
/**
* Calculate the a ships speed based on mass, and thrusters. Currently Innacurate / Incomplete :(

View File

@@ -1,6 +1,12 @@
angular.module('shipyard').service('Components', ['lodash', 'ComponentsDB', 'ShipsDB', 'ComponentSet', function(_, C, Ships, ComponentSet) {
angular.module('shipyard').service('Components', ['lodash', 'ComponentsDB', 'ShipsDB', 'ComponentSet', 'GroupMap', function(_, C, Ships, ComponentSet, GroupMap) {
this.cargoScoop = function() {
var GrpNameToCodeMap = {};
for (var grp in GroupMap) {
GrpNameToCodeMap[GroupMap[grp]] = grp;
}
this.cargoHatch = function() {
return { name: 'Cargo Hatch', class: 1, rating: 'H', power: 0.6 };
};
@@ -36,10 +42,11 @@ angular.module('shipyard').service('Components', ['lodash', 'ComponentsDB', 'Shi
var groups = {};
if (groupName) {
if (!C.internal[groupName]) {
var grpCode = GrpNameToCodeMap[groupName];
if (grpCode && !C.internal[grpCode]) {
throw 'Invalid internal group: ' + groupName;
}
groups[groupName] = C.internal[groupName];
groups[grpCode] = C.internal[grpCode];
} else if (name) {
groups = C.internal;
} else {
@@ -62,10 +69,11 @@ angular.module('shipyard').service('Components', ['lodash', 'ComponentsDB', 'Shi
var groups = {};
if (groupName) {
if (!C.hardpoints[groupName]) {
var grpCode = GrpNameToCodeMap[groupName];
if (grpCode && !C.hardpoints[grpCode]) {
throw 'Invalid internal group: ' + groupName;
}
groups[groupName] = C.hardpoints[groupName];
groups[grpCode] = C.hardpoints[grpCode];
} else if (name) {
groups = C.hardpoints;
} else {

View File

@@ -25,6 +25,9 @@ html, body {
height: 100%;
width: 100%;
text-rendering: optimizeLegibility;
overflow-x: hidden;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
body {
@@ -84,6 +87,14 @@ div, a, li {
text-align: center;
}
.cap {
text-transform: capitalize;
}
.upp {
text-transform: uppercase;
}
.scroll-x {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
@@ -114,6 +125,7 @@ h3 {
u { // Unit (Mj, Km, etc)
font-size: 0.8em;
text-decoration: none;
text-transform: none;
}
a, a:visited {

View File

@@ -5,7 +5,9 @@ button {
fill: @primary;
}
border: none;
text-transform: capitalize;
font-family: @fStandard;
font-size: 0.75em;
vertical-align: middle;
padding: 0.5em;
cursor: pointer;

View File

@@ -29,6 +29,7 @@
height: 100%;
display: inline-block;
padding: 0.3em;
font-size: 1em;
vertical-align: middle;
border: none;
border-right: 1px solid @primary-disabled;

View File

@@ -50,6 +50,7 @@ header {
padding : 0 1em;
cursor: pointer;
color: @warning;
text-transform: capitalize;
// Less than 600px screen width: hide text
&.disabled {
@@ -64,7 +65,7 @@ header {
.menu-item-label {
margin-left: 1em;
.largePhone({
.smallTablet({
display: none;
});
}

View File

@@ -196,12 +196,25 @@ table.total {
width: 100% !important;
});
}
.smallTablet({
.axis.x {
g.tick:nth-child(2n + 1) text {
display: none;
}
}
});
}
.power-band {
text, rect {
cursor: pointer;
}
rect {
stroke-width: 1px;
stroke: #000;
}
}
#componentPriority {

View File

@@ -63,6 +63,8 @@ select {
padding-left: 5px;
border-top: 1px solid @primary-disabled;
border-bottom: 1px solid @primary-disabled;
overflow: hidden;
text-overflow: ellipsis;
}
@optionSpacing: 2em;
@@ -113,6 +115,12 @@ select {
}
}
.lc {
overflow: hidden;
text-overflow: ellipsis;
text-transform: capitalize;
}
.c {
display: inline-block;
width: 2em;
@@ -126,6 +134,7 @@ select {
display: inline-block;
text-align: left;
min-width: 16em;
max-width: 100%;
margin: 0 auto;
padding: 0;
list-style: none;

View File

@@ -41,3 +41,58 @@
cursor: crosshair;
}
}
input[type=range] {
-webkit-appearance: none;
border: 1px solid @bgBlack;
/*required for proper track sizing in FF*/
width: 300px;
&::-moz-range-track, &::-webkit-slider-runnable-track {
width: 300px;
height: 5px;
background: @primary;
border: none;
border-radius: 3px;
}
&::-moz-range-thumb, &::-webkit-slider-thumb {
-webkit-appearance: none;
border: none;
height: 1em;
width: 1em;
border-radius: 50%;
background: @primary;
}
&:focus {
outline: none;
}
/*hide the outline behind the border*/
&:-moz-focusring{
outline: 1px solid @bgBlack;
outline-offset: -1px;
}
&::-ms-track {
width: 300px;
height: 5px;
background: transparent;
border-color: transparent;
border-width: 6px 0;
color: transparent;
}
&::-ms-fill-lower {
background: @primary;
border-radius: 10px;
}
&::-ms-fill-upper {
background: @primary;
border-radius: 10px;
}
&::-ms-thumb {
border: none;
height: 16px;
width: 16px;
border-radius: 50%;
background: goldenrod;
}
}

View File

@@ -36,6 +36,7 @@
}
.l {
text-transform: capitalize;
margin-right: 0.8em;
}
@@ -51,10 +52,11 @@
border-right: 1px solid @primary-disabled;
box-sizing: border-box;
padding-top: 0.2em;
padding-left: 0.1em;
padding-left: 0.05em;
}
.empty {
text-transform: uppercase;
font-size: 1.3em;
color: lighten(@primary-bg, 12%);
text-align: center;

View File

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

View File

@@ -1,5 +1,5 @@
<div id="app-update" ng-show="appCacheUpdate">
<a href="#" onclick="window.location.reload()">Update Available! Click to Refresh</a>
<a href="#" onclick="window.location.reload()">{{ 'PHRASE_UPDATE_RDY' | translate }}</a>
</div>
<header>
@@ -7,8 +7,8 @@
<div class="l menu">
<div class="menu-header" ng-class="{selected: openedMenu=='s'}" ng-click="openMenu($event,'s')">
<svg class="icon warning"><use xlink:href="#rocket"></use></svg><span class="menu-item-label"> Ships</span>
</div>
<svg class="icon warning"><use xlink:href="#rocket"></use></svg><span class="menu-item-label"> {{'ships' | translate}}</span>
</div>
<div class="menu-list dbl no-wrap" ng-if="openedMenu=='s'">
<a class="block" ng-repeat="(shipId,ship) in ships" ui-sref-active="active" ui-sref="outfit({shipId:shipId, code:null, bn:null})">{{::ship.properties.name}}</a>
</div>
@@ -16,7 +16,7 @@
<div class="l menu">
<div class="menu-header" ng-class="{selected: openedMenu=='b', disabled: !bs.hasBuilds}" ng-click="openMenu($event,'b')">
<svg class="icon warning" ng-class="{'warning-disabled': !bs.hasBuilds}"><use xlink:href="#hammer"></use></svg><span class="menu-item-label"> Builds</span>
<svg class="icon warning" ng-class="{'warning-disabled': !bs.hasBuilds}"><use xlink:href="#hammer"></use></svg><span class="menu-item-label"> {{'builds' | translate}}</span>
</div>
<div class="menu-list" ng-if="openedMenu=='b'" ng-click="$event.stopPropagation();">
<div class="dbl" >
@@ -32,44 +32,59 @@
<div class="l menu">
<div class="menu-header" ng-class="{selected: openedMenu=='comp', disabled: !bs.hasBuilds}" ng-click="openMenu($event,'comp')">
<svg class="icon warning" ng-class="{'warning-disabled': !bs.hasBuilds}"><use xlink:href="#stats-bars"></use></svg><span class="menu-item-label"> Compare</span>
</div>
<svg class="icon warning" ng-class="{'warning-disabled': !bs.hasBuilds}"><use xlink:href="#stats-bars"></use></svg><span class="menu-item-label"> {{'compare' | translate}}</span>
</div>
<div class="menu-list" ng-if="openedMenu=='comp'" ng-click="$event.stopPropagation();" style="white-space: nowrap;">
<span ng-if="!bs.hasComparisons">None Created</span>
<span class="cap" ng-if="!bs.hasComparisons" translate="none created"></span>
<a ng-repeat="(name, comp) in allComparisons" ui-sref-active="active" class="block name" ui-sref="compare({name:name})" ng-bind="name"></a>
<hr />
<a ui-sref="compare({name: 'all'})" class="block">Compare All</a>
<a ui-sref="compare({name: null})" class="block">Create New</a>
<a ui-sref="compare({name: 'all'})" class="block cap" translate="compare all"></a>
<a ui-sref="compare({name: null})" class="block cap" translate="create new"></a>
</div>
</div>
<div class="r menu">
<div class="menu-header" ng-class="{selected: openedMenu=='settings'}" ng-click="openMenu($event,'settings')">
<svg class="icon xl warning"><use xlink:href="#cogs"></use></svg><span class="menu-item-label"> Settings</span>
<svg class="icon xl warning"><use xlink:href="#cogs"></use></svg><span class="menu-item-label"> {{'settings' | translate}}</span>
</div>
<div class="menu-list no-wrap" ng-if="openedMenu=='settings'" ng-click="$event.stopPropagation();">
<div class="menu-list no-wrap cap" ng-if="openedMenu=='settings'" ng-click="$event.stopPropagation();">
<ul>
Insurance
<li><select ng-model="insurance.current" ng-options="ins.name for (i,ins) in insurance.opts" ng-change="updateInsurance()"></select></li>
{{'language' | translate}}
<li><select class="cap" ng-model="language.current" ng-options="langCode as langName for (langCode,langName) in language.opts" ng-change="changeLanguage()"></select></li>
</ul><br>
<ul>
Ship Discount
<li><select ng-model="discounts.ship" ng-options="i for (i,d) in discounts.opts" ng-change="updateDiscount()"></select></li>
{{'insurance' | translate}}
<li><select class="cap" ng-model="insurance.current" ng-options="ins.name | translate for (i,ins) in insurance.opts" ng-change="updateInsurance()"></select></li>
</ul><br>
<ul>
Component Discount
<li><select ng-model="discounts.components" ng-options="i for (i,d) in discounts.opts" ng-change="updateDiscount()"></select></li>
{{'ship' | translate}} {{'discount' | translate}}
<li><select class="cap" ng-model="discounts.ship" ng-options="i for (i,d) in discounts.opts" ng-change="updateDiscount()"></select></li>
</ul><br>
<ul>
{{'component' | translate}} {{'discount' | translate}}
<li><select class="cap" ng-model="discounts.components" ng-options="i for (i,d) in discounts.opts" ng-change="updateDiscount()"></select></li>
</ul>
<hr />
<ul>
Builds & Comparisons
<li><a href="#" class="block" ng-click="backup($event)">Backup</a></li>
<li><a href="#" class="block" ng-click="detailedExport($event)">Detailed Export</a></li>
<li><a href="#" class="block" ui-sref="modal.import">Import</a></li>
<li><a href="#" class="block" ui-sref="modal.delete">Delete All</a></li>
{{'builds' | translate}} & {{'comparisons' | translate}}
<li><a href="#" class="block" ng-click="backup($event)" translate="backup"></a></li>
<li><a href="#" class="block" ng-click="detailedExport($event)" translate="detailed export"></a></li>
<li><a href="#" class="block" ui-sref="modal.import" translate="import"></a></li>
<li><a href="#" class="block" ui-sref="modal.delete" translate="delete all"></a></li>
</ul>
<hr />
<a href="#" ui-sref="modal.about" class="block">About</a>
<table style="width: 300px;background-color:transparent">
<tr>
<td style="width: 20px"><u>A</u></td>
<td slider min="0.65" def="sizeRatio" max="1.2" on-change="textSizeChange(val)" ignore-resize="true"></td>
<td style="width: 20px"><span style="font-size: 30px">A</span></td>
</tr>
<tr>
<td></td><td style="text-align:center" class="primary-disabled cap" ng-click="resetTextSize()" translate="reset"></td><td></td>
</tr>
</table>
<hr />
<a href="#" ui-sref="modal.about" class="block" translate="about"></a>
</div>
</div>

View File

@@ -1,17 +1,17 @@
<div class="sz">{{::['U','S','M','L','H'][hp.maxClass]}}</div>
<div class="empty" ng-if="!hp.c">EMPTY</div>
<div class="sz">{{['U','S','M','L','H'][hp.maxClass] | translate}}</div>
<div class="empty" ng-if="!hp.c" translate="empty"></div>
<div ng-if="hp.c">
{{hp.c.class}}{{hp.c.rating}}<span ng-if="hp.c.mode">/{{hp.c.mode}}{{hp.c.missile}}</span> {{hp.c.name || lbl}}
{{hp.c.class}}{{hp.c.rating}}<span ng-if="hp.c.mode">/{{hp.c.mode}}{{hp.c.missile}}</span> {{hp.c.name || hp.c.grp | translate}}
<div class="r">{{hp.c.mass}} <u>T</u></div>
<div class="cb">
<div class="l" ng-if="hp.c.damage">Damage: {{hp.c.damage}} <span ng-if="hp.c.ssdam">({{$r.fCrd(hp.c.ssdam)}} <u>Mj</u>)</span></div>
<div class="l" ng-if="hp.c.dps">DPS: {{hp.c.dps}} <span ng-if="hp.c.mjdps">({{$r.fCrd(hp.c.mjdps)}} <u>Mj</u>)</span></div>
<div class="l" ng-if="hp.c.thermload">T-Load: {{hp.c.thermload}}</div>
<div class="l" ng-if="hp.c.type">Type: {{hp.c.type}}</div>
<div class="l" ng-if="hp.c.rof">ROF: {{hp.c.rof}}<u>/s</u></div>
<div class="l" ng-if="hp.c.armourpen">Pen: {{hp.c.armourpen}}</div>
<div class="l" ng-if="hp.c.damage">{{'damage' | translate}}: {{hp.c.damage}} <span ng-if="hp.c.ssdam">({{$r.fCrd(hp.c.ssdam)}} <u>MJ</u>)</span></div>
<div class="l" ng-if="hp.c.dps">{{'DPS' | translate}}: {{hp.c.dps}} <span ng-if="hp.c.mjdps">({{$r.fCrd(hp.c.mjdps)}} <u>MJ</u>)</span></div>
<div class="l" ng-if="hp.c.thermload">{{'T_LOAD' | translate}}: {{hp.c.thermload}}</div>
<div class="l" ng-if="hp.c.type">{{'type' | translate}}: {{hp.c.type}}</div>
<div class="l" ng-if="hp.c.rof">{{'ROF' | translate}}: {{hp.c.rof}}<u>/s</u></div>
<div class="l" ng-if="hp.c.armourpen">{{'pen' | translate}}: {{hp.c.armourpen}}</div>
<div class="l" ng-if="hp.c.shieldmul">+{{$r.fRPct(hp.c.shieldmul)}}</div>
<div class="l" ng-if="hp.c.range">{{hp.c.range}} <u>KM</u></div>
<div class="l" ng-if="hp.c.ammo">Ammo: {{$r.fCrd(hp.c.clip)}}/{{$r.fCrd(hp.c.ammo)}}</div>
<div class="l" ng-if="hp.c.range">{{hp.c.range}} <u>km</u></div>
<div class="l" ng-if="hp.c.ammo">{{'ammo' | translate}}: {{$r.fCrd(hp.c.clip)}}/{{$r.fCrd(hp.c.ammo)}}</div>
</div>
</div>

View File

@@ -1,22 +1,22 @@
<div class="sz" ng-bind="c.maxClass"></div>
<div class="empty" ng-if="!c.c">EMPTY</div>
<div class="empty" ng-if="!c.c" translate="empty"></div>
<div ng-if="c.c">
<div class="l name">{{c.c.class}}{{c.c.rating}} {{c.c.name || lbl}}</div>
<div class="r">{{c.c.mass || c.c.capacity || '0'}} <u>T</u></div>
<div class="l name">{{c.c.class}}{{c.c.rating}} {{c.c.name || c.c.grp | translate}}</div>
<div class="r">{{c.c.mass || c.c.capacity || '0'}} <u translate="T"></u></div>
<div class="cb"></div>
<div class="l" ng-if="c.c.optmass">Optimal Mass: {{c.c.optmass}} <u>T</u></div>
<div class="l" ng-if="c.c.maxmass">Max Mass: {{c.c.maxmass}} <u>T</u></div>
<div class="l" ng-if="c.c.bins">{{c.c.bins}} <u>Bins</u></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.cells">Cells: {{c.c.cells}}</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>
<div class="l" ng-if="c.c.maximum">Max: {{(c.c.maximum)}}</div>
<div class="l" ng-if="c.c.rangeLS">{{c.c.rangeLS}} <u>LS</u></div>
<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 class="l" ng-if="c.c.optmass">{{'optimal mass' | translate}}: {{c.c.optmass}} <u translate="T"></u></div>
<div class="l" ng-if="c.c.maxmass">{{'max mass' | translate}}: {{c.c.maxmass}} <u translate="T"></u></div>
<div class="l" ng-if="c.c.bins">{{c.c.bins}} <u translate="bins"></u></div>
<div class="l" ng-if="c.c.rate">{{'rate' | translate}}: {{c.c.rate}} <u>Kg/s</u>&nbsp;&nbsp;&nbsp;{{'refuel time' | translate}}: {{$r.fTime(fuel * 1000 / c.c.rate)}}</div>
<div class="l" ng-if="c.c.ammo">{{'ammo' | translate}}: {{c.c.ammo}}</div>
<div class="l" ng-if="c.c.cells">{{'cells' | translate}}: {{c.c.cells}}</div>
<div class="l" ng-if="c.c.recharge">{{'recharge' | translate}}: {{c.c.recharge}} <u>MJ</u>&nbsp;&nbsp;&nbsp;{{'total' | translate}}: {{c.c.cells * c.c.recharge}} <u>MJ</u></div>
<div class="l" ng-if="c.c.repair">{{'repair' | translate}}: {{c.c.repair}}</div>
<div class="l" ng-if="c.c.range">{{'range' | translate}} {{c.c.range}} <u>km</u></div>
<div class="l" ng-if="c.c.time">{{'time' | translate}}: {{$r.fTime(c.c.time)}}</div>
<div class="l" ng-if="c.c.maximum">{{'max' | translate}}: {{(c.c.maximum)}}</div>
<div class="l" ng-if="c.c.rangeLS">{{c.c.rangeLS}} <u translate="LS"></u></div>
<div class="l" ng-if="c.c.rangeLS === null"><svg class="icon"><use xlink:href="#infinite"></use></svg> <u translate="LS"></u></div>
<div class="l" ng-if="c.c.rangeRating">{{'range' | translate}}: {{c.c.rangeRating}}</div>
<div class="l" ng-if="c.c.armouradd">+{{c.c.armouradd}} <u translate="armour"></u></div>
</div>

View File

@@ -26,4 +26,4 @@
<p>Help keep the lights on! Donations will be used to cover costs of running and maintaining Coriolis. Thanks for helping!</p>
<button class="r dismiss" ng-click="dismiss()">Close</button>
<button class="r dismiss cap" ng-click="dismiss()" translate="close"></button>

View File

@@ -1,4 +1,4 @@
<h2>Delete All</h2>
<p style="text-align:center;">Are you sure?</p>
<button class="l" ng-click="deleteAll()">Yes</button>
<button class="r" ng-click="dismiss()">No</button>
<h2 translate="delete all"></h2>
<p style="text-align:center;" translate="PHRASE_CONFIRMATION"></p>
<button class="l cap" ng-click="deleteAll()" translate="yes"></button>
<button class="r cap" ng-click="dismiss()" translate="no"></button>

View File

@@ -1,6 +1,6 @@
<h2 ng-bind="title"></h2>
<div ng-if="description" ng-bind="description"></div>
<h2 ng-bind="title | translate"></h2>
<div ng-if="description" ng-bind="description | translate"></div>
<div>
<textarea class="cb json" ng-click="onTextClick($event)" ng-bind="export"></textarea>
</div>
<button class="r dismiss" ng-click="dismiss()">Close</button>
<button class="r dismiss cap" ng-click="dismiss()" translate="close"></button>

View File

@@ -1,40 +1,46 @@
<h2>Import</h2>
<h2 translate="import"></h2>
<div ng-show="!processed">
<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>
<textarea class="cb json" ng-model="importString" ng-change="validateImport()" placeholder="{{'PHRASE_IMPORT' | translate}}"></textarea>
<button class="l cap" ng-click="process()" ng-disabled="!importValid" translate="proceed"></button>
<div class="l warning" style="margin-left:3em;">{{errorMsg}}</div>
</div>
<div ng-show="processed">
<table class="l" style="overflow:hidden;margin: 1em 0; width: 100%;">
<thead><tr><th style="text-align:left">Ship</th><th style="text-align:left">Build Name</th><th>Action</th></tr></thead>
<thead>
<tr>
<th style="text-align:left" translate="ship"></th>
<th style="text-align:left" translate="build name"></th>
<th translate="action"></th>
</tr>
</thead>
<tbody ng-repeat="(shipId,shipBuilds) in builds">
<tr class="cb" ng-repeat="(buildName, b) in shipBuilds">
<td>{{ships[shipId].properties.name}}</td>
<td><input type="text" ng-model="b.useName"/></td>
<td style="text-align:center" ng-class="{warning: hasBuild(shipId, b.useName) == true, disabled: b.useName == ''}">
<span ng-show="b.useName">{{ hasBuild(shipId, b.useName)? 'Overwrite' : 'Create' }}</span>
<span ng-show="b.useName == ''">Skip</span>
<span ng-show="b.useName" translate="{{ hasBuild(shipId, b.useName)? 'overwrite' : 'create' }}"></span>
<span ng-show="b.useName == ''" translate="skip"></span>
</td>
</tr>
</tbody>
</table>
<table class="l" style="overflow:hidden;margin: 1em 0; width: 100%;" ng-if="comparisons">
<thead><tr><th style="text-align:left">Comparison</th><th>Action</th></tr></thead>
<thead><tr><th style="text-align:left" translate="comparison"></th><th translate="action"></th></tr></thead>
<tbody>
<tr class="cb" ng-repeat="(name, comparison) in comparisons">
<td><input type="text" ng-model="comparison.useName"/></td>
<td style="text-align:center" ng-class="{warning: hasComparison(comparison.useName) == true, disabled: comparison.useName == ''}">
<span ng-show="comparison.useName">{{ hasComparison(comparison.useName)? 'Overwrite' : 'Create' }}</span>
<span ng-show="comparison.useName == ''">Skip</span>
<span ng-show="comparison.useName" translate="{{ hasComparison(comparison.useName)? 'overwrite' : 'create' }}"></span>
<span ng-show="comparison.useName == ''" translate="skip"></span>
</td>
</tr>
</tbody>
</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 Data</button>
<button class="cl l" ng-click="import()"><svg class="icon"><use xlink:href="#download"></use></svg> {{'import' | translate}}</button>
<button class="l cap" style="margin-left: 2em;" ng-click="processed = false" ng-show="canEdit" translate="edit data"></button>
</div>
<button class="r dismiss" ng-click="dismiss()">Cancel</button>
<button class="r dismiss cap" ng-click="dismiss()" translate="cancel"></button>

View File

@@ -1,9 +1,9 @@
<h2>Permalink</h2>
<h2 translate="permalink"></h2>
<br>
<h3>URL</h3>
<h3 translate="URL"></h3>
<input ng-model="url" size="40" ng-click="onTextClick($event)">
<br><br>
<h3>Shortened</h3>
<h3 translate="shortened"></h3>
<input ng-model="shortenedUrl" size="25" ng-click="onTextClick($event)">
<br><br>
<button class="r dismiss" ng-click="dismiss()">Close</button>
<button class="r dismiss cap" ng-click="dismiss()" translate="close"></button>

View File

@@ -1,37 +1,37 @@
<table id="comparison">
<tr ng-show="compareMode">
<td class="head">Comparison</td>
<td class="head" translate="comparison"></td>
<td>
<input ng-model="name" ng-change="nameChange()" placeholder="Enter Comparison Name" maxlength="50" />
<input ng-model="name" ng-change="nameChange()" placeholder="{{'enter name' | translate}}" maxlength="50" />
<button ng-click="save()" ng-disabled="!name || name == 'all' || saved">
<svg class="icon lg "><use xlink:href="#floppy-disk"></use></svg><span class="button-lbl"> Save</span>
<svg class="icon lg "><use xlink:href="#floppy-disk"></use></svg><span class="button-lbl"> {{'save' | translate}}</span>
</button>
<button ng-click="delete()" ng-disabled="name == 'all' || !saved"><svg class="icon lg warning "><use xlink:href="#bin"></use></svg></button>
<button ng-click="selectBuilds(true, $event)">
<svg class="icon lg "><use xlink:href="#rocket"></use></svg><span class="button-lbl"> Builds</span>
<svg class="icon lg "><use xlink:href="#rocket"></use></svg><span class="button-lbl"> {{'builds' | translate}}</span>
</button>
<button class="r" ng-click="permalink($event)" ng-disabled="builds.length == 0">
<svg class="icon lg "><use xlink:href="#link"></use></svg><span class="button-lbl"> Permalink</span>
<svg class="icon lg "><use xlink:href="#link"></use></svg><span class="button-lbl"> {{'permalink' | translate}}</span>
</button>
<button class="r" ng-click="embed($event)" ng-disabled="builds.length == 0">
<svg class="icon lg "><use xlink:href="#embed"></use></svg><span class="button-lbl"> Forum</span>
<svg class="icon lg "><use xlink:href="#embed"></use></svg><span class="button-lbl"> {{'forum' | translate}}</span>
</button>
</td>
</tr>
<tr ng-show="!compareMode">
<td class="head">Comparison</td>
<td class="head" translate="comparison"></td>
<td>
<h3 ng-bind="name"></h3>
<button class="r" ui-sref="modal.import({obj:importObj})"><svg class="icon lg "><use xlink:href="#download"></use></svg> Import Builds</button>
<button class="r" ui-sref="modal.import({obj:importObj})"><svg class="icon lg "><use xlink:href="#download"></use></svg> {{'import' | translate}}</button>
</td>
</tr>
<tr>
<td class="head">Compare</td>
<td class="head" translate="compare"></td>
<td>
<ul id="facet-container" as-sortable="facetSortOpts" ng-model="facets" class="sortable" update="tblUpdate">
<li ng-repeat="(i,f) in facets" as-sortable-item class="facet" ng-class="{active: f.active}" ng-click="toggleFacet(i)">
<div as-sortable-item-handle>&#x2194; <span ng-bind="f.title"></span></div>
<div as-sortable-item-handle>&#x2194; <span ng-bind="f.title | translate"></span></div>
</li>
</ul>
</td>
@@ -43,15 +43,15 @@
</div>
<div ng-repeat="f in facets | filter:{active:true}" ng-if="builds.length > 0" class="chart" bar-chart facet="f" data="builds">
<h3 ng-click="sort(f.props[0])" >{{f.title}}</h3>
<h3 ng-click="sort(f.props[0])" >{{f.title | translate}}</h3>
</div>
<div class="modal-bg" ng-show="showBuilds" ng-click="selectBuilds(false, $event)">
<div class="modal" ui-view="modal-content" ng-click="$event.stopPropagation()">
<h3>Select Builds to Compare</h3>
<h3 translate="PHRASE_SELECT_BUILDS"></h3>
<div id="build-select">
<table>
<thead><tr><th colspan="2">Available</th></tr></thead>
<thead><tr><th colspan="2" translate="available"></th></tr></thead>
<tbody>
<tr ng-repeat="b in unusedBuilds | orderBy:'name'" ng-click="addBuild(b.id, b.buildName)">
<td class="tl" ng-bind="b.name"></td><td class="tl" ng-bind="b.buildName"></td>
@@ -60,7 +60,7 @@
</table>
<h1></h1>
<table>
<thead><tr><th colspan="2">Added</th></tr></thead>
<thead><tr><th colspan="2" translate="added"></th></tr></thead>
<tbody>
<tr ng-repeat="b in builds | orderBy:'name'" ng-click="removeBuild(b.id, b.buildName)">
<td class="tl" ng-bind="b.name"></td><td class="tl" ng-bind="b.buildName"></td>
@@ -69,6 +69,6 @@
</table>
</div>
<br>
<button class="r dismiss" ng-click="selectBuilds(false, $event)">Done</button>
<button class="r dismiss cap" ng-click="selectBuilds(false, $event)" translate="done"></button>
</div>
</div>

View File

@@ -3,27 +3,27 @@
<div id="overview">
<h1 ng-bind="ship.name"></h1>
<div id="build">
<input ng-model="buildName" ng-change="bnChange()" placeholder="Enter Build Name" maxsize="50" />
<input ng-model="buildName" ng-change="bnChange()" placeholder="{{'enter name' | translate}}" maxsize="50" />
<button ng-click="saveBuild()" ng-disabled="!buildName || savedCode && code == savedCode || !canSave">
<svg class="icon lg "><use xlink:href="#floppy-disk"></use></svg><span class="button-lbl">Save</span>
<svg class="icon lg "><use xlink:href="#floppy-disk"></use></svg><span class="button-lbl" translate="save"></span>
</button>
<button ng-click="reloadBuild()" ng-disabled="!savedCode || code == savedCode">
<svg class="icon lg"><use xlink:href="#spinner11"></use></svg><span class="button-lbl">Reload</span>
<svg class="icon lg"><use xlink:href="#spinner11"></use></svg><span class="button-lbl" translate="reload"></span>
</button>
<button class="danger" ng-click="deleteBuild()" ng-disabled="!savedCode">
<svg class="icon lg"><use xlink:href="#bin"></use></svg>
</button>
<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" translate="reset"></span>
</button>
<button ng-click="aRatedBuild()">
<svg class="icon lg"><use xlink:href="#a"></use></svg><span class="button-lbl">A-Rated</span>
<svg class="icon lg"><use xlink:href="#a"></use></svg><span class="button-lbl" translate="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>
<svg class="icon lg"><use xlink:href="#feather"></use></svg><span class="button-lbl" translate="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>
<svg class="icon lg"><use xlink:href="#download"></use></svg><span class="button-lbl" translate="export"></span>
</button>
</div>
</div>
@@ -32,42 +32,42 @@
<table id="summaryTable">
<thead>
<tr class="main">
<th rowspan="2">Size</th>
<th rowspan="2">Agility</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>
<th colspan="3">Mass</th>
<th rowspan="2">Cargo</th>
<th rowspan="2">Fuel</th>
<th colspan="3">Jump Range</th>
<th colspan="3">Total Range</th>
<th rowspan="2">Lock<br>Factor</th>
<th rowspan="2" translate="size"></th>
<th rowspan="2" translate="agility"></th>
<th rowspan="2" ng-class="{'bg-warning-disabled': th.c.maxmass < ship.ladenMass}" translate="speed"></th>
<th rowspan="2" ng-class="{'bg-warning-disabled': (pd.c.enginecapacity < ship.boostEnergy || th.c.maxmass < ship.ladenMass)}" translate="boost"></th>
<th rowspan="2" translate="DPS"></th>
<th rowspan="2" translate="armour"></th>
<th rowspan="2" translate="shields"></th>
<th colspan="3" translate="mass"></th>
<th rowspan="2" translate="cargo"></th>
<th rowspan="2" translate="fuel"></th>
<th colspan="3" translate="jump range"></th>
<th colspan="3" translate="total range"></th>
<th rowspan="2" translate="lock factor"></th>
</tr>
<tr>
<th class="lft">Hull</th>
<th>Unladen</th>
<th>Laden</th>
<th class="lft">Max</th>
<th>Full Tank</th>
<th>Laden</th>
<th class="lft">Jumps</th>
<th>Unladen</th>
<th>Laden</th>
<th class="lft" translate="hull"></th>
<th translate="unladen"></th>
<th translate="laden"></th>
<th class="lft" translate="max"></th>
<th translate="full tank"></th>
<th translate="laden"></th>
<th class="lft" translate="jumps"></th>
<th translate="unladen"></th>
<th translate="laden"></th>
</tr>
</thead>
<tbody>
<tr>
<td ng-bind="SZ[ship.class]"></td>
<td class="cap" ng-bind="['','small','medium','large','capital'][ship.class] | translate"></td>
<td>{{ship.agility}}/10</td>
<td>
<span ng-if="th.c.maxmass >= ship.ladenMass">{{fRound(ship.speed)}} <u>m/s</u></span>
<span ng-if="th.c.maxmass >= ship.ladenMass">{{fRound(ship.speed)}} <u translate>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 ng-if="pd.c.enginecapacity >= ship.boostEnergy && th.c.maxmass >= ship.ladenMass">{{fRound(ship.boost)}} <u translate>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>
@@ -75,21 +75,22 @@
<td>{{fRound(ship.totalDps)}}</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>
<span ng-if="ship.armourAdded || ship.armourMultiplier > 1">
(<span ng-if="ship.armourMultiplier > 1">{{fRPct(ship.armourMultiplier)}}</span><span ng-if="ship.armourAdded && ship.armourMultiplier > 1">&nbsp;</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>
<td>{{fRound(ship.ladenMass)}} <u>T</u></td>
<td>{{fRound(ship.cargoCapacity)}} <u>T</u></td>
<td>{{fRound(ship.fuelCapacity)}} <u>T</u></td>
<td>{{fRound(ship.unladenRange)}} <u>LY</u></td>
<td>{{fRound(ship.fullTankRange)}} <u>LY</u></td>
<td>{{fRound(ship.ladenRange)}} <u>LY</u></td>
<td>{{fRound(ship.shieldStrength)}} <u translate>MJ</u> <span ng-if="ship.shieldMultiplier > 1 && ship.shieldStrength > 0">({{fRPct(ship.shieldMultiplier)}})</span></td>
<td>{{ship.hullMass}} <u translate>T</u></td>
<td>{{fRound(ship.unladenMass)}} <u translate>T</u></td>
<td>{{fRound(ship.ladenMass)}} <u translate>T</u></td>
<td>{{fRound(ship.cargoCapacity)}} <u translate>T</u></td>
<td>{{fRound(ship.fuelCapacity)}} <u translate>T</u></td>
<td>{{fRound(ship.unladenRange)}} <u translate>LY</u></td>
<td>{{fRound(ship.fullTankRange)}} <u translate>LY</u></td>
<td>{{fRound(ship.ladenRange)}} <u translate>LY</u></td>
<td>{{fRound(ship.maxJumpCount)}}</td>
<td>{{fRound(ship.unladenTotalRange)}} <u>LY</u></td>
<td>{{fRound(ship.ladenTotalRange)}} <u>LY</u></td>
<td>{{fRound(ship.unladenTotalRange)}} <u translate>LY</u></td>
<td>{{fRound(ship.ladenTotalRange)}} <u translate>LY</u></td>
<td ng-bind="ship.masslock"></td>
</tr>
</tbody>
@@ -97,103 +98,103 @@
</div>
<div id="standard" class="group">
<h1>Standard</h1>
<h1 translate="standard"></h1>
<div class="slot" ng-click="selectSlot($event, ship.bulkheads)" ng-class="{selected: selectedSlot==ship.bulkheads}">
<div class="details">
<div class="sz"><span>8</span></div>
<div class="l">Bulkheads</div>
<div class="r">{{ship.bulkheads.c.mass}} <u>T</u></div>
<div class="cl l">{{ship.bulkheads.c.name}}</div>
<div class="l cap" translate="bh"></div>
<div class="r">{{ship.bulkheads.c.mass}} <u translate>T</u></div>
<div class="cl l">{{ship.bulkheads.c.name | translate}}</div>
</div>
<div class="select" ng-if="selectedSlot==ship.bulkheads" ng-click="select('b',ship.bulkheads,$event)">
<ul>
<li class="lc" ng-class="{active: ship.bulkheads.id=='0'}" cpid="0">Lightweight Alloy</li>
<li class="lc" ng-class="{active: ship.bulkheads.id=='1'}" cpid="1">Reinforced Alloy</li>
<li class="lc" ng-class="{active: ship.bulkheads.id=='2'}" cpid="2">Military Grade Composite</li>
<li class="lc" ng-class="{active: ship.bulkheads.id=='3'}" cpid="3">Mirrored Surface Composite</li>
<li class="lc" ng-class="{active: ship.bulkheads.id=='4'}" cpid="4">Reactive Surface Composite</li>
<li class="lc" ng-class="{active: ship.bulkheads.id=='0'}" cpid="0" translate="Lightweight Alloy"></li>
<li class="lc" ng-class="{active: ship.bulkheads.id=='1'}" cpid="1" translate="Reinforced Alloy"></li>
<li class="lc" ng-class="{active: ship.bulkheads.id=='2'}" cpid="2" translate="Military Grade Composite"></li>
<li class="lc" ng-class="{active: ship.bulkheads.id=='3'}" cpid="3" translate="Mirrored Surface Composite"></li>
<li class="lc" ng-class="{active: ship.bulkheads.id=='4'}" cpid="4" translate="Reactive Surface Composite"></li>
</ul>
</div>
</div>
<div class="slot" ng-click="selectSlot($event, pp)" ng-class="{selected: selectedSlot==pp}">
<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>
<div class="l">{{pp.id}} {{'pp' | translate}}</div>
<div class="r">{{pp.c.mass}} <u translate>T</u></div>
<div class="cb"></div>
<div class="l">Efficiency: {{pp.c.eff}}</div>
<div class="l">Power: {{pp.c.pGen}} <u>MW</u></div>
<div class="l cap">{{'efficiency' | translate}}: {{pp.c.eff}}</div>
<div class="l cap">{{'power' | translate}}: {{pp.c.pGen}} <u translate>MW</u></div>
</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" 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>
<div class="l">{{th.id}} {{'t' | translate}}</div>
<div class="r">{{th.c.mass}} <u translate>T</u></div>
<div class="cb"></div>
<div class="l">Optimal Mass: {{th.c.optmass}} <u>T</u></div>
<div class="l">Max Mass: {{th.c.maxmass}} <u>T</u></div>
<div class="l">{{'optimal mass' | translate}}: {{th.c.optmass}} <u translate>T</u></div>
<div class="l">{{'max mass' | translate}}: {{th.c.maxmass}} <u translate>T</u></div>
</div>
<div component-select class="select" s="th" mass="ship.ladenMass" opts="availCS.common[1]" ng-if="selectedSlot==th" ng-click="select('c',th,$event)"></div>
</div>
<div class="slot" ng-click="selectSlot($event, fsd)" ng-class="{selected: selectedSlot==fsd}">
<div class="details">
<div class="sz">{{::fsd.maxClass}}</div>
<div class="l">{{fsd.id}} Frame Shift Drive</div>
<div class="r cr">{{fsd.c.mass}} <u>T</u></div>
<div class="l">{{fsd.id}} {{'fd' | translate}}</div>
<div class="r cr">{{fsd.c.mass}} <u translate>T</u></div>
<div class="cb"></div>
<div class="l">Optimal Mass: {{fsd.c.optmass}} <u>T</u></div>
<div class="l">Max Fuel: {{fsd.c.maxfuel}} <u>T</u></div>
<div class="l cap">{{'optimal mass' | translate}}: {{fsd.c.optmass}} <u translate>T</u></div>
<div class="l cap">{{'max' | translate}} {{'fuel' | translate}}: {{fsd.c.maxfuel}} <u translate>T</u></div>
</div>
<div component-select class="select" s="fsd" opts="availCS.common[2]" ng-if="selectedSlot==fsd" ng-click="select('c',fsd,$event)"></div>
</div>
<div class="slot" ng-click="selectSlot($event, ls)" ng-class="{selected: selectedSlot==ls}">
<div class="details">
<div class="sz">{{::ls.maxClass}}</div>
<div class="l">{{ls.id}} Life Support</div>
<div class="r">{{ls.c.mass}} <u>T</u></div>
<div class="l">{{ls.id}} {{'ls' | translate}}</div>
<div class="r">{{ls.c.mass}} <u translate>T</u></div>
<div class="cb"></div>
<div class="l">Time: {{fTime(ls.c.time)}}</div>
<div class="l cap">{{'time' | translate}}: {{fTime(ls.c.time)}}</div>
</div>
<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" 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>
<div class="l">{{pd.id}} {{'pd' | translate}}</div>
<div class="r">{{pd.c.mass}} <u translate>T</u></div>
<div class="cb"></div>
<div class="l">WEP: {{pd.c.weaponcapacity}} <u>MJ</u> / {{pd.c.weaponrecharge}} <u>MW</u></div>
<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 class="l">{{'WEP' | translate}}: {{pd.c.weaponcapacity}} <u translate>MJ</u> / {{pd.c.weaponrecharge}} <u translate>MW</u></div>
<div class="l">{{'SYS' | translate}}: {{pd.c.systemcapacity}} <u translate>MJ</u> / {{pd.c.systemrecharge}} <u translate>MW</u></div>
<div class="l">{{'ENG' | translate}}: {{pd.c.enginecapacity}} <u translate>MJ</u> / {{pd.c.enginerecharge}} <u translate>MW</u></div>
</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">
<div class="sz">{{::ss.maxClass}}</div>
<div class="l">{{ss.id}} Sensors</div>
<div class="r">{{ss.c.mass}} <u>T</u></div>
<div class="l">{{ss.id}} {{'s' | translate}}</div>
<div class="r">{{ss.c.mass}} <u translate>T</u></div>
<div class="cb"></div>
<div class="l">Range: {{ss.c.range}} <u>km</u></div>
<div class="l cap">{{'range' | translate}}: {{ss.c.range}} <u translate>km</u></div>
</div>
<div component-select class="select" s="ss" opts="availCS.common[5]" ng-if="selectedSlot==ss" ng-click="select('c',ss,$event)"></div>
</div>
<div class="slot" ng-click="selectSlot($event, ft)" ng-class="{selected: selectedSlot==ft}">
<div class="details">
<div class="sz">{{::ft.maxClass}}</div>
<div class="l">{{ft.id}} Fuel Tank</div>
<div class="r">{{ft.c.capacity}} <u>T</u></div>
<div class="l">{{ft.id}} {{'ft' | translate}}</div>
<div class="r">{{ft.c.capacity}} <u translate>T</u></div>
</div>
<div component-select class="select" s="ft" opts="availCS.common[6]" ng-if="selectedSlot==ft" ng-click="select('c',ft,$event)"></div>
</div>
</div>
<div id="internal" class="group">
<h1>Internal Compartments</h1>
<h1 translate="internal compartments"></h1>
<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" 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, i.eligible)"></div>
</div>
@@ -201,9 +202,9 @@
</div>
<div id="hardpoints" class="group">
<h1>HardPoints</h1>
<h1 translate="hardpoints"></h1>
<div class="slot" ng-repeat="h in ship.hardpoints | filter:{maxClass: '!0'}" ng-click="selectSlot($event, h)" context-menu="select('h', h, $event, 'empty')" ng-class="{selected: selectedSlot==h}">
<div slot-hardpoint class="details" hp="h" size="HPC[h.maxClass]" lbl="GMAP[h.c.grp]"></div>
<div slot-hardpoint class="details" hp="h" size="HPC[h.maxClass]"></div>
<div class="select" ng-class="{hardpoint: h.maxClass > 0}" ng-if="selectedSlot==h" ng-click="select('h',h,$event)">
<div component-select s="h" groups="availCS.getHps(h.maxClass)"></div>
</div>
@@ -211,9 +212,9 @@
</div>
<div id="utility" class="group">
<h1>Utility Mounts</h1>
<h1 translate="utility mounts"></h1>
<div class="slot" ng-repeat="h in ship.hardpoints | filter:{maxClass: '0'}" ng-click="selectSlot($event, h)" context-menu="select('h', h, $event, 'empty')" ng-class="{selected: selectedSlot==h}">
<div slot-hardpoint class="details" hp="h" size="HPC[h.maxClass]" lbl="GMAP[h.c.grp]"></div>
<div slot-hardpoint class="details" hp="h" size="HPC[h.maxClass]"></div>
<div class="select" ng-class="{hardpoint: h.maxClass > 0}" ng-if="selectedSlot==h" ng-click="select('h',h,$event)">
<div component-select s="h" groups="availCS.getHps(h.maxClass)"></div>
</div>
@@ -224,19 +225,19 @@
<table style="width:100%">
<thead>
<tr class="main">
<th colspan="2" class="sortable le" ng-click="sortPwr(cName)">Component</th>
<th style="width:3em;" class="sortable" ng-click="sortPwr('type')">Type</th>
<th style="width:4em;" class="sortable" ng-click="sortPwr('priority')">Pri</th>
<th colspan="2" class="sortable" ng-click="sortPwr('c.power')">Pwr</th>
<th style="width:3em;" class="sortable" ng-click="sortPwr(statusRetracted)">Ret</th>
<th style="width:3em;" class="sortable" ng-click="sortPwr(statusDeployed)">Dep</th>
<th colspan="2" class="sortable le" ng-click="sortPwr(cName)" translate="COMPONENT"></th>
<th style="width:3em;" class="sortable" ng-click="sortPwr('type')" translate="TYPE"></th>
<th style="width:4em;" class="sortable" ng-click="sortPwr('priority')" translate="PRI"></th>
<th colspan="2" class="sortable" ng-click="sortPwr('c.power')" translate="PWR"></th>
<th style="width:3em;" class="sortable" ng-click="sortPwr(statusRetracted)" translate="RET"></th>
<th style="width:3em;" class="sortable" ng-click="sortPwr(statusDeployed)" translate="DEP"></th>
</tr>
</thead>
<tbody>
<tr>
<td>{{pp.c.class}}{{pp.c.rating}}</td>
<td class="le shorten">Power Plant</td>
<td><u>SYS</u></td>
<td class="le shorten cap" translate="pp"></td>
<td><u translate="SYS"></u></td>
<td>1</td>
<td class="ri">{{fPwr(pp.c.pGen)}}</td>
<td class="ri"><u>100%</u></td>
@@ -246,14 +247,14 @@
<tr><td style="line-height:0;" colspan="8"><hr style="margin: 0 0 3px;background: #ff8c0d;border: 0;height: 1px;" /></td></tr>
<tr class="highlight" ng-repeat="c in powerList | orderBy:pwrPredicate:pwrDesc" ng-if="c.c.power" ng-class="{disabled:!c.enabled}">
<td style="width:1em;" ng-click="togglePwr(c)">{{c.c.class}}{{c.c.rating}}</td>
<td class="le shorten" ng-click="togglePwr(c)" ng-bind="cName(c)"></td>
<td ng-click="togglePwr(c)"><u ng-bind="c.type"></u></td>
<td class="le shorten cap" ng-click="togglePwr(c)" ng-bind="cName(c)"></td>
<td ng-click="togglePwr(c)"><u ng-bind="c.type | translate"></u></td>
<td><span ng-click="decPriority(c)" class="flip">&#9658;</span> {{c.priority + 1}} <span ng-click="incPriority(c)">&#9658;</span></td>
<td class="ri" style="width:3.25em;">{{fPwr(c.c.power)}}</td>
<td class="ri" style="width:3em;"><u>{{f1Pct(c.c.power/ship.powerAvailable)}}</u></td>
<td ng-if="!c.enabled" class="disabled" colspan="2">DISABLED</td>
<td ng-if="c.enabled" ng-class="STATUS_CLASS[statusRetracted(c)]">{{STATUS[statusRetracted(c)]}}</td>
<td ng-if="c.enabled" ng-class="STATUS_CLASS[statusDeployed(c)]">{{STATUS[statusDeployed(c)]}}</td>
<td ng-if="!c.enabled" class="disabled upp" colspan="2" translate="disabled"></td>
<td class="upp" ng-if="c.enabled" ng-class="STATUS_CLASS[statusRetracted(c)]">{{STATUS[statusRetracted(c)] | translate}}</td>
<td class="upp" ng-if="c.enabled" ng-class="STATUS_CLASS[statusDeployed(c)]">{{STATUS[statusDeployed(c)] | translate}}</td>
</tr>
</tbody>
</table>
@@ -264,8 +265,8 @@
<table class="tabs">
<thead>
<tr>
<th style="width:50%" ng-class="{active: costTab == 'retrofit'}" ng-click="updateCostTab('retrofit')">Retrofit Costs</th>
<th style="width:50%" ng-class="{active: costTab == 'costs'}" ng-click="updateCostTab('costs')">Costs</th>
<th style="width:50%" ng-class="{active: costTab == 'retrofit'}" ng-click="updateCostTab('retrofit')" translate="retrofit costs"></th>
<th style="width:50%" ng-class="{active: costTab == 'costs'}" ng-click="updateCostTab('costs')" translate="costs"></th>
</tr>
</thead>
</table>
@@ -275,29 +276,29 @@
<thead>
<tr class="main">
<th colspan="2" class="sortable le" ng-click="sortCost(cName)">
Component
<u class="optional-hide" ng-if="discounts.ship < 1">[Ship {{fRPct(1 - discounts.ship)}} off]</u>
<u class="optional-hide" ng-if="discounts.components < 1">[Components {{fRPct(1 - discounts.components)}} off]</u>
{{'component' | translate}}
<u class="optional-hide" ng-if="discounts.ship < 1">[{{'ship' | translate }} -{{fRPct(1 - discounts.ship)}}]</u>
<u class="optional-hide" ng-if="discounts.components < 1">[{{'components' | translate}} -{{fRPct(1 - discounts.components)}}]</u>
</th>
<th class="sortable le" ng-click="sortCost('discountedCost')">Credits</th>
<th class="sortable le" ng-click="sortCost('discountedCost')" translate="credits"></th>
</tr>
</thead>
<tbody>
<tr class="highlight" ng-repeat="item in costList | orderBy:costPredicate:costDesc" ng-if="item.c.cost > 0" ng-class="{disabled:!item.incCost}">
<td class="toggleable" style="width:1em;" ng-click="toggleCost(item)">{{item.c.class}}{{item.c.rating}}</td>
<td class="le toggleable shorten" ng-click="toggleCost(item)">{{cName(item)}}</td>
<td class="ri toggleable" ng-click="toggleCost(item)">{{fCrd(item.discountedCost)}} <u>CR</u></td>
<td class="le toggleable shorten cap" ng-click="toggleCost(item)">{{cName(item)}}</td>
<td class="ri toggleable" ng-click="toggleCost(item)">{{fCrd(item.discountedCost)}} <u translate>CR</u></td>
</tr>
</tbody>
</table>
<table class="total">
<tr class="ri">
<td class="lbl">Total</td>
<td>{{fCrd(ship.totalCost)}} <u>CR</u></td>
<td class="lbl" translate="total"></td>
<td>{{fCrd(ship.totalCost)}} <u translate>CR</u></td>
</tr>
<tr class="ri">
<td class="lbl">Insurance</td>
<td>{{fCrd(ship.totalCost * insurance.current.pct)}} <u>CR</u></td>
<td class="lbl" translate="insurance"></td>
<td>{{fCrd(ship.totalCost * insurance.current.pct)}} <u translate>CR</u></td>
</tr>
</table>
</div>
@@ -307,38 +308,38 @@
<table style="width:100%">
<thead>
<tr class="main">
<th colspan="2" class="sortable le" ng-click="sortRetrofit('sellName')">Sell</th>
<th colspan="2" class="sortable le" ng-click="sortRetrofit('buyName')">Buy</th>
<th colspan="2" class="sortable le" ng-click="sortRetrofit('sellName | translate')" translate="sell"></th>
<th colspan="2" class="sortable le" ng-click="sortRetrofit('buyName | translate')" translate="buy"></th>
<th class="sortable le" ng-click="sortRetrofit('netCost')">
Net Cost <u class="optional-hide" ng-if="discounts.components < 1">[{{fRPct(1 - discounts.components)}} off]</u>
{{'net cost' | translate}} <u class="optional-hide" ng-if="discounts.components < 1">-[{{fRPct(1 - discounts.components)}}]</u>
</th>
</tr>
</thead>
<tbody>
<tr ng-if="!retrofitList || retrofitList.length == 0">
<td colspan="5" style="padding: 3em 0;">No Retrofitting changes</td>
<td colspan="5" style="padding: 3em 0;" translate="PHRASE_NO_RETROCH"></td>
</tr>
<tr class="highlight" ng-repeat="item in retrofitList | orderBy:retroPredicate:retroDesc">
<td style="width:1em;">{{item.sellClassRating}}</td>
<td class="le shorten">{{item.sellName}}</td>
<td class="le shorten cap">{{item.sellName | translate}}</td>
<td style="width:1em;">{{item.buyClassRating}}</td>
<td class="le shorten">{{item.buyName}}</td>
<td class="ri" ng-class="item.netCost > 0 ? 'warning' : 'secondary-disabled'">{{ fCrd(item.netCost)}} <u>CR</u></td>
<td class="le shorten cap">{{item.buyName | translate}}</td>
<td class="ri" ng-class="item.netCost > 0 ? 'warning' : 'secondary-disabled'">{{ fCrd(item.netCost)}} <u translate>CR</u></td>
</tr>
</tbody>
</table>
</div>
<table class="total">
<tr class="ri">
<td class="lbl">Cost</td>
<td colspan="2" ng-class="retrofitTotal > 0 ? 'warning' : 'secondary-disabled'">{{fCrd(retrofitTotal)}} <u>CR</u></td>
<td class="lbl" translate="cost"></td>
<td colspan="2" ng-class="retrofitTotal > 0 ? 'warning' : 'secondary-disabled'">{{fCrd(retrofitTotal)}} <u translate>CR</u></td>
</tr>
<tr class="ri">
<td class="lbl">Retrofit from</td>
<td class="lbl cap" translate="retrofit from"></td>
<td class="cen" style="border-right:none;width: 1em;"><u class="primary-disabled">&#9662;</u></td>
<td style="border-left:none;padding:0;">
<select style="width: 100%;padding: 0" ng-model="$parent.retrofitBuild" ng-change="setRetrofitBase()" ng-options="name as name for (name, build) in allBuilds[ship.id]">
<option value="">Stock / Standard</option>
<option value="">{{'Stock' | translate}}</option>
</select>
</td>
@@ -348,18 +349,18 @@
</div>
<div class="group half">
<h1>Jump Range</h1>
<h1 translate="jump range"></h1>
<div line-chart config="jrChart" series="jrSeries"></div>
</div>
<div class="group half">
<h1>Total Range</h1>
<h1 translate="total range"></h1>
<div line-chart config="trChart" series="trSeries"></div>
</div>
<!-- TODO: Add back in once calcSpeed is dynamic and accurate
<div class="group third">
<h1>Thruster Speed</h1>
<h1 translate="speed"></h1>
<div line-chart config="speedChart" series="speedSeries"></div>
</div>
-->

View File

@@ -26,7 +26,8 @@
"d3-tip": "~0.6.7",
"ng-sortable": "~1.2.1",
"lz-string": "~1.4.4",
"angular": "~1.4.0"
"angular": "~1.4.0",
"angular-translate": "~2.7.2"
},
"overrides": {
"angular": {
@@ -35,6 +36,9 @@
"angular-ui-router": {
"main": "release/angular-ui-router.min.js"
},
"angular-translate": {
"main": "angular-translate.min.js"
},
"d3": {
"main": "d3.min.js"
},

View File

@@ -221,6 +221,80 @@
"mass": 60
}
],
"imperial_eagle": [
{
"name": "Lightweight Alloy",
"class": 1,
"rating": "I",
"cost": 0,
"mass": 0
},
{
"name": "Reinforced Alloy",
"class": 1,
"rating": "I",
"cost": 66500,
"mass": 4
},
{
"name": "Military Grade Composite",
"class": 1,
"rating": "I",
"cost": 222765,
"mass": 8
},
{
"name": "Mirrored Surface Composite",
"class": 1,
"rating": "I",
"cost": 346555,
"mass": 8
},
{
"name": "Reactive Surface Composite",
"class": 1,
"rating": "I",
"cost": 372044,
"mass": 8
}
],
"federal_assault_ship": [
{
"name": "Lightweight Alloy",
"class": 1,
"rating": "I",
"cost": 0,
"mass": 0
},
{
"name": "Reinforced Alloy",
"class": 1,
"rating": "I",
"cost": 7925682,
"mass": 44
},
{
"name": "Military Grade Composite",
"class": 1,
"rating": "I",
"cost": 17832784,
"mass": 87
},
{
"name": "Mirrored Surface Composite",
"class": 1,
"rating": "I",
"cost": 42144814,
"mass": 87
},
{
"name": "Reactive Surface Composite",
"class": 1,
"rating": "I",
"cost": 46702081,
"mass": 87
}
],
"federal_dropship": [
{
"name": "Lightweight Alloy",
@@ -258,6 +332,43 @@
"mass": 87
}
],
"federal_gunship": [
{
"name": "Lightweight Alloy",
"class": 1,
"rating": "I",
"cost": 0,
"mass": 0
},
{
"name": "Reinforced Alloy",
"class": 1,
"rating": "I",
"cost": 14325688,
"mass": 44
},
{
"name": "Military Grade Composite",
"class": 1,
"rating": "I",
"cost": 32232788,
"mass": 87
},
{
"name": "Mirrored Surface Composite",
"class": 1,
"rating": "I",
"cost": 76176811,
"mass": 87
},
{
"name": "Reactive Surface Composite",
"class": 1,
"rating": "I",
"cost": 84414088,
"mass": 87
}
],
"python": [
{
"name": "Lightweight Alloy",

View File

@@ -1,6 +1,6 @@
{
"6E": {
"grp": "fsd",
"grp": "fd",
"class": 6,
"rating": "E",
"cost": 199747,
@@ -12,7 +12,7 @@
"fuelpower": 2.6
},
"6D": {
"grp": "fsd",
"grp": "fd",
"class": 6,
"rating": "D",
"cost": 599242,
@@ -24,7 +24,7 @@
"fuelpower": 2.6
},
"6C": {
"grp": "fsd",
"grp": "fd",
"class": 6,
"rating": "C",
"cost": 1797726,
@@ -36,7 +36,7 @@
"fuelpower": 2.6
},
"6B": {
"grp": "fsd",
"grp": "fd",
"class": 6,
"rating": "B",
"cost": 5393177,
@@ -48,7 +48,7 @@
"fuelpower": 2.6
},
"6A": {
"grp": "fsd",
"grp": "fd",
"class": 6,
"rating": "A",
"cost": 16179531,
@@ -60,7 +60,7 @@
"fuelpower": 2.6
},
"5E": {
"grp": "fsd",
"grp": "fd",
"class": 5,
"rating": "E",
"cost": 63013,
@@ -72,7 +72,7 @@
"fuelpower": 2.45
},
"5D": {
"grp": "fsd",
"grp": "fd",
"class": 5,
"rating": "D",
"cost": 189036,
@@ -84,7 +84,7 @@
"fuelpower": 2.45
},
"5C": {
"grp": "fsd",
"grp": "fd",
"class": 5,
"rating": "C",
"cost": 567106,
@@ -96,7 +96,7 @@
"fuelpower": 2.45
},
"5B": {
"grp": "fsd",
"grp": "fd",
"class": 5,
"rating": "B",
"cost": 1701318,
@@ -108,7 +108,7 @@
"fuelpower": 2.45
},
"5A": {
"grp": "fsd",
"grp": "fd",
"class": 5,
"rating": "A",
"cost": 5103953,
@@ -120,7 +120,7 @@
"fuelpower": 2.45
},
"4E": {
"grp": "fsd",
"grp": "fd",
"class": 4,
"rating": "E",
"cost": 19878,
@@ -132,7 +132,7 @@
"fuelpower": 2.3
},
"4D": {
"grp": "fsd",
"grp": "fd",
"class": 4,
"rating": "D",
"cost": 59633,
@@ -144,7 +144,7 @@
"fuelpower": 2.3
},
"4C": {
"grp": "fsd",
"grp": "fd",
"class": 4,
"rating": "C",
"cost": 178898,
@@ -156,7 +156,7 @@
"fuelpower": 2.3
},
"4B": {
"grp": "fsd",
"grp": "fd",
"class": 4,
"rating": "B",
"cost": 536693,
@@ -168,7 +168,7 @@
"fuelpower": 2.3
},
"4A": {
"grp": "fsd",
"grp": "fd",
"class": 4,
"rating": "A",
"cost": 1610080,
@@ -180,7 +180,7 @@
"fuelpower": 2.3
},
"3E": {
"grp": "fsd",
"grp": "fd",
"class": 3,
"rating": "E",
"cost": 6271,
@@ -192,7 +192,7 @@
"fuelpower": 2.15
},
"3D": {
"grp": "fsd",
"grp": "fd",
"class": 3,
"rating": "D",
"cost": 18812,
@@ -204,7 +204,7 @@
"fuelpower": 2.15
},
"3C": {
"grp": "fsd",
"grp": "fd",
"class": 3,
"rating": "C",
"cost": 56435,
@@ -216,7 +216,7 @@
"fuelpower": 2.15
},
"3B": {
"grp": "fsd",
"grp": "fd",
"class": 3,
"rating": "B",
"cost": 169304,
@@ -228,7 +228,7 @@
"fuelpower": 2.15
},
"3A": {
"grp": "fsd",
"grp": "fd",
"class": 3,
"rating": "A",
"cost": 507912,
@@ -240,7 +240,7 @@
"fuelpower": 2.15
},
"2E": {
"grp": "fsd",
"grp": "fd",
"class": 2,
"rating": "E",
"cost": 1978,
@@ -252,7 +252,7 @@
"fuelpower": 2
},
"2D": {
"grp": "fsd",
"grp": "fd",
"class": 2,
"rating": "D",
"cost": 5934,
@@ -264,7 +264,7 @@
"fuelpower": 2
},
"2C": {
"grp": "fsd",
"grp": "fd",
"class": 2,
"rating": "C",
"cost": 17803,
@@ -276,7 +276,7 @@
"fuelpower": 2
},
"2B": {
"grp": "fsd",
"grp": "fd",
"class": 2,
"rating": "B",
"cost": 53408,
@@ -288,7 +288,7 @@
"fuelpower": 2
},
"2A": {
"grp": "fsd",
"grp": "fd",
"class": 2,
"rating": "A",
"cost": 160224,

View File

@@ -1,317 +1,43 @@
{
"8E": {
"grp": "s",
"class": 8,
"rating": "E",
"cost": 697584,
"mass": 160,
"power": 0.55,
"range": 5
},
"8D": {
"grp": "s",
"class": 8,
"rating": "D",
"cost": 1743961,
"mass": 64,
"power": 0.62,
"range": 6
},
"8C": {
"grp": "s",
"class": 8,
"rating": "C",
"cost": 4359903,
"mass": 160,
"power": 0.69,
"range": 6
},
"8B": {
"grp": "s",
"class": 8,
"rating": "B",
"cost": 10899756,
"mass": 256,
"power": 1.14,
"range": 7
},
"8A": {
"grp": "s",
"class": 8,
"rating": "A",
"cost": 27249391,
"mass": 160,
"power": 2.07,
"range": 8
},
"6E": {
"grp": "s",
"class": 6,
"rating": "E",
"cost": 88978,
"mass": 40,
"power": 0.4,
"range": 5
},
"6D": {
"grp": "s",
"class": 6,
"rating": "D",
"cost": 222444,
"mass": 16,
"power": 0.45,
"range": 5
},
"6C": {
"grp": "s",
"class": 6,
"rating": "C",
"cost": 556110,
"mass": 40,
"power": 0.5,
"range": 6
},
"6B": {
"grp": "s",
"class": 6,
"rating": "B",
"cost": 1390275,
"mass": 64,
"power": 0.83,
"range": 7
},
"6A": {
"grp": "s",
"class": 6,
"rating": "A",
"cost": 3475688,
"mass": 40,
"power": 1.5,
"range": 7
},
"5E": {
"grp": "s",
"class": 5,
"rating": "E",
"cost": 31778,
"mass": 20,
"power": 0.33,
"range": 4.5
},
"5D": {
"grp": "s",
"class": 5,
"rating": "D",
"cost": 79444,
"mass": 8,
"power": 0.37,
"range": 5
},
"5C": {
"grp": "s",
"class": 5,
"rating": "C",
"cost": 198611,
"mass": 20,
"power": 0.41,
"range": 5.5
},
"5B": {
"grp": "s",
"class": 5,
"rating": "B",
"cost": 496527,
"mass": 32,
"power": 0.68,
"range": 6
},
"5A": {
"grp": "s",
"class": 5,
"rating": "A",
"cost": 1241317,
"mass": 20,
"power": 1.23,
"range": 6.5
},
"4E": {
"grp": "s",
"class": 4,
"rating": "E",
"cost": 11349,
"mass": 10,
"power": 0.27,
"range": 4
},
"4D": {
"grp": "s",
"class": 4,
"rating": "D",
"cost": 28373,
"mass": 4,
"power": 0.31,
"range": 5
},
"4C": {
"grp": "s",
"class": 4,
"rating": "C",
"cost": 70932,
"mass": 10,
"power": 0.34,
"range": 6
},
"4B": {
"grp": "s",
"class": 4,
"rating": "B",
"cost": 177331,
"mass": 16,
"power": 0.56,
"range": 6
},
"4A": {
"grp": "s",
"class": 4,
"rating": "A",
"cost": 443328,
"mass": 10,
"power": 1.02,
"range": 7
},
"3E": {
"grp": "s",
"class": 3,
"rating": "E",
"cost": 4053,
"mass": 5,
"power": 0.22,
"range": 4
},
"3D": {
"grp": "s",
"class": 3,
"rating": "D",
"cost": 10133,
"mass": 2,
"power": 0.25,
"range": 4.5
},
"3C": {
"grp": "s",
"class": 3,
"rating": "C",
"cost": 25333,
"mass": 5,
"power": 0.28,
"range": 5
},
"3B": {
"grp": "s",
"class": 3,
"rating": "B",
"cost": 63333,
"mass": 8,
"power": 0.46,
"range": 5.5
},
"3A": {
"grp": "s",
"class": 3,
"rating": "A",
"cost": 158331,
"mass": 5,
"power": 0.84,
"range": 6
},
"2E": {
"grp": "s",
"class": 2,
"rating": "E",
"cost": 1448,
"mass": 2.5,
"power": 0.18,
"range": 4
},
"2D": {
"grp": "s",
"class": 2,
"rating": "D",
"cost": 3619,
"mass": 1,
"power": 0.21,
"range": 4.5
},
"2C": {
"grp": "s",
"class": 2,
"rating": "C",
"cost": 9048,
"mass": 2.5,
"power": 0.23,
"range": 5
},
"2B": {
"grp": "s",
"class": 2,
"rating": "B",
"cost": 22619,
"mass": 4,
"power": 0.38,
"range": 5.5
},
"2A": {
"grp": "s",
"class": 2,
"rating": "A",
"cost": 56547,
"mass": 2.5,
"power": 0.69,
"range": 6
},
"1E": {
"grp": "s",
"class": 1,
"rating": "E",
"cost": 517,
"mass": 1.3,
"power": 0.16,
"range": 4
},
"1D": {
"grp": "s",
"class": 1,
"rating": "D",
"cost": 1293,
"mass": 0.5,
"power": 0.18,
"range": 4.5
},
"1C": {
"grp": "s",
"class": 1,
"rating": "C",
"cost": 3231,
"mass": 1.3,
"power": 0.2,
"range": 5
},
"1B": {
"grp": "s",
"class": 1,
"rating": "B",
"cost": 8078,
"mass": 2,
"power": 0.33,
"range": 5.5
},
"1A": {
"grp": "s",
"class": 1,
"rating": "A",
"cost": 20195,
"mass": 1.3,
"power": 0.6,
"range": 6
}
"8E": { "grp": "s", "class": 8, "rating": "E", "cost": 697584, "mass": 160, "power": 0.55, "range": 5.12 },
"8D": { "grp": "s", "class": 8, "rating": "D", "cost": 1743961, "mass": 64, "power": 0.62, "range": 5.76 },
"8C": { "grp": "s", "class": 8, "rating": "C", "cost": 4359903, "mass": 160, "power": 0.69, "range": 6.4 },
"8B": { "grp": "s", "class": 8, "rating": "B", "cost": 10899756, "mass": 256, "power": 1.14, "range": 7.04 },
"8A": { "grp": "s", "class": 8, "rating": "A", "cost": 27249391, "mass": 160, "power": 2.07, "range": 7.68 },
"6E": { "grp": "s", "class": 6, "rating": "E", "cost": 88978, "mass": 40, "power": 0.4, "range": 4.8 },
"6D": { "grp": "s", "class": 6, "rating": "D", "cost": 222444, "mass": 16, "power": 0.45, "range": 5.4 },
"6C": { "grp": "s", "class": 6, "rating": "C", "cost": 556110, "mass": 40, "power": 0.5, "range": 6 },
"6B": { "grp": "s", "class": 6, "rating": "B", "cost": 1390275, "mass": 64, "power": 0.83, "range": 6.6 },
"6A": { "grp": "s", "class": 6, "rating": "A", "cost": 3475688, "mass": 40, "power": 1.5, "range": 7.2 },
"5E": { "grp": "s", "class": 5, "rating": "E", "cost": 31778, "mass": 20, "power": 0.33, "range": 4.64 },
"5D": { "grp": "s", "class": 5, "rating": "D", "cost": 79444, "mass": 8, "power": 0.37, "range": 5.22 },
"5C": { "grp": "s", "class": 5, "rating": "C", "cost": 198611, "mass": 20, "power": 0.41, "range": 5.8 },
"5B": { "grp": "s", "class": 5, "rating": "B", "cost": 496527, "mass": 32, "power": 0.68, "range": 6.38 },
"5A": { "grp": "s", "class": 5, "rating": "A", "cost": 1241317, "mass": 20, "power": 1.23, "range": 6.96 },
"4E": { "grp": "s", "class": 4, "rating": "E", "cost": 11349, "mass": 10, "power": 0.27, "range": 4.48 },
"4D": { "grp": "s", "class": 4, "rating": "D", "cost": 28373, "mass": 4, "power": 0.31, "range": 5.04 },
"4C": { "grp": "s", "class": 4, "rating": "C", "cost": 70932, "mass": 10, "power": 0.34, "range": 5.6 },
"4B": { "grp": "s", "class": 4, "rating": "B", "cost": 177331, "mass": 16, "power": 0.56, "range": 6.16 },
"4A": { "grp": "s", "class": 4, "rating": "A", "cost": 443328, "mass": 10, "power": 1.02, "range": 6.72 },
"3E": { "grp": "s", "class": 3, "rating": "E", "cost": 4053, "mass": 5, "power": 0.22, "range": 4.32 },
"3D": { "grp": "s", "class": 3, "rating": "D", "cost": 10133, "mass": 2, "power": 0.25, "range": 4.86 },
"3C": { "grp": "s", "class": 3, "rating": "C", "cost": 25333, "mass": 5, "power": 0.28, "range": 5.4 },
"3B": { "grp": "s", "class": 3, "rating": "B", "cost": 63333, "mass": 8, "power": 0.46, "range": 5.94 },
"3A": { "grp": "s", "class": 3, "rating": "A", "cost": 158331, "mass": 5, "power": 0.84, "range": 6.48 },
"2E": { "grp": "s", "class": 2, "rating": "E", "cost": 1448, "mass": 2.5, "power": 0.18, "range": 4.16 },
"2D": { "grp": "s", "class": 2, "rating": "D", "cost": 3619, "mass": 1, "power": 0.21, "range": 4.68 },
"2C": { "grp": "s", "class": 2, "rating": "C", "cost": 9048, "mass": 2.5, "power": 0.23, "range": 5.2 },
"2B": { "grp": "s", "class": 2, "rating": "B", "cost": 22619, "mass": 4, "power": 0.38, "range": 5.72 },
"2A": { "grp": "s", "class": 2, "rating": "A", "cost": 56547, "mass": 2.5, "power": 0.69, "range": 6.24 },
"1E": { "grp": "s", "class": 1, "rating": "E", "cost": 517, "mass": 1.3, "power": 0.16, "range": 4 },
"1D": { "grp": "s", "class": 1, "rating": "D", "cost": 1293, "mass": 0.5, "power": 0.18, "range": 4.5 },
"1C": { "grp": "s", "class": 1, "rating": "C", "cost": 3231, "mass": 1.3, "power": 0.2, "range": 5 },
"1B": { "grp": "s", "class": 1, "rating": "B", "cost": 8078, "mass": 2, "power": 0.33, "range": 5.5 },
"1A": { "grp": "s", "class": 1, "rating": "A", "cost": 20195, "mass": 1.3, "power": 0.6, "range": 6 }
}

View File

@@ -1,5 +1,5 @@
{
"Beam Laser": [
"bl": [
{
"id": "0u",
"grp": "bl",

View File

@@ -1,5 +1,5 @@
{
"Burst Laser": [
"ul": [
{
"id": "14",
"grp": "ul",

View File

@@ -1,5 +1,5 @@
{
"Cannon": [
"c": [
{
"id": "1q",
"grp": "c",

View File

@@ -1,5 +1,5 @@
{
"Cargo Scanner": [
"cs": [
{
"id": "0d",
"grp": "cs",

View File

@@ -1,5 +1,5 @@
{
"Countermeasure": [
"cm": [
{
"id": "00",
"grp": "cm",

View File

@@ -1,5 +1,5 @@
{
"Fragment Cannon": [
"fc": [
{
"id": "1t",
"grp": "fc",

View File

@@ -1,5 +1,5 @@
{
"Frame Shift Wake Scanner": [
"ws": [
{
"id": "0i",
"grp": "ws",

View File

@@ -1,5 +1,5 @@
{
"Kill Warrant Scanner": [
"kw": [
{
"id": "0n",
"grp": "kw",

View File

@@ -1,5 +1,5 @@
{
"Mine Launcher": [
"nl": [
{
"id": "2j",
"grp": "nl",

View File

@@ -1,5 +1,5 @@
{
"Mining Laser": [
"ml": [
{
"id": "2l",
"grp": "ml",

View File

@@ -1,5 +1,5 @@
{
"Missile Rack": [
"mr": [
{
"id": "2f",
"grp": "mr",

View File

@@ -1,5 +1,5 @@
{
"Multi-cannon": [
"mc": [
{
"id": "26",
"grp": "mc",

View File

@@ -1,5 +1,5 @@
{
"Plasma Accelerator": [
"pa": [
{
"id": "1g",
"grp": "pa",

View File

@@ -1,5 +1,5 @@
{
"Pulse Laser": [
"pl": [
{
"id": "1d",
"grp": "pl",

View File

@@ -1,5 +1,5 @@
{
"Rail Gun": [
"rg": [
{
"id": "29",
"grp": "rg",

View File

@@ -1,5 +1,5 @@
{
"Shield Booster": [
"sb": [
{
"id": "08",
"grp": "sb",

View File

@@ -1,5 +1,5 @@
{
"Torpedo Pylon": [
"tp": [
{
"id": "2h",
"grp": "tp",

View File

@@ -1,5 +1,5 @@
{
"Auto Field-Maintenance Unit": [
"am": [
{
"id": "1f",
"grp": "am",

View File

@@ -1,5 +1,5 @@
{
"Cargo Rack": [
"cr": [
{ "id": "00", "grp": "cr", "class": 1, "rating": "E", "cost": 1000, "capacity": 2 },
{ "id": "01", "grp": "cr", "class": 2, "rating": "E", "cost": 3250, "capacity": 4 },
{ "id": "02", "grp": "cr", "class": 3, "rating": "E", "cost": 10563, "capacity": 8 },

View File

@@ -1,5 +1,5 @@
{
"Collector Limpet Controller": [
"cc": [
{ "id": "Cf", "grp":"cc", "class":7, "rating":"E", "cost": 437400, "mass": 32.0, "power":0.41, "range":1.36, "maximum": 4, "time":300 },
{ "id": "Cg", "grp":"cc", "class":7, "rating":"D", "cost": 874800, "mass": 32.0, "power":0.55, "range":1.02, "maximum": 4, "time":600 },
{ "id": "Ch", "grp":"cc", "class":7, "rating":"C", "cost":1749600, "mass": 80.0, "power":0.69, "range":1.70, "maximum": 4, "time":510 },

View File

@@ -1,5 +1,5 @@
{
"Docking Computer": [
"dc": [
{
"id": "24",
"grp": "dc",

View File

@@ -1,5 +1,5 @@
{
"FSD Interdictor": [
"fi": [
{
"id": "6p",
"grp": "fi",

View File

@@ -1,5 +1,5 @@
{
"Fuel Scoop": [
"fs": [
{
"id": "3q",
"grp": "fs",

View File

@@ -1,5 +1,5 @@
{
"Fuel Transfer Limpet Controller": [
"fx": [
{ "id": "Ff", "grp":"fx", "class":7, "rating":"E", "cost": 437400, "mass": 80.0, "power":0.55, "range":1.02, "maximum": 8 },
{ "id": "Fg", "grp":"fx", "class":7, "rating":"D", "cost": 874800, "mass": 32.0, "power":0.41, "range":1.36, "maximum": 8 },
{ "id": "Fh", "grp":"fx", "class":7, "rating":"C", "cost":1749600, "mass": 80.0, "power":0.69, "range":1.70, "maximum": 8 },

View File

@@ -1,5 +1,5 @@
{
"Hatch Breaker Limpet Controller": [
"hb": [
{
"id": "7d",
"grp": "hb",

View File

@@ -1,5 +1,5 @@
{
"Hull Reinforcement Package": [
"hr": [
{
"id": "2e",
"grp": "hr",

View File

@@ -1,5 +1,5 @@
{
"Fuel Tank": [
"ft": [
{ "id": "f1", "grp": "ft", "class": 1, "rating": "C", "cost": 1000, "capacity": 2 },
{ "id": "f2", "grp": "ft", "class": 2, "rating": "C", "cost": 3750, "capacity": 4 },
{ "id": "f3", "grp": "ft", "class": 3, "rating": "C", "cost": 7063, "capacity": 8 },

View File

@@ -1,5 +1,5 @@
{
"Prismatic Shield Generator": [
"psg": [
{ "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 },

View File

@@ -1,5 +1,5 @@
{
"Prospector Limpet Controller": [
"pc": [
{ "id": "Pf", "grp":"pc", "class":7, "rating":"E", "cost": 437400, "mass": 80.0, "power":0.55, "range": 5.10, "maximum": 8 },
{ "id": "Pg", "grp":"pc", "class":7, "rating":"D", "cost": 874800, "mass": 32.0, "power":0.41, "range": 6.80, "maximum": 8 },
{ "id": "Ph", "grp":"pc", "class":7, "rating":"C", "cost":1749600, "mass": 80.0, "power":0.69, "range": 8.50, "maximum": 8 },

View File

@@ -1,5 +1,5 @@
{
"Refinery": [
"rf": [
{
"id": "23",
"grp": "rf",

View File

@@ -1,5 +1,5 @@
{
"Scanner": [
"sc": [
{
"id": "2f",
"grp": "sc",

View File

@@ -1,5 +1,5 @@
{
"Shield Cell Bank": [
"scb": [
{ "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 },

View File

@@ -1,5 +1,5 @@
{
"Shield Generator": [
"sg": [
{ "id": "4t", "grp": "sg", "class": 8, "rating": "E", "cost": 2007241, "mass": 160, "power": 2.4, "minmass": 900, "optmass": 1800, "maxmass": 4500, "minmul": 1.3, "optmul": 0.8, "maxmul": 0.3 },
{ "id": "4s", "grp": "sg", "class": 8, "rating": "D", "cost": 6021722, "mass": 64, "power": 3.2, "minmass": 900, "optmass": 1800, "maxmass": 4500, "minmul": 1.4, "optmul": 0.9, "maxmul": 0.4 },
{ "id": "4r", "grp": "sg", "class": 8, "rating": "C", "cost": 18065165, "mass": 160, "power": 4, "minmass": 900, "optmass": 1800, "maxmass": 4500, "minmul": 1.5, "optmul": 1, "maxmul": 0.5 },

View File

@@ -12,7 +12,7 @@
"baseShieldStrength": 146,
"baseArmour": 270,
"hullMass": 298,
"masslock": 7
"masslock": 10
},
"retailCost": 1894760,
"slots": {

View File

@@ -0,0 +1,77 @@
{
"federal_assault_ship": {
"properties": {
"name": "Federal Assault Ship",
"manufacturer": "Core Dynamics",
"class": 2,
"hullCost": 19071993,
"speed": 216,
"boost": 361,
"boostEnergy": 21,
"agility": 6,
"baseShieldStrength": 200,
"baseArmour": 540,
"hullMass": 480,
"masslock": 14
},
"retailCost": 19814205,
"slots": {
"common": [
6,
6,
5,
5,
6,
4,
4
],
"hardpoints": [
3,
3,
2,
2,
0,
0,
0,
0
],
"internal": [
5,
5,
4,
3,
2,
2
]
},
"defaults": {
"common": [
"6E",
"6E",
"5E",
"5E",
"6E",
"4E",
"4C"
],
"hardpoints": [
0,
0,
17,
17,
0,
0,
0,
0
],
"internal": [
"4e",
"03",
"02",
"02",
0,
0
]
}
}
}

View File

@@ -0,0 +1,81 @@
{
"federal_gunship": {
"properties": {
"name": "Federal Gunship",
"manufacturer": "Core Dynamics",
"class": 2,
"hullCost": 34774802,
"speed": 172,
"boost": 284,
"boostEnergy": 21,
"agility": 2,
"baseShieldStrength": 250,
"baseArmour": 630,
"hullMass": 580,
"masslock": 14
},
"retailCost": 35814211,
"slots": {
"common": [
6,
6,
5,
5,
7,
5,
4
],
"hardpoints": [
3,
2,
2,
2,
2,
1,
1,
0,
0,
0,
0
],
"internal": [
6,
6,
5,
2,
2
]
},
"defaults": {
"common": [
"6E",
"6E",
"5E",
"5E",
"7E",
"5E",
"4C"
],
"hardpoints": [
0,
17,
17,
0,
0,
0,
0,
0,
0,
0,
0
],
"internal": [
0,
"4j",
"03",
0,
"2h"
]
}
}
}

View File

@@ -0,0 +1,63 @@
{
"imperial_eagle": {
"properties": {
"name": "Imperial Eagle",
"manufacturer": "Core Dynamics",
"class": 1,
"hullCost": 72186,
"speed": 303,
"boost": 405,
"boostEnergy": 9,
"agility": 6,
"baseShieldStrength": 80,
"baseArmour": 108,
"hullMass": 50,
"masslock": 6
},
"retailCost": 110833,
"slots": {
"common": [
3,
3,
3,
1,
2,
2,
2
],
"hardpoints": [
2,
1,
1,
0
],
"internal": [
3,
2,
1
]
},
"defaults": {
"common": [
"3E",
"3E",
"3E",
"1E",
"2E",
"2E",
"2C"
],
"hardpoints": [
0,
17,
17,
0
],
"internal": [
"44",
"00",
"2h"
]
}
}
}

View File

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

View File

@@ -1,6 +1,6 @@
{
"name": "coriolis_shipyard",
"version": "1.4.1",
"version": "1.5.5",
"repository": {
"type": "git",
"url": "https://github.com/cmmcleod/coriolis"

View File

@@ -30,23 +30,23 @@ function writeDB(err, arr) {
var shipOrder = Object.keys(arr[0]).sort();
var internalOrder = Object.keys(arr[3]).sort();
var hpOrder = [
"Pulse Laser",
"Burst Laser",
"Beam Laser",
"Multi-cannon",
"Cannon",
"Fragment Cannon",
"Rail Gun",
"Plasma Accelerator",
"Missile Rack",
"Torpedo Pylon",
"Mine Launcher",
"Mining Laser",
"Cargo Scanner",
"Countermeasure",
"Frame Shift Wake Scanner",
"Kill Warrant Scanner",
"Shield Booster"
"pl",
"ul",
"bl",
"mc",
"c",
"fc",
"rg",
"pa",
"mr",
"tp",
"nl",
"ml",
"cs",
"cm",
"ws",
"kw",
"sb"
];
for (var i = 0; i < internalOrder.length; i++) {

View File

@@ -0,0 +1,286 @@
{
"$schema": "http://cdn.coriolis.io/schemas/ship-loadout/2.json#",
"name": "Test",
"ship": "Anaconda",
"references": [
{
"name": "Coriolis.io",
"url": "http://localhost:3300/outfit/anaconda/48A6A6A5A8A8A5C2c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04--0303326b.Iw18QDBNA%3D%3D%3D.AwhMJBGaei%2BJCyyiA%3D%3D%3D?bn=Test",
"code": "48A6A6A5A8A8A5C2c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04--0303326b.Iw18QDBNA===.AwhMJBGaei+JCyyiA===",
"shipId": "anaconda"
}
],
"components": {
"standard": {
"bulkheads": "Reactive Surface Composite",
"cargoHatch": {
"enabled": false,
"priority": 5
},
"powerPlant": {
"class": 8,
"rating": "A",
"enabled": true,
"priority": 1
},
"thrusters": {
"class": 6,
"rating": "A",
"enabled": true,
"priority": 1
},
"frameShiftDrive": {
"class": 6,
"rating": "A",
"enabled": true,
"priority": 3
},
"lifeSupport": {
"class": 5,
"rating": "A",
"enabled": true,
"priority": 1
},
"powerDistributor": {
"class": 8,
"rating": "A",
"enabled": true,
"priority": 1
},
"sensors": {
"class": 8,
"rating": "A",
"enabled": true,
"priority": 1
},
"fuelTank": {
"class": 5,
"rating": "C",
"enabled": true,
"priority": 1
}
},
"hardpoints": [
{
"class": 4,
"rating": "A",
"enabled": true,
"priority": 2,
"group": "Plasma Accelerator",
"mount": "Fixed"
},
{
"class": 3,
"rating": "D",
"enabled": true,
"priority": 2,
"group": "Beam Laser",
"mount": "Turret"
},
{
"class": 3,
"rating": "D",
"enabled": true,
"priority": 2,
"group": "Beam Laser",
"mount": "Turret"
},
{
"class": 3,
"rating": "D",
"enabled": true,
"priority": 2,
"group": "Beam Laser",
"mount": "Turret"
},
{
"class": 2,
"rating": "E",
"enabled": true,
"priority": 2,
"group": "Cannon",
"mount": "Turret"
},
{
"class": 2,
"rating": "E",
"enabled": true,
"priority": 2,
"group": "Cannon",
"mount": "Turret"
},
{
"class": 1,
"rating": "F",
"enabled": true,
"priority": 2,
"group": "Beam Laser",
"mount": "Turret"
},
{
"class": 1,
"rating": "F",
"enabled": true,
"priority": 2,
"group": "Beam Laser",
"mount": "Turret"
}
],
"utility": [
{
"class": 0,
"rating": "A",
"enabled": true,
"priority": 1,
"group": "Shield Booster"
},
{
"class": 0,
"rating": "A",
"enabled": true,
"priority": 1,
"group": "Shield Booster"
},
null,
{
"class": 0,
"rating": "C",
"enabled": true,
"priority": 2,
"group": "Kill Warrant Scanner"
},
{
"class": 0,
"rating": "C",
"enabled": true,
"priority": 2,
"group": "Cargo Scanner"
},
{
"class": 0,
"rating": "F",
"enabled": false,
"priority": 1,
"group": "Countermeasure",
"name": "Electronic Countermeasure"
},
{
"class": 0,
"rating": "I",
"enabled": true,
"priority": 1,
"group": "Countermeasure",
"name": "Chaff Launcher"
},
{
"class": 0,
"rating": "I",
"enabled": true,
"priority": 2,
"group": "Countermeasure",
"name": "Point Defence"
}
],
"internal": [
{
"class": 7,
"rating": "A",
"enabled": true,
"priority": 1,
"group": "Shield Generator"
},
{
"class": 6,
"rating": "A",
"enabled": true,
"priority": 1,
"group": "Shield Cell Bank"
},
{
"class": 6,
"rating": "E",
"enabled": true,
"priority": 1,
"group": "Cargo Rack"
},
{
"class": 5,
"rating": "D",
"enabled": true,
"priority": 1,
"group": "Hull Reinforcement Package"
},
{
"class": 5,
"rating": "E",
"enabled": true,
"priority": 1,
"group": "Cargo Rack"
},
null,
null,
{
"class": 4,
"rating": "E",
"enabled": true,
"priority": 1,
"group": "Cargo Rack"
},
{
"class": 4,
"rating": "E",
"enabled": true,
"priority": 1,
"group": "Cargo Rack"
},
{
"class": 4,
"rating": "A",
"enabled": true,
"priority": 3,
"group": "Fuel Scoop"
},
{
"class": 2,
"rating": "A",
"enabled": true,
"priority": 3,
"group": "FSD Interdictor"
}
]
},
"stats": {
"class": 3,
"hullCost": 141889932,
"speed": 180,
"boost": 240,
"boostEnergy": 29,
"agility": 2,
"baseShieldStrength": 350,
"baseArmour": 945,
"hullMass": 400,
"masslock": 23,
"shipCostMultiplier": 1,
"componentCostMultiplier": 1,
"fuelCapacity": 32,
"cargoCapacity": 128,
"ladenMass": 1339.2,
"armour": 2078,
"armourAdded": 240,
"armourMultiplier": 1.95,
"shieldMultiplier": 1.4,
"totalCost": 882362049,
"unladenMass": 1179.2,
"totalDps": 29,
"powerAvailable": 36,
"powerRetracted": 23.33,
"powerDeployed": 34.76,
"unladenRange": 18.49,
"fullTankRange": 18.12,
"ladenRange": 16.39,
"unladenTotalRange": 73.21,
"ladenTotalRange": 66.15,
"maxJumpCount": 4,
"shieldStrength": 833
}
}

View File

@@ -98,8 +98,8 @@ describe('Import Controller', function() {
describe('Import Detailed Build', function() {
it('imports a valid build', function() {
var importData = __json__['fixtures/anaconda-test-detailed-export'];
it('imports a valid v1 build', function() {
var importData = __json__['fixtures/anaconda-test-detailed-export-v1'];
scope.importString = angular.toJson(importData);
scope.validateImport();
expect(scope.importValid).toBeTruthy();
@@ -112,8 +112,22 @@ describe('Import Controller', function() {
});
});
it('imports a valid v2 build', function() {
var importData = __json__['fixtures/anaconda-test-detailed-export-v2'];
scope.importString = angular.toJson(importData);
scope.validateImport();
expect(scope.importValid).toBeTruthy();
expect(scope.errorMsg).toEqual(null);
scope.process();
expect(scope.processed).toBeTruthy();
scope.import();
expect(angular.fromJson(localStorage.getItem('builds'))).toEqual({
anaconda: { 'Test': '48A6A6A5A8A8A5C2c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04--0303326b.AwRj4zNKqA==.CwBhCYzBGW9qCTSqs5xA' }
});
});
it('catches an invalid build', function() {
var importData = __json__['fixtures/anaconda-test-detailed-export'];
var importData = __json__['fixtures/anaconda-test-detailed-export-v2'];
scope.importString = angular.toJson(importData).replace('components', 'comps');
scope.validateImport();
expect(scope.importValid).toBeFalsy();

View File

@@ -3,7 +3,7 @@ describe("Serializer Service", function() {
var Ship,
Serializer,
code = '48A6A6A5A8A8A5C2c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04--0303326b',
code = '48A6A6A5A8A8A5C2c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04--0303326b.AwRj4zNKqA==.CwBhCYzBGW9qCTSqs5xA',
anaconda = DB.ships['anaconda'],
testBuild,
exportData;
@@ -21,15 +21,15 @@ describe("Serializer Service", function() {
exportData = Serializer.toDetailedBuild('Test', testBuild, code);
});
it("conforms to the ship-loadout schema", function() {
var shipLoadoutSchema = __json__['schemas/ship-loadout/1'];
it("conforms to the v2 ship-loadout schema", function() {
var shipLoadoutSchema = __json__['schemas/ship-loadout/2'];
var validate = jsen(shipLoadoutSchema);
var valid = validate(exportData);
expect(valid).toBeTruthy();
});
it("contains the correct components and stats", function() {
var anacondaTestExport = __json__['fixtures/anaconda-test-detailed-export'];
var anacondaTestExport = __json__['fixtures/anaconda-test-detailed-export-v2'];
expect(exportData.components).toEqual(anacondaTestExport.components);
expect(exportData.stats).toEqual(anacondaTestExport.stats);
expect(exportData.ship).toEqual(anacondaTestExport.ship);
@@ -41,7 +41,7 @@ describe("Serializer Service", function() {
describe("From Detailed Build", function() {
it("builds the ship correctly", function() {
var anacondaTestExport = __json__['fixtures/anaconda-test-detailed-export'];
var anacondaTestExport = __json__['fixtures/anaconda-test-detailed-export-v2'];
testBuildA = new Ship('anaconda', anaconda.properties, anaconda.slots);
Serializer.toShip(testBuildA, code);
testBuildB = Serializer.fromDetailedBuild(anacondaTestExport);