diff --git a/src/app/components/Modification.jsx b/src/app/components/Modification.jsx index 1ca29bef..1e6dae44 100644 --- a/src/app/components/Modification.jsx +++ b/src/app/components/Modification.jsx @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import TranslatedComponent from './TranslatedComponent'; import cn from 'classnames'; import NumberEditor from 'react-number-editor'; +import { isValueBeneficial } from '../utils/BlueprintFunctions'; /** * Modification @@ -38,22 +39,9 @@ export default class Modification extends TranslatedComponent { * in a value by hand */ _updateValue(value) { - const name = this.props.name; - let scaledValue = Math.round(Number(value) * 100); - // Limit to +1000% / -99.99% - if (scaledValue > 100000) { - scaledValue = 100000; - value = 1000; - } - if (scaledValue < -9999) { - scaledValue = -9999; - value = -99.99; - } - - let m = this.props.m; - let ship = this.props.ship; - ship.setModification(m, name, scaledValue, true); - + let { m, name, ship } = this.props; + value = Math.max(Math.min(value, 50000), -50000); + ship.setModification(m, name, value, true, true); this.setState({ value }); } @@ -75,52 +63,46 @@ export default class Modification extends TranslatedComponent { * @return {React.Component} modification */ render() { - let translate = this.context.language.translate; - let formats = this.context.language.formats; + let { translate, formats, units } = this.context.language; let { m, name } = this.props; + let modValue = m.getChange(name); if (name === 'damagedist') { // We don't show damage distribution return null; } - let symbol; - if (name === 'jitter') { - symbol = '°'; - } else if (name !== 'burst' && name != 'burstrof') { - symbol = '%'; - } - if (symbol) { - symbol = ' (' + symbol + ')'; - } - return ( -
this.props.modItems[name] = modItem }> -
{translate(name, m.grp)}{symbol}
+
this.props.modItems[name] = modItem }> + {translate(name, m.grp)} + - - + diff --git a/src/app/components/ModificationsMenu.jsx b/src/app/components/ModificationsMenu.jsx index 9607d475..8f0b8dcc 100644 --- a/src/app/components/ModificationsMenu.jsx +++ b/src/app/components/ModificationsMenu.jsx @@ -219,7 +219,7 @@ export default class ModificationsMenu extends TranslatedComponent { this.lastNeId = modName; (editable ? modifiableModifications : modifications).push( ); diff --git a/src/app/i18n/Language.jsx b/src/app/i18n/Language.jsx index 3a6cc61b..2fe1f96f 100644 --- a/src/app/i18n/Language.jsx +++ b/src/app/i18n/Language.jsx @@ -73,6 +73,7 @@ export function getLanguage(langCode) { '°/s': {translate('°/s')}, // Degrees per second MW: {translate('MW')}, // Mega Watts (same as Mega Joules per second) mps: {translate('m/s')}, // Metres per second + pct: '%', // Percent ps: {translate('/s')}, // per second pm: {translate('/min')}, // per minute s: {translate('secs')}, // Seconds diff --git a/src/app/shipyard/Module.js b/src/app/shipyard/Module.js index 0d880a4a..512eade2 100755 --- a/src/app/shipyard/Module.js +++ b/src/app/shipyard/Module.js @@ -1,7 +1,7 @@ import * as ModuleUtils from './ModuleUtils'; import { Modifications } from 'coriolis-data/dist'; import React from 'react'; -import { STATS_FORMATING, SI_PREFIXES } from './StatsFormating'; +import { STATS_FORMATTING, SI_PREFIXES } from './StatsFormatting'; /** * Module - active module in a ship's buildout @@ -44,13 +44,7 @@ export default class Module { getModValue(name, raw) { let result = this.mods && this.mods[name] ? this.mods[name] : null; - // Calculate the percentage change for a synthetic value - if (STATS_FORMATING[name] && STATS_FORMATING[name].synthetic) { - const statGetter = this[STATS_FORMATING[name].synthetic]; - let unmodifiedStat = statGetter.call(this, false); - let modifiedStat = statGetter.call(this, true); - result = (modifiedStat / unmodifiedStat - 1) * 10000; - } else if ((!raw) && this.blueprint && this.blueprint.special) { + 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]) { @@ -82,6 +76,15 @@ export default class Module { } } + // Resistance modding for hull reinforcement packages has additional + // diminishing returns implemented. The mod value gets lowered by + // the amount of base resistance the hrp has. + if (!isNaN(result) && this.grp === 'hr' && + (name === 'kinres' || name === 'thermres' || name === 'explres')) { + let baseRes = this[name]; + result = result * (1 - baseRes); + } + // Sanitise the resultant value to 4dp equivalent return isNaN(result) ? result : Math.round(result); } @@ -141,7 +144,7 @@ export default class Module { * @param {Number} modified Whether to return the raw or modified value * @return {Number} The value queried */ - _getValue(name, modified) { + get(name, modified = true) { let val; if (modified) { val = this._getModifiedValue(name); @@ -151,6 +154,85 @@ export default class Module { 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; + if (this.grp === 'hr' && + (name === 'kinres' || name === 'thermres' || name === 'explres')) { + modValue = modValue / (1 - baseValue); + } + } else if (name === 'shieldboost' || name === 'hullboost') { + modValue = (1 + value) / (1 + baseValue) - 1; + } else { // multiplicative + modValue = 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 @@ -172,34 +254,27 @@ export default class Module { 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') { - // Resistance modding for hull reinforcement packages has additional - // diminishing returns implemented. The mod value gets lowered by - // the amount of base resistance the hrp has. - if (this.grp === 'hr' && - (name === 'kinres' || name === 'thermres' || name === 'explres')) { - modValue = modValue * (1 - result); - } - 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); + if (!result && modification.method === 'additive') { + // If the modification is additive and no value is given by default we + // start at zero + result = 0; } - } else if (name === 'burst' || name === 'burstrof') { - // Burst and burst rate of fire are special, as it can not exist but - // have a modification - result = modValue / 100; - } + + 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 === 'burst' || name === 'burstrof') { + // Burst and burst rate of fire are special, as it can not exist but + // have a modification + result = modValue / 100; + } } } @@ -210,7 +285,7 @@ export default class Module { * 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 formating + * @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 @@ -218,10 +293,10 @@ export default class Module { * @returns {React.Component} The formated value as component */ formatModifiedValue(name, language, unit, val) { - const formatingOptions = STATS_FORMATING[name]; + const formattingOptions = STATS_FORMATTING[name]; if (val === undefined) { - if (formatingOptions && formatingOptions.synthetic) { - val = (this[formatingOptions.synthetic]).call(this, true); + if (formattingOptions && formattingOptions.synthetic) { + val = (this[formattingOptions.synthetic]).call(this, true); } else { val = this._getModifiedValue(name); } @@ -229,7 +304,7 @@ export default class Module { val = val || 0; - if (!formatingOptions) { + if (!formattingOptions) { return ( {val} @@ -237,9 +312,9 @@ export default class Module { ); } - let { format } = formatingOptions; - unit = unit || formatingOptions.unit; - let storedUnit = formatingOptions.storedUnit || formatingOptions.unit; + 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 @@ -263,18 +338,88 @@ export default class Module { return ( {val} - {formatingOptions.unit && language.units[formatingOptions.unit]} + {formattingOptions.unit && language.units[formattingOptions.unit]} ); } + /** + * 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); + result = (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._getValue('pgen', modified); + return this.get('pgen', modified); } /** @@ -283,7 +428,7 @@ export default class Module { * @return {Number} the power usage of this module */ getPowerUsage(modified = true) { - return this._getValue('power', modified); + return this.get('power', modified); } /** @@ -292,7 +437,7 @@ export default class Module { * @return {Number} the integrity of this module */ getIntegrity(modified = true) { - return this._getValue('integrity', modified); + return this.get('integrity', modified); } /** @@ -301,7 +446,7 @@ export default class Module { * @return {Number} the mass of this module */ getMass(modified = true) { - return this._getValue('mass', modified); + return this.get('mass', modified); } /** @@ -310,7 +455,7 @@ export default class Module { * @return {Number} the thermal efficiency of this module */ getThermalEfficiency(modified = true) { - return this._getValue('eff', modified); + return this.get('eff', modified); } /** @@ -319,7 +464,7 @@ export default class Module { * @return {Number} the maximum fuel per jump of this module */ getMaxFuelPerJump(modified = true) { - return this._getValue('maxfuel', modified); + return this.get('maxfuel', modified); } /** @@ -328,7 +473,7 @@ export default class Module { * @return {Number} the systems capacity of this module */ getSystemsCapacity(modified = true) { - return this._getValue('syscap', modified); + return this.get('syscap', modified); } /** @@ -337,7 +482,7 @@ export default class Module { * @return {Number} the engines capacity of this module */ getEnginesCapacity(modified = true) { - return this._getValue('engcap', modified); + return this.get('engcap', modified); } /** @@ -346,7 +491,7 @@ export default class Module { * @return {Number} the weapons capacity of this module */ getWeaponsCapacity(modified = true) { - return this._getValue('wepcap', modified); + return this.get('wepcap', modified); } /** @@ -355,7 +500,7 @@ export default class Module { * @return {Number} the systems recharge rate of this module */ getSystemsRechargeRate(modified = true) { - return this._getValue('sysrate', modified); + return this.get('sysrate', modified); } /** @@ -364,7 +509,7 @@ export default class Module { * @return {Number} the engines recharge rate of this module */ getEnginesRechargeRate(modified = true) { - return this._getValue('engrate', modified); + return this.get('engrate', modified); } /** @@ -373,7 +518,7 @@ export default class Module { * @return {Number} the weapons recharge rate of this module */ getWeaponsRechargeRate(modified = true) { - return this._getValue('weprate', modified); + return this.get('weprate', modified); } /** @@ -382,7 +527,7 @@ export default class Module { * @return {Number} the kinetic resistance of this module */ getKineticResistance(modified = true) { - return this._getValue('kinres', modified); + return this.get('kinres', modified); } /** @@ -391,7 +536,7 @@ export default class Module { * @return {Number} the thermal resistance of this module */ getThermalResistance(modified = true) { - return this._getValue('thermres', modified); + return this.get('thermres', modified); } /** @@ -400,7 +545,7 @@ export default class Module { * @return {Number} the explosive resistance of this module */ getExplosiveResistance(modified = true) { - return this._getValue('explres', modified); + return this.get('explres', modified); } /** @@ -409,7 +554,7 @@ export default class Module { * @return {Number} the caustic resistance of this module */ getCausticResistance(modified = true) { - return this._getValue('causres', modified); + return this.get('causres', modified); } /** @@ -418,7 +563,7 @@ export default class Module { * @return {Number} the regeneration rate of this module */ getRegenerationRate(modified = true) { - return this._getValue('regen', modified); + return this.get('regen', modified); } /** @@ -427,7 +572,7 @@ export default class Module { * @return {Number} the broken regeneration rate of this module */ getBrokenRegenerationRate(modified = true) { - return this._getValue('brokenregen', modified); + return this.get('brokenregen', modified); } /** @@ -436,7 +581,7 @@ export default class Module { * @return {Number} the range rate of this module */ getRange(modified = true) { - return this._getValue('range', modified); + return this.get('range', modified); } /** @@ -447,7 +592,7 @@ export default class Module { getFalloff(modified = true) { if (!modified) { const range = this.getRange(false); - const falloff = this._getValue('falloff', false); + const falloff = this.get('falloff', false); return (falloff > range ? range : falloff); } @@ -473,7 +618,7 @@ export default class Module { * @return {Number} the range of this module */ getRangeT(modified = true) { - return this._getValue('ranget', modified); + return this.get('ranget', modified); } /** @@ -482,7 +627,7 @@ export default class Module { * @return {Number} the scan time of this module */ getScanTime(modified = true) { - return this._getValue('scantime', modified); + return this.get('scantime', modified); } /** @@ -491,7 +636,7 @@ export default class Module { * @return {Number} the capture arc of this module */ getCaptureArc(modified = true) { - return this._getValue('arc', modified); + return this.get('arc', modified); } /** @@ -500,7 +645,7 @@ export default class Module { * @return {Number} the hull reinforcement of this module */ getHullReinforcement(modified = true) { - return this._getValue('hullreinforcement', modified); + return this.get('hullreinforcement', modified); } /** @@ -509,7 +654,7 @@ export default class Module { * @return {Number} the protection of this module */ getProtection(modified = true) { - return this._getValue('protection', modified); + return this.get('protection', modified); } /** @@ -518,7 +663,7 @@ export default class Module { * @return {Number} the delay of this module */ getDelay(modified = true) { - return this._getValue('delay', modified); + return this.get('delay', modified); } /** @@ -527,7 +672,7 @@ export default class Module { * @return {Number} the duration of this module */ getDuration(modified = true) { - return this._getValue('duration', modified); + return this.get('duration', modified); } /** @@ -536,7 +681,7 @@ export default class Module { * @return {Number} the shield boost of this module */ getShieldBoost(modified = true) { - return this._getValue('shieldboost', modified); + return this.get('shieldboost', modified); } /** @@ -563,7 +708,7 @@ export default class Module { * @return {Number} the optimum mass of this module */ getOptMass(modified = true) { - return this._getValue('optmass', modified); + return this.get('optmass', modified); } /** @@ -654,7 +799,7 @@ export default class Module { * @return {Number} the damage of this module */ getDamage(modified = true) { - return this._getValue('damage', modified); + return this.get('damage', modified); } /** @@ -663,7 +808,7 @@ export default class Module { * @return {Number} the distributor draw of this module */ getDistDraw(modified = true) { - return this._getValue('distdraw', modified); + return this.get('distdraw', modified); } /** @@ -672,7 +817,7 @@ export default class Module { * @return {Number} the thermal load of this module */ getThermalLoad(modified = true) { - return this._getValue('thermload', modified); + return this.get('thermload', modified); } /** @@ -681,7 +826,7 @@ export default class Module { * @return {Number} the rounds per shot of this module */ getRoundsPerShot(modified = true) { - return this._getValue('roundspershot', modified); + return this.get('roundspershot', modified); } /** @@ -763,7 +908,7 @@ export default class Module { */ getClip(modified = true) { // Clip size is always rounded up - let result = this._getValue('clip', modified); + let result = this.get('clip', modified); if (result) { result = Math.ceil(result); } return result; } @@ -774,7 +919,7 @@ export default class Module { * @return {Number} the ammo size of this module */ getAmmo(modified = true) { - return this._getValue('ammo', modified); + return this.get('ammo', modified); } /** @@ -783,7 +928,7 @@ export default class Module { * @return {Number} the reload time of this module */ getReload(modified = true) { - return this._getValue('reload', modified); + return this.get('reload', modified); } /** @@ -792,7 +937,7 @@ export default class Module { * @return {Number} the burst size of this module */ getBurst(modified = true) { - return this._getValue('burst', modified); + return this.get('burst', modified); } /** @@ -801,7 +946,7 @@ export default class Module { * @return {Number} the burst rate of fire of this module */ getBurstRoF(modified = true) { - return this._getValue('burstrof', modified); + return this.get('burstrof', modified); } /** @@ -816,7 +961,7 @@ export default class Module { getRoF(modified = true) { const burst = this.getBurst(modified) || 1; const burstRoF = this.getBurstRoF(modified) || 1; - const intRoF = this._getValue('rof', modified); + const intRoF = this.get('rof', modified); return burst / (((burst - 1) / burstRoF) + 1 / intRoF); } @@ -827,7 +972,7 @@ export default class Module { * @return {Number} the facing limit for this module */ getFacingLimit(modified = true) { - return this._getValue('facinglimit', modified); + return this.get('facinglimit', modified); } /** @@ -836,7 +981,7 @@ export default class Module { * @return {Number} the hull boost for this module */ getHullBoost(modified = true) { - return this._getValue('hullboost', modified); + return this.get('hullboost', modified); } /** @@ -845,7 +990,7 @@ export default class Module { * @return {Number} the shield reinforcement for this module */ getShieldReinforcement(modified = true) { - return this._getValue('shieldreinforcement', modified); + return this.get('shieldreinforcement', modified); } /** @@ -854,7 +999,7 @@ export default class Module { * @return {Number} the shield addition for this module */ getShieldAddition(modified = true) { - return this._getValue('shieldaddition', modified); + return this.get('shieldaddition', modified); } /** @@ -863,7 +1008,7 @@ export default class Module { * @return {Number} the jump range boost for this module */ getJumpBoost(modified = true) { - return this._getValue('jumpboost', modified); + return this.get('jumpboost', modified); } /** @@ -872,7 +1017,7 @@ export default class Module { * @return {Number} the piercing for this module */ getPiercing(modified = true) { - return this._getValue('piercing', modified); + return this.get('piercing', modified); } /** @@ -881,7 +1026,7 @@ export default class Module { * @return {Number} the bays for this module */ getBays(modified) { - return this._getValue('bays', modified); + return this.get('bays', modified); } /** @@ -890,7 +1035,7 @@ export default class Module { * @return {Number} the rebuilds per bay for this module */ getRebuildsPerBay(modified = true) { - return this._getValue('rebuildsperbay', modified); + return this.get('rebuildsperbay', modified); } /** @@ -899,7 +1044,7 @@ export default class Module { * @return {Number} the jitter for this module */ getJitter(modified = true) { - return this._getValue('jitter', modified); + return this.get('jitter', modified); } /** @@ -917,7 +1062,7 @@ export default class Module { * @return {string} the shot speed for this module */ getShotSpeed(modified = true) { - return this._getValue('shotspeed', modified); + return this.get('shotspeed', modified); } /** @@ -926,7 +1071,7 @@ export default class Module { * @return {string} the spinup for this module */ getSpinup(modified = true) { - return this._getValue('spinup', modified); + return this.get('spinup', modified); } /** @@ -935,7 +1080,7 @@ export default class Module { * @return {string} the time for this module */ getTime(modified = true) { - return this._getValue('time', modified); + return this.get('time', modified); } /** @@ -944,7 +1089,7 @@ export default class Module { * @return {string} the time for this module */ getHackTime(modified = true) { - return this._getValue('hacktime', modified); + return this.get('hacktime', modified); } } diff --git a/src/app/shipyard/Ship.js b/src/app/shipyard/Ship.js index 87be0b90..4e47f060 100755 --- a/src/app/shipyard/Ship.js +++ b/src/app/shipyard/Ship.js @@ -7,6 +7,7 @@ import LZString from 'lz-string'; import * as _ from 'lodash'; import isEqual from 'lodash/lang'; import { Ships, Modifications } from 'coriolis-data/dist'; +import { chain } from 'lodash'; const zlib = require('zlib'); const UNIQUE_MODULES = ['psg', 'sg', 'bsg', 'rf', 'fs', 'fh', 'gfsb']; @@ -493,68 +494,62 @@ export default class Ship { * @param {Object} name The name of the modification to change * @param {Number} value The new value of the modification. The value of the modification is scaled to provide two decimal places of precision in an integer. For example 1.23% is stored as 123 * @param {bool} sentfromui True if this update was sent from the UI + * @param {bool} isAbsolute True if value is an absolute value and not a + * modification value */ - setModification(m, name, value, sentfromui) { + setModification(m, name, value, sentfromui, isAbsolute) { if (isNaN(value)) { // Value passed is invalid; reset it to 0 value = 0; } + + if (isAbsolute) { + m.setPretty(name, value, sentfromui); + } else { + m.setModValue(name, value, sentfromui); + } + // Handle special cases if (name === 'pgen') { // Power generation - m.setModValue(name, value, sentfromui); this.updatePowerGenerated(); } else if (name === 'power') { // Power usage - m.setModValue(name, value, sentfromui); this.updatePowerUsed(); } else if (name === 'mass') { // Mass - m.setModValue(name, value, sentfromui); this.recalculateMass(); this.updateMovement(); this.updateJumpStats(); } else if (name === 'maxfuel') { - m.setModValue(name, value, sentfromui); this.updateJumpStats(); } else if (name === 'optmass') { - m.setModValue(name, value, sentfromui); // Could be for any of thrusters, FSD or shield this.updateMovement(); this.updateJumpStats(); this.recalculateShield(); } else if (name === 'optmul') { - m.setModValue(name, value, sentfromui); // Could be for any of thrusters, FSD or shield this.updateMovement(); this.updateJumpStats(); this.recalculateShield(); } else if (name === 'shieldboost') { - m.setModValue(name, value, sentfromui); this.recalculateShield(); } else if (name === 'hullboost' || name === 'hullreinforcement' || name === 'modulereinforcement') { - m.setModValue(name, value, sentfromui); this.recalculateArmour(); } else if (name === 'shieldreinforcement') { - m.setModValue(name, value, sentfromui); this.recalculateShieldCells(); } else if (name === 'burst' || name == 'burstrof' || name === 'clip' || name === 'damage' || name === 'distdraw' || name === 'jitter' || name === 'piercing' || name === 'range' || name === 'reload' || name === 'rof' || name === 'thermload') { - m.setModValue(name, value, sentfromui); this.recalculateDps(); this.recalculateHps(); this.recalculateEps(); } else if (name === 'explres' || name === 'kinres' || name === 'thermres') { - m.setModValue(name, value, sentfromui); // Could be for shields or armour this.recalculateArmour(); this.recalculateShield(); } else if (name === 'engcap') { - m.setModValue(name, value, sentfromui); // Might have resulted in a change in boostability this.updateMovement(); - } else { - // Generic - m.setModValue(name, value, sentfromui); } } @@ -1187,38 +1182,35 @@ export default class Ship { unladenMass += this.bulkheads.m.getMass(); - for (let slotNum in this.standard) { - const slot = this.standard[slotNum]; - if (slot.m) { - unladenMass += slot.m.getMass(); - if (slot.m.grp === 'ft') { - fuelCapacity += slot.m.fuel; - } - } - } + let slots = this.standard.concat(this.internal, this.hardpoints); + // TODO: create class for slot and also add slot.get + // handle unladen mass + unladenMass += chain(slots) + .map(slot => slot.m ? slot.m.get('mass') : null) + .filter() + .reduce((sum, mass) => sum + mass) + .value(); - for (let slotNum in this.internal) { - const slot = this.internal[slotNum]; - if (slot.m) { - unladenMass += slot.m.getMass(); - if (slot.m.grp === 'ft') { - fuelCapacity += slot.m.fuel; - } else if (slot.m.grp === 'cr') { - cargoCapacity += slot.m.cargo; - } else if (slot.m.grp.slice(0,2) === 'pc') { - if (slot.m.passengers) { - passengerCapacity += slot.m.passengers; - } - } - } - } + // handle fuel capacity + fuelCapacity += chain(slots) + .map(slot => slot.m ? slot.m.get('fuel') : null) + .filter() + .reduce((sum, fuel) => sum + fuel) + .value(); - for (let slotNum in this.hardpoints) { - const slot = this.hardpoints[slotNum]; - if (slot.m) { - unladenMass += slot.m.getMass(); - } - } + // handle cargo capacity + cargoCapacity += chain(slots) + .map(slot => slot.m ? slot.m.get('cargo') : null) + .filter() + .reduce((sum, cargo) => sum + cargo) + .value(); + + // handle passenger capacity + passengerCapacity += chain(slots) + .map(slot => slot.m ? slot.m.get('passengers') : null) + .filter() + .reduce((sum, passengers) => sum + passengers) + .value(); // Update global stats this.unladenMass = unladenMass; diff --git a/src/app/shipyard/StatsFormating.js b/src/app/shipyard/StatsFormatting.js similarity index 93% rename from src/app/shipyard/StatsFormating.js rename to src/app/shipyard/StatsFormatting.js index 1beb772a..8effaa36 100644 --- a/src/app/shipyard/StatsFormating.js +++ b/src/app/shipyard/StatsFormatting.js @@ -22,7 +22,7 @@ export const SI_PREFIXES = { 'y': 1e-24 // Yokto }; -export const STATS_FORMATING = { +export const STATS_FORMATTING = { 'ammo': { 'format': 'int', }, 'boot': { 'format': 'int', 'unit': 'secs' }, 'brokenregen': { 'format': 'round1', 'unit': 'ps' }, @@ -44,7 +44,7 @@ export const STATS_FORMATING = { 'falloff': { 'format': 'round', 'unit': 'km', 'storedUnit': 'm' }, 'fallofffromrange': { 'format': 'round', 'unit': 'km', 'storedUnit': 'm', 'synthetic': 'getFalloff' }, 'hps': { 'format': 'round', 'units': 'ps', 'synthetic': 'getHps' }, - 'hullboost': { 'format': 'pct1' }, + 'hullboost': { 'format': 'pct1', 'change': 'additive' }, 'hullreinforcement': { 'format': 'int' }, 'integrity': { 'format': 'round1' }, 'jitter': { 'format': 'round', 'unit': 'ang' }, @@ -52,7 +52,7 @@ export const STATS_FORMATING = { 'mass': { 'format': 'round1', 'unit': 'T' }, 'maxfuel': { 'format': 'round1', 'unit': 'T' }, 'optmass': { 'format': 'int', 'unit': 'T' }, - 'optmul': { 'format': 'pct' }, + 'optmul': { 'format': 'pct', 'change': 'additive' }, 'pgen': { 'format': 'round1', 'unit': 'MW' }, 'piercing': { 'format': 'int' }, 'power': { 'format': 'round', 'unit': 'MW' }, @@ -68,7 +68,7 @@ export const STATS_FORMATING = { 'sdps': { 'format': 'round1', 'units': 'ps', 'synthetic': 'getSDps' }, 'shield': { 'format': 'int', 'unit': 'MJ' }, 'shieldaddition': { 'format': 'round1', 'unit': 'MJ' }, - 'shieldboost': { 'format': 'pct1' }, + 'shieldboost': { 'format': 'pct1', 'change': 'additive' }, 'shieldreinforcement': { 'format': 'round1', 'unit': 'MJ' }, 'shotspeed': { 'format': 'int', 'unit': 'm/s' }, 'spinup': { 'format': 'round1', 'unit': 's' }, diff --git a/src/less/slot.less b/src/less/slot.less index 9b05bce3..e6c962f9 100755 --- a/src/less/slot.less +++ b/src/less/slot.less @@ -37,6 +37,35 @@ text-overflow: ellipsis; } + .modification-container { + @input-container-width: 75%; + td { + width: 100% - @input-container-width; + text-align: center; + } + + .input-container { + width: @input-container-width; + text-align: right; + } + + input { + width: 80%; + } + + .unit-container { + width: 30px; + padding: 3px; + text-align: left; + display: inline-block; + } + + .header-adjuster { + width: 100% - @input-container-width; + display: inline-block; + } + } + .cb { overflow: hidden; }
- {/* thermload doesn't have any values set therefore we ignore it */} -
{this.props.name !== 'thermload' && - this.props.m.formatModifiedValue( - this.props.name, - this.context.language - ) - }
-
- {this.props.editable ? - : -
+
+ + {this.props.editable ? + : - - } + disabled className={'number-editor'} + style={{ textAlign: 'right', cursor: 'inherit' }}/> + } + + {units[m.getStoredUnitFor(name)]} + + + + {formats.f2(modValue / 100) || 0}%