From c4186faa4a598bc83fe971da882b8dd4916912ca Mon Sep 17 00:00:00 2001 From: Felix Linker Date: Sat, 15 Sep 2018 00:31:00 +0200 Subject: [PATCH 1/9] Allow to set an absolute value for a module --- src/app/shipyard/Module.js | 239 ++++++++++++++++++++++++------------- src/app/shipyard/Ship.js | 26 ++-- 2 files changed, 169 insertions(+), 96 deletions(-) diff --git a/src/app/shipyard/Module.js b/src/app/shipyard/Module.js index 1019e4b5..6fd884e8 100755 --- a/src/app/shipyard/Module.js +++ b/src/app/shipyard/Module.js @@ -135,7 +135,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) { if (modified) { return this._getModifiedValue(name); } else { @@ -143,6 +143,85 @@ export default class Module { } } + /** + * 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 formatingOptions = STATS_FORMATING[name]; + let val = this.get(name, modified) || 0; + if (formatingOptions && formatingOptions.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 formatingOptions = STATS_FORMATING[name]; + if (formatingOptions && formatingOptions.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 @@ -164,34 +243,34 @@ 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') { + // 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); + } + } 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; + } } } @@ -266,7 +345,7 @@ export default class Module { * @return {Number} the power generation of this module */ getPowerGeneration(modified = true) { - return this._getValue('pgen', modified); + return this.get('pgen', modified); } /** @@ -275,7 +354,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); } /** @@ -284,7 +363,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); } /** @@ -293,7 +372,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); } /** @@ -302,7 +381,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); } /** @@ -311,7 +390,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); } /** @@ -320,7 +399,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); } /** @@ -329,7 +408,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); } /** @@ -338,7 +417,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); } /** @@ -347,7 +426,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); } /** @@ -356,7 +435,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); } /** @@ -365,7 +444,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); } /** @@ -374,7 +453,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); } /** @@ -383,7 +462,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); } /** @@ -392,7 +471,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); } /** @@ -401,7 +480,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); } /** @@ -410,7 +489,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); } /** @@ -419,7 +498,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); } /** @@ -428,7 +507,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); } /** @@ -439,7 +518,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); } @@ -465,7 +544,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); } /** @@ -474,7 +553,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); } /** @@ -483,7 +562,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); } /** @@ -492,7 +571,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); } /** @@ -501,7 +580,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); } /** @@ -510,7 +589,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); } /** @@ -519,7 +598,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); } /** @@ -528,7 +607,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); } /** @@ -555,7 +634,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); } /** @@ -646,7 +725,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); } /** @@ -655,7 +734,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); } /** @@ -664,7 +743,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); } /** @@ -673,7 +752,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); } /** @@ -755,7 +834,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; } @@ -766,7 +845,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); } /** @@ -775,7 +854,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); } /** @@ -784,7 +863,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); } /** @@ -793,7 +872,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); } /** @@ -808,7 +887,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); } @@ -819,7 +898,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); } /** @@ -828,7 +907,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); } /** @@ -837,7 +916,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); } /** @@ -846,7 +925,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); } /** @@ -855,7 +934,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); } /** @@ -864,7 +943,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); } /** @@ -873,7 +952,7 @@ export default class Module { * @return {Number} the bays for this module */ getBays(modified) { - return this._getValue('bays', modified); + return this.get('bays', modified); } /** @@ -882,7 +961,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); } /** @@ -891,7 +970,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); } /** @@ -909,7 +988,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); } /** @@ -918,7 +997,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); } /** @@ -927,7 +1006,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); } /** @@ -936,7 +1015,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..00f903ad 100755 --- a/src/app/shipyard/Ship.js +++ b/src/app/shipyard/Ship.js @@ -493,68 +493,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); } } From c295a9f4e429967fd8653e234d64f56ba3c55418 Mon Sep 17 00:00:00 2001 From: Felix Linker Date: Sat, 15 Sep 2018 00:33:31 +0200 Subject: [PATCH 2/9] Added percentage as unit --- src/app/i18n/Language.jsx | 1 + 1 file changed, 1 insertion(+) 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 From f86ce62c27b631a9808370c27e14f175bac8d7b6 Mon Sep 17 00:00:00 2001 From: Felix Linker Date: Sat, 15 Sep 2018 00:35:55 +0200 Subject: [PATCH 3/9] Optimized statistics calculation in shipyard/Ship --- src/app/shipyard/Ship.js | 58 +++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/src/app/shipyard/Ship.js b/src/app/shipyard/Ship.js index 00f903ad..3b740141 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']; @@ -1181,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 capacuty + 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; From 2456ce330badcf2e8acc36628bfb33035dfb8a9b Mon Sep 17 00:00:00 2001 From: Felix Linker Date: Sat, 15 Sep 2018 00:40:19 +0200 Subject: [PATCH 4/9] Change module modding to have absolute values entered --- src/app/components/Modification.jsx | 78 +++++++++--------------- src/app/components/ModificationsMenu.jsx | 2 +- src/app/shipyard/Module.js | 78 +++++++++++++++++++++--- src/app/shipyard/StatsFormating.js | 4 +- src/less/slot.less | 23 +++++++ 5 files changed, 125 insertions(+), 60 deletions(-) diff --git a/src/app/components/Modification.jsx b/src/app/components/Modification.jsx index 1ca29bef..1fb3581e 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,8 @@ 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; + ship.setModification(m, name, value, true, true); this.setState({ value }); } @@ -75,52 +62,43 @@ 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}
+
{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/shipyard/Module.js b/src/app/shipyard/Module.js index 6fd884e8..05690014 100755 --- a/src/app/shipyard/Module.js +++ b/src/app/shipyard/Module.js @@ -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]) { @@ -339,6 +333,76 @@ export default class Module { ); } + /** + * 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 formatingOptions = STATS_FORMATING[name]; + + if (isNaN(val)) { + // Calculate the percentage change for an abstract value + if (formatingOptions && formatingOptions.synthetic) { + const statGetter = this[formatingOptions.synthetic]; + let unmodifiedStat = statGetter.call(this, false); + let modifiedStat = statGetter.call(this, true); + result = (modifiedStat / unmodifiedStat - 1) * 10000; + } else { + val = this.getModValue(name); + } + } + + if (formatingOptions && formatingOptions.change) { + let changeFormating = formatingOptions.change; + let baseVal = this[name]; + let absVal = this._getModifiedValue(name); + if (changeFormating === 'additive') { + val = absVal - baseVal; + } else if (changeFormating === '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 formatingOptions = STATS_FORMATING[name]; + if (!formatingOptions || !formatingOptions.unit) { + if (formatingOptions.format && formatingOptions.format.startsWith('pct')) { + return 'pct'; + } + return ''; + } + + return formatingOptions.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 formatingOptions = STATS_FORMATING[name]; + if (!formatingOptions || !formatingOptions.storedUnit) { + return this.getUnitFor(name); + } + return formatingOptions.storedUnit; + } + /** * Get the power generation of this module * @param {Boolean} [modified=true] Whether to take modifications into account diff --git a/src/app/shipyard/StatsFormating.js b/src/app/shipyard/StatsFormating.js index 1beb772a..8c065901 100644 --- a/src/app/shipyard/StatsFormating.js +++ b/src/app/shipyard/StatsFormating.js @@ -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' }, @@ -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..916db0ae 100755 --- a/src/less/slot.less +++ b/src/less/slot.less @@ -37,6 +37,29 @@ text-overflow: ellipsis; } + .modification-container { + td { + width: 35%; + text-align: center; + } + + .input-container { + width: 65%; + text-align: right; + } + + input { + width: 70%; + } + + .unit-container { + width: 30px; + padding: 3px; + text-align: left; + display: inline-block; + } + } + .cb { overflow: hidden; } From 1151bd1614ae4ee7de9cbdab44145da5c1ed4c74 Mon Sep 17 00:00:00 2001 From: Felix Linker Date: Sat, 15 Sep 2018 00:42:39 +0200 Subject: [PATCH 5/9] optmul changes are displayed additively --- src/app/shipyard/StatsFormating.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/shipyard/StatsFormating.js b/src/app/shipyard/StatsFormating.js index 8c065901..24c9bd0f 100644 --- a/src/app/shipyard/StatsFormating.js +++ b/src/app/shipyard/StatsFormating.js @@ -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' }, From a5e9a71037c9e062153ee67f47e3d220d9dafbd4 Mon Sep 17 00:00:00 2001 From: Felix Linker Date: Sat, 15 Sep 2018 01:12:39 +0200 Subject: [PATCH 6/9] Clamp modification values to -50k and 50k --- src/app/components/Modification.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/components/Modification.jsx b/src/app/components/Modification.jsx index 1fb3581e..2e999c4b 100644 --- a/src/app/components/Modification.jsx +++ b/src/app/components/Modification.jsx @@ -40,6 +40,7 @@ export default class Modification extends TranslatedComponent { */ _updateValue(value) { let { m, name, ship } = this.props; + value = Math.max(Math.min(value, 50000), -50000); ship.setModification(m, name, value, true, true); this.setState({ value }); } From 06d8930777ea9a5c2eae882e0904cbea54f13300 Mon Sep 17 00:00:00 2001 From: Felix Linker Date: Sat, 15 Sep 2018 01:22:22 +0200 Subject: [PATCH 7/9] Typos fixed --- src/app/shipyard/Module.js | 56 +++++++++---------- src/app/shipyard/Ship.js | 2 +- .../{StatsFormating.js => StatsFormatting.js} | 2 +- 3 files changed, 30 insertions(+), 30 deletions(-) rename src/app/shipyard/{StatsFormating.js => StatsFormatting.js} (98%) diff --git a/src/app/shipyard/Module.js b/src/app/shipyard/Module.js index 05690014..c2ada840 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 @@ -191,9 +191,9 @@ export default class Module { * @return {Number} Value for given stat */ getPretty(name, modified = true, places = 2) { - const formatingOptions = STATS_FORMATING[name]; + const formattingOptions = STATS_FORMATTING[name]; let val = this.get(name, modified) || 0; - if (formatingOptions && formatingOptions.format.startsWith('pct')) { + if (formattingOptions && formattingOptions.format.startsWith('pct')) { return 100 * val; } // Round to two decimal places @@ -209,8 +209,8 @@ export default class Module { * @param {Boolean} valueIsWithSpecial True when value includes an special */ setPretty(name, value, valueIsWithSpecial) { - const formatingOptions = STATS_FORMATING[name]; - if (formatingOptions && formatingOptions.format.startsWith('pct')) { + const formattingOptions = STATS_FORMATTING[name]; + if (formattingOptions && formattingOptions.format.startsWith('pct')) { value = value / 100; } this.set(name, value, valueIsWithSpecial); @@ -275,7 +275,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 @@ -283,10 +283,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); } @@ -294,7 +294,7 @@ export default class Module { val = val || 0; - if (!formatingOptions) { + if (!formattingOptions) { return ( {val} @@ -302,9 +302,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 @@ -328,7 +328,7 @@ export default class Module { return ( {val} - {formatingOptions.unit && language.units[formatingOptions.unit]} + {formattingOptions.unit && language.units[formattingOptions.unit]} ); } @@ -343,12 +343,12 @@ export default class Module { * @return {Number} Change rate of the stat according to formatting options */ getChange(name, val) { - const formatingOptions = STATS_FORMATING[name]; + const formattingOptions = STATS_FORMATTING[name]; if (isNaN(val)) { // Calculate the percentage change for an abstract value - if (formatingOptions && formatingOptions.synthetic) { - const statGetter = this[formatingOptions.synthetic]; + 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; @@ -357,13 +357,13 @@ export default class Module { } } - if (formatingOptions && formatingOptions.change) { - let changeFormating = formatingOptions.change; + if (formattingOptions && formattingOptions.change) { + let changeFormatting = formattingOptions.change; let baseVal = this[name]; let absVal = this._getModifiedValue(name); - if (changeFormating === 'additive') { + if (changeFormatting === 'additive') { val = absVal - baseVal; - } else if (changeFormating === 'multiplicative') { + } else if (changeFormatting === 'multiplicative') { val = absVal / baseVal - 1; } val *= 10000; @@ -377,15 +377,15 @@ export default class Module { * @return {String} Unit key */ getUnitFor(name) { - const formatingOptions = STATS_FORMATING[name]; - if (!formatingOptions || !formatingOptions.unit) { - if (formatingOptions.format && formatingOptions.format.startsWith('pct')) { + const formattingOptions = STATS_FORMATTING[name]; + if (!formattingOptions || !formattingOptions.unit) { + if (formattingOptions.format && formattingOptions.format.startsWith('pct')) { return 'pct'; } return ''; } - return formatingOptions.unit; + return formattingOptions.unit; } /** @@ -396,11 +396,11 @@ export default class Module { * @return {String} Unit key */ getStoredUnitFor(name) { - const formatingOptions = STATS_FORMATING[name]; - if (!formatingOptions || !formatingOptions.storedUnit) { + const formattingOptions = STATS_FORMATTING[name]; + if (!formattingOptions || !formattingOptions.storedUnit) { return this.getUnitFor(name); } - return formatingOptions.storedUnit; + return formattingOptions.storedUnit; } /** diff --git a/src/app/shipyard/Ship.js b/src/app/shipyard/Ship.js index 3b740141..4e47f060 100755 --- a/src/app/shipyard/Ship.js +++ b/src/app/shipyard/Ship.js @@ -1191,7 +1191,7 @@ export default class Ship { .reduce((sum, mass) => sum + mass) .value(); - // handle fuel capacuty + // handle fuel capacity fuelCapacity += chain(slots) .map(slot => slot.m ? slot.m.get('fuel') : null) .filter() diff --git a/src/app/shipyard/StatsFormating.js b/src/app/shipyard/StatsFormatting.js similarity index 98% rename from src/app/shipyard/StatsFormating.js rename to src/app/shipyard/StatsFormatting.js index 24c9bd0f..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' }, From 93d8f15f262465a10c1a89bbf60ed8deff0ab429 Mon Sep 17 00:00:00 2001 From: Felix Linker Date: Sat, 15 Sep 2018 01:32:41 +0200 Subject: [PATCH 8/9] Moved diminishing returns for resistance modding on hrp into getModValue --- src/app/shipyard/Module.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/app/shipyard/Module.js b/src/app/shipyard/Module.js index c2ada840..8a3d85c1 100755 --- a/src/app/shipyard/Module.js +++ b/src/app/shipyard/Module.js @@ -76,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); } @@ -245,13 +254,6 @@ export default class Module { 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; From 7f5181a9c720ffbfd8e5821befb461d422b286f7 Mon Sep 17 00:00:00 2001 From: Felix Linker Date: Sat, 15 Sep 2018 01:54:17 +0200 Subject: [PATCH 9/9] Improved modification menu design --- src/app/components/Modification.jsx | 9 ++++++--- src/less/slot.less | 12 +++++++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/app/components/Modification.jsx b/src/app/components/Modification.jsx index 2e999c4b..1e6dae44 100644 --- a/src/app/components/Modification.jsx +++ b/src/app/components/Modification.jsx @@ -73,11 +73,14 @@ export default class Modification extends TranslatedComponent { } return ( -
this.props.modItems[name] = modItem }> -
{translate(name, m.grp)}
+
this.props.modItems[name] = modItem }> + {translate(name, m.grp)} +
- {/* 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}%
- +
{this.props.editable ? diff --git a/src/less/slot.less b/src/less/slot.less index 916db0ae..e6c962f9 100755 --- a/src/less/slot.less +++ b/src/less/slot.less @@ -38,18 +38,19 @@ } .modification-container { + @input-container-width: 75%; td { - width: 35%; + width: 100% - @input-container-width; text-align: center; } .input-container { - width: 65%; + width: @input-container-width; text-align: right; } input { - width: 70%; + width: 80%; } .unit-container { @@ -58,6 +59,11 @@ text-align: left; display: inline-block; } + + .header-adjuster { + width: 100% - @input-container-width; + display: inline-block; + } } .cb {