mirror of
https://github.com/EDCD/coriolis.git
synced 2025-12-08 14:33:22 +00:00
1103 lines
36 KiB
JavaScript
Executable File
1103 lines
36 KiB
JavaScript
Executable File
import * as ModuleUtils from './ModuleUtils';
|
|
import { Modifications } from 'coriolis-data/dist';
|
|
import React from 'react';
|
|
import { STATS_FORMATTING, SI_PREFIXES } from './StatsFormatting';
|
|
|
|
/**
|
|
* Module - active module in a ship's buildout
|
|
*/
|
|
export default class Module {
|
|
/**
|
|
* Construct a new module
|
|
* @param {Object} params Module parameters. Either grp/id or template
|
|
*/
|
|
constructor(params) {
|
|
let properties = Object.assign({ grp: null, id: null, template: null }, params);
|
|
|
|
if (properties.class != undefined) {
|
|
// We already have a fully-formed module; copy the data over
|
|
for (let p in properties) { this[p] = properties[p]; }
|
|
} else if (properties.template != undefined) {
|
|
// We have a template from coriolis-data; copy the data over
|
|
for (let p in properties.template) { this[p] = properties.template[p]; }
|
|
} else {
|
|
// We don't have a template; find it given the group and ID
|
|
return ModuleUtils.findModule(properties.grp, properties.id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clone an existing module
|
|
* @return {Object} A clone of the existing module
|
|
*/
|
|
clone() {
|
|
return new Module(JSON.parse(JSON.stringify(this)));
|
|
}
|
|
|
|
/**
|
|
* Get a value for a given modification
|
|
* @param {Number} name The name of the modification
|
|
* @param {Number} raw True if the value returned should be raw i.e. without the influence of special effects
|
|
* @return {object} The value of the modification. If it is a numeric value then it is returned as an integer value scaled so that 1.23% == 123
|
|
*/
|
|
getModValue(name, raw) {
|
|
let baseVal = this[name];
|
|
let result = this.mods && this.mods[name] ? this.mods[name] : null;
|
|
|
|
if ((!raw) && this.blueprint && this.blueprint.special) {
|
|
// This module has a special effect, see if we need to alter our returned value
|
|
const modifierActions = Modifications.modifierActions[this.blueprint.special.edname];
|
|
if (modifierActions && modifierActions[name]) {
|
|
// this special effect modifies our returned value
|
|
const modification = Modifications.modifications[name];
|
|
const multiplier = modification.type === 'percentage' ? 10000 : 100;
|
|
if (name === 'explres' || name === 'kinres' || name === 'thermres' || name === 'causres') {
|
|
// Apply resistance modding mechanisms to special effects subsequently
|
|
result = result + modifierActions[name] * (1 - (this[name] + result / multiplier)) * 100;
|
|
} else if (modification.method === 'additive') {
|
|
result = result + modifierActions[name] * 100;
|
|
} else if (modification.method === 'overwrite') {
|
|
result = modifierActions[name];
|
|
} else {
|
|
// rate of fire is special, as it's really burst interval. Handle that here
|
|
let mod = null;
|
|
if (name === 'rof') {
|
|
mod = 1 / (1 + modifierActions[name]) - 1;
|
|
} else {
|
|
mod = modifierActions[name];
|
|
}
|
|
result = (((1 + result / multiplier) * (1 + mod)) - 1) * multiplier;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Sanitise the resultant value to 4dp equivalent
|
|
return isNaN(result) ? result : Math.round(result);
|
|
}
|
|
|
|
/**
|
|
* Set a value for a given modification ID
|
|
* @param {Number} name The name of the modification
|
|
* @param {object} value The value of the modification. If it is a numeric value then it should be an integer scaled so that -2.34% == -234
|
|
* @param {Boolean} valueiswithspecial true if the value includes the special effect (when coming from a UI component)
|
|
*/
|
|
setModValue(name, value, valueiswithspecial) {
|
|
if (!this.mods) {
|
|
this.mods = {};
|
|
}
|
|
if (!this.origVals) {
|
|
this.origVals = {};
|
|
}
|
|
if (valueiswithspecial && this.blueprint && this.blueprint.special) {
|
|
// This module has a special effect, see if we need to alter the stored value
|
|
const modifierActions = Modifications.modifierActions[this.blueprint.special.edname];
|
|
if (modifierActions && modifierActions[name]) {
|
|
// This special effect modifies the value being set, so we need to revert it prior to storing the value
|
|
const modification = Modifications.modifications[name];
|
|
if (name === 'explres' || name === 'kinres' || name === 'thermres' || name === 'causres') {
|
|
let res = (this[name] ? this[name] : 0) + value / 10000;
|
|
let experimental = modifierActions[name] / 100;
|
|
value = (experimental - res) / (experimental - 1) - this[name];
|
|
value *= 10000;
|
|
// value = ((baseMult - value / 10000) / (1 - modifierActions[name] / 100) - baseMult) * -10000;
|
|
} else if (modification.method === 'additive') {
|
|
value = value - modifierActions[name];
|
|
} else if (modification.method === 'overwrite') {
|
|
value = null;
|
|
} else {
|
|
// rate of fire is special, as it's really burst interval. Handle that here
|
|
let mod = null;
|
|
if (name === 'rof') {
|
|
mod = 1 / (1 + modifierActions[name]) - 1;
|
|
} else {
|
|
mod = modifierActions[name];
|
|
}
|
|
value = ((value / 10000 + 1) / (1 + mod) - 1) * 10000;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (value == null || value == 0) {
|
|
delete this.mods[name];
|
|
} else {
|
|
this.mods[name] = value;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper to obtain a module's value.
|
|
* @param {String} name The name of the modifier to obtain
|
|
* @param {Number} modified Whether to return the raw or modified value
|
|
* @return {Number} The value queried
|
|
*/
|
|
get(name, modified = true) {
|
|
let val;
|
|
if (modified) {
|
|
val = this._getModifiedValue(name);
|
|
} else {
|
|
val = this[name];
|
|
}
|
|
return isNaN(val) ? null : val;
|
|
}
|
|
|
|
/**
|
|
* Sets mod values such that the overall result for the given stat equals value
|
|
* @param {String} name The name of the modification
|
|
* @param {Number} value The value to effectively set
|
|
* @param {Boolean} valueIsWithSpecial True when value includes an special
|
|
* effects
|
|
*/
|
|
set(name, value, valueIsWithSpecial) {
|
|
const modification = Modifications.modifications[name];
|
|
if (!modification || isNaN(value)) {
|
|
// TODO: throw?
|
|
return;
|
|
}
|
|
|
|
let baseValue = this[name];
|
|
let modValue = 0;
|
|
if (modification.method === 'overwrite') {
|
|
modValue = value;
|
|
} else if (modification.method === 'additive') {
|
|
// additive modifications can be given without a base value
|
|
if (!baseValue) {
|
|
baseValue = 0;
|
|
}
|
|
modValue = value - baseValue;
|
|
} else if (name === 'shieldboost' || name === 'hullboost') {
|
|
modValue = (1 + value) / (1 + baseValue) - 1;
|
|
} else { // multiplicative
|
|
modValue = baseValue == 0 ? 0 : value / baseValue - 1;
|
|
}
|
|
|
|
if (modification.type === 'percentage') {
|
|
modValue = modValue * 10000;
|
|
} else if (modification.type === 'numeric' && name !== 'burst' &&
|
|
name !== 'burstrof') {
|
|
modValue = modValue * 100;
|
|
}
|
|
|
|
this.setModValue(name, modValue, valueIsWithSpecial);
|
|
}
|
|
|
|
/**
|
|
* Returns a value for a given modification in pretty format, i.e. percentages
|
|
* are returned as 90 not as 0.9.
|
|
* @param {String} name Name of the modification to get the value for
|
|
* @param {Boolean} [modified = true] If set to false, the raw value of the
|
|
* raw value of the stat is returned
|
|
* @param {Number} [places = 2] Number of decimal places to round
|
|
* @return {Number} Value for given stat
|
|
*/
|
|
getPretty(name, modified = true, places = 2) {
|
|
const formattingOptions = STATS_FORMATTING[name];
|
|
let val = this.get(name, modified) || 0;
|
|
if (formattingOptions && formattingOptions.format.startsWith('pct')) {
|
|
return 100 * val;
|
|
}
|
|
// Round to two decimal places
|
|
let precisionMult = 10 ** places;
|
|
return Math.round(val * precisionMult) / precisionMult;
|
|
}
|
|
|
|
/**
|
|
* Same as {@see Module#set} but values expects value that are percentages to
|
|
* come in format 90 as opposed to 0.9.
|
|
* @param {String} name The name of the modification
|
|
* @param {Number} value The value to effectively set
|
|
* @param {Boolean} valueIsWithSpecial True when value includes an special
|
|
*/
|
|
setPretty(name, value, valueIsWithSpecial) {
|
|
const formattingOptions = STATS_FORMATTING[name];
|
|
if (formattingOptions && formattingOptions.format.startsWith('pct')) {
|
|
value = value / 100;
|
|
}
|
|
this.set(name, value, valueIsWithSpecial);
|
|
}
|
|
|
|
/**
|
|
* Helper to obtain a modified value using standard multipliers
|
|
* @param {String} name the name of the modifier to obtain
|
|
* @return {Number} the value queried
|
|
*/
|
|
_getModifiedValue(name) {
|
|
const modification = Modifications.modifications[name];
|
|
let result = this[name];
|
|
|
|
if (modification) {
|
|
// We store percentages as decimals, so to get them back we need to divide by 10000. Otherwise
|
|
// we divide by 100. Both ways we end up with a value with two decimal places
|
|
let modValue;
|
|
if (modification.type === 'percentage') {
|
|
modValue = this.getModValue(name) / 10000;
|
|
} else if (modification.type === 'numeric') {
|
|
modValue = this.getModValue(name) / 100;
|
|
} else {
|
|
modValue = this.getModValue(name);
|
|
}
|
|
if (modValue) {
|
|
if (!result && modification.method === 'additive') {
|
|
// If the modification is additive and no value is given by default we
|
|
// start at zero
|
|
result = 0;
|
|
}
|
|
|
|
if (result !== undefined) {
|
|
if (modification.method === 'additive') {
|
|
result = result + modValue;
|
|
} else if (modification.method === 'overwrite') {
|
|
result = modValue;
|
|
} else if (name === 'shieldboost' || name === 'hullboost') {
|
|
result = (1 + result) * (1 + modValue) - 1;
|
|
} else {
|
|
result = result * (1 + modValue);
|
|
}
|
|
} else if (name === 'burstrof') {
|
|
// Burst and burst rate of fire are special, as it can not exist but
|
|
// have a modification
|
|
result = modValue / 100;
|
|
}
|
|
}
|
|
}
|
|
|
|
return isNaN(result) ? null : result;
|
|
}
|
|
|
|
/**
|
|
* Creates a react element that pretty-prints the queried module value
|
|
* @param {String} name The name of the value
|
|
* @param {object} language Language object holding formats and util functions
|
|
* @param {String} [unit] If unit is given not the stat's default formatting
|
|
* unit will be applied but the given one taking into
|
|
* account SI-prefixes such as kilo, milli, etc.
|
|
* @param {Number} [val] If val is given, not the modules value but given
|
|
* one will be formated
|
|
* @returns {React.Component} The formated value as component
|
|
*/
|
|
formatModifiedValue(name, language, unit, val) {
|
|
const formattingOptions = STATS_FORMATTING[name];
|
|
if (val === undefined) {
|
|
if (formattingOptions && formattingOptions.synthetic) {
|
|
val = (this[formattingOptions.synthetic]).call(this, true);
|
|
} else {
|
|
val = this._getModifiedValue(name);
|
|
}
|
|
}
|
|
|
|
val = val || 0;
|
|
|
|
if (!formattingOptions) {
|
|
return (
|
|
<span>
|
|
{val}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
let { format } = formattingOptions;
|
|
unit = unit || formattingOptions.unit;
|
|
let storedUnit = formattingOptions.storedUnit || formattingOptions.unit;
|
|
let factor = 1;
|
|
if (storedUnit && storedUnit !== unit) {
|
|
// Find out si prefix of storedUnit and unit as si prefixes can only take
|
|
// on charactere it suffices to compare the first character of each string
|
|
let prefixUnit = unit[0];
|
|
let prefixStored = unit[0];
|
|
if (unit.length > storedUnit.length) {
|
|
factor /= SI_PREFIXES[prefixUnit];
|
|
} else if (storedUnit.length > unit.length) {
|
|
factor *= SI_PREFIXES[prefixStored];
|
|
} else if (prefixUnit !== prefixStored) {
|
|
factor *= SI_PREFIXES[prefixStored];
|
|
factor /= SI_PREFIXES[prefixUnit];
|
|
}
|
|
}
|
|
|
|
if (format && language.formats[format]) {
|
|
val = (language.formats[format])(val * factor);
|
|
}
|
|
|
|
return (
|
|
<span>
|
|
{val}
|
|
{formattingOptions.unit && language.units[formattingOptions.unit]}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Returns the change rate in percentage of a given stat. Change rate can
|
|
* differ from return value of {@see Module#getModValue} when formatting
|
|
* options are given.
|
|
* @param {String} name Name of the value to get the change for
|
|
* @param {Number} [val] If given not the modules value but this one will be
|
|
* taken as new value
|
|
* @return {Number} Change rate of the stat according to formatting options
|
|
*/
|
|
getChange(name, val) {
|
|
const formattingOptions = STATS_FORMATTING[name];
|
|
|
|
if (isNaN(val)) {
|
|
// Calculate the percentage change for an abstract value
|
|
if (formattingOptions && formattingOptions.synthetic) {
|
|
const statGetter = this[formattingOptions.synthetic];
|
|
let unmodifiedStat = statGetter.call(this, false);
|
|
let modifiedStat = statGetter.call(this, true);
|
|
val = (modifiedStat / unmodifiedStat - 1) * 10000;
|
|
} else {
|
|
val = this.getModValue(name);
|
|
}
|
|
}
|
|
|
|
if (formattingOptions && formattingOptions.change) {
|
|
let changeFormatting = formattingOptions.change;
|
|
let baseVal = this[name];
|
|
let absVal = this._getModifiedValue(name);
|
|
if (changeFormatting === 'additive') {
|
|
val = absVal - baseVal;
|
|
} else if (changeFormatting === 'multiplicative') {
|
|
val = absVal / baseVal - 1;
|
|
}
|
|
val *= 10000;
|
|
}
|
|
return val;
|
|
}
|
|
|
|
/**
|
|
* Returns the the unit key for a given stat. For example '%' for 'kinres'.
|
|
* @param {String} name Name of the stat
|
|
* @return {String} Unit key
|
|
*/
|
|
getUnitFor(name) {
|
|
const formattingOptions = STATS_FORMATTING[name];
|
|
if (!formattingOptions || !formattingOptions.unit) {
|
|
if (formattingOptions.format && formattingOptions.format.startsWith('pct')) {
|
|
return 'pct';
|
|
}
|
|
return '';
|
|
}
|
|
|
|
return formattingOptions.unit;
|
|
}
|
|
|
|
/**
|
|
* Same as {@see Module#getUnitFor} but returns the unit in which the stat is
|
|
* stored. For example 'm' for 'range' as opposed to 'km' which is the unit
|
|
* 'range' is usually displayed.
|
|
* @param {String} name Name of the stat
|
|
* @return {String} Unit key
|
|
*/
|
|
getStoredUnitFor(name) {
|
|
const formattingOptions = STATS_FORMATTING[name];
|
|
if (!formattingOptions || !formattingOptions.storedUnit) {
|
|
return this.getUnitFor(name);
|
|
}
|
|
return formattingOptions.storedUnit;
|
|
}
|
|
|
|
/**
|
|
* Get the power generation of this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the power generation of this module
|
|
*/
|
|
getPowerGeneration(modified = true) {
|
|
return this.get('pgen', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the power usage of this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the power usage of this module
|
|
*/
|
|
getPowerUsage(modified = true) {
|
|
return this.get('power', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the integrity of this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the integrity of this module
|
|
*/
|
|
getIntegrity(modified = true) {
|
|
return this.get('integrity', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the mass of this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the mass of this module
|
|
*/
|
|
getMass(modified = true) {
|
|
return this.get('mass', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the thermal efficiency of this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the thermal efficiency of this module
|
|
*/
|
|
getThermalEfficiency(modified = true) {
|
|
return this.get('eff', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the maximum fuel per jump for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the maximum fuel per jump of this module
|
|
*/
|
|
getMaxFuelPerJump(modified = true) {
|
|
return this.get('maxfuel', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the systems capacity for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the systems capacity of this module
|
|
*/
|
|
getSystemsCapacity(modified = true) {
|
|
return this.get('syscap', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the engines capacity for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the engines capacity of this module
|
|
*/
|
|
getEnginesCapacity(modified = true) {
|
|
return this.get('engcap', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the weapons capacity for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the weapons capacity of this module
|
|
*/
|
|
getWeaponsCapacity(modified = true) {
|
|
return this.get('wepcap', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the systems recharge rate for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the systems recharge rate of this module
|
|
*/
|
|
getSystemsRechargeRate(modified = true) {
|
|
return this.get('sysrate', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the engines recharge rate for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the engines recharge rate of this module
|
|
*/
|
|
getEnginesRechargeRate(modified = true) {
|
|
return this.get('engrate', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the weapons recharge rate for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the weapons recharge rate of this module
|
|
*/
|
|
getWeaponsRechargeRate(modified = true) {
|
|
return this.get('weprate', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the kinetic resistance for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the kinetic resistance of this module
|
|
*/
|
|
getKineticResistance(modified = true) {
|
|
return this.get('kinres', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the thermal resistance for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the thermal resistance of this module
|
|
*/
|
|
getThermalResistance(modified = true) {
|
|
return this.get('thermres', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the explosive resistance for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the explosive resistance of this module
|
|
*/
|
|
getExplosiveResistance(modified = true) {
|
|
return this.get('explres', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the caustic resistance for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the caustic resistance of this module
|
|
*/
|
|
getCausticResistance(modified = true) {
|
|
return this.get('causres', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the regeneration rate for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the regeneration rate of this module
|
|
*/
|
|
getRegenerationRate(modified = true) {
|
|
return this.get('regen', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the broken regeneration rate for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the broken regeneration rate of this module
|
|
*/
|
|
getBrokenRegenerationRate(modified = true) {
|
|
return this.get('brokenregen', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the range for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the range rate of this module
|
|
*/
|
|
getRange(modified = true) {
|
|
return this.get('range', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the falloff for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the falloff of this module
|
|
*/
|
|
getFalloff(modified = true) {
|
|
if (!modified) {
|
|
const range = this.getRange(false);
|
|
const falloff = this.get('falloff', false);
|
|
return (falloff > range ? range : falloff);
|
|
}
|
|
|
|
// Falloff from range is mapped to range
|
|
if (this.mods && this.mods['fallofffromrange']) {
|
|
return this.getRange();
|
|
// Need to find out if we have a focused modification, in which case our
|
|
// falloff is scaled to range
|
|
} else if (this.blueprint && this.blueprint.name === 'Focused') {
|
|
const rangeMod = this.getModValue('range') / 10000;
|
|
return this.falloff * (1 + rangeMod);
|
|
// Standard falloff calculation
|
|
} else {
|
|
const range = this.getRange();
|
|
const falloff = this._getModifiedValue('falloff');
|
|
return (falloff > range ? range : falloff);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the range (in terms of seconds, for FSDI) for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the range of this module
|
|
*/
|
|
getRangeT(modified = true) {
|
|
return this.get('ranget', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the scan time for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the scan time of this module
|
|
*/
|
|
getScanTime(modified = true) {
|
|
return this.get('scantime', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the capture arc for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the capture arc of this module
|
|
*/
|
|
getCaptureArc(modified = true) {
|
|
return this.get('arc', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the hull reinforcement for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the hull reinforcement of this module
|
|
*/
|
|
getHullReinforcement(modified = true) {
|
|
return this.get('hullreinforcement', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the protection for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the protection of this module
|
|
*/
|
|
getProtection(modified = true) {
|
|
return this.get('protection', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the delay for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the delay of this module
|
|
*/
|
|
getDelay(modified = true) {
|
|
return this.get('delay', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the duration for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the duration of this module
|
|
*/
|
|
getDuration(modified = true) {
|
|
return this.get('duration', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the shield boost for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the shield boost of this module
|
|
*/
|
|
getShieldBoost(modified = true) {
|
|
return this.get('shieldboost', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the minimum mass for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the minimum mass of this module
|
|
*/
|
|
getMinMass(modified = true) {
|
|
// Modifier is optmass
|
|
let result = 0;
|
|
if (this['minmass']) {
|
|
result = this['minmass'];
|
|
if (result && modified) {
|
|
let mult = this.getModValue('optmass') / 10000;
|
|
if (mult) { result = result * (1 + mult); }
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Get the optimum mass for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the optimum mass of this module
|
|
*/
|
|
getOptMass(modified = true) {
|
|
return this.get('optmass', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the maximum mass for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the maximum mass of this module
|
|
*/
|
|
getMaxMass(modified = true) {
|
|
// Modifier is optmass
|
|
let result = 0;
|
|
if (this['maxmass']) {
|
|
result = this['maxmass'];
|
|
if (result && modified) {
|
|
let mult = this.getModValue('optmass') / 10000;
|
|
if (mult) { result = result * (1 + mult); }
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Get the minimum multiplier for this module
|
|
* @param {string} type the type for which we are obtaining the multiplier. Can be 'speed', 'rotation', 'acceleration', or null
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the minimum multiplier of this module
|
|
*/
|
|
getMinMul(type = null, modified = true) {
|
|
// Modifier is optmul
|
|
let result = 0;
|
|
if (this['minmul' + type]) {
|
|
result = this['minmul' + type];
|
|
} else if (this['minmul']) {
|
|
result = this['minmul'];
|
|
}
|
|
if (result && modified) {
|
|
let mult = this.getModValue('optmul') / 10000;
|
|
if (mult) { result = result * (1 + mult); }
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Get the optimum multiplier for this module
|
|
* @param {string} type the type for which we are obtaining the multiplier. Can be 'speed', 'rotation', 'acceleration', or null
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the optimum multiplier of this module
|
|
*/
|
|
getOptMul(type = null, modified = true) {
|
|
// Modifier is optmul
|
|
let result = 0;
|
|
if (this['optmul' + type]) {
|
|
result = this['optmul' + type];
|
|
} else if (this['optmul']) {
|
|
result = this['optmul'];
|
|
}
|
|
if (result && modified) {
|
|
let mult = this.getModValue('optmul') / 10000;
|
|
if (mult) { result = result * (1 + mult); }
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Get the maximum multiplier for this module
|
|
* @param {string} type the type for which we are obtaining the multiplier. Can be 'speed', 'rotation', 'acceleration', or null
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the maximum multiplier of this module
|
|
*/
|
|
getMaxMul(type = null, modified = true) {
|
|
// Modifier is optmul
|
|
let result = 0;
|
|
if (this['maxmul' + type]) {
|
|
result = this['maxmul' + type];
|
|
} else if (this['maxmul']) {
|
|
result = this['maxmul'];
|
|
}
|
|
if (result && modified) {
|
|
let mult = this.getModValue('optmul') / 10000;
|
|
if (mult) { result = result * (1 + mult); }
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Get the damage for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the damage of this module
|
|
*/
|
|
getDamage(modified = true) {
|
|
return this.get('damage', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the distributor draw for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the distributor draw of this module
|
|
*/
|
|
getDistDraw(modified = true) {
|
|
return this.get('distdraw', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the thermal load for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the thermal load of this module
|
|
*/
|
|
getThermalLoad(modified = true) {
|
|
return this.get('thermload', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the rounds per shot for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the rounds per shot of this module
|
|
*/
|
|
getRoundsPerShot(modified = true) {
|
|
return this.get('roundspershot', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the DPS for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the DPS of this module
|
|
*/
|
|
getDps(modified = true) {
|
|
// DPS is a synthetic value
|
|
let damage = this.getDamage(modified);
|
|
let rpshot = this.roundspershot || 1;
|
|
let rof = this.getRoF(modified) || 1;
|
|
|
|
return damage * rpshot * rof;
|
|
}
|
|
|
|
/**
|
|
* Get the DPE for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the DPE of this module
|
|
*/
|
|
getDpe(modified = true) {
|
|
return this.getDps(modified) / this.getEps(modified);
|
|
}
|
|
|
|
/**
|
|
* Get the SDPS for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} The SDPS of this module
|
|
*/
|
|
getSDps(modified = true) {
|
|
let dps = this.getDps(modified);
|
|
if (this.getClip(modified)) {
|
|
let clipSize = this.getClip(modified);
|
|
// If auto-loader is applied, effective clip size will be nearly doubled
|
|
// as you get one reload for every two shots fired.
|
|
if (this.blueprint && this.blueprint.special && this.blueprint.special.edname === 'special_auto_loader' && modified) {
|
|
clipSize += clipSize - 1;
|
|
}
|
|
let timeToDeplete = clipSize / this.getRoF(modified);
|
|
return dps * timeToDeplete / (timeToDeplete + this.getReload(modified));
|
|
} else {
|
|
return dps;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the EPS for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the EPS of this module
|
|
*/
|
|
getEps(modified = true) {
|
|
// EPS is a synthetic value
|
|
let distdraw = this.getDistDraw(modified);
|
|
// We don't use rpshot here as dist draw is per combined shot
|
|
let rof = this.getRoF(modified) || 1;
|
|
|
|
return distdraw * rof;
|
|
}
|
|
|
|
/**
|
|
* Get the HPS for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the HPS of this module
|
|
*/
|
|
getHps(modified = true) {
|
|
// HPS is a synthetic value
|
|
let heat = this.getThermalLoad(modified);
|
|
// We don't use rpshot here as dist draw is per combined shot
|
|
let rof = this.getRoF(modified) || 1;
|
|
|
|
return heat * rof;
|
|
}
|
|
|
|
/**
|
|
* Get the clip size for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the clip size of this module
|
|
*/
|
|
getClip(modified = true) {
|
|
// Clip size is always rounded up
|
|
let result = this.get('clip', modified);
|
|
if (result) { result = Math.ceil(result); }
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Get the ammo size for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the ammo size of this module
|
|
*/
|
|
getAmmo(modified = true) {
|
|
return this.get('ammo', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the reload time for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the reload time of this module
|
|
*/
|
|
getReload(modified = true) {
|
|
return this.get('reload', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the burst size for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the burst size of this module
|
|
*/
|
|
getBurst(modified = true) {
|
|
return this.get('burst', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the burst rate of fire for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the burst rate of fire of this module
|
|
*/
|
|
getBurstRoF(modified = true) {
|
|
return this.get('burstrof', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the rate of fire for this module.
|
|
* The rate of fire is a combination value, and needs to take in to account
|
|
* bursts of fire.
|
|
* Firing goes [burst 1] [burst interval] [burst 2] [burst interval] ... [burst n] [interval]
|
|
* where 'n' is 'burst', 'burst interval' is '1/burstrof' and 'interval' is '1/rof'
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the rate of fire for this module
|
|
*/
|
|
getRoF(modified = true) {
|
|
const burst = this.getBurst(modified) || 1;
|
|
const burstRoF = this.getBurstRoF(modified) || 1;
|
|
const intRoF = this.get('rof', modified);
|
|
|
|
return burst / (((burst - 1) / burstRoF) + 1 / intRoF);
|
|
}
|
|
|
|
/**
|
|
* Get the facing limit for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the facing limit for this module
|
|
*/
|
|
getFacingLimit(modified = true) {
|
|
return this.get('facinglimit', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the hull boost for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the hull boost for this module
|
|
*/
|
|
getHullBoost(modified = true) {
|
|
return this.get('hullboost', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the shield reinforcement for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the shield reinforcement for this module
|
|
*/
|
|
getShieldReinforcement(modified = true) {
|
|
return this.get('shieldreinforcement', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the shield addition for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the shield addition for this module
|
|
*/
|
|
getShieldAddition(modified = true) {
|
|
return this.get('shieldaddition', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the jump range boost for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the jump range boost for this module
|
|
*/
|
|
getJumpBoost(modified = true) {
|
|
return this.get('jumpboost', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the piercing for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the piercing for this module
|
|
*/
|
|
getPiercing(modified = true) {
|
|
return this.get('piercing', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the bays for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the bays for this module
|
|
*/
|
|
getBays(modified) {
|
|
return this.get('bays', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the rebuilds per bay for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the rebuilds per bay for this module
|
|
*/
|
|
getRebuildsPerBay(modified = true) {
|
|
return this.get('rebuildsperbay', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the jitter for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {Number} the jitter for this module
|
|
*/
|
|
getJitter(modified = true) {
|
|
return this.get('jitter', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the damage distribution for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {string} the damage distribution for this module
|
|
*/
|
|
getDamageDist(modified = true) {
|
|
return (modified && this.getModValue('damagedist')) || this.damagedist;
|
|
}
|
|
|
|
/**
|
|
* Get the shot speed for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {string} the shot speed for this module
|
|
*/
|
|
getShotSpeed(modified = true) {
|
|
return this.get('shotspeed', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the spinup for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {string} the spinup for this module
|
|
*/
|
|
getSpinup(modified = true) {
|
|
return this.get('spinup', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the time for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {string} the time for this module
|
|
*/
|
|
getTime(modified = true) {
|
|
return this.get('time', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the hack time for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {string} the time for this module
|
|
*/
|
|
getHackTime(modified = true) {
|
|
return this.get('hacktime', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the scan range for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {string} the time for this module
|
|
*/
|
|
getScanRange(modified = true) {
|
|
return this.get('scanrange', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the scan angle for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {string} the time for this module
|
|
*/
|
|
getScanAngle(modified = true) {
|
|
return this.get('scanangle', modified);
|
|
}
|
|
|
|
/**
|
|
* Get the max angle for this module
|
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
* @return {string} the time for this module
|
|
*/
|
|
getMaxAngle(modified = true) {
|
|
return this.get('maxangle', modified);
|
|
}
|
|
}
|