Initial Commit for React

This commit is contained in:
Colin McLeod
2015-11-13 17:43:45 -08:00
parent c527a62ce6
commit ed637addb8
60 changed files with 3362 additions and 3091 deletions

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "data"]
path = data
url = https://github.com/cmmcleod/coriolis-data.git

View File

@@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html ng-app="app" ng-strict-di="true" manifest="/coriolis.appcache"> <html manifest="/coriolis.appcache">
<head> <head>
<title ng-bind="title">Coriolis</title> <title>Coriolis</title>
<link rel="stylesheet" href="/app.css"> <link rel="stylesheet" href="/app.css">
<!-- Standard headers --> <!-- Standard headers -->
@@ -55,22 +55,15 @@
</head> </head>
<body style="background-color:#000;"> <body style="background-color:#000;">
<div style="height: 0; width: 0; overflow:hidden"><%= svgContent %></div> <div style="height: 0; width: 0; overflow:hidden"><%= svgContent %></div>
<shipyard-header></shipyard-header> <section id="coriolis"></section>
<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> <footer>
<div class="right cap"> <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> <a href="https://github.com/cmmcleod/coriolis/releases/" target="_blank" title="Coriolis Github Project"><span translate="version"></span> <%= version %> - <%= date %></a>
</div> </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.
</div>
</footer> </footer>
<script src="/lib.js" type="text/javascript"></script> <script src="/lib.js" type="text/javascript" crossorigin></script>
<script src="/app.js" type="text/javascript"></script> <script src="/app.js" type="text/javascript" crossorigin></script>
<% if (uaTracking) { %> <% if (uaTracking) { %>
<script> <script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
@@ -82,6 +75,5 @@
var GAPI_KEY = '<%= gapiKey %>'; var GAPI_KEY = '<%= gapiKey %>';
</script> </script>
<% } %> <% } %>
</body> </body>
</html> </html>

55
app/js/Coriolis.jsx Normal file
View File

@@ -0,0 +1,55 @@
import { Component } from 'react';
import Router from 'Router';
import ShipyardPage from 'pages/ShipyardPage';
import NotFoundPage from 'pages/NotFoundPage';
import Header from '../components/Header';
class Coriolis extends Component {
constructor(props) {
super(props);
this.setPage = this.setPage.bind(this);
this.state.standAlone = isStandAlone();
window.onerror = errorPage.bind(this);
Router('/', () => this.setPage(<ShipyardPage />));
// Router('/outfitting/:ship', outfitting);
// Router('/outfitting/:ship/:code', outfitting);
// Router('/compare/:name', compare);
// Router('/comparison/:code', comparison);
// Router('/settings', settings);
Router('*', () => this.setPage(null));
if (window.applicationCache) {
// Listen for appcache updated event, present refresh to update view
window.applicationCache.addEventListener('updateready', () => {
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
// Browser downloaded a new app cache.
this.setState({appCacheUpdate: true});
}
}, false);
}
Router.start();
console.log('Root page created');
}
setPage(page) {
this.setState({ page: page });
}
onError(msg, scriptUrl, line, col, errObj) {
this.setPage(<div>Some errors occured!!</div>);
}
render() {
return (
<div>
{/* <Header appCacheUpdate={appCacheUpdate} /> */}
{this.state.page || <NotFoundPage />}
</div>
);
}
}
ReactDOM.render(<Coriolis />, document.getElementById('coriolis'));

333
app/js/Router.js Normal file
View File

@@ -0,0 +1,333 @@
import Persist from 'stores/Persist';
function isStandAlone() {
try {
return window.navigator.standalone || (window.external && window.external.msIsSiteMode && window.external.msIsSiteMode());
} catch (ex) {
return false;
}
}
/**
* Register `path` with callback `fn()`,
* or route `path`, or `Router.start()`.
*
* Router('*', fn);
* Router('/user/:id', load, user);
* Router('/user/' + user.id, { some: 'thing' });
* Router('/user/' + user.id);
* Router();
*
* @param {String} path
* @param {Function} fn...
* @api public
*/
function Router(path, fn) {
var route = new Route(path);
for (var i = 1; i < arguments.length; ++i) {
Router.callbacks.push(route.middleware(arguments[i]));
}
}
/**
* Callback functions.
*/
Router.callbacks = [];
/**
* Bind with the given `options`.
*
* Options:
*
* - `click` bind to click events [true]
* - `popstate` bind to popstate [true]
* - `dispatch` perform initial dispatch [true]
*
* @param {Object} options
* @api public
*/
Router.start = function(){
window.addEventListener('popstate', onpopstate, false);
if (isStandAlone()) {
var state = Persist.getState();
// If a previous state has been stored, load that state
if (state && state.name && state.params) {
Router(this.props.initialPath || '/');
//$state.go(state.name, state.params, { location: 'replace' });
} else {
Router('/');
}
} else {
var url = location.pathname + location.search + location.hash;
Router.replace(url, null, true, dispatch);
}
};
/**
* Show `path` with optional `state` object.
*
* @param {String} path
* @param {Object} state
* @return {Context}
* @api public
*/
Router.go = function(path, state) {
gaTrack(path);
var ctx = new Context(path, state);
if (false !== dispatch) Router.dispatch(ctx);
if (!ctx.unhandled) ctx.pushState();
return ctx;
};
/**
* Replace `path` with optional `state` object.
*
* @param {String} path
* @param {Object} state
* @return {Context}
* @api public
*/
Router.replace = function(path, state, init, dispatch) {
gaTrack(path);
var ctx = new Context(path, state);
ctx.init = init;
if (null == dispatch) dispatch = true;
if (dispatch) Router.dispatch(ctx);
ctx.save();
return ctx;
};
/**
* Dispatch the given `ctx`.
*
* @param {Object} ctx
* @api private
*/
Router.dispatch = function(ctx){
var i = 0;
function next() {
var fn = Router.callbacks[i++];
if (!fn) return unhandled(ctx);
fn(ctx, next);
}
next();
};
/**
* Unhandled `ctx`. When it's not the initial
* popstate then redirect. If you wish to handle
* 404s on your own use `Router('*', callback)`.
*
* @param {Context} ctx
* @api private
*/
function unhandled(ctx) {
var current = window.location.pathname + window.location.search;
if (current == ctx.canonicalPath) return;
window.location = ctx.canonicalPath;
}
/**
* Initialize a new "request" `Context`
* with the given `path` and optional initial `state`.
*
* @param {String} path
* @param {Object} state
* @api public
*/
function Context(path, state) {
var i = path.indexOf('?');
this.canonicalPath = path;
this.path = path || '/';
this.title = document.title;
this.state = state || {};
this.state.path = path;
this.querystring = ~i ? path.slice(i + 1) : '';
this.pathname = ~i ? path.slice(0, i) : path;
this.params = [];
// fragment
this.hash = '';
if (!~this.path.indexOf('#')) return;
var parts = this.path.split('#');
this.path = parts[0];
this.hash = parts[1] || '';
this.querystring = this.querystring.split('#')[0];
}
/**
* Expose `Context`.
*/
Router.Context = Context;
/**
* Push state.
*
* @api private
*/
Context.prototype.pushState = function(){
history.pushState(this.state, this.title, this.canonicalPath);
};
/**
* Save the context state.
*
* @api public
*/
Context.prototype.save = function(){
history.replaceState(this.state, this.title, this.canonicalPath);
};
/**
* Initialize `Route` with the given HTTP `path`,
* and an array of `callbacks` and `options`.
*
* Options:
*
* - `sensitive` enable case-sensitive routes
* - `strict` enable strict matching for trailing slashes
*
* @param {String} path
* @param {Object} options.
* @api private
*/
function Route(path, options) {
options = options || {};
this.path = path;
this.method = 'GET';
this.regexp = pathtoRegexp(path
, this.keys = []
, options.sensitive
, options.strict);
}
/**
* Expose `Route`.
*/
Router.Route = Route;
/**
* Return route middleware with
* the given callback `fn()`.
*
* @param {Function} fn
* @return {Function}
* @api public
*/
Route.prototype.middleware = function(fn){
var self = this;
return function(ctx, next){
if (self.match(ctx.path, ctx.params)) return fn(ctx, next);
next();
};
};
/**
* Check if this route matches `path`, if so
* populate `params`.
*
* @param {String} path
* @param {Array} params
* @return {Boolean}
* @api private
*/
Route.prototype.match = function(path, params){
var keys = this.keys
, qsIndex = path.indexOf('?')
, pathname = ~qsIndex ? path.slice(0, qsIndex) : path
, m = this.regexp.exec(decodeURIComponent(pathname));
if (!m) return false;
for (var i = 1, len = m.length; i < len; ++i) {
var key = keys[i - 1];
var val = 'string' == typeof m[i]
? decodeURIComponent(m[i])
: m[i];
if (key) {
params[key.name] = undefined !== params[key.name]
? params[key.name]
: val;
} else {
params.push(val);
}
}
return true;
};
function gaTrack(path) {
if (window.ga) {
window.ga('send', 'pageview', { page: path });
}
}
/**
* Normalize the given path string,
* returning a regular expression.
*
* An empty array should be passed,
* which will contain the placeholder
* key names. For example "/user/:id" will
* then contain ["id"].
*
* @param {String|RegExp|Array} path
* @param {Array} keys
* @param {Boolean} sensitive
* @param {Boolean} strict
* @return {RegExp}
* @api private
*/
function pathtoRegexp(path, keys, sensitive, strict) {
if (path instanceof RegExp) return path;
if (path instanceof Array) path = '(' + path.join('|') + ')';
path = path
.concat(strict ? '' : '/?')
.replace(/\/\(/g, '(?:/')
.replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g, function(_, slash, format, key, capture, optional){
keys.push({ name: key, optional: !! optional });
slash = slash || '';
return ''
+ (optional ? '' : slash)
+ '(?:'
+ (optional ? slash : '')
+ (format || '') + (capture || (format && '([^/.]+?)' || '([^/]+?)')) + ')'
+ (optional || '');
})
.replace(/([\/.])/g, '\\$1')
.replace(/\*/g, '(.*)');
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
}
/**
* Handle "populate" events.
*/
function onpopstate(e) {
if (e.state) {
var path = e.state.path;
Router.replace(path, e.state);
}
}
export default Router;

255
app/js/Serializer.js Executable file
View File

@@ -0,0 +1,255 @@
import { ModuleGroupToName, MountMap } from './Constants';
import Ships from './Ships';
import Ship from './Ship';
import ModuleUtils from './ModuleUtils';
import LZString from 'LZString';
/**
* Service managing seralization and deserialization of models for use in URLs and persistene.
*/
/**
* Utility function to retrieve a safe string for selected component for a slot.
* Used for serialization to code only.
* TODO: comment on binding
* @private
* @param {object} slot The slot object.
* @return {string} The id of the selected component or '-' if none selected
*/
function mapGroup(slot) {
export function enabled.push(slot.enabled ? 1 : 0);
export function priorities.push(slot.priority);
return slot.id === null ? '-' : slot.id;
}
function decodeToArray(code, arr, codePos) {
for (let i = 0; i < arr.length; i++) {
if (code.charAt(codePos) == '-') {
arr[i] = 0;
codePos++;
} else {
arr[i] = code.substring(codePos, codePos + 2);
codePos += 2;
}
}
return codePos;
}
function slotToSchema(slot) {
if (slot.c) {
let o = {
class: slot.c.class,
rating: slot.c.rating,
enabled: Boolean(slot.enabled),
priority: slot.priority + 1,
group: ModuleGroupToName[slot.c.grp]
};
if (slot.c.name) {
o.name = slot.c.name;
}
if (slot.c.mode) {
o.mount = MountMap[slot.c.mode];
}
if (slot.c.missile) {
o.missile = slot.c.missile;
}
return o;
}
return null;
}
/**
* Serializes the ships selected components for all slots to a URL friendly string.
* @param {Ship} ship The ship to be serialized.
* @return {string} Encoded string of components
*/
export function fromShip(ship) {
let power = {
enabled: [ship.cargoHatch.enabled ? 1 : 0],
priorities: [ship.cargoHatch.priority]
};
let data = [
ship.bulkheads.id,
_.map(ship.standard, mapGroup, power),
_.map(ship.hardpoints, mapGroup, power),
_.map(ship.internal, mapGroup, power),
'.',
LZString.compressToBase64(power.enabled.join('')).replace(/\//g, '-'),
'.',
LZString.compressToBase64(power.priorities.join('')).replace(/\//g, '-')
];
return _.flatten(data).join('');
};
/**
* Updates an existing ship instance's slots with components determined by the
* code.
*
* @param {Ship} ship The ship instance to be updated
* @param {string} dataString The string to deserialize
*/
export function toShip(ship, dataString) {
var standard = new Array(ship.standard.length),
hardpoints = new Array(ship.hardpoints.length),
internal = new Array(ship.internal.length),
parts = dataString.split('.'),
priorities = null,
enabled = null,
code = parts[0];
if (parts[1]) {
enabled = LZString.decompressFromBase64(parts[1].replace(/-/g, '/')).split('');
}
if (parts[2]) {
priorities = LZString.decompressFromBase64(parts[2].replace(/-/g, '/')).split('');
}
decodeToArray(code, internal, decodeToArray(code, hardpoints, decodeToArray(code, standard, 1)));
ship.buildWith(
{
bulkheads: code.charAt(0) * 1,
standard: standard,
hardpoints: hardpoints,
internal: internal
},
priorities,
enabled
);
};
export function toDetailedBuild(buildName, ship, code) {
var standard = ship.standard,
hardpoints = ship.hardpoints,
internal = ship.internal;
var data = {
$schema: 'http://cdn.coriolis.io/schemas/ship-loadout/2.json#',
name: buildName,
ship: ship.name,
references: [{
name: 'Coriolis.io',
url: $state.href('outfit', { shipId: ship.id, code: code, bn: buildName }, { absolute: true }),
code: code,
shipId: ship.id
}],
components: {
standard: {
bulkheads: ship.bulkheads.c.name,
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),
internal: _.map(internal, slotToSchema)
},
stats: {}
};
for (var stat in ship) {
if (!isNaN(ship[stat])) {
data.stats[stat] = Math.round(ship[stat] * 100) / 100;
}
}
return data;
};
export function fromDetailedBuild(detailedBuild) {
var shipId = _.findKey(ShipsDB, { properties: { name: detailedBuild.ship } });
if (!shipId) {
throw 'No such ship: ' + detailedBuild.ship;
}
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 = ModuleUtils.bulkheadIndex(standard.bulkheads);
if (bulkheads < 0) {
throw 'Invalid bulkheads: ' + standard.bulkheads;
}
var standardIds = _.map(
['powerPlant', 'thrusters', 'frameShiftDrive', 'lifeSupport', 'powerDistributor', 'sensors', 'fuelTank'],
function(c) {
if (!standard[c].class || !standard[c].rating) {
throw 'Invalid value for ' + c;
}
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;
}
);
var internal = _.map(comps.internal, function(c) { return c ? ModuleUtils.findInternalId(c.group, c.class, c.rating, c.name) : 0; });
var hardpoints = _.map(comps.hardpoints, function(c) {
return c ? ModuleUtils.findHardpointId(c.group, c.class, c.rating, c.name, MountMap[c.mount], c.missile) : 0;
}).concat(_.map(comps.utility, function(c) {
return c ? ModuleUtils.findHardpointId(c.group, c.class, c.rating, c.name, MountMap[c.mount]) : 0;
}));
// 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, standard: standardIds, hardpoints: hardpoints, internal: internal }, priorities, enabled);
return ship;
};
export function toDetailedExport(builds) {
var data = [];
for (var shipId in builds) {
for (var buildName in builds[shipId]) {
var code = builds[shipId][buildName];
var shipData = ShipsDB[shipId];
var ship = new Ship(shipId, shipData.properties, shipData.slots);
export function toShip(ship, code);
data.push(export function toDetailedBuild(buildName, ship, code));
}
}
return data;
};
export function fromComparison(name, builds, facets, predicate, desc) {
var shipBuilds = [];
builds.forEach(function(b) {
shipBuilds.push({ s: b.id, n: b.buildName, c: export function fromShip(b) });
}.bind(this));
return LZString.compressToBase64(angular.toJson({
n: name,
b: shipBuilds,
f: facets,
p: predicate,
d: desc ? 1 : 0
})).replace(/\//g, '-');
};
export function toComparison(code) {
return angular.fromJson(LZString.decompressFromBase64(code.replace(/-/g, '/')));
};

View File

@@ -0,0 +1,118 @@
import { Component } from 'react';
export default class Header extends Component {
render() {
let openedMenu = this.state.openedMenu;
if (this.props.appCacheUpdate) {
return <div id="app-update" onClick={window.location.reload}>{ 'PHRASE_UPDATE_RDY' | translate }</div>;
}
return (
<header>
<a class="l" ui-sref="shipyard" style="margin-right: 1em;" title="Ships"><svg class="icon xl"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#coriolis"></use></svg></a>
<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' | translate}}</span>
</div>
{openedMenu == 's' ? this.getShipsMenu() : null}
</div>
<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' | translate}}</span>
</div>
{openedMenu == 'b' ? this.getBuildsMenu() : null}
</div>
<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' | translate}}</span>
</div>
{openedMenu == 'comp' ? this.getComparisonsMenu() : null}
</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' | translate}}</span>
</div>
{openedMenu == 'settings' ? this.getSettingsMenu() : null}
</div>
</header>
);
}
getShipsMenu() {
return (<div class="menu-list dbl no-wrap">
<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>);
}
getBuildsMenu() {
return (<div class="menu-list" ng-if="openedMenu=='b'" ng-click="$event.stopPropagation();">
<div class="dbl" >
<div><ul ng-repeat="shipId in buildsList">
{{ships[shipId].properties.name}}
<li ng-repeat="(i, name) in cleanedBuildList(shipId)">
<a ui-sref-active="active" class="name" ui-sref="outfit({shipId:shipId, code:allBuilds[shipId][name], bn:name})" ng-bind="name"></a>
</li>
</ul></div>
</div>
</div>);
}
getComparisonsMenu() {
return (<div class="menu-list" ng-if="openedMenu=='comp'" ng-click="$event.stopPropagation();" style="white-space: nowrap;">
<span class="cap" ng-if="!bs.hasComparisons" translate="none created"></span>
<a ng-repeat="(i, name) 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 cap" translate="compare all"></a>
<a ui-sref="compare({name: null})" class="block cap" translate="create new"></a>
</div>);
}
getSettingsMenu() {
return (<div class="menu-list no-wrap cap" ng-if="openedMenu=='settings'" ng-click="$event.stopPropagation();">
<ul>
{{'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>
{{'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>
{{'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' | 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 />
<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>);
}
}

View File

@@ -1,81 +0,0 @@
/**
* Sets up the routes and handlers before the Angular app is kicked off.
*/
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.
*/
$stateProvider
.state('outfit', {
url: '/outfit/:shipId/:code?bn',
params: {
shipId: { value: 'sidewinder', squash: false }, // Allow 'shipId' parameter to default to sidewinder
code: { value: null, squash: true } // Allow 'code' parameter to be empty/optional
},
templateUrl: 'views/page-outfit.html',
controller: 'OutfitController',
resolve: {
shipId: ['$stateParams', function($p) { // Ensure ship exists before loading controller
if (!ships[$p.shipId]) {
throw { type: 'no-ship', message: $p.shipId };
}
}]
},
sticky: true
})
.state('compare', {
url: '/compare/:name',
params: {
name: { value: null, squash: true }
},
templateUrl: 'views/page-comparison.html',
controller: 'ComparisonController',
sticky: true
})
.state('comparison', {
url: '/comparison/:code',
templateUrl: 'views/page-comparison.html',
controller: 'ComparisonController',
sticky: true
})
.state('shipyard', { url: '/', templateUrl: 'views/page-shipyard.html', controller: 'ShipyardController', sticky: true })
.state('error', { params: { type: null, message: null, details: null }, templateUrl: 'views/page-error.html', controller: 'ErrorController', sticky: true })
// Modal States and views
.state('modal', { abstract: true, views: { 'modal': { templateUrl: 'views/_modal.html', controller: 'ModalController' } } })
.state('modal.about', { views: { 'modal-content': { templateUrl: 'views/modal-about.html' } } })
.state('modal.export', { params: { title: null, data: null, promise: null, description: null }, views: { 'modal-content': { templateUrl: 'views/modal-export.html', controller: 'ExportController' } } })
.state('modal.import', { params: { obj: null }, views: { 'modal-content': { templateUrl: 'views/modal-import.html', controller: 'ImportController' } } })
.state('modal.link', { params: { url: null }, views: { 'modal-content': { templateUrl: 'views/modal-link.html', controller: 'LinkController' } } })
.state('modal.delete', { views: { 'modal-content': { templateUrl: 'views/modal-delete.html', controller: 'DeleteController' } } });
// Redirects
$urlRouterProvider.when('/outfit', '/outfit/sidewinder');
/**
* 404 Handler - Keep current URL/ do not redirect, change to error state.
*/
$urlRouterProvider.otherwise(function($injector, $location) {
// Go to error state, reload the controller, keep the current URL
$injector.get('$state').go('error', { type: 404, message: null, details: null }, { location: false, reload: true });
return $location.path;
});
/**
* Global Error Handler. Decorates the existing error handler such that it
* redirects uncaught errors to the error page.
*
*/
$provide.decorator('$exceptionHandler', ['$delegate', '$injector', function($delegate, $injector) {
return function(err, cause) {
// Go to error state, reload the controller, keep the current URL
$injector.get('$state').go('error', { type: null, message: err.message, details: err.stack }, { location: false, reload: true });
$delegate(err, cause);
};
}]);
}]);

View File

@@ -1,59 +0,0 @@
angular.module('app').controller('ShipyardController', ['$rootScope', '$scope', 'ShipsDB', 'Ship', 'Components', function($rootScope, $scope, ShipsDB, Ship, Components) {
$rootScope.title = 'Coriolis - Shipyard';
$scope.shipPredicate = 'properties.name';
$scope.shipDesc = false;
function countHp(slot) {
this.hp[slot.maxClass]++;
this.hpCount++;
}
function countInt(slot) {
var crEligible = !slot.eligible || slot.eligible.cr;
this.int[slot.maxClass - 1]++; // Subtract 1 since there is no Class 0 Internal compartment
this.intCount++;
this.maxCargo += crEligible ? Components.findInternal('cr', slot.maxClass, 'E').capacity : 0;
}
function shipSummary(shipId, shipData) {
var summary = angular.copy(shipData.properties);
var ship = new Ship(shipId, shipData.properties, shipData.slots);
summary.id = s;
summary.hpCount = 0;
summary.intCount = 0;
summary.maxCargo = 0;
summary.hp = [0, 0, 0, 0, 0]; // Utility, Small, Medium, Large, Huge
summary.int = [0, 0, 0, 0, 0, 0, 0, 0]; // Sizes 1 - 8
// Build Ship
ship.buildWith(shipData.defaults); // Populate with stock/default components
ship.hardpoints.forEach(countHp.bind(summary)); // Count Hardpoints by class
ship.internal.forEach(countInt.bind(summary)); // Count Internal Compartments by class
summary.retailCost = ship.totalCost; // Record Stock/Default/retail cost
ship.optimizeMass({ pd: '1D' }); // Optimize Mass with 1D PD for maximum possible jump range
summary.maxJumpRange = ship.unladenRange; // Record Jump Range
ship.optimizeMass({ th: ship.standard[1].maxClass + 'A' }); // Optmize mass with Max Thrusters
summary.topSpeed = ship.topSpeed;
summary.topBoost = ship.topBoost;
return summary;
}
/* Initialization */
if (!$rootScope.shipsOverview) { // Only generate this once
$rootScope.shipsOverview = [];
for (var s in ShipsDB) {
$scope.shipsOverview.push(shipSummary(s, ShipsDB[s]));
}
}
/**
* Sort ships
* @param {object} key Sort predicate
*/
$scope.sortShips = function(key) {
$scope.shipDesc = $scope.shipPredicate == key ? !$scope.shipDesc : $scope.shipDesc;
$scope.shipPredicate = key;
};
}]);

View File

@@ -1,14 +0,0 @@
angular.module('app').directive('contextMenu', ['$parse', function($parse) {
return function(scope, element, attrs) {
var fn = $parse(attrs.contextMenu);
element.bind('contextmenu', function(e) {
if (!e.shiftKey) {
scope.$apply(function() {
e.preventDefault();
fn(scope, { $event: e });
});
}
});
};
}]);

View File

@@ -1,65 +0,0 @@
/**
* BBCode Generator functions for embedding in the Elite Dangerous Forums
*/
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=';
function shortenUrl(url) {
if ($window.navigator.onLine) {
return $http.post(shortenAPI + GAPI_KEY, { longUrl: url }).then(function(response) {
return response.data.id;
});
} else {
return $q.reject({ statusText: 'Not Online' });
}
}
function comparisonBBCode(facets, builds, link) {
var colCount = 2, b, i, j, k, f, fl, p, pl, l = [];
for (i = 0; i < facets.length; i++) {
if (facets[i].active) {
f = facets[i];
p = f.props;
if (p.length == 1) {
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]', $translate.instant(f.title).toUpperCase(), '\n', $translate.instant(f.lbls[j]).toUpperCase(), '[/COLOR][/B][/th]');
colCount++;
}
}
}
}
l.push('[/tr]\n');
for (i = 0; i < builds.length; i++) {
b = builds[i];
//var href = $state.href('outfit',{shipId: b.id, code: b.code, bn: b.buildName}, {absolute: true});
l.push('[tr][td]', b.name, '[/td][td]', b.buildName, '[/td]');
for (j = 0, fl = facets.length; j < fl; j++) {
if (facets[j].active) {
f = facets[j];
p = f.props;
for (k = 0, pl = p.length; k < pl; k++) {
l.push('[td="align: right"]', $rootScope[f.fmt](b[p[k]]), ' [size=-2]', $translate.instant(f.unit), '[/size][/td]');
}
}
}
l.push('[/tr]\n');
}
l.push('[tr][td="align: center, colspan:', colCount, '"][size=-3]\n[url=', link, ']Interactive Comparison at Coriolis.io[/url][/td][/tr]\n[/size][/table]');
l.unshift('[table="width:', colCount * 90, ',align: center"]\n[tr][th][B][COLOR=#FF8C0D]Ship[/COLOR][/B][/th][th][B][COLOR="#FF8C0D"]Build[/COLOR][/B][/th]');
return l.join('');
}
return {
comparisonBBCode: comparisonBBCode,
shortenUrl: shortenUrl
};
}]);

52
app/js/i18n/Language.js Normal file
View File

@@ -0,0 +1,52 @@
import EN from 'en';
import DE from 'de';
import ES from 'es';
import FR from 'fr';
import IT from 'it';
import RU from 'RU';
import d3 from 'd3';
let fallbackTerms = EN.terms;
let currentLanguage;
let currentTerms;
let format = {
rPct: d3.format('%')
};
export format;
export function setLanguage(langCode) {
let lang;
switch (langCode) {
case 'de': lang = DE; break;
case 'es': lang = ES; break;
case 'fr': lang = FR; break;
case 'it': lang = IT; break;
case 'ru': lang = RU; break;
default: lang = EN;
}
currentTerms = lang.terms;
d3Locale = d3.locale(lang.formats);
format.gen = d3Locale.numberFormat('n');
format.crd = d3Locale.numberFormat(',.0f');
format.pwr = d3Locale.numberFormat(',.2f');
format.round = (d) => format.gen(d3.round(d, 2));
format.pct = d3Locale.numberFormat('.2%');
format.pct1 = d3Locale.numberFormat('.1%');
}
export const Languages = {
en: 'English',
de: 'Deutsh',
it: 'Italiano',
es: 'Español',
fr: 'Français',
ru: 'ру́сский'
};
export function term(t) {
return currentTerms[t] || fallbackTerms[t];
}

View File

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

View File

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

View File

@@ -1,212 +1,208 @@
angular.module('app').config(['$translateProvider', 'localeFormatProvider', function($translateProvider, localeFormatProvider) { export const formats = {
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']
};
// Declare number format settings export const terms = {
localeFormatProvider.addFormat('es', { 'PHRASE_EXPORT_DESC': 'Una detallada exportaci\u00f3n JSON de tu construcci\u00f3n para usarlo en otros sitios web y herramientas',
decimal: ',', 'A-Rated': 'Calidad-A',
thousands: '.', 'about': 'Acerca',
grouping: [3], 'action': 'Acci\u00f3n',
currency: ['', ' €'], 'added': 'A\u00f1adido',
dateTime: '%A, %e de %B de %Y, %X', 'Advanced Discovery Scanner': 'Esc\u00e1ner de exploraci\u00f3n avanzado',
date: '%d/%m/%Y', 'agility': 'Maniobrabilidad',
time: '%H:%M:%S', 'alpha': 'Alfa',
periods: ['AM', 'PM'], 'ammo': 'Munici\u00f3n',
days: ['domingo', 'lunes', 'martes', 'miércoles', 'jueves', 'viernes', 'sábado'], 'PHRASE_CONFIRMATION': '\u00bfEst\u00e1s seguro?',
shortDays: ['dom', 'lun', 'mar', 'mié', 'jue', 'vie', 'sáb'], 'armour': 'Blindaje',
months: ['enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio', 'julio', 'agosto', 'septiembre', 'octubre', 'noviembre', 'diciembre'], 'am': 'Unidad de auto-reparaciones',
shortMonths: ['ene', 'feb', 'mar', 'abr', 'may', 'jun', 'jul', 'ago', 'sep', 'oct', 'nov', 'dic'] 'available': 'Disponible',
}); 'backup': 'Reserva',
'Basic Discovery Scanner': 'Esc\u00e1ner de exploraci\u00f3n b\u00e1sico',
$translateProvider.translations('es', { 'bl': 'L\u00e1ser de haz',
'PHRASE_EXPORT_DESC': 'Una detallada exportaci\u00f3n JSON de tu construcci\u00f3n para usarlo en otros sitios web y herramientas', 'bins': 'contenedores',
'A-Rated': 'Calidad-A', 'boost': 'incrementar',
'about': 'Acerca', 'build': 'Construcci\u00f3n',
'action': 'Acci\u00f3n', 'build name': 'Nombre de la construcci\u00f3n',
'added': 'A\u00f1adido', 'builds': 'Construcciones',
'Advanced Discovery Scanner': 'Esc\u00e1ner de exploraci\u00f3n avanzado', 'bh': 'mamparos',
'agility': 'Maniobrabilidad', 'ul': 'Laser de r\u00e1fagas',
'alpha': 'Alfa', 'buy': 'Comprar',
'ammo': 'Munici\u00f3n', 'cancel': 'Cancelar',
'PHRASE_CONFIRMATION': '\u00bfEst\u00e1s seguro?', 'c': 'Ca\u00f1\u00f3n',
'armour': 'Blindaje', 'capital': 'capital',
'am': 'Unidad de auto-reparaciones', 'cargo': 'Carga',
'available': 'Disponible', 'Cargo Hatch': 'Compuerta de carga',
'backup': 'Reserva', 'cr': 'Compartimento de carga',
'Basic Discovery Scanner': 'Esc\u00e1ner de exploraci\u00f3n b\u00e1sico', 'cs': 'Esc\u00e1ner de carga',
'bl': 'L\u00e1ser de haz', 'cells': 'celdas',
'bins': 'contenedores', 'Chaff Launcher': 'Lanzador de birutas',
'boost': 'incrementar', 'close': 'Cerrar',
'build': 'Construcci\u00f3n', 'cc': 'Controlador de Drones de Recogida',
'build name': 'Nombre de la construcci\u00f3n', 'compare': 'Comparar',
'builds': 'Construcciones', 'compare all': 'comparar todas',
'bh': 'mamparos', 'comparison': 'Comparativa',
'ul': 'Laser de r\u00e1fagas', 'comparisons': 'Comparativas',
'buy': 'Comprar', 'component': 'Componente',
'cancel': 'Cancelar', 'cost': 'Coste',
'c': 'Ca\u00f1\u00f3n', 'costs': 'Costes',
'capital': 'capital', 'cm': 'Contramedidas',
'cargo': 'Carga', 'create': 'Crear',
'Cargo Hatch': 'Compuerta de carga', 'create new': 'Crear nuevo',
'cr': 'Compartimento de carga', 'credits': 'Cr\u00e9ditos',
'cs': 'Esc\u00e1ner de carga', 'damage': 'Da\u00f1o',
'cells': 'celdas', 'delete': 'Borrar',
'Chaff Launcher': 'Lanzador de birutas', 'delete all': 'Borrar todo',
'close': 'Cerrar', 'dep': 'desp',
'cc': 'Controlador de Drones de Recogida', 'deployed': 'Desplegado',
'compare': 'Comparar', 'detailed export': 'Exportacion detallada',
'compare all': 'comparar todas', 'Detailed Surface Scanner': 'Escaner de exploraci\u00f3n detallada',
'comparison': 'Comparativa', 'disabled': 'Desactivado',
'comparisons': 'Comparativas', 'discount': 'Descuento',
'component': 'Componente', 'dc': 'Ordenador de aterrizaje',
'cost': 'Coste', 'done': 'Hecho',
'costs': 'Costes', 'DPS': 'DPS (Da\u00f1o Por Segundo)',
'cm': 'Contramedidas', 'edit data': 'Editar datos',
'create': 'Crear', 'efficiency': 'Eficiencia',
'create new': 'Crear nuevo', 'Electronic Countermeasure': 'Contramedidas electr\u00f3nicas',
'credits': 'Cr\u00e9ditos', 'empty': 'Vac\u00edo',
'damage': 'Da\u00f1o', 'ENG': 'MOT',
'delete': 'Borrar', 'enter name': 'Introduce el nombre',
'delete all': 'Borrar todo', 'export': 'exportar',
'dep': 'desp', 'fixed': 'fijo',
'deployed': 'Desplegado', 'forum': 'Foro',
'detailed export': 'Exportacion detallada', 'fc': 'Ca\u00f1\u00f3n de fragmentaci\u00f3n',
'Detailed Surface Scanner': 'Escaner de exploraci\u00f3n detallada', 'fd': 'Motor de salto',
'disabled': 'Desactivado', 'ws': 'Esc\u00e1ner de Salto',
'discount': 'Descuento', 'fi': 'Interdictor FSD',
'dc': 'Ordenador de aterrizaje', 'fuel': 'Combustible',
'done': 'Hecho', 'fs': 'Recolector de Combustible',
'DPS': 'DPS (Da\u00f1o Por Segundo)', 'ft': 'Tanque de combustible',
'edit data': 'Editar datos', 'fx': 'Sistema de Transferencia de Combustilble',
'efficiency': 'Eficiencia', 'full tank': 'Tanque lleno',
'Electronic Countermeasure': 'Contramedidas electr\u00f3nicas', 'Gimballed': 'Card\u00e1n',
'empty': 'Vac\u00edo', 'H': 'E',
'ENG': 'MOT', 'hardpoints': 'Montura de armas',
'enter name': 'Introduce el nombre', 'hb': 'Controlador de Apertura de Bah\u00eda de Carga',
'export': 'exportar', 'Heat Sink Launcher': 'Eyector de Acumulador de Calor',
'fixed': 'fijo', 'huge': 'enorme',
'forum': 'Foro', 'hull': 'Casco',
'fc': 'Ca\u00f1\u00f3n de fragmentaci\u00f3n', 'hr': 'Sistema de Casco Reforzado',
'fd': 'Motor de salto', 'import': 'Importar',
'ws': 'Esc\u00e1ner de Salto', 'import all': 'Importar todo',
'fi': 'Interdictor FSD', 'insurance': 'Seguro',
'fuel': 'Combustible', 'Intermediate Discovery Scanner': 'Esc\u00e1ner de exploraci\u00f3n media',
'fs': 'Recolector de Combustible', 'internal compartments': 'Compartimentos internos',
'ft': 'Tanque de combustible', 'jump range': 'Rango de salto',
'fx': 'Sistema de Transferencia de Combustilble', 'jumps': 'Saltos',
'full tank': 'Tanque lleno', 'kw': 'Esc\u00e1ner Detector de Recompensas',
'Gimballed': 'Card\u00e1n', 'L': 'G',
'H': 'E', 'laden': 'Cargada',
'hardpoints': 'Montura de armas', 'language': 'Idioma',
'hb': 'Controlador de Apertura de Bah\u00eda de Carga', 'large': 'Grande',
'Heat Sink Launcher': 'Eyector de Acumulador de Calor', 'ls': 'Soporte vital',
'huge': 'enorme', 'Lightweight Alloy': 'Aleaci\u00f3n ligera',
'hull': 'Casco', 'limpets': 'Drones',
'hr': 'Sistema de Casco Reforzado', 'lock factor': 'factor de bloqueo',
'import': 'Importar', 'mass': 'Masa',
'import all': 'Importar todo', 'max': 'm\u00e1x',
'insurance': 'Seguro', 'max mass': 'Masa m\u00e1xima',
'Intermediate Discovery Scanner': 'Esc\u00e1ner de exploraci\u00f3n media', 'medium': 'medio',
'internal compartments': 'Compartimentos internos', 'Military Grade Composite': 'Blindaje Militar',
'jump range': 'Rango de salto', 'nl': 'Lanzaminas',
'jumps': 'Saltos', 'Mining Lance': 'Lanza de miner\u00eda',
'kw': 'Esc\u00e1ner Detector de Recompensas', 'ml': 'L\u00e1ser de miner\u00eda',
'L': 'G', 'Mirrored Surface Composite': 'Blindaje Reflectante',
'laden': 'Cargada', 'mr': 'Bah\u00eda de Misiles',
'language': 'Idioma', 'mc': 'Ca\u00f1\u00f3n m\u00faltiple',
'large': 'Grande', 'net cost': 'Coste neto',
'ls': 'Soporte vital', 'PHRASE_NO_BUILDS': '\u00a1No se a\u00f1adieron plantillas para comparaci\u00f3n!',
'Lightweight Alloy': 'Aleaci\u00f3n ligera', 'PHRASE_NO_RETROCH': 'No hay cambios en los ajutes',
'limpets': 'Drones', 'none': 'Nada',
'lock factor': 'factor de bloqueo', 'none created': 'Nada creado',
'mass': 'Masa', 'off': 'apagado',
'max': 'm\u00e1x', 'on': 'encendido',
'max mass': 'Masa m\u00e1xima', 'optimal': '\u00f3ptimo',
'medium': 'medio', 'optimal mass': 'masa \u00f3ptima',
'Military Grade Composite': 'Blindaje Militar', 'optimize mass': 'optimizar masa',
'nl': 'Lanzaminas', 'overwrite': 'Sobreescribir',
'Mining Lance': 'Lanza de miner\u00eda', 'PHRASE_IMPORT': 'Pega el JSON o imp\u00f3rtalo aqu\u00ed',
'ml': 'L\u00e1ser de miner\u00eda', 'penetration': 'penetraci\u00f3n',
'Mirrored Surface Composite': 'Blindaje Reflectante', 'permalink': 'enlace permanente',
'mr': 'Bah\u00eda de Misiles', 'pa': 'Acelerador de Plasma',
'mc': 'Ca\u00f1\u00f3n m\u00faltiple', 'Point Defence': 'Punto de Defensa',
'net cost': 'Coste neto', 'power': 'energ\u00eda',
'PHRASE_NO_BUILDS': '\u00a1No se a\u00f1adieron plantillas para comparaci\u00f3n!', 'pd': 'distribuidor de energ\u00eda',
'PHRASE_NO_RETROCH': 'No hay cambios en los ajutes', 'pp': 'Planta de Energ\u00eda',
'none': 'Nada', 'priority': 'prioridad',
'none created': 'Nada creado', 'proceed': 'Proceder',
'off': 'apagado', 'pc': 'Controlador de drones de prospecci\u00f3n',
'on': 'encendido', 'pl': 'L\u00e1ser de Pulso',
'optimal': '\u00f3ptimo', 'PWR': 'POT',
'optimal mass': 'masa \u00f3ptima', 'rg': 'Ca\u00f1\u00f3n de Riel',
'optimize mass': 'optimizar masa', 'range': 'rango',
'overwrite': 'Sobreescribir', 'rate': 'ratio',
'PHRASE_IMPORT': 'Pega el JSON o imp\u00f3rtalo aqu\u00ed', 'Reactive Surface Composite': 'Blindaje Reactivo',
'penetration': 'penetraci\u00f3n', 'recharge': 'recargar',
'permalink': 'enlace permanente', 'rf': 'Refineria',
'pa': 'Acelerador de Plasma', 'refuel time': 'Tiempo para repostar',
'Point Defence': 'Punto de Defensa', 'Reinforced Alloy': 'Armadura reforzada',
'power': 'energ\u00eda', 'reload': 'Recargar',
'pd': 'distribuidor de energ\u00eda', 'rename': 'Renombrar',
'pp': 'Planta de Energ\u00eda', 'repair': 'Reparar',
'priority': 'prioridad', 'reset': 'Reiniciar',
'proceed': 'Proceder', 'ret': 'PLE',
'pc': 'Controlador de drones de prospecci\u00f3n', 'retracted': 'plegadas',
'pl': 'L\u00e1ser de Pulso', 'retrofit costs': 'costes de equipamiento',
'PWR': 'POT', 'retrofit from': 'equipamiento desde',
'rg': 'Ca\u00f1\u00f3n de Riel', 'ROF': 'RDF',
'range': 'rango', 'S': 'P',
'rate': 'ratio', 'save': 'guardar',
'Reactive Surface Composite': 'Blindaje Reactivo', 'sc': 'sc\u00e1ner',
'recharge': 'recargar', 'PHRASE_SELECT_BUILDS': 'Selecciona equipamientos para comparar',
'rf': 'Refineria', 'sell': 'Vender',
'refuel time': 'Tiempo para repostar', 's': 'Sensores',
'Reinforced Alloy': 'Armadura reforzada', 'settings': 'Configuraci\u00f3n',
'reload': 'Recargar', 'sb': 'Potenciador de Escudos',
'rename': 'Renombrar', 'scb': 'C\u00e9lula de Energ\u00eda de Escudos',
'repair': 'Reparar', 'sg': 'Generador de escudos',
'reset': 'Reiniciar', 'shields': 'Escudos',
'ret': 'PLE', 'ship': 'Nave ',
'retracted': 'plegadas', 'ships': 'Naves',
'retrofit costs': 'costes de equipamiento', 'shortened': 'Abreviado',
'retrofit from': 'equipamiento desde', 'size': 'Tama\u00f1o',
'ROF': 'RDF', 'skip': 'omitir',
'S': 'P', 'small': 'Peque\u00f1o',
'save': 'guardar', 'speed': 'velocidad',
'sc': 'sc\u00e1ner', 'standard': 'est\u00e1ndar',
'PHRASE_SELECT_BUILDS': 'Selecciona equipamientos para comparar', 'Standard Docking Computer': 'Computador de Atraque Est\u00e1ndar',
'sell': 'Vender', 'Stock': 'De serie',
's': 'Sensores', 'SYS': 'SIS',
'settings': 'Configuraci\u00f3n', 'T_LOAD': 'c-t\u00e9rmica',
'sb': 'Potenciador de Escudos', 't': 'Propulsores',
'scb': 'C\u00e9lula de Energ\u00eda de Escudos', 'time': 'Tiempo',
'sg': 'Generador de escudos', 'tp': 'Anclaje de torpedo',
'shields': 'Escudos', 'total': 'Total',
'ship': 'Nave ', 'total range': 'Rango total',
'ships': 'Naves', 'turret': 'torreta',
'shortened': 'Abreviado', 'type': 'Tipo',
'size': 'Tama\u00f1o', 'unladen': 'Sin carga',
'skip': 'omitir', 'PHRASE_UPDATE_RDY': 'Actualizacion disponible! Haz click para recargar',
'small': 'Peque\u00f1o', 'URL': 'Enlace',
'speed': 'velocidad', 'utility': 'utilidad',
'standard': 'est\u00e1ndar', 'utility mounts': 'monturas de utilidad',
'Standard Docking Computer': 'Computador de Atraque Est\u00e1ndar', 'version': 'Versi\u00f3n',
'Stock': 'De serie', 'WEP': 'ARM',
'SYS': 'SIS', 'yes': 'si',
'T_LOAD': 'c-t\u00e9rmica', 'PHRASE_BACKUP_DESC': 'Copia de seguridad de todos los datos de Coriolis para guardarlos o transferirlos a otro navegador\/dispositivo'
't': 'Propulsores', };
'time': 'Tiempo',
'tp': 'Anclaje de torpedo',
'total': 'Total',
'total range': 'Rango total',
'turret': 'torreta',
'type': 'Tipo',
'unladen': 'Sin carga',
'PHRASE_UPDATE_RDY': 'Actualizacion disponible! Haz click para recargar',
'URL': 'Enlace',
'utility': 'utilidad',
'utility mounts': 'monturas de utilidad',
'version': 'Versi\u00f3n',
'WEP': 'ARM',
'yes': 'si',
'PHRASE_BACKUP_DESC': 'Copia de seguridad de todos los datos de Coriolis para guardarlos o transferirlos a otro navegador\/dispositivo'
});
}]);

View File

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

View File

@@ -1,133 +1,129 @@
angular.module('app').config(['$translateProvider', 'localeFormatProvider', function($translateProvider, localeFormatProvider) { export const formats = {
decimal: ',',
thousands: '.',
grouping: [3],
currency: ['€', ''],
dateTime: '%A %e %B %Y, %X',
date: '%d/%m/%Y',
time: '%H:%M:%S',
periods: ['AM', 'PM'], // unused
days: ['Domenica', 'Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato'],
shortDays: ['Dom', 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab'],
months: ['Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre'],
shortMonths: ['Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic']
};
// Declare number format settings export const terms = {
localeFormatProvider.addFormat('es', { PHRASE_EXPORT_DESC: 'Un export dettagliato in formato JSON della tua configurazione per essere usato in altri siti o tools',
decimal: ',', 'A-Rated': 'Classe A',
thousands: '.', about: 'Info su Coriolis',
grouping: [3], action: 'azione',
currency: ['€', ''], added: 'aggiunto',
dateTime: '%A %e %B %Y, %X', Advanced: 'Avanzato',
date: '%d/%m/%Y', agility: 'agilità',
time: '%H:%M:%S', ammo: 'munizioni',
periods: ['AM', 'PM'], // unused PHRASE_CONFIRMATION: 'Sei sicuro ?',
days: ['Domenica', 'Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato'], armour: 'armatura',
shortDays: ['Dom', 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab'], available: 'disponibile',
months: ['Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre'], bins: 'contenitore',
shortMonths: ['Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic'] build: 'configurazione',
}); 'build name': 'Nome Configurazione',
builds: 'configurazioni',
$translateProvider.translations('it', { buy: 'compra',
PHRASE_EXPORT_DESC: 'Un export dettagliato in formato JSON della tua configurazione per essere usato in altri siti o tools', cancel: 'cancella',
'A-Rated': 'Classe A', cells: 'celle',
about: 'Info su Coriolis', close: 'chiudi',
action: 'azione', compare: 'confronta',
added: 'aggiunto', 'compare all': 'confronta tutti',
Advanced: 'Avanzato', comparison: 'comparazione',
agility: 'agilità', comparisons: 'comparazioni',
ammo: 'munizioni', component: 'componente',
PHRASE_CONFIRMATION: 'Sei sicuro ?', cost: 'costo',
armour: 'armatura', costs: 'costi',
available: 'disponibile', cm: 'Contromisure',
bins: 'contenitore', create: 'crea',
build: 'configurazione', 'create new': 'crea nuovo',
'build name': 'Nome Configurazione', credits: 'crediti',
builds: 'configurazioni', damage: 'danno',
buy: 'compra', delete: 'elimina',
cancel: 'cancella', 'delete all': 'elimina tutto',
cells: 'celle', dep: 'dep',
close: 'chiudi', deployed: 'deployed',
compare: 'confronta', 'detailed export': 'esportazione dettagliata',
'compare all': 'confronta tutti', disabled: 'disabilita',
comparison: 'comparazione', discount: 'sconto',
comparisons: 'comparazioni', done: 'fatto',
component: 'componente', 'edit data': 'modifica i dati',
cost: 'costo', efficiency: 'efficenza',
costs: 'costi', empty: 'vuoto',
cm: 'Contromisure', Enforcer: 'Rinforzatore',
create: 'crea', 'enter name': 'Inserisci un nome',
'create new': 'crea nuovo', export: 'esporta',
credits: 'crediti', fixed: 'fissi',
damage: 'danno', fuel: 'carburante',
delete: 'elimina', 'full tank': 'Serbatoio Pieno',
'delete all': 'elimina tutto', huge: 'enorme',
dep: 'dep', hull: 'corazza',
deployed: 'deployed', import: 'importa',
'detailed export': 'esportazione dettagliata', 'import all': 'importa tutto',
disabled: 'disabilita', insurance: 'assicurazione',
discount: 'sconto', 'internal compartments': 'compartimenti interni',
done: 'fatto', 'jump range': 'distanza di salto',
'edit data': 'modifica i dati', jumps: 'salti',
efficiency: 'efficenza', laden: 'carico',
empty: 'vuoto', language: 'lingua',
Enforcer: 'Rinforzatore', large: 'largo',
'enter name': 'Inserisci un nome', mass: 'massa',
export: 'esporta', max: 'massimo',
fixed: 'fissi', 'max mass': 'massa massimale',
fuel: 'carburante', medium: 'medio',
'full tank': 'Serbatoio Pieno', 'net cost': 'costo netto',
huge: 'enorme', PHRASE_NO_BUILDS: 'nessuna configurazione è stata aggiunta per la comparazione!',
hull: 'corazza', PHRASE_NO_RETROCH: 'Nessun cambiamento di Retrofitting',
import: 'importa', none: 'nessuno',
'import all': 'importa tutto', 'none created': 'nessuno creato',
insurance: 'assicurazione', optimal: 'ottimale',
'internal compartments': 'compartimenti interni', 'optimal mass': 'massa ottimale',
'jump range': 'distanza di salto', 'optimize mass': 'ottimizza la massa',
jumps: 'salti', overwrite: 'sovrasscrivi',
laden: 'carico', PHRASE_IMPORT: 'Incolla un JSON o importalo qua',
language: 'lingua', penetration: 'penetrazione',
large: 'largo', power: 'potenza',
mass: 'massa', priority: 'priorità',
max: 'massimo', proceed: 'procedi',
'max mass': 'massa massimale', range: 'distanza',
medium: 'medio', rate: 'rateo',
'net cost': 'costo netto', recharge: 'ricarica',
PHRASE_NO_BUILDS: 'nessuna configurazione è stata aggiunta per la comparazione!', reload: 'ricarica',
PHRASE_NO_RETROCH: 'Nessun cambiamento di Retrofitting', rename: 'rinomina',
none: 'nessuno', repair: 'ripara',
'none created': 'nessuno creato', reset: 'resetta',
optimal: 'ottimale', retracted: 'retratti',
'optimal mass': 'massa ottimale', 'retrofit costs': 'costi di retrofit',
'optimize mass': 'ottimizza la massa', 'retrofit from': 'retrofit da',
overwrite: 'sovrasscrivi', save: 'salva',
PHRASE_IMPORT: 'Incolla un JSON o importalo qua', sell: 'vendi',
penetration: 'penetrazione', settings: 'impostazioni',
power: 'potenza', shields: 'scudi',
priority: 'priorità', ship: 'nave',
proceed: 'procedi', ships: 'navi',
range: 'distanza', shortened: 'accorciato',
rate: 'rateo', size: 'grandezza',
recharge: 'ricarica', skip: 'salta',
reload: 'ricarica', small: 'piccolo',
rename: 'rinomina', speed: 'velocità',
repair: 'ripara', Stock: 'appena comprata',
reset: 'resetta', t: 'thrusters',
retracted: 'retratti', time: 'tempo',
'retrofit costs': 'costi di retrofit', total: 'totale',
'retrofit from': 'retrofit da', 'total range': 'distanza totale',
save: 'salva', turret: 'torrette',
sell: 'vendi', type: 'tipo',
settings: 'impostazioni', unladen: 'scarico',
shields: 'scudi', PHRASE_UPDATE_RDY: 'Aggiornamenti disponibili ! Clicca per Aggiornare',
ship: 'nave', utility: 'supporti',
ships: 'navi', 'utility mounts': 'supporti di utilità',
shortened: 'accorciato', version: 'versione',
size: 'grandezza', yes: '',
skip: 'salta', PHRASE_BACKUP_DESC: 'Esportazione di tutti i dati su Coriolis per salvarli o trasferirli in un altro Browser/dispositivo'
small: 'piccolo', };
speed: 'velocità',
Stock: 'appena comprata',
t: 'thrusters',
time: 'tempo',
total: 'totale',
'total range': 'distanza totale',
turret: 'torrette',
type: 'tipo',
unladen: 'scarico',
PHRASE_UPDATE_RDY: 'Aggiornamenti disponibili ! Clicca per Aggiornare',
utility: 'supporti',
'utility mounts': 'supporti di utilità',
version: 'versione',
yes: 'sì',
PHRASE_BACKUP_DESC: 'Esportazione di tutti i dati su Coriolis per salvarli o trasferirli in un altro Browser/dispositivo'
});
}]);

View File

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

View File

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

180
app/js/pages/ShipyardPage.jsx Executable file
View File

@@ -0,0 +1,180 @@
import { Component } from 'react';
import { Ships, Components } from 'coriolis-data';
import cn from 'classnames';
import Ship from 'Ship';
function countHp(slot) {
this.hp[slot.maxClass]++;
this.hpCount++;
}
function countInt(slot) {
var crEligible = !slot.eligible || slot.eligible.cr;
this.int[slot.maxClass - 1]++; // Subtract 1 since there is no Class 0 Internal compartment
this.intCount++;
this.maxCargo += crEligible ? Components.findInternal('cr', slot.maxClass, 'E').capacity : 0;
}
function shipSummary(shipId, shipData) {
let summary = {
id: shipId,
hpCount: 0,
intCount: 0,
maxCargo: 0,
hp: [0, 0, 0, 0, 0], // Utility, Small, Medium, Large, Huge
int: [0, 0, 0, 0, 0, 0, 0, 0] // Sizes 1 - 8
};
Object.assign(summary, shipData.properties);
let ship = new Ship(shipId, shipData.properties, shipData.slots);
// Build Ship
ship.buildWith(shipData.defaults); // Populate with stock/default components
ship.hardpoints.forEach(countHp.bind(summary)); // Count Hardpoints by class
ship.internal.forEach(countInt.bind(summary)); // Count Internal Compartments by class
summary.retailCost = ship.totalCost; // Record Stock/Default/retail cost
ship.optimizeMass({ pd: '1D' }); // Optimize Mass with 1D PD for maximum possible jump range
summary.maxJumpRange = ship.unladenRange; // Record Jump Range
ship.optimizeMass({ th: ship.standard[1].maxClass + 'A' }); // Optmize mass with Max Thrusters
summary.topSpeed = ship.topSpeed;
summary.topBoost = ship.topBoost;
return summary;
}
let shipSummaries = [];
for (var s in Ships) {
shipSummaries.push(shipSummary(s, Ships[s]));
}
export default class ShipyardPage extends Component {
constructor(props) {
super(props);
this.state = {
title: 'Coriolis - Shipyard',
shipPredicate: 'properties.name',
shipDesc = false
};
}
shouldComponentUpdate(nextProps, nextState) {
// Only on language change. Context?
return false;
}
/**
* Sort ships
* @param {object} key Sort predicate
*/
_sortShips(shipPredicate, shipPredicateIndex) {
let shipDesc = this.state.shipPredicate == shipPredicate ? !this.state.shipDesc : this.state.shipDesc;
this.setState({ shipPredicate, shipDesc, shipPredicateIndex });
};
render() {
let sortShips = this._sortShips.bind(this);
let shipPredicate = this.state.shipPredicate;
let shipPredicateIndex = this.state.shipPredicateIndex;
let shipRows = [];
// Sort shipsOverview
shipSummaries.sort((a, b) => {
let valA = a[shipPredicate], valB = b[shipPredicate];
if (shipPredicateIndex != undefined) {
valA = valA[shipPredicateIndex];
valB = valB[shipPredicateIndex];
}
return this.state.shipDesc ? (valA > valB) : (valB > valA);
});
for (s of shipSummaries) {
shipRows.push(
<tr className={'highlight'}>
<td className={'le'}><a ui-sref='outfit({shipId: s.id})'>{s.name}</a></td>
<td className={'le'}>{s.manufacturer}</td>
<td className={'cap'}>{SZM[s.class] | translate}</td>
<td className={'ri'}>{{fCrd(s.speed)}} <u translate>m/s</u></td>
<td className={'ri'}>{{fCrd(s.boost)}} <u translate>m/s</u></td>
<td className={'ri'}>{s.baseArmour}</td>
<td className={'ri'}>{{fCrd(s.baseShieldStrength)}} <u translate>Mj</u></td>
<td className={'ri'}>{{fCrd(s.topSpeed)}} <u translate>m/s</u></td>
<td className={'ri'}>{{fCrd(s.topBoost)}} <u translate>m/s</u></td>
<td className={'ri'}>{{fRound(s.maxJumpRange)}} <u translate>LY</u></td>
<td className={'ri'}>{{fCrd(s.maxCargo)}} <u translate>T</u></td>
<td className={cn({ disabled: !s.hp[1] })}>{s.hp[1]}</td>
<td className={cn({ disabled: !s.hp[2] })}>{s.hp[2]}</td>
<td className={cn({ disabled: !s.hp[3] })}>{s.hp[3]}</td>
<td className={cn({ disabled: !s.hp[4] })}>{s.hp[4]}</td>
<td className={cn({ disabled: !s.hp[0] })}>{s.hp[0]}</td>
<td className={cn({ disabled: !s.int[0] })}>{s.int[0]}</td>
<td className={cn({ disabled: !s.int[1] })}>{s.int[1]}</td>
<td className={cn({ disabled: !s.int[2] })}>{s.int[2]}</td>
<td className={cn({ disabled: !s.int[3] })}>{s.int[3]}</td>
<td className={cn({ disabled: !s.int[4] })}>{s.int[4]}</td>
<td className={cn({ disabled: !s.int[5] })}>{s.int[5]}</td>
<td className={cn({ disabled: !s.int[6] })}>{s.int[6]}</td>
<td className={cn({ disabled: !s.int[7] })}>{s.int[7]}</td>
<td className={'ri'}>{fCrd(s.hullMass)} <u translate>T</u></td>
<td className={'ri'}>{s.masslock}</td>
<td className={'ri'}>{fCrd(s.retailCost)} <u translate>CR</u></td>
</tr>
);
}
return (
<div id='shipyard'>
<div className={'scroll-x'}>
<table style={{ fontSize:'0.85em', whiteSpace:'nowrap' }}>
<thead>
<tr className={'main'}>
<th rowspan='2' className={'sortable le'} onClick={sortShips('name')} translate='ship'></th>
<th rowspan='2' className={'sortable'} onClick={sortShips('manufacturer')} translate='manufacturer'></th>
<th rowspan='2' className={'sortable'} onClick={sortShips('class')} translate='size'></th>
<th colspan='4' translate='base'></th>
<th colspan='4' translate='max'></th>
<th colspan='5' className={'sortable'} onClick={sortShips('hpCount')} translate='hardpoints'></th>
<th colspan='8' className={'sortable'} onClick={sortShips('intCount')} translate='internal compartments'></th>
<th rowspan='2' className={'sortable'} onClick={sortShips('hullMass')} translate='hull'></th>
<th rowspan='2' className={'sortable'} onClick={sortShips('masslock')} translate='MLF'></th>
<th rowspan='2' className={'sortable'} onClick={sortShips('retailCost')} translate='cost'></th>
</tr>
<tr>
{/* Base */}
<th className={'sortable lft'} onClick={sortShips('speed')} translate='speed'></th>
<th className={'sortable'} onClick={sortShips('boost')} translate='boost'></th>
<th className={'sortable'} onClick={sortShips('baseArmour')} translate='armour'></th>
<th className={'sortable'} onClick={sortShips('baseShieldStrength')} translate='shields'></th>
{/* Max */}
<th className={'sortable lft'} onClick={sortShips('topSpeed')} translate='speed'></th>
<th className={'sortable'} onClick={sortShips('topBoost')} translate='boost'></th>
<th className={'sortable'} onClick={sortShips('maxJumpRange')} translate='jump'></th>
<th className={'sortable'} onClick={sortShips('maxCargo')} translate='cargo'></th>
{/* Hardpoints */}
<th className={'sortable lft'} onClick={sortShips('hp',1)} translate='S'></th>
<th className={'sortable'} onClick={sortShips('hp', 2)} translate='M'></th>
<th className={'sortable'} onClick={sortShips('hp', 3)} translate='L'></th>
<th className={'sortable'} onClick={sortShips('hp', 4)} translate='H'></th>
<th className={'sortable'} onClick={sortShips('hp', 0)} translate='U'></th>
{/* Internal */}
<th className={'sortable lft'} onClick={sortShips('int', 0)} >1</th>
<th className={'sortable'} onClick={sortShips('int', 1)} >2</th>
<th className={'sortable'} onClick={sortShips('int', 2)} >3</th>
<th className={'sortable'} onClick={sortShips('int', 3)} >4</th>
<th className={'sortable'} onClick={sortShips('int', 4)} >5</th>
<th className={'sortable'} onClick={sortShips('int', 5)} >6</th>
<th className={'sortable'} onClick={sortShips('int', 6)} >7</th>
<th className={'sortable'} onClick={sortShips('int', 7)} >8</th>
</tr>
</thead>
<tbody>
{shipRows}
</tbody>
</table>
</div>
</div>
);
}
}

View File

@@ -1,36 +0,0 @@
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

@@ -1,314 +0,0 @@
/**
* [description]
*/
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';
var localStorage = $window.localStorage;
var buildJson = null;
var comparisonJson = null;
// Safe check to determine if localStorage is enabled
try {
localStorage.setItem('s', 1);
localStorage.removeItem('s');
buildJson = localStorage.getItem(LS_KEY_BUILDS);
comparisonJson = localStorage.getItem(LS_KEY_COMPARISONS);
this.lsEnabled = true;
} catch(e) {
this.lsEnabled = false;
}
this.builds = buildJson ? angular.fromJson(buildJson) : {};
this.comparisons = comparisonJson ? angular.fromJson(comparisonJson) : {};
var buildCount = Object.keys(this.builds).length;
this.state = {
buildCount: buildCount,
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.
*
* @param {string} shipId The unique id for a model of ship
* @param {string} name The name of the build
* @param {string} code The serialized code
*/
this.saveBuild = function(shipId, name, code) {
if (!this.lsEnabled) {
return;
}
if (!this.builds[shipId]) {
this.builds[shipId] = {};
}
if (!this.builds[shipId][name]) {
this.state.buildCount++;
this.state.hasBuilds = true;
}
this.builds[shipId][name] = code;
// Persist updated build collection to localStorage
localStorage.setItem(LS_KEY_BUILDS, angular.toJson(this.builds));
};
/**
* Get the serialized code/string for a build. Returns null if a
* build is not found.
*
* @param {string} shipId The unique id for a model of ship
* @param {string} name The name of the build
* @return {string} The serialized build string.
*/
this.getBuild = function(shipId, name) {
if (this.builds[shipId] && this.builds[shipId][name]) {
return this.builds[shipId][name];
}
return null;
};
/**
* Delete a build from local storage. It will also delete the ship build collection if
* it becomes empty
*
* @param {string} shipId The unique id for a model of ship
* @param {string} name The name of the build
*/
this.deleteBuild = function(shipId, name) {
if (this.lsEnabled && this.builds[shipId][name]) {
delete this.builds[shipId][name];
if (Object.keys(this.builds[shipId]).length === 0) {
delete this.builds[shipId];
this.state.buildCount--;
this.state.hasBuilds = this.state.buildCount > 0;
}
// Persist updated build collection to localStorage
localStorage.setItem(LS_KEY_BUILDS, angular.toJson(this.builds));
// Check if the build was used in existing comparisons
var comps = this.comparisons;
for (var c in comps) {
for (var i = 0; i < comps[c].builds.length; i++) { // For all builds in the current comparison
if (comps[c].builds[i].shipId == shipId && comps[c].builds[i].buildName == name) {
comps[c].builds.splice(i, 1);
break; // A build is unique ber comparison
}
}
}
localStorage.setItem(LS_KEY_COMPARISONS, angular.toJson(this.comparisons));
}
};
/**
* Persist a comparison in localstorage.
*
* @param {string} name The name of the comparison
* @param {array} builds Array of builds
* @param {array} facets Array of facet indices
*/
this.saveComparison = function(name, builds, facets) {
if (!this.lsEnabled) {
return;
}
if (!this.comparisons[name]) {
this.comparisons[name] = {};
}
this.comparisons[name] = {
facets: facets,
builds: _.map(builds, function(b) { return { shipId: b.id || b.shipId, buildName: b.buildName }; })
};
localStorage.setItem(LS_KEY_COMPARISONS, angular.toJson(this.comparisons));
this.state.hasComparisons = true;
};
/**
* [getComparison description]
* @param {string} name [description]
* @return {object} Object containing array of facets and ship id + build names
*/
this.getComparison = function(name) {
if (this.comparisons[name]) {
return this.comparisons[name];
}
return null;
};
/**
* Removes the comparison from localstorage.
* @param {string} name Comparison name
*/
this.deleteComparison = function(name) {
if (this.lsEnabled && this.comparisons[name]) {
delete this.comparisons[name];
localStorage.setItem(LS_KEY_COMPARISONS, angular.toJson(this.comparisons));
this.state.hasComparisons = Object.keys(this.comparisons).length > 0;
}
};
/**
* Delete all builds and comparisons from localStorage
*/
this.deleteAll = function() {
angular.copy({}, this.builds); // Empty object but keep original instance
angular.copy({}, this.comparisons);
this.state.hasBuilds = false;
this.state.buildCount = 0;
if (this.lsEnabled) {
localStorage.removeItem(LS_KEY_BUILDS);
localStorage.removeItem(LS_KEY_COMPARISONS);
}
};
this.getAll = function() {
var data = {};
data[LS_KEY_BUILDS] = this.builds;
data[LS_KEY_COMPARISONS] = this.comparisons;
data[LS_KEY_INSURANCE] = this.getInsurance();
data[LS_KEY_DISCOUNTS] = this.getDiscount();
return data;
};
/**
* Get the saved insurance type
* @return {string} The name of the saved insurance type of null
*/
this.getInsurance = function() {
if (this.lsEnabled) {
return localStorage.getItem(LS_KEY_INSURANCE);
}
return null;
};
/**
* Persist selected insurance type
* @param {string} name Insurance type name
*/
this.setInsurance = function(name) {
if (this.lsEnabled) {
return localStorage.setItem(LS_KEY_INSURANCE, name);
}
};
/**
* Persist selected discount
* @param {number} val Discount value/amount
*/
this.setDiscount = function(val) {
if (this.lsEnabled) {
return localStorage.setItem(LS_KEY_DISCOUNTS, angular.toJson(val));
}
};
/**
* Get the saved discount
* @return {number} val Discount value/amount
*/
this.getDiscount = function() {
if (this.lsEnabled) {
return angular.fromJson(localStorage.getItem(LS_KEY_DISCOUNTS));
}
return null;
};
/**
* Persist selected cost tab
* @param {number} val Discount value/amount
*/
this.setCostTab = function(tabName) {
if (this.lsEnabled) {
return localStorage.setItem(LS_KEY_COST_TAB, tabName);
}
};
/**
* Get the saved discount
* @return {number} val Discount value/amount
*/
this.getCostTab = function() {
if (this.lsEnabled) {
return localStorage.getItem(LS_KEY_COST_TAB);
}
return null;
};
/**
* Retrieve the last router state from local storage
* @return {object} state State object containing state name and params
*/
this.getState = function() {
if (this.lsEnabled) {
var state = localStorage.getItem('state');
if (state) {
return angular.fromJson(state);
}
}
return null;
};
/**
* Save the current router state to localstorage
* @param {object} state State object containing state name and params
*/
this.setState = function(state) {
if (this.lsEnabled) {
localStorage.setItem('state', angular.toJson(state));
}
};
/**
* 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
*/
this.isEnabled = function() {
return this.lsEnabled;
};
}]);

View File

@@ -1,245 +0,0 @@
/**
* Service managing seralization and deserialization of models for use in URLs and persistene.
*/
angular.module('app').service('Serializer', ['lodash', 'GroupMap', 'MountMap', 'ShipsDB', 'Ship', 'Components', '$state', function(_, GroupMap, MountMap, ShipsDB, Ship, Components, $state) {
/**
* Serializes the ships selected components for all slots to a URL friendly string.
* @param {Ship} ship The ship to be serialized.
* @return {string} Encoded string of components
*/
this.fromShip = function(ship) {
var power = {
enabled: [ship.cargoHatch.enabled ? 1 : 0],
priorities: [ship.cargoHatch.priority]
};
var data = [
ship.bulkheads.id,
_.map(ship.standard, mapGroup, power),
_.map(ship.hardpoints, mapGroup, power),
_.map(ship.internal, mapGroup, power),
'.',
LZString.compressToBase64(power.enabled.join('')).replace(/\//g, '-'),
'.',
LZString.compressToBase64(power.priorities.join('')).replace(/\//g, '-')
];
return _.flatten(data).join('');
};
/**
* Updates an existing ship instance's slots with components determined by the
* code.
*
* @param {Ship} ship The ship instance to be updated
* @param {string} dataString The string to deserialize
*/
this.toShip = function(ship, dataString) {
var standard = new Array(ship.standard.length),
hardpoints = new Array(ship.hardpoints.length),
internal = new Array(ship.internal.length),
parts = dataString.split('.'),
priorities = null,
enabled = null,
code = parts[0];
if (parts[1]) {
enabled = LZString.decompressFromBase64(parts[1].replace(/-/g, '/')).split('');
}
if (parts[2]) {
priorities = LZString.decompressFromBase64(parts[2].replace(/-/g, '/')).split('');
}
decodeToArray(code, internal, decodeToArray(code, hardpoints, decodeToArray(code, standard, 1)));
ship.buildWith(
{
bulkheads: code.charAt(0) * 1,
standard: standard,
hardpoints: hardpoints,
internal: internal
},
priorities,
enabled
);
};
this.toDetailedBuild = function(buildName, ship, code) {
var standard = ship.standard,
hardpoints = ship.hardpoints,
internal = ship.internal;
var data = {
$schema: 'http://cdn.coriolis.io/schemas/ship-loadout/2.json#',
name: buildName,
ship: ship.name,
references: [{
name: 'Coriolis.io',
url: $state.href('outfit', { shipId: ship.id, code: code, bn: buildName }, { absolute: true }),
code: code,
shipId: ship.id
}],
components: {
standard: {
bulkheads: ship.bulkheads.c.name,
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),
internal: _.map(internal, slotToSchema)
},
stats: {}
};
for (var stat in ship) {
if (!isNaN(ship[stat])) {
data.stats[stat] = Math.round(ship[stat] * 100) / 100;
}
}
return data;
};
this.fromDetailedBuild = function(detailedBuild) {
var shipId = _.findKey(ShipsDB, { properties: { name: detailedBuild.ship } });
if (!shipId) {
throw 'No such ship: ' + detailedBuild.ship;
}
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(standard.bulkheads);
if (bulkheads < 0) {
throw 'Invalid bulkheads: ' + standard.bulkheads;
}
var standardIds = _.map(
['powerPlant', 'thrusters', 'frameShiftDrive', 'lifeSupport', 'powerDistributor', 'sensors', 'fuelTank'],
function(c) {
if (!standard[c].class || !standard[c].rating) {
throw 'Invalid value for ' + c;
}
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;
}
);
var internal = _.map(comps.internal, function(c) { return c ? Components.findInternalId(c.group, c.class, c.rating, c.name) : 0; });
var hardpoints = _.map(comps.hardpoints, function(c) {
return c ? Components.findHardpointId(c.group, c.class, c.rating, c.name, MountMap[c.mount], c.missile) : 0;
}).concat(_.map(comps.utility, function(c) {
return c ? Components.findHardpointId(c.group, c.class, c.rating, c.name, MountMap[c.mount]) : 0;
}));
// 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, standard: standardIds, hardpoints: hardpoints, internal: internal }, priorities, enabled);
return ship;
};
this.toDetailedExport = function(builds) {
var data = [];
for (var shipId in builds) {
for (var buildName in builds[shipId]) {
var code = builds[shipId][buildName];
var shipData = ShipsDB[shipId];
var ship = new Ship(shipId, shipData.properties, shipData.slots);
this.toShip(ship, code);
data.push(this.toDetailedBuild(buildName, ship, code));
}
}
return data;
};
this.fromComparison = function(name, builds, facets, predicate, desc) {
var shipBuilds = [];
builds.forEach(function(b) {
shipBuilds.push({ s: b.id, n: b.buildName, c: this.fromShip(b) });
}.bind(this));
return LZString.compressToBase64(angular.toJson({
n: name,
b: shipBuilds,
f: facets,
p: predicate,
d: desc ? 1 : 0
})).replace(/\//g, '-');
};
this.toComparison = function(code) {
return angular.fromJson(LZString.decompressFromBase64(code.replace(/-/g, '/')));
};
/**
* Utility function to retrieve a safe string for selected component for a slot.
* Used for serialization to code only.
*
* @private
* @param {object} slot The slot object.
* @return {string} The id of the selected component or '-' if none selected
*/
function mapGroup(slot) {
this.enabled.push(slot.enabled ? 1 : 0);
this.priorities.push(slot.priority);
return slot.id === null ? '-' : slot.id;
}
function decodeToArray(code, arr, codePos) {
for (var i = 0; i < arr.length; i++) {
if (code.charAt(codePos) == '-') {
arr[i] = 0;
codePos++;
} else {
arr[i] = code.substring(codePos, codePos + 2);
codePos += 2;
}
}
return codePos;
}
function slotToSchema(slot) {
if (slot.c) {
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;
}
if (slot.c.mode) {
o.mount = MountMap[slot.c.mode];
}
if (slot.c.missile) {
o.missile = slot.c.missile;
}
return o;
}
return null;
}
}]);

View File

@@ -0,0 +1,84 @@
/**
* Calculate the maximum single jump range based on mass and a specific FSD
*
* @param {number} mass Mass of a ship: laden, unlanden, partially laden, etc
* @param {object} fsd The FDS object/component with maxfuel, fuelmul, fuelpower, optmass
* @param {number} fuel Optional - The fuel consumed during the jump (must be less than the drives max fuel per jump)
* @return {number} Distance in Light Years
*/
export function jumpRange(mass, fsd, fuel) {
return Math.pow(Math.min(fuel === undefined ? fsd.maxfuel : fuel, fsd.maxfuel) / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass;
}
/**
* Calculate the total range based on mass and a specific FSD, and all fuel available
*
* @param {number} mass Mass of a ship: laden, unlanden, partially laden, etc
* @param {object} fsd The FDS object/component with maxfuel, fuelmul, fuelpower, optmass
* @param {number} fuel The total fuel available
* @return {number} Distance in Light Years
*/
export function totalRange(mass, fsd, fuel) {
var fuelRemaining = fuel % fsd.maxfuel; // Fuel left after making N max jumps
var jumps = Math.floor(fuel / fsd.maxfuel);
mass += fuelRemaining;
// Going backwards, start with the last jump using the remaining fuel
var totalRange = fuelRemaining > 0 ? Math.pow(fuelRemaining / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass : 0;
// For each max fuel jump, calculate the max jump range based on fuel mass left in the tank
for (var j = 0; j < jumps; j++) {
mass += fsd.maxfuel;
totalRange += Math.pow(fsd.maxfuel / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass;
}
return totalRange;
};
/**
* Calculate the a ships shield strength based on mass, shield generator and shield boosters used.
*
* @param {number} mass Current mass of the ship
* @param {number} shields Base Shield strength MJ for ship
* @param {object} sg The shield generator used
* @param {number} multiplier Shield multiplier for ship (1 + shield boosters if any)
* @return {number} Approximate shield strengh in MJ
*/
export function shieldStrength(mass, shields, sg, multiplier) {
var opt;
if (mass < sg.minmass) {
return shields * multiplier * sg.minmul;
}
if (mass > sg.maxmass) {
return shields * multiplier * sg.maxmul;
}
if (mass < sg.optmass) {
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) );
}
}
/**
* Calculate the a ships speed based on mass, and thrusters.
*
* @param {number} mass Current mass of the ship
* @param {number} baseSpeed Base speed m/s for ship
* @param {number} baseBoost Base boost speed m/s for ship
* @param {object} thrusters The Thrusters used
* @param {number} pipSpeed Speed pip multiplier
* @return {object} Approximate speed by pips
*/
export function speed(mass, baseSpeed, baseBoost, thrusters, pipSpeed) {
var multiplier = mass > thrusters.maxmass ? 0 : ((1 - thrusters.M) + (thrusters.M * Math.pow(3 - (2 * Math.max(0.5, mass / thrusters.optmass)), thrusters.P)));
var speed = baseSpeed * multiplier;
return {
'0 Pips': speed * (1 - (pipSpeed * 4)),
'2 Pips': speed * (1 - (pipSpeed * 2)),
'4 Pips': speed,
'boost': baseBoost * multiplier
};
}

183
app/js/shipyard/Constants.js Executable file
View File

@@ -0,0 +1,183 @@
export const ArmourMultiplier = [
1, // Lightweight
1.4, // Reinforced
1.945, // Military
1.945, // Mirrored
1.945 // Reactive
];
export const SizeMap = ['', 'small', 'medium', 'large', 'capital'];
// Map to lookup group labels/names for component grp, used for JSON Serialization
const ModuleGroupToName = {
// Standard
pp: 'Power Plant',
t: 'Thrusters',
fsd: 'Frame Shift Drive',
ls: 'Life Support',
pd: 'Power Distributor',
s: 'Sensors',
ft: 'Fuel Tank',
// Internal
fs: 'Fuel Scoop',
sc: 'Scanner',
am: 'Auto Field-Maintenance Unit',
cr: 'Cargo Rack',
fi: 'Frame Shift Drive Interdictor',
hb: 'Hatch Breaker Limpet Controller',
hr: 'Hull Reinforcement Package',
rf: 'Refinery',
scb: 'Shield Cell Bank',
sg: 'Shield Generator',
psg: 'Prismatic Shield Generator',
dc: 'Docking Computer',
fx: 'Fuel Transfer Limpet Controller',
pc: 'Prospector Limpet Controller',
cc: 'Collector Limpet Controller',
// Hard Points
bl: 'Beam Laser',
ul: 'Burst Laser',
c: 'Cannon',
cs: 'Cargo Scanner',
cm: 'Countermeasure',
fc: 'Fragment Cannon',
ws: 'Frame Shift Wake Scanner',
kw: 'Kill Warrant Scanner',
nl: 'Mine Launcher',
ml: 'Mining Laser',
mr: 'Missile Rack',
pa: 'Plasma Accelerator',
mc: 'Multi-cannon',
pl: 'Pulse Laser',
rg: 'Rail Gun',
sb: 'Shield Booster',
tp: 'Torpedo Pylon'
};
let GrpNameToCodeMap = {};
for (let grp in ModuleGroupToName) {
GrpNameToCodeMap[ModuleGroupToName[grp]] = grp;
}
export ModuleGroupToName;
export const ModuleNameToGroup = GrpNameToCodeMap;
export const MountMap = {
'F': 'Fixed',
'G': 'Gimballed',
'T': 'Turret',
'Fixed': 'F',
'Gimballed': 'G',
'Turret': 'T'
};
export const BulkheadNames = [
'Lightweight Alloy',
'Reinforced Alloy',
'Military Grade Composite',
'Mirrored Surface Composite',
'Reactive Surface Composite'
];
/**
* Array of all Ship properties (facets) organized into groups
* used for ship comparisons.
*
* @type {Array}
*/
export const ShipFacets = [
{ // 0
title: 'agility',
props: ['agility'],
unit: '',
fmt: 'fCrd'
},
{ // 1
title: 'speed',
props: ['topSpeed', 'topBoost'],
lbls: ['thrusters', 'boost'],
unit: 'm/s',
fmt: 'fCrd'
},
{ // 2
title: 'armour',
props: ['armour'],
unit: '',
fmt: 'fCrd'
},
{ // 3
title: 'shields',
props: ['shieldStrength'],
unit: 'MJ',
fmt: 'fRound'
},
{ // 4
title: 'jump range',
props: ['unladenRange', 'fullTankRange', 'ladenRange'],
lbls: ['max', 'full tank', 'laden'],
unit: 'LY',
fmt: 'fRound'
},
{ // 5
title: 'mass',
props: ['unladenMass', 'ladenMass'],
lbls: ['unladen', 'laden'],
unit: 'T',
fmt: 'fRound'
},
{ // 6
title: 'cargo',
props: ['cargoCapacity'],
unit: 'T',
fmt: 'fRound'
},
{ // 7
title: 'fuel',
props: ['fuelCapacity'],
unit: 'T',
fmt: 'fRound'
},
{ // 8
title: 'power',
props: ['powerRetracted', 'powerDeployed', 'powerAvailable'],
lbls: ['retracted', 'deployed', 'available'],
unit: 'MW',
fmt: 'fPwr'
},
{ // 9
title: 'cost',
props: ['totalCost'],
unit: 'CR',
fmt: 'fCrd'
},
{ // 10
title: 'total range',
props: ['unladenTotalRange', 'ladenTotalRange'],
lbls: ['unladen', 'laden'],
unit: 'LY',
fmt: 'fRound'
},
{ // 11
title: 'DPS',
props: ['totalDps'],
lbls: ['DPS'],
unit: '',
fmt: 'fRound'
}
];
/**
* Set of all available / theoretical discounts
*/
export const Discounts = {
'0%': 1,
'5%': 0.95,
'10%': 0.90,
'15%': 0.85,
'20%': 0.80,
'25%': 0.75
};

139
app/js/shipyard/ModuleSet.js Executable file
View File

@@ -0,0 +1,139 @@
function filter(arr, maxClass, minClass, mass) {
return arr.filter(m => m.class <= maxClass && m.class >= minClass && (m.maxmass === undefined || mass <= m.maxmass));
}
function filterToArray(data, maxClass, minClass, mass) {
let arr = [];
for (let id in data) {
let m = data[id];
if (m.class <= maxClass && m.class >= minClass && (m.maxmass === undefined || mass <= m.maxmass)) {
arr.push(m);
}
}
return arr;
}
export default class ModuleSet {
constructor(modules, mass, maxStandardArr, maxInternal, maxHardPoint) {
this.mass = mass;
this.standard = {};
this.internal = {};
this.hardpoints = {};
this.hpClass = {};
this.intClass = {};
this.standard[0] = filterToArray(modules.standard[0], maxStandardArr[0], 0, mass); // Power Plant
this.standard[2] = filterToArray(modules.standard[2], maxStandardArr[2], 0, mass); // FSD
this.standard[4] = filterToArray(modules.standard[4], maxStandardArr[4], 0, mass); // Power Distributor
this.standard[6] = filterToArray(modules.standard[6], maxStandardArr[6], 0, mass); // Fuel Tank
// Thrusters, filter modules by class only (to show full list of ratings for that class)
let ths = modules.standard[1];
let minThrusterClass = Object.keys(modules.standard[1]).reduce(
(clazz, thId) => (ths[thId].maxmass >= mass && ths[thId].class < clazz) ? ths[thId].class : clazz,
maxStandardArr[1]
);
this.standard[1] = filterToArray(modules.standard[1], maxStandardArr[1], minThrusterClass, 0); // Thrusters
// Slots where module class must be equal to slot class
this.standard[3] = filterToArray(modules.standard[3], maxStandardArr[3], maxStandardArr[3], 0); // Life Supprt
this.standard[5] = filterToArray(modules.standard[5], maxStandardArr[5], maxStandardArr[5], mass); // Sensors
for (let h in modules.hardpoints) {
this.hardpoints[h] = filter(modules.hardpoints[h], maxHardPoint, 0, mass);
}
for (let g in modules.internal) {
this.internal[g] = filter(modules.internal[g], maxInternal, 0, mass);
}
}
/**
* Determine the modules that areeligible for an internal slot
* @param {integer} c The max class module that can be mounted in the slot
* @param {Object} eligible) The map of eligible internal groups
* @return {object} A map of all eligible modules by group
*/
getInts(c, eligible) {
let o = {};
for (let key in this.internal) {
if (eligible && !eligible[key]) {
continue;
}
let data = filter(this.internal[key], c, 0, this.mass);
if (data.length) { // If group is not empty
o[key] = data;
}
}
return o;
}
/**
* Determining the modules that are eligible for an hardpoint slot
* @param {integer} c The max class module that can be mounted in the slot
* @param {Object} eligible) The map of eligible hardpoint groups
* @return {object} A map of all eligible modules by group
*/
getHps(c, eligible) {
var o = {};
for (var key in this.hardpoints) {
if (eligible && !eligible[key]) {
continue;
}
var data = filter(this.hardpoints[key], c, c ? 1 : 0, this.mass);
if (data.length) { // If group is not empty
o[key] = data;
}
}
return o;
}
lightestPowerDist(boostEnergy) {
var pd = this.standard[4][0];
for (let p of this.standard[4]) {
if (p.mass < pd.mass && p.enginecapacity >= boostEnergy) {
pd = p;
}
}
return pd.class + pd.rating;
};
lightestThruster(ladenMass) {
var th = this.standard[1][0];
for (t of this.standard[1]) {
if (t.mass < th.mass && t.maxmass >= ladenMass) {
th = t;
}
}
return th.class + th.rating;
};
lightestShieldGenerator(hullMass) {
var sg = this.internal.sg[0];
for (let s of this.internal.sg) {
if (s.mass < sg.mass && s.minmass <= hullMass && s.maxmass > hullMass) {
sg = s;
}
}
return sg.id;
};
lightestPowerPlant(powerUsed, rating) {
var pp = this.standard[0][0];
for (let p of this.standard[0]) {
if (p.mass < pp.mass && p.pGen >= powerUsed) {
pp = p;
}
}
return pp.class + (pp.rating != 'D' || rating == 'A' ? 'A' : 'D'); // Use A rated if C,E
}
}

175
app/js/shipyard/ModuleUtils.js Executable file
View File

@@ -0,0 +1,175 @@
import { ModuleNameToGroup, BulkheadNames } from 'Constants';
import ModuleSet from 'ModuleSet';
import { Ships, Modules } from 'coriolis-data';
export function cargoHatch() {
return { name: 'Cargo Hatch', class: 1, rating: 'H', power: 0.6 };
};
export function standard(typeIndex, componentId) {
return Modules.standard[typeIndex][componentId];
};
export function hardpoints(id) {
for (let n in Modules.hardpoints) {
let group = Modules.hardpoints[n];
for (let i = 0; i < group.length; i++) {
if (group[i].id == id) {
return group[i];
}
}
}
return null;
};
export function internal(id) {
for (let n in Modules.internal) {
let group = Modules.internal[n];
for (let i = 0; i < group.length; i++) {
if (group[i].id == id) {
return group[i];
}
}
}
return null;
};
/**
* Finds an internal Component based on Class, Rating, Group and/or name.
* At least one ofGroup name or unique component name must be provided
*
* @param {string} groupName [Optional] Full name or abbreviated name for component group
* @param {integer} clss Component Class
* @param {string} rating Component Rating
* @param {string} name [Optional] Long/unique name for component -e.g. 'Advanced Discover Scanner'
* @return {String} The id of the component if found, null if not found
*/
export function findInternal(groupName, clss, rating, name) {
let groups = {};
if (groupName) {
if (Modules.internal[groupName]) {
groups[groupName] = Modules.internal[groupName];
} else {
let grpCode = ModuleNameToGroup[groupName];
if (grpCode && Modules.internal[grpCode]) {
groups[grpCode] = Modules.internal[grpCode];
}
}
} else if (name) {
groups = Modules.internal;
}
for (let g in groups) {
let group = groups[g];
for (let i = 0, l = group.length; i < l; i++) {
if (group[i].class == clss && group[i].rating == rating && ((!name && !group[i].name) || group[i].name == name)) {
return group[i];
}
}
}
return null;
}
/**
* Finds an internal Component ID based on Class, Rating, Group and/or name.
* At least one ofGroup name or unique component name must be provided
*
* @param {string} groupName [Optional] Full name or abbreviated name for component group
* @param {integer} clss Component Class
* @param {string} rating Component Rating
* @param {string} name [Optional] Long/unique name for component -e.g. 'Advanced Discover Scanner'
* @return {String} The id of the component if found, null if not found
*/
export function findInternalId(groupName, clss, rating, name) {
let i = this.findInternal(groupName, clss, rating, name);
return i ? i.id : 0;
}
/**
* Finds a hardpoint Component based on Class, Rating, Group and/or name.
* At least one ofGroup name or unique component name must be provided
*
* @param {string} groupName [Optional] Full name or abbreviated name for component group
* @param {integer} clss Component Class
* @param {string} rating [Optional] Component Rating
* @param {string} name [Optional] Long/unique name for component -e.g. 'Heat Sink Launcher'
* @param {string} mount Mount type - [F]ixed, [G]imballed, [T]urret
* @param {string} missile [Optional] Missile type - [D]umbfire, [S]eeker
* @return {String} The id of the component if found, null if not found
*/
export function findHardpoint(groupName, clss, rating, name, mount, missile) {
let groups = {};
if (groupName) {
if (Modules.hardpoints[groupName]) {
groups[groupName] = Modules.hardpoints[groupName];
} else {
let grpCode = ModuleNameToGroup[groupName];
if (grpCode && Modules.hardpoints[grpCode]) {
groups[grpCode] = Modules.hardpoints[grpCode];
}
}
} else if (name) {
groups = Modules.hardpoints;
}
for (let g in groups) {
let group = groups[g];
for (let i = 0, l = group.length; i < l; i++) {
if (group[i].class == clss && (!rating || group[i].rating == rating) && group[i].mount == mount
&& ((!name && !group[i].name) || group[i].name == name)
&& ((!missile && !group[i].missile) || group[i].missile == missile)
) {
return group[i];
}
}
}
return null;
}
/**
* Finds a hardpoint Component ID based on Class, Rating, Group and/or name.
* At least one of Group name or unique component name must be provided
*
* @param {string} groupName [Optional] Full name or abbreviated name for component group
* @param {integer} clss Component Class
* @param {string} rating Component Rating
* @param {string} name [Optional] Long/unique name for component -e.g. 'Heat Sink Launcher'
* @param {string} mount Mount type - [F]ixed, [G]imballed, [T]urret
* @param {string} missile [Optional] Missile type - [D]umbfire, [S]eeker
* @return {String} The id of the component if found, null if not found
*/
export function findHardpointId(groupName, clss, rating, name, mount, missile) {
let h = this.findHardpoint(groupName, clss, rating, name, mount, missile);
return h ? h.id : 0;
}
/**
* Looks up the bulkhead component for a specific ship and bulkhead
* @param {string} shipId Unique ship Id/Key
* @param {number} bulkheadsId Id/Index for the specified bulkhead
* @return {object} The bulkhead component object
*/
export function bulkheads(shipId, bulkheadsId) {
return Modules.bulkheads[shipId][bulkheadsId];
}
export function bulkheadIndex(bulkheadName) {
return Bulkheads.indexOf(bulkheadName);
}
/**
* Creates a new ModuleSet that contains all available components
* that the specified ship is eligible to use.
*
* @param {string} shipId Unique ship Id/Key
* @return {ModuleSet} The set of components the ship can install
*/
export function forShip(shipId) {
let ship = Ships[shipId];
let maxInternal = isNaN(ship.slots.internal[0]) ? ship.slots.internal[0].class : ship.slots.internal[0];
return new ModuleSet(Modules, ship.minMassFilter || ship.properties.hullMass + 5, ship.slots.standard, maxInternal, ship.slots.hardpoints[0]);
}

View File

@@ -1,71 +1,74 @@
angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', 'calcJumpRange', 'calcTotalRange', 'calcSpeed', 'lodash', 'ArmourMultiplier', function(Components, calcShieldStrength, calcJumpRange, calcTotalRange, calcSpeed, _, ArmourMultiplier) { import { ArmourMultiplier } from 'Constants';
import Calc from 'Calculations';
import ModuleUtils from 'ModuleUtils';
/** const UNIQUE_MODULES = ['psg', 'sg', 'rf', 'fs'];
* Returns the power usage type of a slot and it's particular component
* @param {object} slot The Slot /**
* @param {object} component The component in the slot * Returns the power usage type of a slot and it's particular modul
* @return {string} The key for the power usage type * @param {object} slot The Slot
*/ * @param {object} modul The modul in the slot
function powerUsageType(slot, component) { * @return {string} The key for the power usage type
if (component) { */
if (component.passive) { function powerUsageType(slot, modul) {
return 'retracted'; if (modul) {
} if (modul.passive) {
return 'retracted';
} }
return slot.cat != 1 ? 'retracted' : 'deployed';
} }
return slot.cat != 1 ? 'retracted' : 'deployed';
}
/**
* Ship model used to track all ship ModuleUtils and properties.
*/
export default class Ship {
/** /**
* Ship model used to track all ship components and properties.
*
* @param {string} id Unique ship Id / Key * @param {string} id Unique ship Id / Key
* @param {object} properties Basic ship properties such as name, manufacturer, mass, etc * @param {object} properties Basic ship properties such as name, manufacturer, mass, etc
* @param {object} slots Collection of slot groups (standard/standard, internal, hardpoints) with their max class size. * @param {object} slots Collection of slot groups (standard/standard, internal, hardpoints) with their max class size.
*/ */
function Ship(id, properties, slots) { constructor(id, properties, slots) {
this.id = id; this.id = id;
this.cargoHatch = { c: Components.cargoHatch(), type: 'SYS' }; this.cargoHatch = { m: ModuleUtils.cargoHatch(), type: 'SYS' };
this.bulkheads = { incCost: true, maxClass: 8 }; this.bulkheads = { incCost: true, maxClass: 8 };
this.availCS = Components.forShip(id); this.availCS = ModuleUtils.forShip(id);
for (var p in properties) { this[p] = properties[p]; } // Copy all base properties from shipData for (var p in properties) { this[p] = properties[p]; } // Copy all base properties from shipData
for (var slotType in slots) { // Initialize all slots for (var slotType in slots) { // Initialize all slots
var slotGroup = slots[slotType]; var slotGroup = slots[slotType];
var group = this[slotType] = []; // Initialize Slot group (Standard, Hardpoints, Internal) var group = this[slotType] = []; // Initialize Slot group (Standard, Hardpoints, Internal)
for (var i = 0; i < slotGroup.length; i++) { for (let slot of slotGroup) {
if (typeof slotGroup[i] == 'object') { if (typeof slot == 'object') {
group.push({ id: null, c: null, incCost: true, maxClass: slotGroup[i].class, eligible: slotGroup[i].eligible }); group.push({ id: null, m: null, incCost: true, maxClass: slot.class, eligible: slot.eligible });
} else { } else {
group.push({ id: null, c: null, incCost: true, maxClass: slotGroup[i] }); group.push({ id: null, m: null, incCost: true, maxClass: slot });
} }
} }
} }
// Make a Ship 'slot'/item similar to other slots // Make a Ship 'slot'/item similar to other slots
this.c = { incCost: true, type: 'SHIP', discountedCost: this.hullCost, c: { name: this.name, cost: this.hullCost } }; this.m = { incCost: true, type: 'SHIP', discountedCost: this.hullCost, m: { name: this.name, cost: this.hullCost } };
this.costList = this.internal.concat(this.m, this.standard, this.hardpoints, this.bulkheads);
this.costList = _.union(this.internal, this.standard, this.hardpoints); this.powerList = this.internal.concat(
this.costList.push(this.bulkheads); // Add The bulkheads this.cargoHatch,
this.costList.unshift(this.c); // Add the ship itself to the list this.standard[0], // Add Power Plant
this.standard[2], // Add FSD
this.powerList = _.union(this.internal, this.hardpoints); this.standard[1], // Add Thrusters
this.powerList.unshift(this.cargoHatch); this.standard[4], // Add Power Distributor
this.powerList.unshift(this.standard[1]); // Add Thrusters this.standard[5], // Add Sensors
this.powerList.unshift(this.standard[5]); // Add Sensors this.standard[3], // Add Life Support
this.powerList.unshift(this.standard[4]); // Add Power Distributor this.hardpoints
this.powerList.unshift(this.standard[3]); // Add Life Support ];
this.powerList.unshift(this.standard[2]); // Add FSD
this.powerList.unshift(this.standard[0]); // Add Power Plant
this.shipCostMultiplier = 1; this.shipCostMultiplier = 1;
this.componentCostMultiplier = 1; this.modulCostMultiplier = 1;
this.priorityBands = [ this.priorityBands = [
{ deployed: 0, retracted: 0, retOnly: 0 }, { deployed: 0, retracted: 0, },
{ deployed: 0, retracted: 0, retOnly: 0 }, { deployed: 0, retracted: 0, },
{ deployed: 0, retracted: 0, retOnly: 0 }, { deployed: 0, retracted: 0, },
{ deployed: 0, retracted: 0, retOnly: 0 }, { deployed: 0, retracted: 0, },
{ deployed: 0, retracted: 0, retOnly: 0 } { deployed: 0, retracted: 0, }
]; ];
} }
@@ -73,58 +76,49 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
// GETTERS // // GETTERS //
//*********// //*********//
Ship.prototype.getAvailableComponents = function() { getAvailableModules() {
return this.availCS; return this.availCS;
}; }
Ship.prototype.getSlotStatus = function(slot, deployed) { getSlotStatus(slot, deployed) {
if (!slot.c) { // Empty Slot if (!slot.m) { // Empty Slot
return 0; // No Status (Not possible to be active in this state) return 0; // No Status (Not possible to be active in this state)
} else if (!slot.enabled) { } else if (!slot.enabled) {
return 1; // Disabled return 1; // Disabled
} else if (deployed) { } else if (deployed) {
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 // Active hardpoints have no retracted status
} else if ((slot.cat === 1 && !slot.c.passive)) { } else if ((slot.cat === 1 && !slot.m.passive)) {
return 0; // No Status (Not possible to be active in this state) return 0; // No Status (Not possible to be active in this state)
} }
return this.priorityBands[slot.priority].retractedSum >= this.powerAvailable ? 2 : 3; // Offline : Online return this.priorityBands[slot.priority].retractedSum >= this.powerAvailable ? 2 : 3; // Offline : Online
}; }
/** /**
* Calculate jump range using the installed FSD and the * Calculate jump range using the installed FSD and the
* specified mass which can be more or less than ships actual mass * specified mass which can be more or less than ships actual mass
* @param {number} mass Mass in tons * @param {number} mass Mass in tons
* @param {number} fuel Fuel available in tons * @param {number} fuel Fuel available in tons
* @return {number} Jump range in Light Years * @return {number} Jump range in Light Years
*/ */
Ship.prototype.getJumpRangeForMass = function(mass, fuel) { getJumpRangeForMass(mass, fuel) {
return calcJumpRange(mass, this.standard[2].c, fuel); return Calc.jumpRange(mass, this.standard[2].m, fuel);
}; }
/** /**
* Find an internal slot that has an installed component of the specific group. * Find an internal slot that has an installed modul of the specific group.
* *
* @param {string} group Component group/type * @param {string} group Module group/type
* @return {number} The index of the slot in ship.internal * @return {number} The index of the slot in ship.internal
*/ */
Ship.prototype.findInternalByGroup = function(group) { findInternalByGroup(group) {
var index; var index;
if (group == 'sg' || group == 'psg') { if (group == 'sg' || group == 'psg') {
index = _.findIndex(this.internal, function(slot) { return this.internal.find(slot => slot.m && (slot.m.grp == 'sg' || slot.m.grp == 'psg');
return slot.c && (slot.c.grp == 'sg' || slot.c.grp == 'psg');
});
} else { } else {
index = _.findIndex(this.internal, function(slot) { return this.internal.find(slot => slot.m && slot.m.grp == group);
return slot.c && slot.c.grp == group;
});
} }
}
if (index !== -1) {
return this.internal[index];
}
return null;
};
//**********************// //**********************//
// Mutate / Update Ship // // Mutate / Update Ship //
@@ -133,32 +127,32 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
/** /**
* Recalculate all item costs and total based on discounts. * Recalculate all item costs and total based on discounts.
* @param {number} shipCostMultiplier Ship cost multiplier discount (e.g. 0.9 === 10% discount) * @param {number} shipCostMultiplier Ship cost multiplier discount (e.g. 0.9 === 10% discount)
* @param {number} componentCostMultiplier Component cost multiplier discount (e.g. 0.75 === 25% discount) * @param {number} modulCostMultiplier Module cost multiplier discount (e.g. 0.75 === 25% discount)
*/ */
Ship.prototype.applyDiscounts = function(shipCostMultiplier, componentCostMultiplier) { applyDiscounts(shipCostMultiplier, modulCostMultiplier) {
var total = 0; var total = 0;
var costList = this.costList; var costList = this.costList;
for (var i = 0, l = costList.length; i < l; i++) { for (var i = 0, l = costList.length; i < l; i++) {
var item = costList[i]; var item = costList[i];
if (item.c && item.c.cost) { if (item.m && item.m.cost) {
item.discountedCost = item.c.cost * (item.type == 'SHIP' ? shipCostMultiplier : componentCostMultiplier); item.discountedCost = item.m.cost * (item.type == 'SHIP' ? shipCostMultiplier : modulCostMultiplier);
if (item.incCost) { if (item.incCost) {
total += item.discountedCost; total += item.discountedCost;
} }
} }
} }
this.shipCostMultiplier = shipCostMultiplier; this.shipCostMultiplier = shipCostMultiplier;
this.componentCostMultiplier = componentCostMultiplier; this.modulCostMultiplier = modulCostMultiplier;
this.totalCost = total; this.totalCost = total;
return this; return this;
}; }
/** /**
* Builds/Updates the ship instance with the components[comps] passed in. * Builds/Updates the ship instance with the ModuleUtils[comps] passed in.
* @param {object} comps Collection of components used to build the ship * @param {object} comps Collection of ModuleUtils used to build the ship
*/ */
Ship.prototype.buildWith = function(comps, priorities, enabled) { buildWith(comps, priorities, enabled) {
var internal = this.internal, var internal = this.internal,
standard = this.standard, standard = this.standard,
hps = this.hardpoints, hps = this.hardpoints,
@@ -173,11 +167,11 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
this.armourAdded = 0; this.armourAdded = 0;
this.armourMultiplier = 1; this.armourMultiplier = 1;
this.shieldMultiplier = 1; this.shieldMultiplier = 1;
this.totalCost = this.c.incCost ? this.c.discountedCost : 0; this.totalCost = this.m.incCost ? this.m.discountedCost : 0;
this.unladenMass = this.hullMass; this.unladenMass = this.hullMass;
this.totalDps = 0; this.totalDps = 0;
this.bulkheads.c = null; this.bulkheads.m = null;
this.useBulkhead(comps && comps.bulkheads ? comps.bulkheads : 0, true); this.useBulkhead(comps && comps.bulkheads ? comps.bulkheads : 0, true);
this.cargoHatch.priority = priorities ? priorities[0] * 1 : 0; this.cargoHatch.priority = priorities ? priorities[0] * 1 : 0;
this.cargoHatch.enabled = enabled ? enabled[0] * 1 : true; this.cargoHatch.enabled = enabled ? enabled[0] * 1 : true;
@@ -185,11 +179,10 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
for (i = 0, l = this.priorityBands.length; i < l; i++) { for (i = 0, l = this.priorityBands.length; i < l; i++) {
this.priorityBands[i].deployed = 0; this.priorityBands[i].deployed = 0;
this.priorityBands[i].retracted = 0; this.priorityBands[i].retracted = 0;
this.priorityBands[i].retOnly = 0;
} }
if (this.cargoHatch.enabled) { if (this.cargoHatch.enabled) {
bands[this.cargoHatch.priority].retracted += this.cargoHatch.c.power; bands[this.cargoHatch.priority].retracted += this.cargoHatch.m.power;
} }
for (i = 0; i < cl; i++) { for (i = 0; i < cl; i++) {
@@ -197,11 +190,11 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
standard[i].enabled = enabled ? enabled[i + 1] * 1 : true; standard[i].enabled = enabled ? enabled[i + 1] * 1 : true;
standard[i].priority = priorities && priorities[i + 1] ? priorities[i + 1] * 1 : 0; standard[i].priority = priorities && priorities[i + 1] ? priorities[i + 1] * 1 : 0;
standard[i].type = 'SYS'; standard[i].type = 'SYS';
standard[i].c = standard[i].id = null; // Resetting 'old' component if there was one standard[i].m = standard[i].id = null; // Resetting 'old' modul if there was one
standard[i].discountedCost = 0; standard[i].discountedCost = 0;
if (comps) { if (comps) {
this.use(standard[i], comps.standard[i], Components.standard(i, comps.standard[i]), true); this.use(standard[i], comps.standard[i], ModuleUtils.standard(i, comps.standard[i]), true);
} }
} }
@@ -214,11 +207,11 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
hps[i].enabled = enabled ? enabled[cl + i] * 1 : true; hps[i].enabled = enabled ? enabled[cl + i] * 1 : true;
hps[i].priority = priorities && priorities[cl + i] ? priorities[cl + i] * 1 : 0; hps[i].priority = priorities && priorities[cl + i] ? priorities[cl + i] * 1 : 0;
hps[i].type = hps[i].maxClass ? 'WEP' : 'SYS'; hps[i].type = hps[i].maxClass ? 'WEP' : 'SYS';
hps[i].c = hps[i].id = null; // Resetting 'old' component if there was one hps[i].m = hps[i].id = null; // Resetting 'old' modul if there was one
hps[i].discountedCost = 0; hps[i].discountedCost = 0;
if (comps && comps.hardpoints[i] !== 0) { if (comps && comps.hardpoints[i] !== 0) {
this.use(hps[i], comps.hardpoints[i], Components.hardpoints(comps.hardpoints[i]), true); this.use(hps[i], comps.hardpoints[i], ModuleUtils.hardpoints(comps.hardpoints[i]), true);
} }
} }
@@ -229,11 +222,11 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
internal[i].enabled = enabled ? enabled[cl + i] * 1 : true; internal[i].enabled = enabled ? enabled[cl + i] * 1 : true;
internal[i].priority = priorities && priorities[cl + i] ? priorities[cl + i] * 1 : 0; internal[i].priority = priorities && priorities[cl + i] ? priorities[cl + i] * 1 : 0;
internal[i].type = 'SYS'; internal[i].type = 'SYS';
internal[i].id = internal[i].c = null; // Resetting 'old' component if there was one internal[i].id = internal[i].m = null; // Resetting 'old' modul if there was one
internal[i].discountedCost = 0; internal[i].discountedCost = 0;
if (comps && comps.internal[i] !== 0) { if (comps && comps.internal[i] !== 0) {
this.use(internal[i], comps.internal[i], Components.internal(comps.internal[i]), true); this.use(internal[i], comps.internal[i], ModuleUtils.internal(comps.internal[i]), true);
} }
} }
@@ -246,85 +239,85 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
} }
return this; return this;
}; }
Ship.prototype.emptyHardpoints = function() { emptyHardpoints() {
for (var i = this.hardpoints.length; i--; ) { for (var i = this.hardpoints.length; i--; ) {
this.use(this.hardpoints[i], null, null); this.use(this.hardpoints[i], null, null);
} }
return this; return this;
}; }
Ship.prototype.emptyInternal = function() { emptyInternal() {
for (var i = this.internal.length; i--; ) { for (var i = this.internal.length; i--; ) {
this.use(this.internal[i], null, null); this.use(this.internal[i], null, null);
} }
return this; return this;
}; }
Ship.prototype.emptyUtility = function() { emptyUtility() {
for (var i = this.hardpoints.length; i--; ) { for (var i = this.hardpoints.length; i--; ) {
if (!this.hardpoints[i].maxClass) { if (!this.hardpoints[i].maxClass) {
this.use(this.hardpoints[i], null, null); this.use(this.hardpoints[i], null, null);
} }
} }
return this; return this;
}; }
Ship.prototype.emptyWeapons = function() { emptyWeapons() {
for (var i = this.hardpoints.length; i--; ) { for (var i = this.hardpoints.length; i--; ) {
if (this.hardpoints[i].maxClass) { if (this.hardpoints[i].maxClass) {
this.use(this.hardpoints[i], null, null); this.use(this.hardpoints[i], null, null);
} }
} }
return this; return this;
}; }
/** /**
* Optimize for the lower mass build that can still boost and power the ship * Optimize for the lower mass build that can still boost and power the ship
* without power management. * without power management.
* @param {object} c Standard Component overrides * @param {object} m Standard Module overrides
*/ */
Ship.prototype.optimizeMass = function(c) { optimizeMass(m) {
return this.emptyHardpoints().emptyInternal().useLightestStandard(c); return this.emptyHardpoints().emptyInternal().useLightestStandard(m);
}; }
Ship.prototype.setCostIncluded = function(item, included) { setCostIncluded(item, included) {
if (item.incCost != included && item.c) { if (item.incCost != included && item.m) {
this.totalCost += included ? item.discountedCost : -item.discountedCost; this.totalCost += included ? item.discountedCost : -item.discountedCost;
} }
item.incCost = included; item.incCost = included;
return this; return this;
}; }
Ship.prototype.setSlotEnabled = function(slot, enabled) { setSlotEnabled(slot, enabled) {
if (slot.enabled != enabled) { // Enabled state is changing if (slot.enabled != enabled) { // Enabled state is changing
slot.enabled = enabled; slot.enabled = enabled;
if (slot.c) { if (slot.m) {
this.priorityBands[slot.priority][powerUsageType(slot, slot.c)] += enabled ? slot.c.power : -slot.c.power; this.priorityBands[slot.priority][powerUsageType(slot, slot.m)] += enabled ? slot.m.power : -slot.m.power;
if (slot.c.grp == 'sg' || slot.c.grp == 'psg') { if (slot.m.grp == 'sg' || slot.m.grp == 'psg') {
this.updateShieldStrength(); this.updateShieldStrength();
} else if (slot.c.grp == 'sb') { } else if (slot.m.grp == 'sb') {
this.shieldMultiplier += slot.c.shieldmul * (enabled ? 1 : -1); this.shieldMultiplier += slot.m.shieldmul * (enabled ? 1 : -1);
this.updateShieldStrength(); this.updateShieldStrength();
} else if (slot.c.dps) { } else if (slot.m.dps) {
this.totalDps += slot.c.dps * (enabled ? 1 : -1); this.totalDps += slot.m.dps * (enabled ? 1 : -1);
} }
this.updatePower(); this.updatePower();
} }
} }
return this; return this;
}; }
/** /**
* Updates the ship's cumulative and aggregated stats based on the component change. * Updates the ship's cumulative and aggregated stats based on the modul change.
*/ */
Ship.prototype.updateStats = function(slot, n, old, preventUpdate) { updateStats(slot, n, old, preventUpdate) {
var powerChange = slot == this.standard[0]; var powerChange = slot == this.standard[0];
if (old) { // Old component now being removed if (old) { // Old modul now being removed
switch (old.grp) { switch (old.grp) {
case 'ft': case 'ft':
this.fuelCapacity -= old.capacity; this.fuelCapacity -= old.capacity;
@@ -341,7 +334,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
} }
if (slot.incCost && old.cost) { if (slot.incCost && old.cost) {
this.totalCost -= old.cost * this.componentCostMultiplier; this.totalCost -= old.cost * this.modulCostMultiplier;
} }
if (old.power && slot.enabled) { if (old.power && slot.enabled) {
@@ -372,7 +365,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
} }
if (slot.incCost && n.cost) { if (slot.incCost && n.cost) {
this.totalCost += n.cost * this.componentCostMultiplier; this.totalCost += n.cost * this.modulCostMultiplier;
} }
if (n.power && slot.enabled) { if (n.power && slot.enabled) {
@@ -398,82 +391,82 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
this.updateShieldStrength(); this.updateShieldStrength();
} }
return this; return this;
}; }
Ship.prototype.updatePower = function() { updatePower() {
var bands = this.priorityBands; var bands = this.priorityBands;
var prevRetracted = 0, prevDeployed = 0; var prevRetracted = 0, prevDeployed = 0;
for (var i = 0, l = bands.length; i < l; i++) { for (var i = 0, l = bands.length; i < l; i++) {
var band = bands[i]; var band = bands[i];
prevRetracted = band.retractedSum = prevRetracted + band.retracted + band.retOnly; prevRetracted = band.retractedSum = prevRetracted + band.retracted;
prevDeployed = band.deployedSum = prevDeployed + band.deployed + band.retracted; prevDeployed = band.deployedSum = prevDeployed + band.deployed + band.retracted;
} }
this.powerAvailable = this.standard[0].c.pGen; this.powerAvailable = this.standard[0].m.pGen;
this.powerRetracted = prevRetracted; this.powerRetracted = prevRetracted;
this.powerDeployed = prevDeployed; this.powerDeployed = prevDeployed;
return this; return this;
}; };
Ship.prototype.updateTopSpeed = function() { updateTopSpeed() {
var speeds = calcSpeed(this.unladenMass + this.fuelCapacity, this.speed, this.boost, this.standard[1].c, this.pipSpeed); var speeds = Calc.speed(this.unladenMass + this.fuelCapacity, this.speed, this.boost, this.standard[1].m, this.pipSpeed);
this.topSpeed = speeds['4 Pips']; this.topSpeed = speeds['4 Pips'];
this.topBoost = speeds.boost; this.topBoost = speeds.boost;
return this; return this;
}; }
Ship.prototype.updateShieldStrength = function() { updateShieldStrength() {
var sgSlot = this.findInternalByGroup('sg'); // Find Shield Generator slot Index if any var sgSlot = this.findInternalByGroup('sg'); // Find Shield Generator slot Index if any
this.shieldStrength = sgSlot && sgSlot.enabled ? calcShieldStrength(this.hullMass, this.baseShieldStrength, sgSlot.c, this.shieldMultiplier) : 0; this.shieldStrength = sgSlot && sgSlot.enabled ? Calc.shieldStrength(this.hullMass, this.baseShieldStrength, sgSlot.m, this.shieldMultiplier) : 0;
return this; return this;
}; }
/** /**
* Jump Range and total range calculations * Jump Range and total range calculations
*/ */
Ship.prototype.updateJumpStats = function() { updateJumpStats() {
var fsd = this.standard[2].c; // Frame Shift Drive; var fsd = this.standard[2].m; // Frame Shift Drive;
this.unladenRange = calcJumpRange(this.unladenMass + fsd.maxfuel, fsd, this.fuelCapacity); // Include fuel weight for jump this.unladenRange = Calc.jumpRange(this.unladenMass + fsd.maxfuel, fsd, this.fuelCapacity); // Include fuel weight for jump
this.fullTankRange = calcJumpRange(this.unladenMass + this.fuelCapacity, fsd, this.fuelCapacity); // Full Tanke this.fullTankRange = Calc.jumpRange(this.unladenMass + this.fuelCapacity, fsd, this.fuelCapacity); // Full Tanke
this.ladenRange = calcJumpRange(this.ladenMass, fsd, this.fuelCapacity); this.ladenRange = Calc.jumpRange(this.ladenMass, fsd, this.fuelCapacity);
this.unladenTotalRange = calcTotalRange(this.unladenMass, fsd, this.fuelCapacity); this.unladenTotalRange = Calc.totalRange(this.unladenMass, fsd, this.fuelCapacity);
this.ladenTotalRange = calcTotalRange(this.unladenMass + this.cargoCapacity, fsd, this.fuelCapacity); this.ladenTotalRange = Calc.totalRange(this.unladenMass + this.cargoCapacity, fsd, this.fuelCapacity);
this.maxJumpCount = Math.ceil(this.fuelCapacity / fsd.maxfuel); this.maxJumpCount = Math.ceil(this.fuelCapacity / fsd.maxfuel);
return this; return this;
}; }
/** /**
* Update a slot with a the component if the id is different from the current id for this slot. * Update a slot with a the modul if the id is different from the current id for this slot.
* Has logic handling components that you may only have 1 of (Shield Generator or Refinery). * Has logic handling ModuleUtils that you may only have 1 of (Shield Generator or Refinery).
* *
* @param {object} slot The component slot * @param {object} slot The modul slot
* @param {string} id Unique ID for the selected component * @param {string} id Unique ID for the selected module
* @param {object} component Properties for the selected component * @param {object} modul Properties for the selected module
* @param {boolean} preventUpdate If true, do not update aggregated stats * @param {boolean} preventUpdate If true, do not update aggregated stats
*/ */
Ship.prototype.use = function(slot, id, component, preventUpdate) { use(slot, id, modul, preventUpdate) {
if (slot.id != id) { // Selecting a different component if (slot.id != id) { // Selecting a different modul
// Slot is an internal slot, is not being emptied, and the selected component group/type must be of unique // Slot is an internal slot, is not being emptied, and the selected modul group/type must be of unique
if (slot.cat == 2 && component && _.includes(['psg', 'sg', 'rf', 'fs'], component.grp)) { if (slot.cat == 2 && modul && UNIQUE_MODULES.includes(modul.grp)) {
// Find another internal slot that already has this type/group installed // Find another internal slot that already has this type/group installed
var similarSlot = this.findInternalByGroup(component.grp); var similarSlot = this.findInternalByGroup(modul.grp);
// If another slot has an installed component with of the same type // If another slot has an installed modul with of the same type
if (!preventUpdate && similarSlot && similarSlot !== slot) { if (!preventUpdate && similarSlot && similarSlot !== slot) {
this.updateStats(similarSlot, null, similarSlot.c); this.updateStats(similarSlot, null, similarSlot.m);
similarSlot.id = similarSlot.c = null; // Empty the slot similarSlot.id = similarSlot.m = null; // Empty the slot
similarSlot.discountedCost = 0; similarSlot.discountedCost = 0;
} }
} }
var oldComponent = slot.c; var oldModule = slot.m;
slot.id = id; slot.id = id;
slot.c = component; slot.m = modul;
slot.discountedCost = (component && component.cost) ? component.cost * this.componentCostMultiplier : 0; slot.discountedCost = (modul && modul.cost) ? modul.cost * this.modulCostMultiplier : 0;
this.updateStats(slot, component, oldComponent, preventUpdate); this.updateStats(slot, modul, oldModule, preventUpdate);
} }
return this; return this;
}; }
/** /**
* [useBulkhead description] * [useBulkhead description]
@@ -481,98 +474,98 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
* @param {[type]} preventUpdate [description] * @param {[type]} preventUpdate [description]
* @return {[type]} [description] * @return {[type]} [description]
*/ */
Ship.prototype.useBulkhead = function(index, preventUpdate) { useBulkhead(index, preventUpdate) {
var oldBulkhead = this.bulkheads.c; var oldBulkhead = this.bulkheads.m;
this.bulkheads.id = index; this.bulkheads.id = index;
this.bulkheads.c = Components.bulkheads(this.id, index); this.bulkheads.m = ModuleUtils.bulkheads(this.id, index);
this.bulkheads.discountedCost = this.bulkheads.c.cost * this.componentCostMultiplier; this.bulkheads.discountedCost = this.bulkheads.m.cost * this.modulCostMultiplier;
this.armourMultiplier = ArmourMultiplier[index]; this.armourMultiplier = ArmourMultiplier[index];
this.updateStats(this.bulkheads, this.bulkheads.c, oldBulkhead, preventUpdate); this.updateStats(this.bulkheads, this.bulkheads.m, oldBulkhead, preventUpdate);
return this; return this;
}; }
/** /**
* [useStandard description] * [useStandard description]
* @param {[type]} rating [description] * @param {[type]} rating [description]
* @return {[type]} [description] * @return {[type]} [description]
*/ */
Ship.prototype.useStandard = function(rating) { useStandard(rating) {
for (var i = this.standard.length - 1; i--; ) { // All except Fuel Tank for (var i = this.standard.length - 1; i--; ) { // All except Fuel Tank
var id = this.standard[i].maxClass + rating; var id = this.standard[i].maxClass + rating;
this.use(this.standard[i], id, Components.standard(i, id)); this.use(this.standard[i], id, ModuleUtils.standard(i, id));
} }
return this; return this;
}; }
/** /**
* Use the lightest standard components unless otherwise specified * Use the lightest standard ModuleUtils unless otherwise specified
* @param {object} c Component overrides * @param {object} m Module overrides
*/ */
Ship.prototype.useLightestStandard = function(c) { useLightestStandard(m) {
c = c || {}; m = m || {};
var standard = this.standard, var standard = this.standard,
pd = c.pd || this.availCS.lightestPowerDist(this.boostEnergy), // Find lightest Power Distributor that can still boost; pd = m.pd || this.availCS.lightestPowerDist(this.boostEnergy), // Find lightest Power Distributor that can still boost;
fsd = c.fsd || standard[2].maxClass + 'A', fsd = m.fsd || standard[2].maxClass + 'A',
ls = c.ls || standard[3].maxClass + 'D', ls = m.ls || standard[3].maxClass + 'D',
s = c.s || standard[5].maxClass + 'D', s = m.s || standard[5].maxClass + 'D',
updated; updated;
this.useBulkhead(0) this.useBulkhead(0)
.use(standard[2], fsd, Components.standard(2, fsd)) // FSD .use(standard[2], fsd, ModuleUtils.standard(2, fsd)) // FSD
.use(standard[3], ls, Components.standard(3, ls)) // Life Support .use(standard[3], ls, ModuleUtils.standard(3, ls)) // Life Support
.use(standard[5], s, Components.standard(5, s)) // Sensors .use(standard[5], s, ModuleUtils.standard(5, s)) // Sensors
.use(standard[4], pd, Components.standard(4, pd)); // Power Distributor .use(standard[4], pd, ModuleUtils.standard(4, pd)); // Power Distributor
// Thrusters and Powerplant must be determined after all other components are mounted // Thrusters and Powerplant must be determined after all other ModuleUtils are mounted
// Loop at least once to determine absolute lightest PD and TH // Loop at least once to determine absolute lightest PD and TH
do { do {
updated = false; updated = false;
// Find lightest Thruster that still works for the ship at max mass // Find lightest Thruster that still works for the ship at max mass
var th = c.th || this.availCS.lightestThruster(this.ladenMass); var th = m.th || this.availCS.lightestThruster(this.ladenMass);
if (th != standard[1].id) { if (th != standard[1].id) {
this.use(standard[1], th, Components.standard(1, th)); this.use(standard[1], th, ModuleUtils.standard(1, th));
updated = true; updated = true;
} }
// Find lightest Power plant that can power the ship // Find lightest Power plant that can power the ship
var pp = c.pp || this.availCS.lightestPowerPlant(Math.max(this.powerRetracted, this.powerDeployed), c.ppRating); var pp = m.pp || this.availCS.lightestPowerPlant(Math.max(this.powerRetracted, this.powerDeployed), m.ppRating);
if (pp != standard[0].id) { if (pp != standard[0].id) {
this.use(standard[0], pp, Components.standard(0, pp)); this.use(standard[0], pp, ModuleUtils.standard(0, pp));
updated = true; updated = true;
} }
} while (updated); } while (updated);
return this; return this;
}; }
Ship.prototype.useUtility = function(group, rating, clobber) { useUtility(group, rating, clobber) {
var component = Components.findHardpoint(group, 0, rating); var modul = ModuleUtils.findHardpoint(group, 0, rating);
for (var i = this.hardpoints.length; i--; ) { for (var i = this.hardpoints.length; i--; ) {
if ((clobber || !this.hardpoints[i].c) && !this.hardpoints[i].maxClass) { if ((clobber || !this.hardpoints[i].m) && !this.hardpoints[i].maxClass) {
this.use(this.hardpoints[i], component.id, component); this.use(this.hardpoints[i], modul.id, modul);
} }
} }
return this; return this;
}; }
Ship.prototype.useWeapon = function(group, mount, clobber, missile) { useWeapon(group, mount, clobber, missile) {
var hps = this.hardpoints; var hps = this.hardpoints;
for (var i = hps.length; i--; ) { for (var i = hps.length; i--; ) {
if (hps[i].maxClass) { if (hps[i].maxClass) {
var size = hps[i].maxClass, component; var size = hps[i].maxClass, modul;
do { do {
component = Components.findHardpoint(group, size, null, null, mount, missile); modul = ModuleUtils.findHardpoint(group, size, null, null, mount, missile);
if ((clobber || !hps[i].c) && component) { if ((clobber || !hps[i].m) && modul) {
this.use(hps[i], component.id, component); this.use(hps[i], modul.id, modul);
break; break;
} }
} while (!component && (--size > 0)); } while (!modul && (--size > 0));
} }
} }
return this; return this;
}; }
/** /**
* Will change the priority of the specified slot if the new priority is valid * Will change the priority of the specified slot if the new priority is valid
@@ -580,21 +573,19 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
* @param {number} newPriority The new priority to be set * @param {number} newPriority The new priority to be set
* @return {boolean} Returns true if the priority was changed (within range) * @return {boolean} Returns true if the priority was changed (within range)
*/ */
Ship.prototype.changePriority = function(slot, newPriority) { changePriority(slot, newPriority) {
if (newPriority >= 0 && newPriority < this.priorityBands.length) { if (newPriority >= 0 && newPriority < this.priorityBands.length) {
var oldPriority = slot.priority; var oldPriority = slot.priority;
slot.priority = newPriority; slot.priority = newPriority;
if (slot.enabled) { // Only update power if the slot is enabled if (slot.enabled) { // Only update power if the slot is enabled
var usage = powerUsageType(slot, slot.c); var usage = powerUsageType(slot, slot.m);
this.priorityBands[oldPriority][usage] -= slot.c.power; this.priorityBands[oldPriority][usage] -= slot.m.power;
this.priorityBands[newPriority][usage] += slot.c.power; this.priorityBands[newPriority][usage] += slot.m.power;
this.updatePower(); this.updatePower();
} }
return true; return true;
} }
return false; return false;
}; }
}
return Ship;
}]);

View File

@@ -1,145 +0,0 @@
angular.module('shipyard').factory('ComponentSet', ['lodash', function(_) {
function filter(data, maxClass, minClass, mass) {
return _.filter(data, function(c) {
return c.class <= maxClass && c.class >= minClass && (c.maxmass === undefined || mass <= c.maxmass);
});
}
function getKey(maxClass, eligible) {
if (eligible) {
return maxClass + Object.keys(eligible).join('-');
}
return maxClass;
}
function ComponentSet(components, mass, maxStandardArr, maxInternal, maxHardPoint) {
this.mass = mass;
this.standard = {};
this.internal = {};
this.hardpoints = {};
this.hpClass = {};
this.intClass = {};
this.standard[0] = filter(components.standard[0], maxStandardArr[0], 0, mass); // Power Plant
this.standard[2] = filter(components.standard[2], maxStandardArr[2], 0, mass); // FSD
this.standard[4] = filter(components.standard[4], maxStandardArr[4], 0, mass); // Power Distributor
this.standard[6] = filter(components.standard[6], maxStandardArr[6], 0, mass); // Fuel Tank
// Thrusters, filter components by class only (to show full list of ratings for that class)
var minThrusterClass = _.reduce(components.standard[1], function(minClass, thruster) {
return (thruster.maxmass >= mass && thruster.class < minClass) ? thruster.class : minClass;
}, maxStandardArr[1]);
this.standard[1] = filter(components.standard[1], maxStandardArr[1], minThrusterClass, 0); // Thrusters
// Slots where component class must be equal to slot class
this.standard[3] = filter(components.standard[3], maxStandardArr[3], maxStandardArr[3], 0); // Life Supprt
this.standard[5] = filter(components.standard[5], maxStandardArr[5], maxStandardArr[5], mass); // Sensors
for (var h in components.hardpoints) {
this.hardpoints[h] = filter(components.hardpoints[h], maxHardPoint, 0, mass);
}
for (var g in components.internal) {
this.internal[g] = filter(components.internal[g], maxInternal, 0, mass);
}
/**
* Create a memoized function for determining the components that are
* eligible for an internal slot
* @param {integer} c The max class component that can be mounted in the slot
* @param {Object} eligible) The map of eligible internal groups
* @return {object} A map of all eligible components by group
*/
this.getInts = _.memoize(
function(c, eligible) {
var o = {};
for (var key in this.internal) {
if (eligible && !eligible[key]) {
continue;
}
var data = filter(this.internal[key], c, 0, this.mass);
if (data.length) { // If group is not empty
o[key] = data;
}
}
return o;
},
getKey
);
/**
* Create a memoized function for determining the components that are
* eligible for an hardpoint slot
* @param {integer} c The max class component that can be mounted in the slot
* @param {Object} eligible) The map of eligible hardpoint groups
* @return {object} A map of all eligible components by group
*/
this.getHps = _.memoize(
function(c, eligible) {
var o = {};
for (var key in this.hardpoints) {
if (eligible && !eligible[key]) {
continue;
}
var data = filter(this.hardpoints[key], c, c ? 1 : 0, this.mass);
if (data.length) { // If group is not empty
o[key] = data;
}
}
return o;
},
getKey
);
}
ComponentSet.prototype.lightestPowerDist = function(boostEnergy) {
var pds = this.standard[4];
var pd = pds[0];
for (var i = 1; i < pds.length; i++) {
if (pds[i].mass < pd.mass && pds[i].enginecapacity >= boostEnergy) {
pd = pds[i];
}
}
return pd.class + pd.rating;
};
ComponentSet.prototype.lightestThruster = function(ladenMass) {
var ths = this.standard[1];
var th = ths[0];
for (var i = 1; i < ths.length; i++) {
if (ths[i].mass < th.mass && ths[i].maxmass >= ladenMass) {
th = ths[i];
}
}
return th.class + th.rating;
};
ComponentSet.prototype.lightestShieldGenerator = function(hullMass) {
var sg = null;
_.forEach(this.internal.sg, function(s) {
if (sg == null || (s.mass < sg.mass && s.minmass <= hullMass && s.maxmass > hullMass)) {
sg = s;
}
});
return sg.id;
};
ComponentSet.prototype.lightestPowerPlant = function(powerUsed, rating) {
var pps = this.standard[0];
var pp = null;
for (var i = 0; i < pps.length; i++) {
if (pp == null || (pps[i].mass < pp.mass && pps[i].pGen >= powerUsed)) {
pp = pps[i];
}
}
return pp.class + (pp.rating != 'D' || rating == 'A' ? 'A' : 'D'); // Use A rated if C,E
};
return ComponentSet;
}]);

View File

@@ -1,252 +0,0 @@
/**
* This module contains all of the logic and models corresponding to
* information or behavoir in Elite Dangerous.
*
* This file contains values and functions that can be reused across the app.
*
* @requires ngLodash
*/
angular.module('shipyard', ['ngLodash'])
// Create 'angularized' references to DB. This will aid testing
.constant('ShipsDB', DB.ships)
.constant('ComponentsDB', DB.components)
.constant('ArmourMultiplier', [
1, // Lightweight
1.4, // Reinforced
1.945, // Military
1.945, // Mirrored
1.945 // Reactive
])
.constant('SizeMap', ['', 'small', 'medium', 'large', 'capital'])
// Map to lookup group labels/names for component grp, used for JSON Serialization
.constant('GroupMap', {
// Standard
pp: 'Power Plant',
t: 'Thrusters',
fsd: 'Frame Shift Drive',
ls: 'Life Support',
pd: 'Power Distributor',
s: 'Sensors',
ft: 'Fuel Tank',
// Internal
fs: 'Fuel Scoop',
sc: 'Scanner',
am: 'Auto Field-Maintenance Unit',
cr: 'Cargo Rack',
fi: 'Frame Shift Drive Interdictor',
hb: 'Hatch Breaker Limpet Controller',
hr: 'Hull Reinforcement Package',
rf: 'Refinery',
scb: 'Shield Cell Bank',
sg: 'Shield Generator',
psg: 'Prismatic Shield Generator',
dc: 'Docking Computer',
fx: 'Fuel Transfer Limpet Controller',
pc: 'Prospector Limpet Controller',
cc: 'Collector Limpet Controller',
// Hard Points
bl: 'Beam Laser',
ul: 'Burst Laser',
c: 'Cannon',
cs: 'Cargo Scanner',
cm: 'Countermeasure',
fc: 'Fragment Cannon',
ws: 'Frame Shift Wake Scanner',
kw: 'Kill Warrant Scanner',
nl: 'Mine Launcher',
ml: 'Mining Laser',
mr: 'Missile Rack',
pa: 'Plasma Accelerator',
mc: 'Multi-cannon',
pl: 'Pulse Laser',
rg: 'Rail Gun',
sb: 'Shield Booster',
tp: 'Torpedo Pylon'
})
.constant('MountMap', {
'F': 'Fixed',
'G': 'Gimballed',
'T': 'Turret',
'Fixed': 'F',
'Gimballed': 'G',
'Turret': 'T'
})
/**
* Array of all Ship properties (facets) organized into groups
* used for ship comparisons.
*
* @type {Array}
*/
.constant('ShipFacets', [
{ // 0
title: 'agility',
props: ['agility'],
unit: '',
fmt: 'fCrd'
},
{ // 1
title: 'speed',
props: ['topSpeed', 'topBoost'],
lbls: ['thrusters', 'boost'],
unit: 'm/s',
fmt: 'fCrd'
},
{ // 2
title: 'armour',
props: ['armour'],
unit: '',
fmt: 'fCrd'
},
{ // 3
title: 'shields',
props: ['shieldStrength'],
unit: 'MJ',
fmt: 'fRound'
},
{ // 4
title: 'jump range',
props: ['unladenRange', 'fullTankRange', 'ladenRange'],
lbls: ['max', 'full tank', 'laden'],
unit: 'LY',
fmt: 'fRound'
},
{ // 5
title: 'mass',
props: ['unladenMass', 'ladenMass'],
lbls: ['unladen', 'laden'],
unit: 'T',
fmt: 'fRound'
},
{ // 6
title: 'cargo',
props: ['cargoCapacity'],
unit: 'T',
fmt: 'fRound'
},
{ // 7
title: 'fuel',
props: ['fuelCapacity'],
unit: 'T',
fmt: 'fRound'
},
{ // 8
title: 'power',
props: ['powerRetracted', 'powerDeployed', 'powerAvailable'],
lbls: ['retracted', 'deployed', 'available'],
unit: 'MW',
fmt: 'fPwr'
},
{ // 9
title: 'cost',
props: ['totalCost'],
unit: 'CR',
fmt: 'fCrd'
},
{ // 10
title: 'total range',
props: ['unladenTotalRange', 'ladenTotalRange'],
lbls: ['unladen', 'laden'],
unit: 'LY',
fmt: 'fRound'
},
{ // 11
title: 'DPS',
props: ['totalDps'],
lbls: ['DPS'],
unit: '',
fmt: 'fRound'
}
])
/**
* Set of all available / theoretical discounts
*/
.constant('Discounts', {
'0%': 1,
'5%': 0.95,
'10%': 0.90,
'15%': 0.85,
'20%': 0.80,
'25%': 0.75
})
/**
* Calculate the maximum single jump range based on mass and a specific FSD
*
* @param {number} mass Mass of a ship: laden, unlanden, partially laden, etc
* @param {object} fsd The FDS object/component with maxfuel, fuelmul, fuelpower, optmass
* @param {number} fuel Optional - The fuel consumed during the jump (must be less than the drives max fuel per jump)
* @return {number} Distance in Light Years
*/
.value('calcJumpRange', function(mass, fsd, fuel) {
return Math.pow(Math.min(fuel === undefined ? fsd.maxfuel : fuel, fsd.maxfuel) / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass;
})
/**
* Calculate the total range based on mass and a specific FSD, and all fuel available
*
* @param {number} mass Mass of a ship: laden, unlanden, partially laden, etc
* @param {object} fsd The FDS object/component with maxfuel, fuelmul, fuelpower, optmass
* @param {number} fuel The total fuel available
* @return {number} Distance in Light Years
*/
.value('calcTotalRange', function(mass, fsd, fuel) {
var fuelRemaining = fuel % fsd.maxfuel; // Fuel left after making N max jumps
var jumps = Math.floor(fuel / fsd.maxfuel);
mass += fuelRemaining;
// Going backwards, start with the last jump using the remaining fuel
var totalRange = fuelRemaining > 0 ? Math.pow(fuelRemaining / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass : 0;
// For each max fuel jump, calculate the max jump range based on fuel mass left in the tank
for (var j = 0; j < jumps; j++) {
mass += fsd.maxfuel;
totalRange += Math.pow(fsd.maxfuel / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass;
}
return totalRange;
})
/**
* Calculate the a ships shield strength based on mass, shield generator and shield boosters used.
*
* @param {number} mass Current mass of the ship
* @param {number} shields Base Shield strength MJ for ship
* @param {object} sg The shield generator used
* @param {number} multiplier Shield multiplier for ship (1 + shield boosters if any)
* @return {number} Approximate shield strengh in MJ
*/
.value('calcShieldStrength', function(mass, shields, sg, multiplier) {
var opt;
if (mass < sg.minmass) {
return shields * multiplier * sg.minmul;
}
if (mass > sg.maxmass) {
return shields * multiplier * sg.maxmul;
}
if (mass < sg.optmass) {
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) );
}
})
/**
* Calculate the a ships speed based on mass, and thrusters.
*
* @param {number} mass Current mass of the ship
* @param {number} baseSpeed Base speed m/s for ship
* @param {number} baseBoost Base boost speed m/s for ship
* @param {object} thrusters The Thrusters used
* @param {number} pipSpeed Speed pip multiplier
* @return {object} Approximate speed by pips
*/
.value('calcSpeed', function(mass, baseSpeed, baseBoost, thrusters, pipSpeed) {
var multiplier = mass > thrusters.maxmass ? 0 : ((1 - thrusters.M) + (thrusters.M * Math.pow(3 - (2 * Math.max(0.5, mass / thrusters.optmass)), thrusters.P)));
var speed = baseSpeed * multiplier;
return {
'0 Pips': speed * (1 - (pipSpeed * 4)),
'2 Pips': speed * (1 - (pipSpeed * 2)),
'4 Pips': speed,
'boost': baseBoost * multiplier
};
});

View File

@@ -1,181 +0,0 @@
angular.module('shipyard').service('Components', ['lodash', 'ComponentsDB', 'ShipsDB', 'ComponentSet', 'GroupMap', function(_, C, Ships, ComponentSet, GroupMap) {
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 };
};
this.standard = function(typeIndex, componentId) {
return C.standard[typeIndex][componentId];
};
this.hardpoints = function(id) {
for (var n in C.hardpoints) {
var group = C.hardpoints[n];
for (var i = 0; i < group.length; i++) {
if (group[i].id == id) {
return group[i];
}
}
}
return null;
};
this.internal = function(id) {
for (var n in C.internal) {
var group = C.internal[n];
for (var i = 0; i < group.length; i++) {
if (group[i].id == id) {
return group[i];
}
}
}
return null;
};
/**
* Finds an internal Component based on Class, Rating, Group and/or name.
* At least one ofGroup name or unique component name must be provided
*
* @param {string} groupName [Optional] Full name or abbreviated name for component group
* @param {integer} clss Component Class
* @param {string} rating Component Rating
* @param {string} name [Optional] Long/unique name for component -e.g. 'Advanced Discover Scanner'
* @return {String} The id of the component if found, null if not found
*/
this.findInternal = function(groupName, clss, rating, name) {
var groups = {};
if (groupName) {
if (C.internal[groupName]) {
groups[groupName] = C.internal[groupName];
} else {
var grpCode = GrpNameToCodeMap[groupName];
if (grpCode && C.internal[grpCode]) {
groups[grpCode] = C.internal[grpCode];
}
}
} else if (name) {
groups = C.internal;
}
for (var g in groups) {
var group = groups[g];
for (var i = 0, l = group.length; i < l; i++) {
if (group[i].class == clss && group[i].rating == rating && ((!name && !group[i].name) || group[i].name == name)) {
return group[i];
}
}
}
return null;
};
/**
* Finds an internal Component ID based on Class, Rating, Group and/or name.
* At least one ofGroup name or unique component name must be provided
*
* @param {string} groupName [Optional] Full name or abbreviated name for component group
* @param {integer} clss Component Class
* @param {string} rating Component Rating
* @param {string} name [Optional] Long/unique name for component -e.g. 'Advanced Discover Scanner'
* @return {String} The id of the component if found, null if not found
*/
this.findInternalId = function(groupName, clss, rating, name) {
var i = this.findInternal(groupName, clss, rating, name);
return i ? i.id : 0;
};
/**
* Finds a hardpoint Component based on Class, Rating, Group and/or name.
* At least one ofGroup name or unique component name must be provided
*
* @param {string} groupName [Optional] Full name or abbreviated name for component group
* @param {integer} clss Component Class
* @param {string} rating [Optional] Component Rating
* @param {string} name [Optional] Long/unique name for component -e.g. 'Heat Sink Launcher'
* @param {string} mode Mount mode/type - [F]ixed, [G]imballed, [T]urret
* @param {string} missile [Optional] Missile type - [D]umbfire, [S]eeker
* @return {String} The id of the component if found, null if not found
*/
this.findHardpoint = function(groupName, clss, rating, name, mode, missile) {
var groups = {};
if (groupName) {
if (C.hardpoints[groupName]) {
groups[groupName] = C.hardpoints[groupName];
} else {
var grpCode = GrpNameToCodeMap[groupName];
if (grpCode && C.hardpoints[grpCode]) {
groups[grpCode] = C.hardpoints[grpCode];
}
}
} else if (name) {
groups = C.hardpoints;
}
for (var g in groups) {
var group = groups[g];
for (var i = 0, l = group.length; i < l; i++) {
if (group[i].class == clss && (!rating || group[i].rating == rating) && group[i].mode == mode
&& ((!name && !group[i].name) || group[i].name == name)
&& ((!missile && !group[i].missile) || group[i].missile == missile)
) {
return group[i];
}
}
}
return null;
};
/**
* Finds a hardpoint Component ID based on Class, Rating, Group and/or name.
* At least one of Group name or unique component name must be provided
*
* @param {string} groupName [Optional] Full name or abbreviated name for component group
* @param {integer} clss Component Class
* @param {string} rating Component Rating
* @param {string} name [Optional] Long/unique name for component -e.g. 'Heat Sink Launcher'
* @param {string} mode Mount mode/type - [F]ixed, [G]imballed, [T]urret
* @param {string} missile [Optional] Missile type - [D]umbfire, [S]eeker
* @return {String} The id of the component if found, null if not found
*/
this.findHardpointId = function(groupName, clss, rating, name, mode, missile) {
var h = this.findHardpoint(groupName, clss, rating, name, mode, missile);
return h ? h.id : 0;
};
/**
* Looks up the bulkhead component for a specific ship and bulkhead
* @param {string} shipId Unique ship Id/Key
* @param {number} bulkheadsId Id/Index for the specified bulkhead
* @return {object} The bulkhead component object
*/
this.bulkheads = function(shipId, bulkheadsId) {
return C.bulkheads[shipId][bulkheadsId];
};
this.bulkheadIndex = function(bulkheadName) {
return ['Lightweight Alloy', 'Reinforced Alloy', 'Military Grade Composite', 'Mirrored Surface Composite', 'Reactive Surface Composite'].indexOf(bulkheadName);
};
/**
* Creates a new ComponentSet that contains all available components
* that the specified ship is eligible to use.
*
* @param {string} shipId Unique ship Id/Key
* @return {ComponentSet} The set of components the ship can install
*/
this.forShip = function(shipId) {
var ship = Ships[shipId];
var maxInternal = isNaN(ship.slots.internal[0]) ? ship.slots.internal[0].class : ship.slots.internal[0];
return new ComponentSet(C, ship.minMassFilter || ship.properties.hullMass + 5, ship.slots.standard, maxInternal, ship.slots.hardpoints[0]);
};
}]);

308
app/js/stores/Persist.js Normal file
View File

@@ -0,0 +1,308 @@
import { EventEmitter } from 'fbemitter';
const LS_KEY_BUILDS = 'builds';
const LS_KEY_COMPARISONS = 'comparisons';
const LS_KEY_LANG = 'NG_TRANSLATE_LANG_KEY';
const LS_KEY_COST_TAB = 'costTab';
const LS_KEY_INSURANCE = 'insurance';
const LS_KEY_DISCOUNTS = 'discounts';
const LS_KEY_DISCOUNTS = 'state';
const LS_KEY_SIZE_RATIO = 'sizeRatio';
let LS;
// Safe check to determine if localStorage is enabled
try {
localStorage.setItem('s', 1);
localStorage.removeItem('s');
LS = localStorage;
} catch(e) {
LS = null;
}
function _put(key, value) {
if (LS) {
LS.setItem(key, typeof value != "string" ? JSON.stringify(value) : value);
}
}
function _getString(key) {
return LS.getItem(key) : null;
}
function _get(key) {
let str = _getString(key);
return str ? JSON.parse(str) : null;
}
function _delete(key) {
if (LS) {
LS.removeItem(key);
}
}
/**
* [description]
*/
class Persist extends EventEmitter {
constructor() {
let buildJson = _get(LS_KEY_BUILDS);
let comparisonJson = _get(LS_KEY_COMPARISONS);
this.builds = buildJson ? JSON.parse(buildJson) : {};
this.comparisons = comparisonJson ? JSON.parse(comparisonJson) : {};
this.buildCount = Object.keys(this.builds).length;
this.langCode = _getString(LS_KEY_LANG) || 'en';
this.insurance = _getString(LS_KEY_INSURANCE);
this.discount = _getString(LS_KEY_DISCOUNTS);
this.costTab = _getString(LS_KEY_COST_TAB);
this.state = _get(LS_KEY_STATE);
this.sizeRatio = _get(LS_KEY_SIZE_RATIO) || 1;
}
getLangCode() {
return this.langCode;
};
setLangCode(langCode) {
this.langCode = langCode;
_put(LS_KEY_LANG, langCode);
this.emit('language', langCode);
}
/**
* Persist a ship build in local storage.
*
* @param {string} shipId The unique id for a model of ship
* @param {string} name The name of the build
* @param {string} code The serialized code
*/
saveBuild(shipId, name, code) {
if (LS) {
if (!this.builds[shipId]) {
this.builds[shipId] = {};
}
let newBuild = !this.builds[shipId][name];
this.builds[shipId][name] = code;
_put(LS_KEY_BUILDS, this.builds);
if (newBuild) {
this.emit('builds', this.builds);
}
}
};
/**
* Get the serialized code/string for a build. Returns null if a
* build is not found.
*
* @param {string} shipId The unique id for a model of ship
* @param {string} name The name of the build
* @return {string} The serialized build string.
*/
getBuild(shipId, name) {
if (this.builds[shipId] && this.builds[shipId][name]) {
return this.builds[shipId][name];
}
return null;
};
getBuilds() {
return this.builds;
}
/**
* Delete a build from local storage. It will also delete the ship build collection if
* it becomes empty
*
* @param {string} shipId The unique id for a model of ship
* @param {string} name The name of the build
*/
deleteBuild(shipId, name) {
if (this.builds[shipId][name]) {
delete this.builds[shipId][name];
if (Object.keys(this.builds[shipId]).length === 0) {
delete this.builds[shipId];
}
_put(LS_KEY_BUILDS, this.builds);
// Check if the build was used in existing comparisons
var comps = this.comparisons;
for (var c in comps) {
for (var i = 0; i < comps[c].builds.length; i++) { // For all builds in the current comparison
if (comps[c].builds[i].shipId == shipId && comps[c].builds[i].buildName == name) {
comps[c].builds.splice(i, 1);
break; // A build is unique per comparison
}
}
}
_put(LS_KEY_COMPARISONS, this.comparisons);
this.emit('builds', this.builds);
}
};
/**
* Persist a comparison in localstorage.
*
* @param {string} name The name of the comparison
* @param {array} builds Array of builds
* @param {array} facets Array of facet indices
*/
saveComparison(name, builds, facets) {
if (!this.comparisons[name]) {
this.comparisons[name] = {};
}
this.comparisons[name] = {
facets: facets,
builds: builds.map(b => { shipId: b.id || b.shipId, buildName: b.buildName })
};
_put(LS_KEY_COMPARISONS, this.comparisons);
this.emit('comparisons', this.comparisons);
};
/**
* [getComparison description]
* @param {string} name [description]
* @return {object} Object containing array of facets and ship id + build names
*/
getComparison(name) {
if (this.comparisons[name]) {
return this.comparisons[name];
}
return null;
};
getComparisons() {
return this.comparisons;
}
/**
* Removes the comparison from localstorage.
* @param {string} name Comparison name
*/
deleteComparison(name) {
if (this.comparisons[name]) {
delete this.comparisons[name];
_put(LS_KEY_COMPARISONS, this.comparisons);
this.emit('comparisons', this.comparisons);
}
};
/**
* Delete all builds and comparisons from localStorage
*/
deleteAll() {
this.builds = {};
this.comparisons = {};
_delete(LS_KEY_BUILDS);
_delete(LS_KEY_COMPARISONS);
this.emit('deletedall');
};
getAll() {
var data = {};
data[LS_KEY_BUILDS] = this.getBuilds();
data[LS_KEY_COMPARISONS] = this.getComparisons();
data[LS_KEY_INSURANCE] = this.getInsurance();
data[LS_KEY_DISCOUNTS] = this.getDiscount();
return data;
};
/**
* Get the saved insurance type
* @return {string} The name of the saved insurance type of null
*/
getInsurance() {
return this.insurance;
};
/**
* Persist selected insurance type
* @param {string} name Insurance type name
*/
setInsurance(insurance) {
this.insurance = insurance
_put(LS_KEY_INSURANCE, insurance);
this.emit('insurance', insurance);
};
/**
* Persist selected discount
* @param {number} val Discount value/amount
*/
setDiscount(discount) {
this.discount = discount;
_put(LS_KEY_DISCOUNTS, discount);
this.emit('discount', discount);
};
/**
* Get the saved discount
* @return {number} val Discount value/amount
*/
getDiscount() {
return this.discount;
};
/**
* Persist selected cost tab
* @param {number} val Discount value/amount
*/
setCostTab(tabName) {
this.costTab = tabName;
_put(LS_KEY_COST_TAB, tabName);
};
/**
* Get the saved discount
* @return {number} val Discount value/amount
*/
getCostTab() {
return this.costTab;
};
/**
* Retrieve the last router state from local storage
* @return {object} state State object containing state name and params
*/
getState() {
return this.state;
};
/**
* Save the current router state to localstorage
* @param {object} state State object containing state name and params
*/
setState(state) {
this.state = state;
_put(LS_KEY_STATE, state);
};
/**
* Retrieve the last router state from local storage
* @return {number} size Ratio
*/
getSizeRatio() {
return this.sizeRatio;
};
/**
* Save the current size ratio to localstorage
* @param {number} sizeRatio
*/
setSizeRatio(sizeRatio) {
this.sizeRatio = sizeRatio;
_put(LS_KEY_SIZE_RATIO, sizeRatio);
this.emit('sizeRatio', sizeRatio);
};
/**
* Check if localStorage is enabled/active
* @return {Boolean} True if localStorage is enabled
*/
isEnabled() {
return LS != null;
}
}
export default new Persist();

43
app/js/utils/BBCode.js Normal file
View File

@@ -0,0 +1,43 @@
import { term, format } from '../i18n/Language';
export default function comparisonBBCode(facets, builds, link) {
var colCount = 2, b, i, j, k, f, fl, p, pl, l = [];
for (i = 0; i < facets.length; i++) {
if (facets[i].active) {
f = facets[i];
p = f.props;
if (p.length == 1) {
l.push('[th][B][COLOR=#FF8C0D]', term(f.title).toUpperCase(), '[/COLOR][/B][/th]');
colCount++;
} else {
for (j = 0; j < p.length; j++) {
l.push('[th][B][COLOR=#FF8C0D]', term(f.title).toUpperCase(), '\n', term(f.lbls[j]).toUpperCase(), '[/COLOR][/B][/th]');
colCount++;
}
}
}
}
l.push('[/tr]\n');
for (i = 0; i < builds.length; i++) {
b = builds[i];
//var href = $state.href('outfit',{shipId: b.id, code: b.code, bn: b.buildName}, {absolute: true});
l.push('[tr][td]', b.name, '[/td][td]', b.buildName, '[/td]');
for (j = 0, fl = facets.length; j < fl; j++) {
if (facets[j].active) {
f = facets[j];
p = f.props;
for (k = 0, pl = p.length; k < pl; k++) {
l.push('[td="align: right"]', format[f.fmt](b[p[k]]), ' [size=-2]', term(f.unit), '[/size][/td]');
}
}
}
l.push('[/tr]\n');
}
l.push('[tr][td="align: center, colspan:', colCount, '"][size=-3]\n[url=', link, ']Interactive Comparison at Coriolis.io[/url][/td][/tr]\n[/size][/table]');
l.unshift('[table="width:', colCount * 90, ',align: center"]\n[tr][th][B][COLOR=#FF8C0D]Ship[/COLOR][/B][/th][th][B][COLOR="#FF8C0D"]Build[/COLOR][/B][/th]');
return l.join('');
}

View File

@@ -0,0 +1,10 @@
export default function shortenUrl(url) {
/*if (window.navigator.onLine) {
return $http.post(shortenAPI + GAPI_KEY, { longUrl: url }).then(function(response) {
return response.data.id;
});
} else {
return $q.reject({ statusText: 'Not Online' });
}*/
}

View File

@@ -45,7 +45,7 @@ div, a, li {
-webkit-tap-highlight-color: rgba(0,0,0,0); -webkit-tap-highlight-color: rgba(0,0,0,0);
} }
#main { #coriolis {
margin: 0; margin: 0;
padding: 0.5em 0.5em; padding: 0.5em 0.5em;
width: 100%; width: 100%;

View File

@@ -1,91 +0,0 @@
<div id="app-update" ng-show="appCacheUpdate">
<a href="#" onclick="window.location.reload()">{{ 'PHRASE_UPDATE_RDY' | translate }}</a>
</div>
<header>
<a class="l" ui-sref="shipyard" style="margin-right: 1em;" title="Ships"><svg class="icon xl"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#coriolis"></use></svg></a>
<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' | 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>
</div>
<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' | translate}}</span>
</div>
<div class="menu-list" ng-if="openedMenu=='b'" ng-click="$event.stopPropagation();">
<div class="dbl" >
<div><ul ng-repeat="shipId in buildsList">
{{ships[shipId].properties.name}}
<li ng-repeat="(i, name) in cleanedBuildList(shipId)">
<a ui-sref-active="active" class="name" ui-sref="outfit({shipId:shipId, code:allBuilds[shipId][name], bn:name})" ng-bind="name"></a>
</li>
</ul></div>
</div>
</div>
</div>
<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' | translate}}</span>
</div>
<div class="menu-list" ng-if="openedMenu=='comp'" ng-click="$event.stopPropagation();" style="white-space: nowrap;">
<span class="cap" ng-if="!bs.hasComparisons" translate="none created"></span>
<a ng-repeat="(i, name) 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 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' | translate}}</span>
</div>
<div class="menu-list no-wrap cap" ng-if="openedMenu=='settings'" ng-click="$event.stopPropagation();">
<ul>
{{'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>
{{'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>
{{'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' | 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 />
<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>
</header>

View File

@@ -1,87 +0,0 @@
<div id="shipyard">
<div class="scroll-x">
<table align="center" style="font-size:0.85em;white-space:nowrap">
<thead>
<tr class="main">
<th rowspan="2" class="sortable le" ng-click="sortShips('name')" translate="ship"></th>
<th rowspan="2" class="sortable" ng-click="sortShips('manufacturer')" translate="manufacturer"></th>
<th rowspan="2" class="sortable" ng-click="sortShips('class')" translate="size"></th>
<th colspan="4" translate="base"></th>
<th colspan="4" translate="max"></th>
<th colspan="5" class="sortable" ng-click="sortShips('hpCount')" translate="hardpoints"></th>
<th colspan="8" class="sortable" ng-click="sortShips('intCount')" translate="internal compartments"></th>
<th rowspan="2" class="sortable" ng-click="sortShips('hullMass')" translate="hull"></th>
<th rowspan="2" class="sortable" ng-click="sortShips('masslock')" translate="MLF"></th>
<th rowspan="2" class="sortable" ng-click="sortShips('retailCost')" translate="cost"></th>
</tr>
<tr>
<!-- Base -->
<th class="sortable lft" ng-click="sortShips('speed')" translate="speed"></th>
<th class="sortable" ng-click="sortShips('boost')" translate="boost"></th>
<th class="sortable" ng-click="sortShips('baseArmour')" translate="armour"></th>
<th class="sortable" ng-click="sortShips('baseShieldStrength')" translate="shields"></th>
<!-- Max -->
<th class="sortable lft" ng-click="sortShips('topSpeed')" translate="speed"></th>
<th class="sortable " ng-click="sortShips('topBoost')" translate="boost"></th>
<th class="sortable " ng-click="sortShips('maxJumpRange')" translate="jump"></th>
<th class="sortable" ng-click="sortShips('maxCargo')" translate="cargo"></th>
<!-- Hardpoints -->
<th class="sortable lft" ng-click="sortShips('hp[1]')" translate="S"></th>
<th class="sortable" ng-click="sortShips('hp[2]')" translate="M"></th>
<th class="sortable" ng-click="sortShips('hp[3]')" translate="L"></th>
<th class="sortable" ng-click="sortShips('hp[4]')" translate="H"></th>
<th class="sortable" ng-click="sortShips('hp[0]')" translate="U"></th>
<!-- Internal -->
<th class="sortable lft" ng-click="sortShips('int[0]')" translate="1"></th>
<th class="sortable" ng-click="sortShips('int[1]')" translate="2"></th>
<th class="sortable" ng-click="sortShips('int[2]')" translate="3"></th>
<th class="sortable" ng-click="sortShips('int[3]')" translate="4"></th>
<th class="sortable" ng-click="sortShips('int[4]')" translate="5"></th>
<th class="sortable" ng-click="sortShips('int[5]')" translate="6"></th>
<th class="sortable" ng-click="sortShips('int[6]')" translate="7"></th>
<th class="sortable" ng-click="sortShips('int[7]')" translate="8"></th>
</tr>
</thead>
<tbody>
<tr class="highlight" ng-repeat="s in shipsOverview | orderBy:shipPredicate:shipDesc">
<td class="le"><a ui-sref="outfit({shipId: s.id})" ng-bind="s.name"></a></td>
<td class="le" ng-bind="s.manufacturer"></td>
<!-- Pad Size -->
<td class="cap" ng-bind="SZM[s.class] | translate"></td>
<!-- Base -->
<td class="ri">{{fCrd(s.speed)}} <u translate>m/s</u></td>
<td class="ri">{{fCrd(s.boost)}} <u translate>m/s</u></td>
<td class="ri" ng-bind="s.baseArmour"></td>
<td class="ri">{{fCrd(s.baseShieldStrength)}} <u translate>Mj</u></td>
<!-- Max -->
<td class="ri">{{fCrd(s.topSpeed)}} <u translate>m/s</u></td>
<td class="ri">{{fCrd(s.topBoost)}} <u translate>m/s</u></td>
<td class="ri">{{fRound(s.maxJumpRange)}} <u translate>LY</u></td>
<td class="ri">{{fCrd(s.maxCargo)}} <u translate>T</u></td>
<!-- Hardpoints -->
<td ng-bind="s.hp[1]" ng-class="{disabled: !s.hp[1]}"></td>
<td ng-bind="s.hp[2]" ng-class="{disabled: !s.hp[2]}"></td>
<td ng-bind="s.hp[3]" ng-class="{disabled: !s.hp[3]}"></td>
<td ng-bind="s.hp[4]" ng-class="{disabled: !s.hp[4]}"></td>
<td ng-bind="s.hp[0]" ng-class="{disabled: !s.hp[0]}"></td>
<!-- Internal -->
<td ng-bind="s.int[0]" ng-class="{disabled: !s.int[0]}"></td>
<td ng-bind="s.int[1]" ng-class="{disabled: !s.int[1]}"></td>
<td ng-bind="s.int[2]" ng-class="{disabled: !s.int[2]}"></td>
<td ng-bind="s.int[3]" ng-class="{disabled: !s.int[3]}"></td>
<td ng-bind="s.int[4]" ng-class="{disabled: !s.int[4]}"></td>
<td ng-bind="s.int[5]" ng-class="{disabled: !s.int[5]}"></td>
<td ng-bind="s.int[6]" ng-class="{disabled: !s.int[6]}"></td>
<td ng-bind="s.int[7]" ng-class="{disabled: !s.int[7]}"></td>
<!-- Other Stats -->
<td class="ri">{{fCrd(s.hullMass)}} <u translate>T</u></td>
<td class="ri" ng-bind="s.masslock"></td>
<td class="ri">{{fCrd(s.retailCost)}} <u translate>CR</u></td>
</tr>
</tbody>
</table>
</div>
</div>

View File

@@ -1,61 +0,0 @@
{
"name": "coriolis_shipyard",
"authors": [
"Colin McLeod <colin@mcleod.eu>"
],
"description": "Coriolis Shipyard for Elite Dangerous",
"main": "app/app.js",
"keywords": [
"elite",
"shipyard"
],
"license": "MIT",
"private": true,
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"d3": "~3.5.5",
"ng-lodash": "~0.2.0",
"ui-router-extras": "0.0.13",
"angular-ui-router": "^0.2.15",
"d3-tip": "~0.6.7",
"ng-sortable": "~1.2.1",
"lz-string": "~1.4.4",
"angular": "~1.4.0",
"angular-translate": "~2.7.2"
},
"overrides": {
"angular": {
"main": "angular.min.js"
},
"angular-ui-router": {
"main": "release/angular-ui-router.min.js"
},
"angular-translate": {
"main": "angular-translate.min.js"
},
"d3": {
"main": "d3.min.js"
},
"ng-lodash": {
"main": "build/ng-lodash.min.js"
},
"ui-router-extras": {
"main": [
"release/modular/ct-ui-router-extras.core.min.js",
"release/modular/ct-ui-router-extras.sticky.min.js"
]
},
"ng-sortable": {
"main": "dist/ng-sortable.min.js"
}
},
"resolutions": {
"angular": "~1.4.0"
}
}

1
data

Submodule data deleted from 5350fb5e07

View File

@@ -1,6 +1,6 @@
{ {
"name": "coriolis_shipyard", "name": "coriolis_shipyard",
"version": "1.9.0", "version": "2.0.0-alpha",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/cmmcleod/coriolis" "url": "https://github.com/cmmcleod/coriolis"
@@ -11,14 +11,11 @@
"engine": "node >= 0.12.2", "engine": "node >= 0.12.2",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"angular-mocks": "1.4.x",
"async": "0.9.x", "async": "0.9.x",
"del": "1.2.x", "del": "1.2.x",
"gulp": "3.9.x", "gulp": "3.9.x",
"gulp-angular-templatecache": "1.6.x",
"gulp-concat": "2.5.x", "gulp-concat": "2.5.x",
"gulp-eslint": "0.13.x", "gulp-eslint": "0.13.x",
"gulp-htmlmin": "1.1.x",
"gulp-jasmine": "2.0.x", "gulp-jasmine": "2.0.x",
"gulp-jsonlint": "1.1.x", "gulp-jsonlint": "1.1.x",
"gulp-less": "3.0.x", "gulp-less": "3.0.x",
@@ -40,9 +37,14 @@
"karma-json-fixtures-preprocessor": "0.0.4", "karma-json-fixtures-preprocessor": "0.0.4",
"karma-mocha-reporter": "1.0.x", "karma-mocha-reporter": "1.0.x",
"karma-phantomjs-launcher": "0.2.x", "karma-phantomjs-launcher": "0.2.x",
"main-bower-files": "2.8.x",
"phantomjs": "1.9.x", "phantomjs": "1.9.x",
"run-sequence": "1.1.x", "run-sequence": "1.1.x",
"uglify-js": "2.4.x" "uglify-js": "2.4.x"
},
"dependencies": {
"classnames": "^2.2.0",
"fbemitter": "^2.0.0",
"react": "^0.14.2",
"react-dom": "^0.14.2"
} }
} }