Compare commits

..

40 Commits

Author SHA1 Message Date
Colin McLeod
806e545361 Fix charts in comparison page 2015-06-17 23:32:56 -07:00
Colin McLeod
ae62781d53 Bump version to 0.13.0 2015-06-17 23:17:15 -07:00
Colin McLeod
3abfcf7c95 Tweak chart axis UI 2015-06-17 23:12:27 -07:00
Colin McLeod
dc8b829d8a fix: total range calculation bug 2015-06-17 20:41:54 -07:00
Colin McLeod
353396398b Linting fix 2015-06-17 20:41:11 -07:00
Colin McLeod
bf99b34596 Tweak outfit page charts responsiveness 2015-06-16 15:28:06 -07:00
Colin McLeod
f3af0f3a99 Toggling shield and boosters updates shield strength 2015-06-16 15:27:41 -07:00
Colin McLeod
0fd4a8395e Tweak area chart tooltip 2015-06-16 15:26:47 -07:00
Colin McLeod
cb664003a5 Tweak slider 2015-06-16 15:26:22 -07:00
Colin McLeod
4686f17d18 Strip build should reset bulkheads 2015-06-16 15:26:05 -07:00
Colin McLeod
45c96dc136 Icon tweaks, added feather icon 2015-06-16 15:25:25 -07:00
Colin McLeod
389fdc8dfa Removing unused svg icon 2015-06-15 23:25:42 -07:00
Colin McLeod
b94e6126cd Chart performance tweaks, UI tweaks 2015-06-15 21:46:55 -07:00
Colin McLeod
bee4f7e6bc Fix strip build bug, and update state 2015-06-15 18:18:27 -07:00
Colin McLeod
345b7f5ffe Removing codeship, adding travis build status to readme 2015-06-15 18:08:41 -07:00
Colin McLeod
f1b40eb38c Adding gulp back to package.json 2015-06-15 18:06:09 -07:00
Colin McLeod
f459c26bd7 Locking down npm dependencies, add caching to travis 2015-06-15 18:03:02 -07:00
Colin McLeod
825b678fb0 Total Range chart feature added 2015-06-15 17:43:28 -07:00
Colin McLeod
ce3818f99a Use Travis CI instead of Codeship 2015-06-15 17:32:18 -07:00
Colin McLeod
94e2b60cd1 Changing version link 2015-06-15 17:31:27 -07:00
Colin McLeod
3bbef71a5e Merge pull request #58 from shearn89/strip-ship
Adding in 'Strip Ship' functionality.
2015-06-15 16:26:01 -07:00
Alex Shearn
ca280673d1 Fixing indentation 2015-06-15 22:09:18 +01:00
Alex Shearn
ff477c035a Moving button as per comments 2015-06-15 20:28:15 +01:00
Alex Shearn
1c0b76a8c2 Adding in 'Strip Ship' functionality.
This commit adds a simple button next to the save/reload icons that strips the ship to maximum class, D-rated modules, and no optional modules. Still needs a custom icon! May try to add in future things like 'all cargo' or 'fill empty with...' options.
2015-06-15 20:07:13 +01:00
Colin McLeod
bef741332d Bumping version to 0.12.1 2015-06-15 10:11:34 -07:00
Colin McLeod
f54620ee24 Imperial Courier shield correction 2015-06-15 10:11:12 -07:00
Colin McLeod
7d28e69b1c Bumping version to 0.12.0 2015-06-15 09:32:59 -07:00
Colin McLeod
abfe1b4a68 Updating base shield strength for Diamondback ships 2015-06-15 09:31:33 -07:00
Colin McLeod
59e400d7b8 Detailed suface scanner power management special case 2015-06-14 18:58:27 -07:00
Colin McLeod
4b3bb3bcde License readme tweak 2015-06-14 18:58:05 -07:00
Colin McLeod
a4a562bd40 Linting fixes 2015-06-14 17:47:16 -07:00
Colin McLeod
a1506d4f37 Selectable power bands, with right click to clear feature 2015-06-14 17:26:21 -07:00
Colin McLeod
8b0f58cb69 Right-click to clear slots feature 2015-06-14 17:26:04 -07:00
Colin McLeod
1a14674352 Updating License details to comply with Frontier terms and conditions 2015-06-14 17:25:28 -07:00
Colin McLeod
a2c32dd908 Bumping version to 0.11.1 2015-06-13 00:56:08 -07:00
Colin McLeod
eb7383b31e Lint fix 2015-06-13 00:44:15 -07:00
Colin McLeod
2106ec0e93 Ship building edge case, plus unit test to cover change 2015-06-13 00:43:10 -07:00
Colin McLeod
5649dc9079 Adding founders world discount 2015-06-12 23:40:32 -07:00
Colin McLeod
0d09607d30 Ship build, reset bug 2015-06-12 23:38:33 -07:00
Colin McLeod
d7415ea44a Updating hull prices for diamondback scout+exp, imperial courier 2015-06-12 20:14:56 -07:00
28 changed files with 462 additions and 216 deletions

19
.travis.yml Normal file
View File

@@ -0,0 +1,19 @@
language: node_js
notifications:
email: false
sudo: false
node_js:
- "0.12"
cache:
directories:
- node_modules
- bower_components
before_script:
- npm install -g gulp
- npm install -g bower
- bower install
script:
- gulp lint
- gulp build-prod
- gulp test

View File

@@ -1,4 +1,4 @@
[ ![Codeship Status for cmmcleod/coriolis](https://codeship.com/projects/637858c0-f2a5-0132-7af7-5ed004d44c71/status?branch=master)](https://codeship.com/projects/85232) [![Tasks in Ready](https://badge.waffle.io/cmmcleod/coriolis.png?label=ready&title=Ready)](https://waffle.io/cmmcleod/coriolis) [![Tasks in Progress](https://badge.waffle.io/cmmcleod/coriolis.svg?label=in%20progress&title=In%20Progress)](http://waffle.io/cmmcleod/coriolis) [![Build Status](https://travis-ci.org/cmmcleod/coriolis.svg?branch=master)](https://travis-ci.org/cmmcleod/coriolis) [![Tasks in Ready](https://badge.waffle.io/cmmcleod/coriolis.png?label=ready&title=Ready)](https://waffle.io/cmmcleod/coriolis) [![Tasks in Progress](https://badge.waffle.io/cmmcleod/coriolis.svg?label=in%20progress&title=In%20Progress)](http://waffle.io/cmmcleod/coriolis)
@@ -28,12 +28,14 @@ See [Data wiki](https://github.com/cmmcleod/coriolis/wiki/Database) for details
## License ## License
The MIT License All Data and [associated JSON](https://github.com/cmmcleod/coriolis/tree/master/data) files are intellectual property and copyright of Frontier Developments plc ('Frontier', 'Frontier Developments') and are subject to their
[terms and conditions](https://www.frontierstore.net/terms-and-conditions/).
The code specificially for Coriolis.io is released under the MIT License.
Copyright (c) 2015 Coriolis.io, Colin McLeod Copyright (c) 2015 Coriolis.io, Colin McLeod
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software (Javascript, CSS, HTML, and SVG files only), and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by IcoMoon.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<path d="M16 0c-8.837 0-16 7.163-16 16s7.163 16 16 16 16-7.163 16-16-7.163-16-16-16zM16 29c-7.18 0-13-5.82-13-13s5.82-13 13-13 13 5.82 13 13-5.82 13-13 13z"></path>
<path d="M21 8l-5 5-5-5-3 3 5 5-5 5 3 3 5-5 5 5 3-3-5-5 5-5z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 554 B

3
app/icons/feather.svg Normal file
View File

@@ -0,0 +1,3 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="724" height="1024" viewBox="0 0 1024 1024">
<path d="M0 1024c128-384 463-1024 1024-1024-263 211-384 704-576 704s-192 0-192 0l-192 320h-64z"></path>
</svg>

After

Width:  |  Height:  |  Size: 218 B

View File

@@ -1,6 +1,3 @@
<?xml version="1.0" encoding="utf-8"?> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="33" height="33" viewBox="0 0 33 33">
<!-- Generated by IcoMoon.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<path d="M32 12h-12l4.485-4.485c-2.267-2.266-5.28-3.515-8.485-3.515s-6.219 1.248-8.485 3.515c-2.266 2.267-3.515 5.28-3.515 8.485s1.248 6.219 3.515 8.485c2.267 2.266 5.28 3.515 8.485 3.515s6.219-1.248 8.485-3.515c0.189-0.189 0.371-0.384 0.546-0.583l3.010 2.634c-2.933 3.349-7.239 5.464-12.041 5.464-8.837 0-16-7.163-16-16s7.163-16 16-16c4.418 0 8.418 1.791 11.313 4.687l4.687-4.687v12z"></path> <path d="M32 12h-12l4.485-4.485c-2.267-2.266-5.28-3.515-8.485-3.515s-6.219 1.248-8.485 3.515c-2.266 2.267-3.515 5.28-3.515 8.485s1.248 6.219 3.515 8.485c2.267 2.266 5.28 3.515 8.485 3.515s6.219-1.248 8.485-3.515c0.189-0.189 0.371-0.384 0.546-0.583l3.010 2.634c-2.933 3.349-7.239 5.464-12.041 5.464-8.837 0-16-7.163-16-16s7.163-16 16-16c4.418 0 8.418 1.791 11.313 4.687l4.687-4.687v12z"></path>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 713 B

After

Width:  |  Height:  |  Size: 499 B

View File

@@ -1,6 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by IcoMoon.io --> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="33" height="33" viewBox="0 0 33 33">
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<path d="M20 4.581v4.249c1.131 0.494 2.172 1.2 3.071 2.099 1.889 1.889 2.929 4.4 2.929 7.071s-1.040 5.182-2.929 7.071c-1.889 1.889-4.4 2.929-7.071 2.929s-5.182-1.040-7.071-2.929c-1.889-1.889-2.929-4.4-2.929-7.071s1.040-5.182 2.929-7.071c0.899-0.899 1.94-1.606 3.071-2.099v-4.249c-5.783 1.721-10 7.077-10 13.419 0 7.732 6.268 14 14 14s14-6.268 14-14c0-6.342-4.217-11.698-10-13.419zM14 0h4v16h-4z"></path> <path d="M20 4.581v4.249c1.131 0.494 2.172 1.2 3.071 2.099 1.889 1.889 2.929 4.4 2.929 7.071s-1.040 5.182-2.929 7.071c-1.889 1.889-4.4 2.929-7.071 2.929s-5.182-1.040-7.071-2.929c-1.889-1.889-2.929-4.4-2.929-7.071s1.040-5.182 2.929-7.071c0.899-0.899 1.94-1.606 3.071-2.099v-4.249c-5.783 1.721-10 7.077-10 13.419 0 7.732 6.268 14 14 14s14-6.268 14-14c0-6.342-4.217-11.698-10-13.419zM14 0h4v16h-4z"></path>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 723 B

After

Width:  |  Height:  |  Size: 510 B

View File

@@ -63,7 +63,7 @@
<footer> <footer>
<div class="right"> <div class="right">
<a href="https://github.com/cmmcleod/coriolis" target="_blank" title="Coriolis Github Project">Version <%= version %> - <%= date %></a> <a href="https://github.com/cmmcleod/coriolis/releases/" target="_blank" title="Coriolis Github Project">Version <%= version %> - <%= date %></a>
</div> </div>
<div style="max-width:50%" class="l"> <div style="max-width:50%" class="l">
Coriolis Shipyard was created for non-commercial purposes. It is not endorsed by nor reflects the views or opinions of Frontier Developments. Coriolis Shipyard was created for non-commercial purposes. It is not endorsed by nor reflects the views or opinions of Frontier Developments.

View File

@@ -33,6 +33,8 @@ function($rootScope, $location, $window, $doc, $state, CArr, shipPurpose, sz, hp
$rootScope.SZ = sz; $rootScope.SZ = sz;
$rootScope.HPC = hpc; $rootScope.HPC = hpc;
$rootScope.GMAP = GroupMap; $rootScope.GMAP = GroupMap;
$rootScope.insurance = { opts: [{ name: 'Standard', pct: 0.05 }, { name: 'Alpha', pct: 0.025 }, { name: 'Beta', pct: 0.035 }] };
$rootScope.discounts = { opts: [{ name: 'None', pct: 1 }, { name: 'Founders World - 10%', pct: 0.90 }] };
$rootScope.STATUS = ['', 'DISABLED', 'OFF', 'ON']; $rootScope.STATUS = ['', 'DISABLED', 'OFF', 'ON'];
$rootScope.STATUS_CLASS = ['', 'disabled', 'warning', 'secondary-disabled']; $rootScope.STATUS_CLASS = ['', 'disabled', 'warning', 'secondary-disabled'];
$rootScope.title = 'Coriolis'; $rootScope.title = 'Coriolis';

View File

@@ -1,4 +1,4 @@
angular.module('app').controller('OutfitController', ['$window', '$rootScope', '$scope', '$state', '$stateParams', 'ShipsDB', 'Ship', 'Components', 'Serializer', 'Persist', function($window, $rootScope, $scope, $state, $p, Ships, Ship, Components, Serializer, Persist) { angular.module('app').controller('OutfitController', ['$window', '$rootScope', '$scope', '$state', '$stateParams', 'ShipsDB', 'Ship', 'Components', 'Serializer', 'Persist', 'calcTotalRange', function($window, $rootScope, $scope, $state, $p, Ships, Ship, Components, Serializer, Persist, calcTotalRange) {
var data = Ships[$p.shipId]; // Retrieve the basic ship properties, slots and defaults var data = Ships[$p.shipId]; // Retrieve the basic ship properties, slots and defaults
var ship = new Ship($p.shipId, data.properties, data.slots); // Create a new Ship instance var ship = new Ship($p.shipId, data.properties, data.slots); // Create a new Ship instance
var win = angular.element($window); // Angularized window object for event triggering var win = angular.element($window); // Angularized window object for event triggering
@@ -39,8 +39,7 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
$scope.jrSeries = { $scope.jrSeries = {
xMin: 0, xMin: 0,
xMax: ship.cargoCapacity, xMax: ship.cargoCapacity,
// Slightly higher than actual based bacuse components are excluded yMax: ship.unladenRange,
yMax: ship.jumpRangeWithMass(ship.unladenMass),
yMin: 0, yMin: 0,
func: function(cargo) { // X Axis is Cargo func: function(cargo) { // X Axis is Cargo
return ship.jumpRangeWithMass(ship.unladenMass + $scope.fuel + cargo, $scope.fuel); return ship.jumpRangeWithMass(ship.unladenMass + $scope.fuel + cargo, $scope.fuel);
@@ -60,6 +59,29 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
watch: $scope.fsd watch: $scope.fsd
}; };
$scope.trSeries = {
xMin: 0,
xMax: ship.cargoCapacity,
yMax: ship.unladenTotalRange,
yMin: 0,
func: function(cargo) { // X Axis is Cargo
return calcTotalRange(ship.unladenMass + cargo, $scope.fsd.c, $scope.fuel);
}
};
$scope.trChart = {
labels: {
xAxis: {
title: 'Cargo',
unit: 'T'
},
yAxis: {
title: 'Total Range',
unit: 'LY'
}
},
watch: $scope.fsd
};
/** /**
* 'Opens' a select for component selection. * 'Opens' a select for component selection.
* *
@@ -83,9 +105,9 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
* @param {[type]} slot The slot object belonging to the ship instance * @param {[type]} slot The slot object belonging to the ship instance
* @param {[type]} e The event object * @param {[type]} e The event object
*/ */
$scope.select = function(type, slot, e) { $scope.select = function(type, slot, e, id) {
e.stopPropagation(); e.stopPropagation();
var id = angular.element(e.target).attr('cpid'); // Get component ID id = id || angular.element(e.target).attr('cpid'); // Get component ID
if (id) { if (id) {
if (id == 'empty') { if (id == 'empty') {
@@ -116,6 +138,21 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
} }
}; };
/**
* Strip ship to D-class and no other components.
*/
$scope.stripBuild = function() {
for (var i = 0, l = ship.common.length - 1; i < l; i++) { // All except Fuel Tank
var id = ship.common[i].maxClass + 'D';
ship.use(ship.common[i], id, Components.common(i, id));
}
ship.hardpoints.forEach(function(slot) { ship.use(slot, null, null); });
ship.internal.forEach(function(slot) { ship.use(slot, null, null); });
ship.useBulkhead(0);
$scope.code = Serializer.fromShip(ship);
updateState();
};
/** /**
* Save the current build. Will replace the saved build if there is one * Save the current build. Will replace the saved build if there is one
* for this ship & with the exact name. * for this ship & with the exact name.
@@ -216,9 +253,9 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
function updateState() { function updateState() {
$state.go('outfit', { shipId: ship.id, code: $scope.code, bn: $scope.buildName }, { location: 'replace', notify: false }); $state.go('outfit', { shipId: ship.id, code: $scope.code, bn: $scope.buildName }, { location: 'replace', notify: false });
$scope.jrSeries.xMax = ship.cargoCapacity; $scope.trSeries.xMax = $scope.jrSeries.xMax = ship.cargoCapacity;
$scope.jrSeries.yMax = ship.jumpRangeWithMass(ship.unladenMass); $scope.jrSeries.yMax = ship.unladenRange;
$scope.jrSeries.mass = ship.unladenMass; $scope.trSeries.yMax = ship.unladenTotalRange;
win.triggerHandler('pwrchange'); win.triggerHandler('pwrchange');
} }

View File

@@ -19,7 +19,8 @@ angular.module('app').directive('areaChart', ['$window', function($window) {
xAxis = d3.svg.axis().outerTickSize(0).orient('bottom').tickFormat(d3.format('.2r')), xAxis = d3.svg.axis().outerTickSize(0).orient('bottom').tickFormat(d3.format('.2r')),
yAxis = d3.svg.axis().ticks(6).outerTickSize(0).orient('left').tickFormat(fmt), yAxis = d3.svg.axis().ticks(6).outerTickSize(0).orient('left').tickFormat(fmt),
x = d3.scale.linear(), x = d3.scale.linear(),
y = d3.scale.linear(); y = d3.scale.linear(),
data = [];
// Create chart // Create chart
var svg = d3.select(element[0]).append('svg'); var svg = d3.select(element[0]).append('svg');
@@ -61,13 +62,35 @@ angular.module('app').directive('areaChart', ['$window', function($window) {
// Create and Add tooltip // Create and Add tooltip
var tip = vis.append('g').style('display', 'none'); var tip = vis.append('g').style('display', 'none');
tip.append('rect').attr('width', '4em').attr('height', '2em').attr('x', '0.5em').attr('y', '-1em').attr('class', 'tip'); tip.append('rect').attr('width', '4.5em').attr('height', '2em').attr('x', '0.5em').attr('y', '-1em').attr('class', 'tip');
tip.append('circle') tip.append('circle')
.attr('class', 'marker') .attr('class', 'marker')
.attr('r', 4); .attr('r', 4);
tip.append('text').attr('class', 'label x').attr('y', '-0.25em'); tip.append('text').attr('class', 'label x').attr('y', '-0.25em');
tip.append('text').attr('class', 'label y').attr('y', '0.85em'); tip.append('text').attr('class', 'label y').attr('y', '0.85em');
vis.insert('path', ':first-child') // Area/Path to appear behind everything else
.data([data])
.attr('class', 'area')
.attr('fill', 'url(#gradient)')
.attr('d', area)
.on('mouseover', showTip)
.on('mouseout', hideTip)
.on('mousemove', moveTip)
.call(drag);
drag
.on('dragstart', function() {
dragging = true;
moveTip.call(this);
showTip();
})
.on('dragend', function() {
dragging = false;
hideTip();
})
.on('drag', moveTip);
/** /**
* Watch for changes in the series data (mass changes, etc) * Watch for changes in the series data (mass changes, etc)
*/ */
@@ -78,8 +101,9 @@ angular.module('app').directive('areaChart', ['$window', function($window) {
var width = element[0].parentElement.offsetWidth, var width = element[0].parentElement.offsetWidth,
height = width * 0.5, height = width * 0.5,
w = width - margin.left - margin.right, w = width - margin.left - margin.right,
h = height - margin.top - margin.bottom, h = height - margin.top - margin.bottom;
data = [];
data.length = 0; // Reset Data array
if (series.xMax == series.xMin) { if (series.xMax == series.xMin) {
var yVal = func(series.xMin); var yVal = func(series.xMin);
@@ -95,7 +119,7 @@ angular.module('app').directive('areaChart', ['$window', function($window) {
// Update Chart Size // Update Chart Size
svg.attr('width', width).attr('height', height); svg.attr('width', width).attr('height', height);
// Update domain and scale for axes; // Update domain and scale for axes
x.range([0, w]).domain([series.xMin, series.xMax]).clamp(true); x.range([0, w]).domain([series.xMin, series.xMax]).clamp(true);
xAxis.scale(x); xAxis.scale(x);
xLbl.attr('transform', 'translate(0,' + h + ')'); xLbl.attr('transform', 'translate(0,' + h + ')');
@@ -106,30 +130,9 @@ angular.module('app').directive('areaChart', ['$window', function($window) {
vis.selectAll('.y.axis').call(yAxis); vis.selectAll('.y.axis').call(yAxis);
vis.selectAll('.x.axis').call(xAxis); vis.selectAll('.x.axis').call(xAxis);
// Remove existing elements vis.selectAll('path.area') // Area/Path to appear behind everything else
vis.selectAll('path.area').remove(); .data([data])
.attr('d', area);
vis.insert('path', ':first-child') // Area/Path to appear behind everything else
.datum(data)
.attr('class', 'area')
.attr('fill', 'url(#gradient)')
.attr('d', area)
.on('mouseover', showTip)
.on('mouseout', hideTip)
.on('mousemove', moveTip)
.call(drag);
drag
.on('dragstart', function() {
dragging = true;
moveTip.call(this);
showTip();
})
.on('dragend', function() {
dragging = false;
hideTip();
})
.on('drag', moveTip);
} }
function showTip() { function showTip() {
@@ -143,10 +146,10 @@ angular.module('app').directive('areaChart', ['$window', function($window) {
} }
function moveTip() { function moveTip() {
var xPos = d3.mouse(this)[0], x0 = x.invert(xPos), y0 = func(x0), flip = (x0 / x.domain()[1] > 0.75); var xPos = d3.mouse(this)[0], x0 = x.invert(xPos), y0 = func(x0), flip = (x0 / x.domain()[1] > 0.65);
tip.attr('transform', 'translate(' + x(x0) + ',' + y(y0) + ')'); tip.attr('transform', 'translate(' + x(x0) + ',' + y(y0) + ')');
tip.selectAll('rect').attr('x', flip ? '-4.5em' : '0.5em').style('text-anchor', flip ? 'end' : 'start'); tip.selectAll('rect').attr('x', flip ? '-5.75em' : '0.5em').style('text-anchor', flip ? 'end' : 'start');
tip.selectAll('text.label').attr('x', flip ? '-1em' : '1em').style('text-anchor', flip ? 'end' : 'start'); tip.selectAll('text.label').attr('x', flip ? '-2em' : '1em').style('text-anchor', flip ? 'end' : 'start');
tip.select('text.label.x').text(fmtLong(x0) + ' ' + labels.xAxis.unit); tip.select('text.label.x').text(fmtLong(x0) + ' ' + labels.xAxis.unit);
tip.select('text.label.y').text(fmtLong(y0) + ' ' + labels.yAxis.unit); tip.select('text.label.y').text(fmtLong(y0) + ' ' + labels.yAxis.unit);
} }

View File

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

View File

@@ -12,17 +12,9 @@ angular.module('app').directive('shipyardHeader', ['lodash', '$rootScope', 'Pers
scope.allComparisons = Persist.comparisons; scope.allComparisons = Persist.comparisons;
scope.bs = Persist.state; scope.bs = Persist.state;
// Insurance options and management here for now.
$rootScope.insurance = {
opts: [
{ name: 'Standard', pct: 0.05 },
{ name: 'Alpha', pct: 0.025 },
{ name: 'Beta', pct: 0.035 }
]
};
var insIndex = _.findIndex($rootScope.insurance.opts, 'name', Persist.getInsurance()); var insIndex = _.findIndex($rootScope.insurance.opts, 'name', Persist.getInsurance());
$rootScope.insurance.current = $rootScope.insurance.opts[insIndex != -1 ? insIndex : 0]; $rootScope.insurance.current = $rootScope.insurance.opts[insIndex != -1 ? insIndex : 0];
$rootScope.discounts.current = $rootScope.discounts.opts[Persist.getDiscount() || 0];
// Close menus if a navigation change event occurs // Close menus if a navigation change event occurs
$rootScope.$on('$stateChangeStart', function() { $rootScope.$on('$stateChangeStart', function() {
@@ -42,6 +34,13 @@ angular.module('app').directive('shipyardHeader', ['lodash', '$rootScope', 'Pers
Persist.setInsurance($rootScope.insurance.current.name); Persist.setInsurance($rootScope.insurance.current.name);
}; };
/**
* Save selected discount option
*/
scope.updateDiscount = function() {
Persist.setDiscount($rootScope.discounts.opts.indexOf($rootScope.discounts.current));
};
scope.openMenu = function(e, menu) { scope.openMenu = function(e, menu) {
e.stopPropagation(); e.stopPropagation();
if (menu == scope.openedMenu) { if (menu == scope.openedMenu) {

View File

@@ -8,6 +8,7 @@ angular.module('app').directive('powerBands', ['$window', function($window) {
link: function(scope, element) { link: function(scope, element) {
var margin = { top: 20, right: 130, bottom: 20, left: 40 }, var margin = { top: 20, right: 130, bottom: 20, left: 40 },
barHeight = 20, barHeight = 20,
bands = null,
innerHeight = (barHeight * 2) + 3, innerHeight = (barHeight * 2) + 3,
height = innerHeight + margin.top + margin.bottom + 1, height = innerHeight + margin.top + margin.bottom + 1,
wattScale = d3.scale.linear(), wattScale = d3.scale.linear(),
@@ -19,8 +20,17 @@ angular.module('app').directive('powerBands', ['$window', function($window) {
// Create chart // Create chart
svg = d3.select(element[0]).append('svg'), svg = d3.select(element[0]).append('svg'),
vis = svg.append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'), vis = svg.append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'),
deployed = vis.append('g'), deployed = vis.append('g').attr('class', 'power-band'),
retracted = vis.append('g'); retracted = vis.append('g').attr('class', 'power-band');
svg.on('contextmenu', function() {
d3.event.preventDefault();
for (var i = 0, l = bands.length; i < l; i++) {
bands[i].retSelected = false;
bands[i].depSelected = false;
}
render();
});
// Create Y Axis SVG Elements // Create Y Axis SVG Elements
vis.append('g').attr('class', 'watt axis'); vis.append('g').attr('class', 'watt axis');
@@ -36,12 +46,17 @@ angular.module('app').directive('powerBands', ['$window', function($window) {
angular.element($window).bind('orientationchange resize pwrchange', render); angular.element($window).bind('orientationchange resize pwrchange', render);
function render() { function render() {
var bands = scope.bands, bands = scope.bands;
available = scope.available,
var available = scope.available,
width = element[0].offsetWidth, width = element[0].offsetWidth,
w = width - margin.left - margin.right, w = width - margin.left - margin.right,
maxBand = bands[bands.length - 1], maxBand = bands[bands.length - 1],
maxPwr = Math.max(available, maxBand.deployedSum); deployedSum = 0,
retractedSum = 0,
retBandsSelected = false,
depBandsSelected = false,
maxPwr = Math.max(available, maxBand.retractedSum, maxBand.deployedSum);
// Update chart size // Update chart size
svg.attr('width', width).attr('height', height); svg.attr('width', width).attr('height', height);
@@ -55,50 +70,80 @@ angular.module('app').directive('powerBands', ['$window', function($window) {
// Update X & Y Axis // Update X & Y Axis
wattScale.range([0, w]).domain([0, maxPwr]).clamp(true); wattScale.range([0, w]).domain([0, maxPwr]).clamp(true);
pctScale.range([0, w]).domain([0, maxPwr / available]).clamp(true); pctScale.range([0, w]).domain([0, maxPwr / available]).clamp(true);
vis.selectAll('.watt.axis').call(wattAxis); vis.selectAll('.watt.axis').call(wattAxis);
vis.selectAll('.pct.axis').attr('transform', 'translate(0,' + innerHeight + ')').call(pctAxis); vis.selectAll('.pct.axis').attr('transform', 'translate(0,' + innerHeight + ')').call(pctAxis);
retLbl for (var b = 0, l = bands.length; b < l; b++) {
.attr('x', w + 5 ) if (bands[b].retSelected) {
.attr('class', maxBand.retractedSum > available ? 'warning' : 'primary') retractedSum += bands[b].retracted + bands[b].retOnly;
.text(wattFmt(Math.max(0, maxBand.retractedSum)) + ' (' + pctFmt(Math.max(0, maxBand.retractedSum / available)) + ')'); retBandsSelected = true;
}
if (bands[b].depSelected) {
deployedSum += bands[b].deployed + bands[b].retracted;
depBandsSelected = true;
}
}
depLbl updateLabel(retLbl, w, retBandsSelected, retBandsSelected ? retractedSum : maxBand.retractedSum, available);
.attr('x', w + 5 ) updateLabel(depLbl, w, depBandsSelected, depBandsSelected ? deployedSum : maxBand.deployedSum, available);
.attr('class', maxBand.deployedSum > available ? 'warning' : 'primary')
.text(wattFmt(Math.max(0, maxBand.deployedSum)) + ' (' + pctFmt(Math.max(0, maxBand.deployedSum / available)) + ')');
retracted.selectAll('rect').data(bands).enter().append('rect') retracted.selectAll('rect').data(bands).enter().append('rect')
.attr('height', barHeight) .attr('height', barHeight)
.attr('width', function(d) { return Math.max(wattScale(d.retracted) - 1, 0); }) .attr('width', function(d) { return Math.max(wattScale(d.retracted + d.retOnly) - 1, 0); })
.attr('x', function(d) { return wattScale(d.retractedSum) - wattScale(d.retracted); }) .attr('x', function(d) { return wattScale(d.retractedSum) - wattScale(d.retracted + d.retOnly); })
.attr('y', 1) .attr('y', 1)
.attr('class', function(d) { return (d.retractedSum > available) ? 'warning' : 'primary'; }); .on('click', function(d) {
d.retSelected = !d.retSelected;
render();
})
.attr('class', function(d) { return getClass(d.retSelected, d.retractedSum, available); });
retracted.selectAll('text').data(bands).enter().append('text') retracted.selectAll('text').data(bands).enter().append('text')
.attr('x', function(d) { return wattScale(d.retractedSum) - (wattScale(d.retracted) / 2); }) .attr('x', function(d) { return wattScale(d.retractedSum) - (wattScale(d.retracted + d.retOnly) / 2); })
.attr('y', 15) .attr('y', 15)
.style('text-anchor', 'middle') .style('text-anchor', 'middle')
.attr('class', 'primary-bg') .attr('class', 'primary-bg')
.text(function(d, i) { return bandText(d.retracted, i); }); .on('click', function(d) {
d.retSelected = !d.retSelected;
render();
})
.text(function(d, i) { return bandText(d.retracted + d.retOnly, i); });
deployed.selectAll('rect').data(bands).enter().append('rect') deployed.selectAll('rect').data(bands).enter().append('rect')
.attr('height', barHeight) .attr('height', barHeight)
.attr('width', function(d) { return Math.max(wattScale(d.deployed + d.retracted) - 1, 0); }) .attr('width', function(d) { return Math.max(wattScale(d.deployed + d.retracted) - 1, 0); })
.attr('x', function(d) { return wattScale(d.deployedSum) - wattScale(d.retracted) - wattScale(d.deployed); }) .attr('x', function(d) { return wattScale(d.deployedSum) - wattScale(d.retracted) - wattScale(d.deployed); })
.attr('y', barHeight + 2) .attr('y', barHeight + 2)
.attr('class', function(d) { return (d.deployedSum > available) ? 'warning' : 'primary'; }); .on('click', function(d) {
d.depSelected = !d.depSelected;
render();
})
.attr('class', function(d) { return getClass(d.depSelected, d.deployedSum, available); });
deployed.selectAll('text').data(bands).enter().append('text') deployed.selectAll('text').data(bands).enter().append('text')
.attr('x', function(d) { return wattScale(d.deployedSum) - ((wattScale(d.retracted) + wattScale(d.deployed)) / 2); }) .attr('x', function(d) { return wattScale(d.deployedSum) - ((wattScale(d.retracted) + wattScale(d.deployed)) / 2); })
.attr('y', barHeight + 17) .attr('y', barHeight + 17)
.style('text-anchor', 'middle') .style('text-anchor', 'middle')
.attr('class', 'primary-bg') .attr('class', 'primary-bg')
.on('click', function(d) {
d.depSelected = !d.depSelected;
render();
})
.text(function(d, i) { return bandText(d.deployed + d.retracted, i); }); .text(function(d, i) { return bandText(d.deployed + d.retracted, i); });
} }
function updateLabel(lbl, width, selected, sum, available) {
lbl
.attr('x', width + 5 )
.attr('class', getClass(selected, sum, available))
.text(wattFmt(Math.max(0, sum)) + ' (' + pctFmt(Math.max(0, sum / available)) + ')');
}
function getClass(selected, sum, available) {
return selected ? 'secondary' : (sum > available) ? 'warning' : 'primary';
}
function bandText(val, index) { function bandText(val, index) {
if (val > 0 && wattScale(val) > 13) { if (val > 0 && wattScale(val) > 13) {
return index + 1; return index + 1;

View File

@@ -8,7 +8,7 @@ angular.module('app').directive('slider', ['$window', function($window) {
change: '&onChange' change: '&onChange'
}, },
link: function(scope, element) { link: function(scope, element) {
var margin = { top: -10, right: 140, bottom: 0, left: 50 }, var margin = { top: -10, right: 145, bottom: 0, left: 50 },
height = 40, // Height is fixed height = 40, // Height is fixed
h = height - margin.top - margin.bottom, h = height - margin.top - margin.bottom,
fmt = d3.format('.2f'), fmt = d3.format('.2f'),

View File

@@ -183,6 +183,27 @@ angular.module('app').service('Persist', ['$window', 'lodash', function($window,
} }
}; };
/**
* Persist selected discount
* @param {number} val Discount value/amount
*/
this.setDiscount = function(val) {
if (this.lsEnabled) {
return localStorage.setItem('discount', val);
}
};
/**
* Get the saved discount
* @return {number} val Discount value/amount
*/
this.getDiscount = function() {
if (this.lsEnabled) {
return localStorage.getItem('discount');
}
return null;
};
/** /**
* Retrieve the last router state from local storage * Retrieve the last router state from local storage
* @param {object} state State object containing state name and params * @param {object} state State object containing state name and params

View File

@@ -1,4 +1,22 @@
angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', 'calcJumpRange', 'lodash', function(Components, calcShieldStrength, calcJumpRange, _) { angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', 'calcJumpRange', 'calcTotalRange', 'lodash', function(Components, calcShieldStrength, calcJumpRange, calcTotalRange, _) {
/**
* 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
* @return {string} The key for the power usage type
*/
function powerUsageType(slot, component) {
if (component) {
if (component.retractedOnly) {
return 'retOnly';
}
if (component.passive) {
return 'retracted';
}
}
return slot.cat != 1 ? 'retracted' : 'deployed';
}
/** /**
* Ship model used to track all ship components and properties. * Ship model used to track all ship components and properties.
@@ -10,7 +28,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
function Ship(id, properties, slots) { function Ship(id, properties, slots) {
this.id = id; this.id = id;
this.cargoScoop = { c: Components.cargoScoop(), type: 'SYS' }; this.cargoScoop = { c: Components.cargoScoop(), type: 'SYS' };
this.bulkheads = { incCost: true, maxClass: 8 }; this.bulkheads = { incCost: true, maxClass: 8, discount: 1 };
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
@@ -18,10 +36,10 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
var slotGroup = slots[slotType]; var slotGroup = slots[slotType];
var group = this[slotType] = []; // Initialize Slot group (Common, Hardpoints, Internal) var group = this[slotType] = []; // Initialize Slot group (Common, Hardpoints, Internal)
for (var i = 0; i < slotGroup.length; i++) { for (var i = 0; i < slotGroup.length; i++) {
group.push({ id: null, c: null, incCost: true, maxClass: slotGroup[i] }); group.push({ id: null, c: null, incCost: true, maxClass: slotGroup[i], discount: 1 });
} }
} }
this.c = { incCost: true, c: { name: this.name, cost: this.cost } }; // Make a 'Ship' component similar to other components this.c = { incCost: true, discount: 1, c: { name: this.name, cost: this.cost } }; // Make a 'Ship' component similar to other components
this.costList = _.union(this.internal, this.common, this.hardpoints); this.costList = _.union(this.internal, this.common, this.hardpoints);
this.costList.push(this.bulkheads); // Add The bulkheads this.costList.push(this.bulkheads); // Add The bulkheads
@@ -37,22 +55,12 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
this.powerList.unshift(this.common[0]); // Add Power Plant this.powerList.unshift(this.common[0]); // Add Power Plant
this.priorityBands = [ this.priorityBands = [
{ 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 } { deployed: 0, retracted: 0, retOnly: 0 }
]; ];
// Cumulative and aggragate stats
this.fuelCapacity = 0;
this.cargoCapacity = 0;
this.ladenMass = 0;
this.armourAdded = 0;
this.shieldMultiplier = 1;
this.totalCost = this.cost;
this.unladenMass = this.mass;
this.armourTotal = this.armour;
} }
/** /**
@@ -67,6 +75,17 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
cl = common.length, cl = common.length,
i, l; i, l;
// Reset Cumulative stats
this.fuelCapacity = 0;
this.cargoCapacity = 0;
this.ladenMass = 0;
this.armourAdded = 0;
this.shieldMultiplier = 1;
this.totalCost = this.cost;
this.unladenMass = this.mass;
this.armourTotal = this.armour;
this.bulkheads.c = null;
this.useBulkhead(comps.bulkheads || 0, true); this.useBulkhead(comps.bulkheads || 0, true);
this.cargoScoop.priority = priorities ? priorities[0] * 1 : 0; this.cargoScoop.priority = priorities ? priorities[0] * 1 : 0;
this.cargoScoop.enabled = enabled ? enabled[0] * 1 : true; this.cargoScoop.enabled = enabled ? enabled[0] * 1 : true;
@@ -74,6 +93,7 @@ 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.cargoScoop.enabled) { if (this.cargoScoop.enabled) {
@@ -81,6 +101,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
} }
for (i = 0; i < cl; i++) { for (i = 0; i < cl; i++) {
common[i].cat = 0;
common[i].enabled = enabled ? enabled[i + 1] * 1 : true; common[i].enabled = enabled ? enabled[i + 1] * 1 : true;
common[i].priority = priorities ? priorities[i + 1] * 1 : 0; common[i].priority = priorities ? priorities[i + 1] * 1 : 0;
common[i].type = 'SYS'; common[i].type = 'SYS';
@@ -93,6 +114,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
cl++; // Increase accounts for Cargo Scoop cl++; // Increase accounts for Cargo Scoop
for (i = 0, l = hps.length; i < l; i++) { for (i = 0, l = hps.length; i < l; i++) {
hps[i].cat = 1;
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] * 1 : 0; hps[i].priority = priorities ? priorities[cl + i] * 1 : 0;
hps[i].type = hps[i].maxClass ? 'WEP' : 'SYS'; hps[i].type = hps[i].maxClass ? 'WEP' : 'SYS';
@@ -106,6 +128,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
cl += hps.length; // Increase accounts for hardpoints cl += hps.length; // Increase accounts for hardpoints
for (i = 0, l = internal.length; i < l; i++) { for (i = 0, l = internal.length; i < l; i++) {
internal[i].cat = 2;
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] * 1 : 0; internal[i].priority = priorities ? priorities[cl + i] * 1 : 0;
internal[i].type = 'SYS'; internal[i].type = 'SYS';
@@ -140,18 +163,14 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
*/ */
Ship.prototype.use = function(slot, id, component, preventUpdate) { Ship.prototype.use = function(slot, id, component, preventUpdate) {
if (slot.id != id) { // Selecting a different component if (slot.id != id) { // Selecting a different component
var slotIndex = this.internal.indexOf(slot);
// 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 component group/type must be of unique
if (slotIndex != -1 && component && _.includes(['sg', 'rf', 'fs'], component.grp)) { if (slot.cat != 2 && component && _.includes(['sg', 'rf', 'fs'], component.grp)) {
// Find another internal slot that already has this type/group installed // Find another internal slot that already has this type/group installed
var similarSlotIndex = this.findInternalByGroup(component.grp); var similarSlot = this.findInternalByGroup(component.grp);
// If another slot has an installed component with of the same type // If another slot has an installed component with of the same type
if (similarSlotIndex != -1 && similarSlotIndex != slotIndex) { if (similarSlot && similarSlot !== slot) {
// Empty the slot
var similarSlot = this.internal[similarSlotIndex];
this.updateStats(similarSlot, null, similarSlot.c, true); // Update stats but don't trigger a global update this.updateStats(similarSlot, null, similarSlot.c, true); // Update stats but don't trigger a global update
similarSlot.id = null; similarSlot.id = similarSlot.c = null; // Empty the slot
similarSlot.c = null;
} }
} }
var oldComponent = slot.c; var oldComponent = slot.c;
@@ -180,9 +199,13 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
* @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) { Ship.prototype.findInternalByGroup = function(group) {
return _.findIndex(this.internal, function(slot) { var index = _.findIndex(this.internal, function(slot) {
return slot.c && slot.c.grp == group; return slot.c && slot.c.grp == group;
}); });
if (index !== -1) {
return this.internal[index];
}
return null;
}; };
/** /**
@@ -197,7 +220,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
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 = (slot.c.passive || this.hardpoints.indexOf(slot) == -1) ? 'retracted' : 'deployed'; var usage = powerUsageType(slot, slot.c);
this.priorityBands[oldPriority][usage] -= slot.c.power; this.priorityBands[oldPriority][usage] -= slot.c.power;
this.priorityBands[newPriority][usage] += slot.c.power; this.priorityBands[newPriority][usage] += slot.c.power;
this.updatePower(); this.updatePower();
@@ -215,12 +238,21 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
}; };
Ship.prototype.setSlotEnabled = function(slot, enabled) { Ship.prototype.setSlotEnabled = function(slot, enabled) {
if (slot.enabled != enabled && slot.c) { // Enabled state is changing if (slot.enabled != enabled) { // Enabled state is changing
var usage = (slot.c.passive || this.hardpoints.indexOf(slot) == -1) ? 'retracted' : 'deployed'; slot.enabled = enabled;
this.priorityBands[slot.priority][usage] += enabled ? slot.c.power : -slot.c.power; if (slot.c) {
this.updatePower(); this.priorityBands[slot.priority][powerUsageType(slot, slot.c)] += enabled ? slot.c.power : -slot.c.power;
if (slot.c.grp == 'sg') {
this.updateShieldStrength();
} else if (slot.c.grp == 'sb') {
this.shieldMultiplier += slot.c.shieldmul * (enabled ? 1 : -1);
this.updateShieldStrength();
}
this.updatePower();
}
} }
slot.enabled = enabled;
}; };
Ship.prototype.getSlotStatus = function(slot, deployed) { Ship.prototype.getSlotStatus = function(slot, deployed) {
@@ -228,9 +260,10 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
return 0; // No Status (Not possible) return 0; // No Status (Not possible)
} else if (!slot.enabled) { } else if (!slot.enabled) {
return 1; // Disabled return 1; // Disabled
} else if (deployed) { } else if (deployed && !slot.c.retractedOnly) { // Certain component (e.g. Detaild Surface scanner) are power only while retracted
return this.priorityBands[slot.priority].deployedSum > this.powerAvailable ? 2 : 3; // Offline : Online return this.priorityBands[slot.priority].deployedSum > this.powerAvailable ? 2 : 3; // Offline : Online
} else if (this.hardpoints.indexOf(slot) != -1 && !slot.c.passive) { // Active hardpoints have no retracted status // Active hardpoints have no retracted status
} else if ((deployed && slot.c.retractedOnly) || (slot.cat === 1 && !slot.c.passive)) {
return 0; // No Status (Not possible) return 0; // No Status (Not possible)
} }
return this.priorityBands[slot.priority].retractedSum > this.powerAvailable ? 2 : 3; // Offline : Online return this.priorityBands[slot.priority].retractedSum > this.powerAvailable ? 2 : 3; // Offline : Online
@@ -240,7 +273,6 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
* Updates the ship's cumulative and aggregated stats based on the component change. * Updates the ship's cumulative and aggregated stats based on the component change.
*/ */
Ship.prototype.updateStats = function(slot, n, old, preventUpdate) { Ship.prototype.updateStats = function(slot, n, old, preventUpdate) {
var isHardPoint = this.hardpoints.indexOf(slot) != -1;
var powerChange = slot == this.common[0]; var powerChange = slot == this.common[0];
if (old) { // Old component now being removed if (old) { // Old component now being removed
@@ -255,7 +287,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
this.armourAdded -= old.armouradd; this.armourAdded -= old.armouradd;
break; break;
case 'sb': case 'sb':
this.shieldMultiplier -= old.shieldmul; this.shieldMultiplier -= slot.enabled ? old.shieldmul : 0;
break; break;
} }
@@ -264,7 +296,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
} }
if (old.power && slot.enabled) { if (old.power && slot.enabled) {
this.priorityBands[slot.priority][(isHardPoint && !old.passive) ? 'deployed' : 'retracted'] -= old.power; this.priorityBands[slot.priority][powerUsageType(slot, old)] -= old.power;
powerChange = true; powerChange = true;
} }
this.unladenMass -= old.mass || 0; this.unladenMass -= old.mass || 0;
@@ -285,7 +317,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
this.armourAdded += n.armouradd; this.armourAdded += n.armouradd;
break; break;
case 'sb': case 'sb':
this.shieldMultiplier += n.shieldmul; this.shieldMultiplier += slot.enabled ? n.shieldmul : 0;
break; break;
} }
@@ -294,7 +326,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
} }
if (n.power && slot.enabled) { if (n.power && slot.enabled) {
this.priorityBands[slot.priority][(isHardPoint && !n.passive) ? 'deployed' : 'retracted'] += n.power; this.priorityBands[slot.priority][powerUsageType(slot, n)] += n.power;
powerChange = true; powerChange = true;
} }
this.unladenMass += n.mass || 0; this.unladenMass += n.mass || 0;
@@ -318,7 +350,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
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; prevRetracted = band.retractedSum = prevRetracted + band.retracted + band.retOnly;
prevDeployed = band.deployedSum = prevDeployed + band.deployed + band.retracted; prevDeployed = band.deployedSum = prevDeployed + band.deployed + band.retracted;
} }
@@ -328,32 +360,21 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
}; };
Ship.prototype.updateShieldStrength = function() { Ship.prototype.updateShieldStrength = function() {
var sgSI = this.findInternalByGroup('sg'); // Find Shield Generator slot Index if any var sgSlot = this.findInternalByGroup('sg'); // Find Shield Generator slot Index if any
this.shieldStrength = sgSI != -1 ? calcShieldStrength(this.mass, this.shields, this.internal[sgSI].c, this.shieldMultiplier) : 0; this.shieldStrength = sgSlot && sgSlot.enabled ? calcShieldStrength(this.mass, this.shields, sgSlot.c, this.shieldMultiplier) : 0;
}; };
/** /**
* Jump Range and total range calculations * Jump Range and total range calculations
*/ */
Ship.prototype.updateJumpStats = function() { Ship.prototype.updateJumpStats = function() {
var fsd = this.common[2].c; // Frame Shift Drive; var fsd = this.common[2].c; // Frame Shift Drive;
var fuelRemaining = this.fuelCapacity % fsd.maxfuel; // Fuel left after making N max jumps
var jumps = this.fuelCapacity / fsd.maxfuel;
this.unladenRange = calcJumpRange(this.unladenMass + fsd.maxfuel, fsd, this.fuelCapacity); // Include fuel weight for jump this.unladenRange = calcJumpRange(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 = calcJumpRange(this.unladenMass + this.fuelCapacity, fsd, this.fuelCapacity); // Full Tanke
this.ladenRange = calcJumpRange(this.ladenMass, fsd, this.fuelCapacity); this.ladenRange = calcJumpRange(this.ladenMass, fsd, this.fuelCapacity);
this.maxJumpCount = Math.ceil(jumps); // Number of full fuel jumps + final jump to empty tank this.unladenTotalRange = calcTotalRange(this.unladenMass, fsd, this.fuelCapacity);
this.ladenTotalRange = calcTotalRange(this.unladenMass + this.cargoCapacity, fsd, this.fuelCapacity);
// Going backwards, start with the last jump using the remaining fuel this.maxJumpCount = Math.ceil(this.fuelCapacity / fsd.maxfuel);
this.unladenTotalRange = fuelRemaining > 0 ? calcJumpRange(this.unladenMass + fuelRemaining, fsd, fuelRemaining) : 0;
this.ladenTotalRange = fuelRemaining > 0 ? calcJumpRange(this.unladenMass + this.cargoCapacity + fuelRemaining, fsd, fuelRemaining) : 0;
// For each max fuel jump, calculate the max jump range based on fuel left in the tank
for (var j = 0, l = Math.floor(jumps); j < l; j++) {
fuelRemaining += fsd.maxfuel;
this.unladenTotalRange += calcJumpRange(this.unladenMass + fuelRemaining, fsd);
this.ladenTotalRange += calcJumpRange(this.unladenMass + this.cargoCapacity + fuelRemaining, fsd);
}
}; };
return Ship; return Ship;

View File

@@ -175,6 +175,27 @@ angular.module('shipyard', ['ngLodash'])
*/ */
.value('calcJumpRange', function(mass, fsd, fuel) { .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; 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 = 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 left in the tank
for (var j = 0, l = Math.floor(jumps); j < l; j++) {
fuelRemaining += 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. * Calculate the a ships shield strength based on mass, shield generator and shield boosters used.

View File

@@ -1,11 +1,9 @@
.chart { .chart {
.user-select-none(); .user-select-none();
display: inline-block; display: inline-block;
margin: 0; margin: 0;
cursor: default; cursor: default;
overflow: hidden; overflow: hidden;
width: 33%; width: 33%;
box-sizing: border-box; box-sizing: border-box;
@@ -17,12 +15,23 @@
width: 100%; width: 100%;
}); });
.medPhone({
.axis {
font-size: 0.8em;
g.tick:nth-child(2n + 1) text {
display: none;
}
}
});
h3 { h3 {
text-align: center; text-align: center;
&[ng-click] { &[ng-click] {
cursor: pointer; cursor: pointer;
} }
} }
} }
@@ -63,5 +72,3 @@ svg {
stroke-width: 1px; stroke-width: 1px;
} }
} }

View File

@@ -162,16 +162,38 @@ table.total {
}); });
.smallTablet({ .smallTablet({
overflow-x: auto; width: 100% !important;
-webkit-overflow-scrolling: touch; });
}
&.semi {
width: 50%;
.smallTablet({
.axis {
font-size: 0.8em;
g.tick:nth-child(2n + 1) text {
display: none;
}
}
});
.medPhone({
width: 100% !important; width: 100% !important;
}); });
} }
} }
.power-band {
text, rect {
cursor: pointer;
}
}
#componentPriority { #componentPriority {
.tablet({ .tablet({
text.primary, text.warning, text.primary-bg { text.primary, text.warning, text.primary-bg, text.secondary {
font-size: 0.8em; font-size: 0.8em;
} }

View File

@@ -51,6 +51,10 @@
<ul> <ul>
Insurance Insurance
<li><select ng-model="insurance.current" ng-options="ins.name for (i,ins) in insurance.opts" ng-change="updateInsurance()"></select></li> <li><select ng-model="insurance.current" ng-options="ins.name for (i,ins) in insurance.opts" ng-change="updateInsurance()"></select></li>
</ul><br>
<ul>
Discount
<li><select ng-model="discounts.current" ng-options="d.name for (i,d) in discounts.opts" ng-change="updateDiscount()"></select></li>
</ul> </ul>
<hr /> <hr />
<ul> <ul>

View File

@@ -16,6 +16,9 @@
<button ui-sref="outfit({shipId: ship.id,code:null, bn: buildName})" ng-disabled="!code"> <button ui-sref="outfit({shipId: ship.id,code:null, bn: buildName})" ng-disabled="!code">
<svg class="icon lg"><use xlink:href="#switch"></use></svg><span class="button-lbl">Reset</span> <svg class="icon lg"><use xlink:href="#switch"></use></svg><span class="button-lbl">Reset</span>
</button> </button>
<button ng-click="stripBuild()">
<svg class="icon lg"><use xlink:href="#feather"></use></svg><span class="button-lbl">Low-Weight</span>
</button>
</div> </div>
</div> </div>
@@ -53,7 +56,7 @@
<td>{{fRound(ship.speed)}} <u>m/s</u></td> <td>{{fRound(ship.speed)}} <u>m/s</u></td>
<td>{{fRound(ship.boost)}} <u>m/s</u></td> <td>{{fRound(ship.boost)}} <u>m/s</u></td>
<td>{{ship.armourTotal}} <span ng-if="ship.armourAdded">({{ship.armour}} + {{ship.armourAdded}})</span></td> <td>{{ship.armourTotal}} <span ng-if="ship.armourAdded">({{ship.armour}} + {{ship.armourAdded}})</span></td>
<td>{{fRound(ship.shieldStrength)}} <u>MJ</u> <span ng-if="ship.shieldMultiplier > 1">({{fRPct(ship.shieldMultiplier)}})</span></td> <td>{{fRound(ship.shieldStrength)}} <u>MJ</u> <span ng-if="ship.shieldMultiplier > 1 && ship.shieldStrength > 0">({{fRPct(ship.shieldMultiplier)}})</span></td>
<td>{{fRound(ship.unladenMass)}} <u>T</u></td> <td>{{fRound(ship.unladenMass)}} <u>T</u></td>
<td>{{fRound(ship.ladenMass)}} <u>T</u></td> <td>{{fRound(ship.ladenMass)}} <u>T</u></td>
<td>{{fRound(ship.cargoCapacity)}} <u>T</u></td> <td>{{fRound(ship.cargoCapacity)}} <u>T</u></td>
@@ -165,7 +168,7 @@
<div id="internal" class="group"> <div id="internal" class="group">
<h1>Internal Compartments</h1> <h1>Internal Compartments</h1>
<div class="slot" ng-repeat="i in ship.internal" ng-click="selectSlot($event, i)" ng-class="{selected: selectedSlot==i}"> <div class="slot" ng-repeat="i in ship.internal" ng-click="selectSlot($event, i)" context-menu="select('i', i, $event, 'empty')" ng-class="{selected: selectedSlot==i}">
<div slot-internal class="details" slot="i" lbl="GMAP[i.c.grp]" fuel="ship.fuelCapacity"></div> <div slot-internal class="details" slot="i" lbl="GMAP[i.c.grp]" fuel="ship.fuelCapacity"></div>
<div class="select" ng-if="selectedSlot==i" ng-click="select('i',i,$event)"> <div class="select" ng-if="selectedSlot==i" ng-click="select('i',i,$event)">
<div component-select s="i" groups="availCS.getInts(i.maxClass)"></div> <div component-select s="i" groups="availCS.getInts(i.maxClass)"></div>
@@ -175,7 +178,7 @@
<div id="hardpoints" class="group"> <div id="hardpoints" class="group">
<h1>HardPoints</h1> <h1>HardPoints</h1>
<div class="slot" ng-repeat="h in ship.hardpoints | filter:{maxClass: '!0'}" ng-click="selectSlot($event, h)" ng-class="{selected: selectedSlot==h}"> <div class="slot" ng-repeat="h in ship.hardpoints | filter:{maxClass: '!0'}" ng-click="selectSlot($event, h)" context-menu="select('h', h, $event, 'empty')" ng-class="{selected: selectedSlot==h}">
<div slot-hardpoint class="details" hp="h" size="HPC[h.maxClass]" lbl="GMAP[h.c.grp]"></div> <div slot-hardpoint class="details" hp="h" size="HPC[h.maxClass]" lbl="GMAP[h.c.grp]"></div>
<div class="select" ng-class="{hardpoint: h.maxClass > 0}" ng-if="selectedSlot==h" ng-click="select('h',h,$event)"> <div class="select" ng-class="{hardpoint: h.maxClass > 0}" ng-if="selectedSlot==h" ng-click="select('h',h,$event)">
<div component-select s="h" groups="availCS.getHps(h.maxClass)"></div> <div component-select s="h" groups="availCS.getHps(h.maxClass)"></div>
@@ -185,7 +188,7 @@
<div id="utility" class="group"> <div id="utility" class="group">
<h1>Utility Mounts</h1> <h1>Utility Mounts</h1>
<div class="slot" ng-repeat="h in ship.hardpoints | filter:{maxClass: '0'}" ng-click="selectSlot($event, h)" ng-class="{selected: selectedSlot==h}"> <div class="slot" ng-repeat="h in ship.hardpoints | filter:{maxClass: '0'}" ng-click="selectSlot($event, h)" context-menu="select('h', h, $event, 'empty')" ng-class="{selected: selectedSlot==h}">
<div slot-hardpoint class="details" hp="h" size="HPC[h.maxClass]" lbl="GMAP[h.c.grp]"></div> <div slot-hardpoint class="details" hp="h" size="HPC[h.maxClass]" lbl="GMAP[h.c.grp]"></div>
<div class="select" ng-class="{hardpoint: h.maxClass > 0}" ng-if="selectedSlot==h" ng-click="select('h',h,$event)"> <div class="select" ng-class="{hardpoint: h.maxClass > 0}" ng-if="selectedSlot==h" ng-click="select('h',h,$event)">
<div component-select s="h" groups="availCS.getHps(h.maxClass)"></div> <div component-select s="h" groups="availCS.getHps(h.maxClass)"></div>
@@ -242,32 +245,38 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr class="toggleable" ng-repeat="c in costList | orderBy:costPredicate:costDesc" ng-if="c.c.cost > 0" ng-class="{disabled:!c.incCost}" ng-click="toggleCost(c)"> <tr ng-repeat="c in costList | orderBy:costPredicate:costDesc" ng-if="c.c.cost > 0" ng-class="{disabled:!c.incCost}">
<td style="width:1em;">{{c.c.class}}{{c.c.rating}}</td> <td class="toggleable" style="width:1em;" ng-click="toggleCost(c)">{{c.c.class}}{{c.c.rating}}</td>
<td class="le shorten" ng-bind="cName(c)"></td> <td class="le toggleable shorten" ng-bind="cName(c)" ng-click="toggleCost(c)"></td>
<td class="ri">{{fCrd(c.c.cost)}} <u>CR</u></td> <td class="ri toggleable" ng-click="toggleCost(c)">{{fCrd(discounts.current.pct * c.c.cost)}} <u>CR</u></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<table class="total"> <table class="total">
<tr class="ri"> <tr class="ri">
<td class="lbl">Total</td> <td class="lbl">Total</td>
<td>{{fCrd(ship.totalCost)}} <u>CR</u></td> <td>{{fCrd(ship.totalCost * discounts.current.pct)}} <u>CR</u></td>
</tr> </tr>
<tr class="ri"> <tr class="ri">
<td class="lbl">Insurance</td> <td class="lbl">Insurance</td>
<td>{{fCrd(ship.totalCost * insurance.current.pct)}} <u>CR</u></td> <td>{{fCrd(ship.totalCost * discounts.current.pct * insurance.current.pct)}} <u>CR</u></td>
</tr> </tr>
</table> </table>
</div> </div>
<div class="group dbl"> <div class="group semi">
<h1>Jump Range</h1> <h1>Jump Range</h1>
<div class="cen"> <div area-chart config="jrChart" series="jrSeries"></div>
<div area-chart config="jrChart" series="jrSeries"></div> </div>
<div slider max="ship.fuelCapacity" unit="'T'" on-change="::fuelChange(val)" style="position:relative; margin: 0 auto;">
<div class="group semi">
<h1>Total Range</h1>
<div area-chart config="trChart" series="trSeries"></div>
</div>
<div class="group dbl">
<div slider max="ship.fuelCapacity" unit="'T'" on-change="::fuelChange(val)" style="position:relative; margin: 0 auto;">
<svg class="icon xl primary-disabled" style="position:absolute;height: 100%;"><use xlink:href="#fuel"></use></svg> <svg class="icon xl primary-disabled" style="position:absolute;height: 100%;"><use xlink:href="#fuel"></use></svg>
</div>
</div> </div>
</div> </div>

View File

@@ -38,6 +38,7 @@
"grp": "sc", "grp": "sc",
"name": "Detailed Surface Scanner", "name": "Detailed Surface Scanner",
"class": 1, "class": 1,
"retractedOnly": 1,
"rating": "C", "rating": "C",
"cost": 250000, "cost": 250000,
"mass": 1.3, "mass": 1.3,

View File

@@ -5,16 +5,16 @@
"name": "Diamondback Scout", "name": "Diamondback Scout",
"manufacturer": "Lakon", "manufacturer": "Lakon",
"class": 1, "class": 1,
"cost": 461312, "cost": 461342,
"speed": 283, "speed": 283,
"boost": 384, "boost": 384,
"agility": 8, "agility": 8,
"shields": 93, "shields": 118,
"armour": 216, "armour": 216,
"fuelcost": 50, "fuelcost": 50,
"mass": 170 "mass": 170
}, },
"retailCost": 564300, "retailCost": 564330,
"slots": { "slots": {
"common": [ "common": [
4, 4,

View File

@@ -5,16 +5,16 @@
"name": "Diamondback Explorer", "name": "Diamondback Explorer",
"manufacturer": "Lakon", "manufacturer": "Lakon",
"class": 1, "class": 1,
"cost": 1740931, "cost": 1635691,
"speed": 242, "speed": 242,
"boost": 316, "boost": 316,
"agility": 5, "agility": 5,
"shields": 115, "shields": 146,
"armour": 270, "armour": 270,
"fuelcost": 50, "fuelcost": 50,
"mass": 298 "mass": 298
}, },
"retailCost": 2000000, "retailCost": 1894760,
"slots": { "slots": {
"common": [ "common": [
4, 4,

View File

@@ -5,16 +5,16 @@
"name": "Imperial Courier", "name": "Imperial Courier",
"manufacturer": "Gutamaya", "manufacturer": "Gutamaya",
"class": 1, "class": 1,
"cost": 2481521, "cost": 2481552,
"speed": 277, "speed": 277,
"boost": 380, "boost": 380,
"agility": 6, "agility": 6,
"shields": 230, "shields": 197,
"armour": 144, "armour": 144,
"fuelcost": 50, "fuelcost": 50,
"mass": 35 "mass": 35
}, },
"retailCost": 2542900, "retailCost": 2542931,
"slots": { "slots": {
"common": [ "common": [
4, 4,

View File

@@ -1,6 +1,6 @@
{ {
"name": "coriolis_shipyard", "name": "coriolis_shipyard",
"version": "0.11.0", "version": "0.13.1",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/cmmcleod/coriolis" "url": "https://github.com/cmmcleod/coriolis"
@@ -9,33 +9,35 @@
"engine": "node >= 0.12.2", "engine": "node >= 0.12.2",
"dependencies": {}, "dependencies": {},
"devDependencies": { "devDependencies": {
"angular-mocks": "^1.3.16", "angular-mocks": "1.3.x",
"async": "^0.9.0", "async": "0.9.x",
"del": "^1.1.1", "del": "1.2.x",
"gulp": "^3.8.11", "gulp": "3.9.x",
"gulp-angular-templatecache": "^1.6.0", "gulp-angular-templatecache": "1.6.x",
"gulp-concat": "^2.5.2", "gulp-concat": "2.5.x",
"gulp-eslint": "^0.13.2", "gulp-eslint": "0.13.x",
"gulp-htmlmin": "^1.1.1", "gulp-htmlmin": "1.1.x",
"gulp-jasmine": "^2.0.1", "gulp-jasmine": "2.0.x",
"gulp-jsonlint": "^1.0.2", "gulp-jsonlint": "1.1.x",
"gulp-less": "^3.0.2", "gulp-less": "3.0.x",
"gulp-manifest": "0.0.6", "gulp-manifest": "0.0.6",
"gulp-minify-css": "^1.0.0", "gulp-minify-css": "1.1.x",
"gulp-rev-all": "0.8.18", "gulp-rev-all": "0.8.18",
"gulp-sourcemaps": "^1.5.1", "gulp-sourcemaps": "1.5.x",
"gulp-svgmin": "^1.1.2", "gulp-svgmin": "1.1.x",
"gulp-svgstore": "^5.0.1", "gulp-svgstore": "5.0.x",
"gulp-template": "^3.0.0", "gulp-template": "3.0.x",
"gulp-uglify": "^1.2.0", "gulp-uglify": "1.2.x",
"gulp-util": "^3.0.4", "gulp-util": "3.0.x",
"jasmine-core": "^2.3.4", "jasmine-core": "2.3.x",
"json-concat": "0.0.0", "json-concat": "0.0.x",
"karma": "^0.12.36", "karma": "0.12.x",
"karma-chrome-launcher": "^0.1.12", "karma-jasmine": "0.3.x",
"karma-jasmine": "^0.3.5", "karma-mocha-reporter": "1.0.x",
"main-bower-files": "^2.6.2", "karma-phantomjs-launcher": "0.2.x",
"run-sequence": "^1.0.2", "main-bower-files": "2.8.x",
"uglify-js": "^2.4.19" "phantomjs": "1.9.x",
"run-sequence": "1.1.x",
"uglify-js": "2.4.x"
} }
} }

View File

@@ -14,21 +14,13 @@ module.exports = function(config) {
'../build/app*.js', '../build/app*.js',
'tests/**/*.js' 'tests/**/*.js'
], ],
// list of files to exclude reporters: ['mocha'],
exclude: [],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress'],
port: 9876, port: 9876,
colors: true, colors: true,
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO, logLevel: config.LOG_INFO,
autoWatch: false, autoWatch: false,
browsers: ['Chrome'], browsers: ['PhantomJS'],
singleRun: false singleRun: false
}); });
}; };

View File

@@ -31,4 +31,40 @@ describe("Ship Factory", function() {
} }
}); });
it("resets and rebuilds properly", function() {
var id = 'cobra_mk_iii';
var cobra = DB.ships[id];
var shipA = new Ship(id, cobra.properties, cobra.slots);
var shipB = new Ship(id, cobra.properties, cobra.slots);
var testShip = new Ship(id, cobra.properties, cobra.slots);
var buildA = cobra.defaults;
var buildB = {
common:['4A', '4A', '4A', '3D', '3A', '3A', '4C'],
hardpoints: ['0s', '0s', '2d', '2d', 0, '04'],
internal: ['45', '03', '2b', '2o', '27', '53']
};
shipA.buildWith(buildA); // Build A
shipB.buildWith(buildB);// Build B
testShip.buildWith(buildA);
for(var p in testShip) {
expect(testShip[p]).toEqual(shipA[p], p + ' does not match');
}
testShip.buildWith(buildB);
for(var p in testShip) {
expect(testShip[p]).toEqual(shipB[p], p + ' does not match');
}
testShip.buildWith(buildA);
for(var p in testShip) {
expect(testShip[p]).toEqual(shipA[p], p + ' does not match');
}
});
}); });