UI changes, added utilitiy services, persistance, serialization

This commit is contained in:
Colin McLeod
2015-05-01 01:14:29 -07:00
parent f736a078ec
commit 51ac98d10f
82 changed files with 2709 additions and 2516 deletions

View File

@@ -1,25 +1,45 @@
angular.module('app', ['ngRoute', 'shipyard', 'ngLodash', 'n3-line-chart', 'app.templates'])
.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
angular.module('app', ['ui.router', 'shipyard', 'ngLodash', 'app.templates'])
.config(['$stateProvider', '$urlRouterProvider', '$locationProvider', function($stateProvider, $urlRouterProvider, $locationProvider) {
$locationProvider.html5Mode(true);
$routeProvider
.when('/:ship', { templateUrl: 'views/ship.html', controller: 'ShipController' })
.when('/:ship/:code', { templateUrl: 'views/ship.html', controller: 'ShipController' })
.when('/', { templateUrl: 'views/ships.html', controller: 'ShipyardController' });
$stateProvider
.state('outfit', {
url: '/outfit/:shipId/:code?bn',
params: {
// TODO: fix below, default, squash false not working
//shipId: { value: 'sidewinder', squash: false }, // Allow 'shipId' parameter to default to
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 (!DB.ships[$p.shipId]) {
throw { type: 404, message: 'Ship "' + $p.shipId + '" does not exist'};
}
}]
}
})
.state('shipyard', { url: '/', templateUrl: 'views/page-shipyard.html', controller: 'ShipyardController' })
.state('error', { params: {type:null, message:null, details: null }, templateUrl: 'views/page-error.html', controller: 'ErrorController' })
.state('notfound', { url: '*path', templateUrl: 'views/page-error.html', controller: 'ErrorController' });
}])
.run(['$rootScope','$document','$location','$route','commonArray','shipPurpose','shipSize','hardPointClass','internalGroupMap', function ($rootScope, $doc, $loc, $route, CArr, shipPurpose, sz, hpc, igMap) {
// Allow URL changes without reloading controllers/view
var original = $loc.path;
$loc.path = function (path, reload) {
if (reload === false) {
var lastRoute = $route.current;
var un = $rootScope.$on('$locationChangeSuccess', function () {
$route.current = lastRoute;
un();
});
}
return original.apply($loc, [path]);
};
.config(['$provide',function($provide) {
// Global Error Handler, redirects uncaught errors to the error page
$provide.decorator('$exceptionHandler', ['$delegate', '$injector', function ($delegate, $injector) {
return function(exception, cause) {
$injector.get('$state').go('error', { details: exception }, {location:false, reload:true}); // Go to error state, reload the controller, keep the current URL
$delegate(exception, cause);
};
}]);
}])
.run(['$rootScope','$document','$state','commonArray','shipPurpose','shipSize','hardPointClass','internalGroupMap','hardpointsGroupMap', function ($rootScope, $doc, $state, CArr, shipPurpose, sz, hpc, igMap, hgMap) {
// Redirect any state transition errors to the error controller/state
$rootScope.$on('$stateChangeError', function(e, toState, toParams, fromState, fromParams, error){
e.preventDefault();
$state.go('error',error, {location:false, reload:true}); // Go to error state, reload the controller, keep the current URL
});
// Global Reference variables
$rootScope.CArr = CArr;
@@ -27,7 +47,9 @@ angular.module('app', ['ngRoute', 'shipyard', 'ngLodash', 'n3-line-chart', 'app.
$rootScope.SZ = sz;
$rootScope.HPC = hpc;
$rootScope.igMap = igMap;
window.hgmap = $rootScope.hgMap = hgMap;
$rootScope.ships = DB.ships;
$rootScope.title = 'Coriolis';
// Formatters
$rootScope.fCrd = d3.format(',.0f');

View File

@@ -0,0 +1,15 @@
angular.module('app')
.controller('ErrorController', ['$rootScope','$scope','$stateParams', '$location', function ($rootScope, $scope, $p, $location) {
$rootScope.title = 'Error';
if ($p.path) { // If path is specified, 404
$scope.type = 404; // Deep Space Image...
$scope.message = ""
$scope.path = $p.path;
} else {
$scope.type = $p.type || 'unknown';
$scope.message = $p.message || "Uh, this is bad..";
$scope.path = $location.path();
}
}]);

View File

@@ -0,0 +1,101 @@
angular.module('app').controller('OutfitController', ['$rootScope','$scope', '$state', '$stateParams', 'Ship', 'Components', 'Serializer', 'Persist', function ($rootScope, $scope, $state, $p, Ship, Components, Serializer, Persist) {
var data = DB.ships[$p.shipId];
var ship = new Ship($p.shipId, data.properties, data.slots); // Create a new Ship instance
if ($p.code) {
Serializer.toShip(ship, $p.code); // Populate components from 'code' URL param
$scope.code = $p.code;
} else {
ship.buildWith(data.defaults); // Populate with default components
}
$scope.buildName = $p.bn;
$rootScope.title = ship.name + $scope.buildName? ' - ' + $scope.buildName: '';
$scope.ship = ship;
$scope.pp = ship.common[0]; // Power Plant
$scope.th = ship.common[1]; // Thruster
$scope.fsd = ship.common[2]; // Frame Shrift Drive
$scope.ls = ship.common[3]; // Life Support
$scope.pd = ship.common[4]; // Power Distributor
$scope.ss = ship.common[5]; // Sensors
$scope.ft = ship.common[6]; // Fuel Tank
$scope.hps = ship.hardpoints;
$scope.internal = ship.internal;
$scope.availCS = Components.forShip(ship.id);
$scope.selectedSlot = null;
$scope.lastSaveCode = Persist.getBuild(ship.id, $scope.buildName);
// for debugging
window.myScope = $scope;
$scope.selectSlot = function(e, slot) {
e.stopPropagation();
if ($scope.selectedSlot == slot) {
$scope.selectedSlot = null;
} else {
$scope.selectedSlot = slot;
}
};
$scope.select = function(type, slot, e) {
e.stopPropagation();
if (e.srcElement.id) {
if(type == 'h') {
ship.use(slot, e.srcElement.id, Components.hardpoints(e.srcElement.id));
} else if (type == 'c') {
ship.use(slot, e.srcElement.id, Components.common(ship.common.indexOf(slot), e.srcElement.id));
} else if (type == 'i') {
ship.use(slot, e.srcElement.id, Components.internal(e.srcElement.id));
} else if (type == 'b') {
ship.useBulkhead(slot, e.srcElement.id);
} else {
ship.use(slot, null, null);
}
$scope.selectedSlot = null;
$scope.code = Serializer.fromShip(ship);
$state.go('outfit', {shipId: ship.id, code: $scope.code, bn: $scope.buildName}, {location:'replace', notify:false});
$scope.canSave = true;
}
}
/**
* Reload the build from the last save.
*/
$scope.reloadBuild = function() {
if ($scope.buildName && $scope.lastSaveCode) {
Serializer.toShip(ship, $scope.lastSaveCode); // Repopulate with components from last save
$scope.code = $scope.lastSaveCode;
$state.go('outfit', {shipId: ship.id, code: $scope.lastSaveCode, bn: $scope.buildName}, {location:'replace', notify:false});
}
};
$scope.saveBuild = function() {
if ($scope.code && $scope.code != $scope.lastSaveCode) {
Persist.saveBuild(ship.id, $scope.buildName, $scope.code);
$scope.lastSaveCode = $scope.code;
$rootScope.$broadcast('buildSaved', ship.id, $scope.buildName, $scope.code);
}
}
$scope.deleteBuild = function() {
Persist.deleteBuild(ship.id, $scope.buildName);
$rootScope.$broadcast('buildDeleted', $scope.saveName, ship.id);
$state.go('outfit', {shipId: ship.id, code: null, bn: null}, {location:'replace', reload:true});
}
$rootScope.$on('keyup', function (e, keyEvent) {
if(keyEvent.keyCode == 27) { // on Escape
$scope.selectedSlot = null;
$scope.$apply();
}
else if(keyEvent.keycode == 83 && keyEvent.ctrlKey){ // CTRL + S
e.preventDefault();
$scope.saveBuild();
}
});
$rootScope.$on('bgClicked', function (e, keyEvent) {
$scope.selectedSlot = null;
});
}]);

View File

@@ -1,61 +0,0 @@
angular.module('app')
.controller('ShipController', ['$rootScope','$scope', '$routeParams', '$location', 'ShipFactory', 'components', function ($rootScope, $scope, $p, $loc, ShipFactory, Components) {
$scope.shipId = $p.ship;
// TODO: show 404 if ship not found.
var ship = ShipFactory($scope.shipId, DB.ships[$scope.shipId], $p.code);
$scope.ship = ship;
$scope.pp = ship.common[0]; // Power Plant
$scope.th = ship.common[1]; // Thruster
$scope.fsd = ship.common[2]; // Frame Shrift Drive
$scope.ls = ship.common[3]; // Life Support
$scope.pd = ship.common[4]; // Power Distributor
$scope.ss = ship.common[5]; // Sensors
$scope.ft = ship.common[6]; // Fuel Tank
$scope.hps = ship.hardpoints;
$scope.internal = ship.internal;
$scope.availCS = Components.forShip($scope.shipId);
$scope.selectedSlot = null;
// for debugging
window.ship = ship;
window.availcs = $scope.availCS;
$scope.selectSlot = function(e, slot) {
e.stopPropagation();
if ($scope.selectedSlot == slot) {
$scope.selectedSlot = null;
} else {
$scope.selectedSlot = slot;
}
};
$scope.selectComponent = function(slot, id, component) {
ship.use(slot, id, component);
$scope.selectedSlot = null;
$loc.path(ship.id + '/' + ship.code, false).replace();
}
$scope.hideMenus = function() {
$scope.selectedSlot = null;
}
$rootScope.$on('keyup', function (e, keyEvent) {
if(keyEvent.keyCode == 27) { // on Escape
$scope.hideMenus();
$scope.$apply();
}
// TODO: CTRL+S -> Save
});
$rootScope.$on('bgClicked', function (e, keyEvent) {
$scope.hideMenus();
});
// TODO: Save build
// TODO: name build + save
// Push new url history in this case
// TODO: delete build
// TODO: reset to ship defaults
// TODO: revert to last save
}]);

View File

@@ -1,4 +1,4 @@
angular.module('app')
.controller('ShipyardController', function () {
});
.controller('ShipyardController', ['$rootScope', function ($rootScope) {
$rootScope.title = 'Coriolis - Shipyard';
}]);

View File

@@ -2,15 +2,39 @@ angular.module('app').directive('componentSelect', [ function() {
return {
restrict: 'A',
scope:{
opts: '=', // Component Options object
slot: '=', // Slot Object
selectComponent: '&sc' // Select Component function
opts: '=', // Component Options object
},
templateUrl: 'views/component_select.html',
link: function (scope) {
scope.use = function(id, component) {
scope.selectComponent({s: scope.slot, id: id, c: component});
};
link: function(scope, element) {
var list = [], o, id;
var opts = scope.opts;
//TODO: take current ship mass into account if provided
// Generting the HTML in this manner is MUCH faster than using an angular template.
for (id in opts) {
o = opts[id];
list.push('<li class="');
list.push(o.name? 'lc' : 'c');
if (false) { // Omit id if mass is exceeded making it 'disabled'
list.push(' disabled"');
} else {
list.push('" id="');
}
list.push(id);
list.push('">');
list.push(o.class);
list.push(o.rating);
if(o.mode) {
list.push('/' + o.mode);
if(o.missile) {
list.push(o.missile);
}
}
if(o.name) {
list.push(' ' + o.name);
}
list.push('</li>');
}
element.html('<ul>' + list.join('') + '</ul>');
}
};
}]);

View File

@@ -1,4 +1,4 @@
angular.module('app').directive('shipRange', ['$rootScope','CalcJumpRange', function ($r, calcJumpRange) {
angular.module('app').directive('shipRange', ['$rootScope','calcJumpRange', function ($r, calcJumpRange) {
return {
restrict: 'A',

View File

@@ -1,12 +1,12 @@
angular.module('app').directive('hardpoint', ['$rootScope', function ($r) {
angular.module('app').directive('slotHardpoint', ['$rootScope', function ($r) {
return {
restrict: 'A',
scope:{
hp: '=',
size: '=',
opts: '='
lbl: '=',
},
templateUrl: 'views/hardpoint.html',
templateUrl: 'views/slot-hardpoint.html',
link: function (scope) {
scope.$r = $r;
}

View File

@@ -1,12 +1,12 @@
angular.module('app').directive('slotDetails', ['$rootScope', function ($r) {
angular.module('app').directive('slotInternal', ['$rootScope', function ($r) {
return {
restrict: 'A',
scope:{
c: '=',
c: '=slot',
lbl: '=',
opts: '='
},
templateUrl: 'views/slot.html',
templateUrl: 'views/slot-internal.html',
link: function(scope) {
scope.$r = $r;
}

58
app/js/service-persist.js Normal file
View File

@@ -0,0 +1,58 @@
angular.module('app').service('Persist', ['lodash', function (_) {
var LS_KEY = 'builds';
var buildJson = localStorage.getItem(LS_KEY);
if (buildJson) {
this.builds = angular.fromJson(localStorage.getItem(LS_KEY));
} else {
this.builds = {};
}
/**
* 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.builds[shipId]) {
this.builds[shipId] = {};
}
this.builds[shipId][name] = code;
localStorage.setItem(LS_KEY, angular.toJson(this.builds)); // Persist updated build collection to localstorage
}
/**
* 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]) {
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) {
delete build[shipId][name];
if (Object.keys(build[shipId]).length == 0) {
delete build[shipId];
}
}
}]);

View File

@@ -0,0 +1,69 @@
/**
* Service managing seralization and deserialization of models for use in URLs and persistene.
*/
angular.module('app').service('Serializer', ['lodash', function (_) {
/**
* 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 data = [
ship.bulkheads.id,
_.map(ship.common, idToStr),
_.map(ship.hardpoints, idToStr),
_.map(ship.internal, idToStr),
];
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} code The string to deserialize
*/
this.toShip = function (ship, code) {
var commonCount = ship.common.length;
var hpCount = commonCount + ship.hardpoints.length;
var comps = {
bulkheads: code.charAt(0) * 1,
common: new Array(ship.common.length),
hardpoints: new Array(ship.hardpoints.length),
internal: new Array(ship.internal.length)
};
// TODO: improve...
for (var i = 1, c = 0, l = code.length; i < l; i++) {
var empty = code.charAt(i) == '-';
if (c < commonCount) {
comps.common[c] = empty? 0 : code.substring(i, i + 2);
} else if (c < hpCount) {
comps.hardpoints[c - commonCount] = empty? 0 : code.substring(i, i + 2);
} else {
comps.internal[c - hpCount] = empty? 0 : code.substring(i, i + 2);
}
if (!empty) {
i++;
}
c++;
}
ship.buildWith(comps);
};
/**
* 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 idToStr(slot) {
return (slot.id === null)? '-' : slot.id;
}
}]);

View File

@@ -1,40 +1,45 @@
angular.module('shipyard').factory('components', ['lodash', function (_) {
var C = DB.components;
angular.module('shipyard').factory('ComponentSet', ['lodash', function (_) {
function ComponentSet(shipId) {
var ship = DB.ships[shipId];
var maxInternal = ship.slotCap.internal[0];
this.mass = ship.mass;
function ComponentSet(components, mass, maxCommonArr, maxInternal, maxHardPoint) {
this.mass = mass;
this.common = {};
this.internal = {};
this.hardpoints = filter(C.hardpoints, ship.slotCap.hardpoints[0], 0, ship.mass);
this.bulkheads = C.bulkheads[shipId];
this.hardpoints = {};
this.hpClass = {};
this.intClass = {};
for (var i = 0; i < C.common.length; i ++) {
var max = ship.slotCap.common[i];
for (var i = 0; i < components.common.length; i ++) {
var max = maxCommonArr[i];
switch (i) {
// Slots where component class must be equal to slot class
case 3: // Life Support
case 5: // Sensors
this.common[i] = filter(C.common[i], max, max, ship.mass);
this.common[i] = filter(components.common[i], max, max, this.mass);
break;
// Other slots can have a component of class lower than the slot class
default:
this.common[i] = filter(C.common[i], max, 0, ship.mass);
this.common[i] = filter(components.common[i], max, 0, this.mass);
}
}
for(var g in C.internal) {
this.internal[g] = filter(C.internal[g], maxInternal, 0, ship.mass);
for(var h in components.hardpoints) {
this.hardpoints[h] = filter(components.hardpoints[h], maxHardPoint, 0, this.mass);
}
for(var g in components.internal) {
this.internal[g] = filter(components.internal[g], maxInternal, 0, this.mass);
}
}
ComponentSet.prototype.getHps = function(c) {
if(!this.hpClass[c]) {
this.hpClass[c] = filter(this.hardpoints, c, c? 1 : 0, this.mass);
var o = this.hpClass[c] = {};
for(var key in this.hardpoints) {
var data = filter(this.hardpoints[key], c, c? 1 : 0, this.mass);
if(Object.keys(data).length) { // If group is not empty
o[key] = data;
}
}
}
return this.hpClass[c];
};
@@ -44,7 +49,7 @@ angular.module('shipyard').factory('components', ['lodash', function (_) {
var o = this.intClass[c] = {};
for(var key in this.internal) {
var data = filter(this.internal[key], c, 0, this.mass);
if(Object.keys(data).length) {
if(Object.keys(data).length) { // If group is not empty
o[key] = data;
}
}
@@ -62,16 +67,6 @@ angular.module('shipyard').factory('components', ['lodash', function (_) {
return set;
}
return {
forShip: function (shipId) {
return new ComponentSet(shipId);
},
findInternal: function(id) {
var c = _.find(C.internal, function(o) {
return o[id];
})
return c[id];
}
};
return ComponentSet;
}]);

View File

@@ -1,47 +1,30 @@
angular.module('shipyard').factory('ShipFactory', ['components', 'CalcShieldStrength', 'CalcJumpRange', 'lodash', function (Components, calcShieldStrength, calcJumpRange, _) {
angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', 'calcJumpRange', 'lodash', function (Components, calcShieldStrength, calcJumpRange, _) {
/**
* Ship model used to track all ship components and properties.
*
* @param {string} id Unique ship Id / Key
* @param {object} shipData Data/defaults from the Ship database.
* @param {string} id Unique ship Id / Key
* @param {object} properties Basic ship properties such as name, manufacturer, mass, etc
* @param {object} slots Collection of slot groups (standard/common, internal, hardpoints) with their max class size.
*/
function Ship(id, shipData) {
function Ship(id, properties, slots) {
this.id = id;
this.defaults = shipData.defaultComponents;
this.incCost = true;
this.cargoScoop = { enabled: true, c: { name: 'Cargo Scoop', class: 1, rating: 'H', power: 0.6} };
this.sgSI = null; // Shield Generator Slot Index
this.cargoScoop = { enabled: true, c: Components.cargoScoop() };
this.bulkheads = { incCost: true, maxClass: 8 };
this.sgSI = null; // Shield Generator Index
// Copy all base properties from shipData
angular.forEach(shipData,function(o,k){
if(typeof o != 'object') {
this[k] = o;
}
}.bind(this));
for (p in properties) { this[p] = properties[p]; } // Copy all base properties from shipData
angular.forEach(shipData.slotCap, function (slots, slotGroup) { // Initialize all slots
this[slotGroup] = []; // Initialize Slot group (Common, Hardpoints, Internal)
for(var i = 0; i < slots.length; i++){
this[slotGroup].push({id: null, c: null, enabled: true, incCost: true, maxClass: slots[i]});
for (groupName in slots) { // Initialize all slots
var slotGroup = slots[groupName];
var group = this[groupName] = []; // Initialize Slot group (Common, Hardpoints, Internal)
for(var i = 0; i < slotGroup.length; i++){
group.push({id: null, c: null, enabled: true, incCost: true, maxClass: slotGroup[i]});
}
}.bind(this));
}
}
/**
* Reset the ship to the original 'manufacturer' defaults.
*/
Ship.prototype.clear = function() {
this.buildWith(DB.ships[this.id].defaultComponents);
};
/**
* Reset the current build to the previously used default
*/
Ship.prototype.reset = function() {
this.buildWith(this.defaults);
};
/**
* Builds/Updates the ship instance with the components[comps] passed in.
* @param {object} comps Collection of components used to build the ship
@@ -50,98 +33,37 @@ angular.module('shipyard').factory('ShipFactory', ['components', 'CalcShieldStre
var internal = this.internal;
var common = this.common;
var hps = this.hardpoints;
var availCommon = DB.components.common;
var availHardPoints = DB.components.hardpoints;
var availInternal = DB.components.internal;
var i,l;
this.bulkheads = { incCost: true, maxClass: 8, id: comps.bulkheads || 0, c: DB.components.bulkheads[this.id][comps.bulkheads || 0] };
this.bulkheads.id = comps.bulkheads || 0;
this.bulkheads.c = Components.bulkheads(this.id, this.bulkheads.id);
for(i = 0, l = comps.common.length; i < l; i++) {
common[i].id = comps.common[i];
common[i].c = availCommon[i][comps.common[i]];
common[i].c = Components.common(i, comps.common[i]);
}
for(i = 0, l = comps.hardpoints.length; i < l; i++) {
if(comps.hardpoints[i] !== 0) {
if (comps.hardpoints[i] !== 0) {
hps[i].id = comps.hardpoints[i];
hps[i].c = availHardPoints[comps.hardpoints[i]];
hps[i].c = Components.hardpoints(comps.hardpoints[i]);
} else {
hps[i].c = hps[i].id = null;
}
}
for(i = 0, l = comps.internal.length; i < l; i++) {
if(comps.internal[i] !== 0) {
if (comps.internal[i] !== 0) {
internal[i].id = comps.internal[i];
internal[i].c = Components.findInternal(comps.internal[i]);
if(internal[i].c.group == 'sg') {
internal[i].c = Components.internal(comps.internal[i]);
if (internal[i].c.group == 'sg') {
this.sgSI = i;
}
}
}
this.code = this.toCode();
this.updateTotals();
};
/**
* Serializes the selected components for all slots to a URL friendly string.
* @return {string} Encoded string of components
*/
Ship.prototype.toCode = function() {
var data = [
this.bulkheads.id,
_.map(this.common, idToStr),
_.map(this.hardpoints, idToStr),
_.map(this.internal, idToStr),
];
return _.flatten(data).join('');
};
/**
* 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 idToStr(slot) {
return (slot.id === null)? '-' : slot.id;
}
/**
* Updates the current ship instance's slots with components determined by the
* code.
*
* @param {string} code [description]
*/
Ship.prototype.buildFromCode = function (code) {
var commonCount = this.common.length;
var hpCount = commonCount + this.hardpoints.length;
var comps = {
bulkheads: code.charAt(0) * 1,
common: new Array(this.common.length),
hardpoints: new Array(this.hardpoints.length),
internal: new Array(this.internal.length)
};
// TODO: improve...
for (var i = 1, c = 0, l = code.length; i < l; i++) {
var isNull = code.charAt(i) == '-';
if (c < commonCount) {
comps.common[c] = isNull? 0 : code.substring(i, i + 2);
} else if (c < hpCount) {
comps.hardpoints[c - commonCount] = isNull? 0 : code.substring(i, i + 2);
} else {
comps.internal[c - hpCount] = isNull? 0 : code.substring(i, i + 2);
internal[i].id = internal[i].c = null;
}
if (!isNull) {
i++;
}
c++;
}
this.defaults = comps;
this.buildWith(comps);
this.updateTotals();
};
/**
@@ -171,7 +93,6 @@ angular.module('shipyard').factory('ShipFactory', ['components', 'CalcShieldStre
// TODO: shield recharge rate
// TODO: armor bonus / damage reduction for bulkheads
// TODO: thermal load and weapon recharge rate
this.code = this.toCode();
};
/**
@@ -195,6 +116,10 @@ angular.module('shipyard').factory('ShipFactory', ['components', 'CalcShieldStre
return sum;
}
function findInternal(slots, group) {
}
Ship.prototype.useBulkhead = function(index) {
this.bulkheads.id = index;
this.bulkheads.c = DB.components.bulkheads[this.id][index];
@@ -238,21 +163,5 @@ angular.module('shipyard').factory('ShipFactory', ['components', 'CalcShieldStre
}
};
/**
* Ship Factory function. Created a new instance of a ship based on the ship type.
*
* @param {string} id Id/Key for the Ship type
* @param {object} shipData [description]
* @param {string} code [optional] Code to build the ship with
* @return {Ship} A new Ship instance
*/
return function (id, shipData, code) {
var s = new Ship(id, shipData);
if (code) {
s.buildFromCode(code);
} else {
s.clear();
}
return s;
};
return Ship;
}]);

View File

@@ -1,3 +1,9 @@
/**
* 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.
*/
angular.module('shipyard', [])
.value('commonArray', [
'Power Plant',
@@ -13,14 +19,33 @@ angular.module('shipyard', [])
sc:'Scanners',
am:'Auto Field-Maintenance Unit',
cr:'Cargo Racks',
fi:'Frame Shift Drive Interdictor',
hb:'Hatch Breaker Limpet Controller',
fi:'FSD Interdictor',
hb:'Hatch Breaker Limpet Ctrl',
hr:'Hull Reinforcement Package',
rf:'Refinery',
sb:'Shield Cell Bank',
sg:'Shield Generator',
dc:'Docking Computer'
})
.value('hardpointsGroupMap', {
'bl': "Beam Laser",
'ul': "Burst Laser",
'c': "Cannon",
'cs': "Cargo Scanner",
'cm': "Countermeasure",
'fc': "Fragment Cannon",
'fs': "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"
})
.value('shipPurpose', {
mp: 'Multi Purpose',
fr: 'Freighter',
@@ -35,13 +60,6 @@ angular.module('shipyard', [])
'Large',
'Capital',
])
.factory('commonMap', ['commonArray', function (commonArray) {
var commonMap = {};
for(var i = 0; i < commonArray.length; i++) {
commonMap[commonArray[i]] = i;
}
return commonMap;
}])
.value('hardPointClass', [
'Utility',
'Small',
@@ -49,53 +67,7 @@ angular.module('shipyard', [])
'Large',
'Huge'
])
.factory('hardpointGroup', function () {
function groupToLabel (grp) {
var a = grp.toLowerCase().split('');
var l = [];
switch(a[0]) {
case 's':
l.push('Small');
break;
case 'm':
l.push('Medium');
break;
case 'l':
l.push('Large');
break;
case 'h':
l.push('Huge');
break;
case 'u':
l.push('Utility');
break;
}
switch(a[1]) {
case 'o':
l.push('Other');
break;
case 'k':
l.push('Kinetic');
break;
case 't':
l.push('Thermal');
break;
case 's':
l.push('Scanner');
break;
case 'b':
l.push('Booster');
break;
case 'm':
l.push('Mount');
break;
}
return l.join(' ');
}
return groupToLabel;
})
.factory('CalcJumpRange', function() {
.factory('calcJumpRange', function() {
/**
* 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
@@ -107,7 +79,7 @@ angular.module('shipyard', [])
return Math.pow(Math.min(fuel || Infinity, fsd.maxfuel) / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass;
};
})
.factory('CalcShieldStrength', function() {
.factory('calcShieldStrength', function() {
/**
* Calculate the a ships shield strength based on mass, shield generator and shield boosters used.
*
@@ -119,6 +91,9 @@ angular.module('shipyard', [])
* @return {number} Approximate shield strengh in MJ
*/
return function (mass, shields, sg, multiplier) {
if (!sg) {
return 0;
}
if (mass <= sg.minmass) {
return shields * multiplier * sg.minmul;
}

View File

@@ -0,0 +1,35 @@
angular.module('shipyard').service('Components', ['lodash', 'ComponentSet', function (_, ComponentSet) {
var C = DB.components;
this.cargoScoop = function() {
return { name: 'Cargo Scoop', class: 1, rating: 'H', power: 0.6};
}
this.common = function (typeIndex, componentId) {
return C.common[typeIndex][componentId];
};
this.hardpoints = function(id) {
var c = _.find(C.hardpoints, function(o) {
return o[id];
})
return c[id];
};
this.internal = function(id) {
var c = _.find(C.internal, function(o) {
return o[id];
})
return c[id];
};
this.bulkheads = function(shipId, bulkheadsId) {
return C.bulkheads[shipId][bulkheadsId];
};
this.forShip = function (shipId) {
var ship = DB.ships[shipId];
return new ComponentSet(C, ship.properties.mass, ship.slots.common, ship.slots.internal[0], ship.slots.hardpoints[0]);
};
}]);