mirror of
https://github.com/EDCD/coriolis.git
synced 2025-12-08 14:33:22 +00:00
260 lines
8.6 KiB
JavaScript
260 lines
8.6 KiB
JavaScript
angular.module('shipyard').factory('ShipFactory', ['components', 'lodash', function (Components, _) {
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
function Ship(id, shipData) {
|
|
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
|
|
|
|
angular.forEach(shipData,function(o,k){
|
|
if(typeof o != 'object') {
|
|
this[k] = o;
|
|
} else if (k == 'slotCap') {
|
|
angular.forEach(o,function(arr,g){
|
|
this[g] = [];
|
|
for(var i = 0; i < arr.length; i++){
|
|
this[g].push({
|
|
enabled: true,
|
|
incCost: true,
|
|
maxClass: arr[i]
|
|
});
|
|
}
|
|
}.bind(this));
|
|
}
|
|
}.bind(this));
|
|
}
|
|
|
|
/**
|
|
* Reset the ship to the original purchase 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
|
|
*/
|
|
Ship.prototype.buildWith = function(comps) {
|
|
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, id: comps.bulkheads || 0, c: DB.components.bulkheads[this.id][comps.bulkheads || 0] };
|
|
|
|
for(i = 0, l = comps.common.length; i < l; i++) {
|
|
common[i].id = comps.common[i];
|
|
common[i].c = availCommon[i][comps.common[i]];
|
|
}
|
|
|
|
for(i = 0, l = comps.hardpoints.length; i < l; i++) {
|
|
if(comps.hardpoints[i] !== 0) {
|
|
hps[i].id = comps.hardpoints[i];
|
|
hps[i].c = availHardPoints[comps.hardpoints[i]];
|
|
}
|
|
}
|
|
|
|
for(i = 0, l = comps.internal.length; i < l; i++) {
|
|
if(comps.internal[i] !== 0) {
|
|
internal[i].id = comps.internal[i];
|
|
internal[i].c = availInternal[comps.internal[i]];
|
|
}
|
|
}
|
|
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 === undefined? '-' : 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++) {
|
|
if(code.charAt(i) != '-') {
|
|
if (c < commonCount) {
|
|
comps.common[c] = code.substring(i, i + 2);
|
|
} else if (c < hpCount) {
|
|
comps.hardpoints[c - commonCount] = code.substring(i, i + 2);
|
|
} else {
|
|
comps.internal[c - hpCount] = code.substring(i, i + 2);
|
|
}
|
|
i++;
|
|
}
|
|
c++;
|
|
}
|
|
|
|
this.defaults = comps;
|
|
this.buildWidth(comps);
|
|
};
|
|
|
|
/**
|
|
* Updates the ship totals based on currently selected component in each slot.
|
|
*/
|
|
Ship.prototype.updateTotals = function() {
|
|
var c = _.reduce(this.common, optsSum, {cost: 0, power: 0, mass: 0, capacity: 0});
|
|
var i = _.reduce(this.internal, optsSum, {cost: 0, power: 0, mass: 0, capacity: 0});
|
|
var h = _.reduce(this.hardpoints, optsSum, {cost: 0, power: 0, mass: 0, capacity: 0});
|
|
|
|
this.totalCost = c.cost + i.cost + h.cost + (this.incCost? this.cost : 0) + (this.bulkheads.incCost? this.bulkheads.c.cost : 0);
|
|
this.unladenMass = c.mass + i.mass + h.mass + this.mass + this.bulkheads.c.mass;
|
|
this.powerAvailable = this.common[0].c.pGen;
|
|
this.fuelCapacity = this.common[6].c.capacity;
|
|
this.cargoCapacity = i.capacity;
|
|
this.ladenMass = this.unladenMass + this.cargoCapacity + this.fuelCapacity;
|
|
this.powerRetracted = c.power + i.power + (this.cargoScoop.enabled? this.cargoScoop.c.power : 0);
|
|
this.powerDeployed = this.powerRetracted + h.power;
|
|
|
|
// TODO: range
|
|
this.calcShieldStrength = this.sgSI !== null? calcShieldStrength(this.mass, this.shields, this.internal[this.sgSI], 1) : 0;
|
|
this.armourAdded = 0; // internal.armoradd TODO: Armour (reinforcement, bulkheads)
|
|
this.armorTotal = this.armourAdded + this.armour;
|
|
};
|
|
|
|
/**
|
|
* Update a slot with a the component if the id is different from the current id for this slot.
|
|
* Frees the slot of the current component if the id matches the current id for the slot.
|
|
*
|
|
* @param {object} slot The component slot
|
|
* @param {string} id Unique ID for the selected component
|
|
* @param {object} component Properties for the selected component
|
|
*/
|
|
Ship.prototype.use = function(slot, id, component) {
|
|
if (slot.id != id) { // Selecting a different component
|
|
slot.id = id;
|
|
slot.c = component;
|
|
|
|
// Selected componnent is a Shield Generator
|
|
if(component.group == 'sg') {
|
|
var slotIndex = this.internal.indexOf(slot);
|
|
// You can only have one shield Generator
|
|
if (this.sgSI !== null && this.sgSI != slotIndex) {
|
|
// A shield generator is already selected in a different slot
|
|
this.internal[this.sgSI].id = null;
|
|
this.internal[this.sgSI].c = null;
|
|
}
|
|
this.sgSI = slotIndex;
|
|
}
|
|
} else {
|
|
// Deselect current component
|
|
slot.id = null;
|
|
slot.c = null;
|
|
}
|
|
this.updateTotals();
|
|
};
|
|
|
|
/**
|
|
* Calculate the a ships shield strength based on mass, shield generator and shield boosters used.
|
|
*
|
|
* @private
|
|
* @param {number} mass Current mass of the ship
|
|
* @param {number} shields Base Shield strength MJ for ship
|
|
* @param {object} sg The shield generator used
|
|
* @param {number} multiplier Shield multiplier for ship (1 + shield boosters if any)
|
|
* @return {number} Approximate shield strengh in MJ
|
|
*/
|
|
function calcShieldStrength (mass, shields, sg, multiplier) {
|
|
if (mass <= sg.minmass) {
|
|
return shields * multiplier * sg.minmul;
|
|
}
|
|
if (mass < sg.optmass) {
|
|
return shields * multiplier * (sg.minmul + (mass - sg.minmass) / (sg.optmass - sg.minmass) * (sg.optmul - sg.minmul));
|
|
}
|
|
if (mass < sg.maxmass) {
|
|
return shields * multiplier * (sg.optmul + (mass - sg.optmass) / (sg.maxmass - sg.optmass) * (sg.maxmul - sg.optmul));
|
|
}
|
|
return shields * multiplier * sg.maxmul;
|
|
}
|
|
|
|
/**
|
|
* Utilify function for summing the components properties
|
|
*
|
|
* @private
|
|
* @param {object} sum Sum of cost, power, mass, capacity
|
|
* @param {object} slot Slot object
|
|
* @return {object} The mutated sum object
|
|
*/
|
|
function optsSum(sum, slot) {
|
|
if (slot.c) { // The slot has a component selected
|
|
sum.cost += (slot.incCost && slot.c.cost)? slot.c.cost : 0;
|
|
sum.power += (slot.enabled && slot.c.power)? slot.c.power : 0;
|
|
sum.mass += slot.c.mass || 0;
|
|
sum.capacity += slot.c.capacity || 0;
|
|
}
|
|
return sum;
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
};
|
|
}]);
|