diff --git a/ChangeLog.md b/ChangeLog.md index 517c85d1..bc86add2 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,3 +1,15 @@ +#2.2.10 + * Fix detailed export of module reinforcement packages + * Use damagedist for exact breakdown of weapons that have more than one type of damage + * Use new-style modification validity data + * Provide ability to select engineering blueprint and roll sample values for them + * Use coriolis-data 2.2.10: + * Fix incorrect base shield values for Cutter and Corvette + * Update weapons to have %-based damage distributions + * Remove power draw for detailed surface scanner - although shown in outfitting it is not part of active power + * Fix incorrect names for lightweight and kinetic armour + * Add engineering blueprints + #2.2.9 * Use SSL-enabled server for shortlinks * Add falloff for weapons diff --git a/__tests__/fixtures/anaconda-test-detailed-export-v4.json b/__tests__/fixtures/anaconda-test-detailed-export-v4.json index 12327c14..402c67f2 100644 --- a/__tests__/fixtures/anaconda-test-detailed-export-v4.json +++ b/__tests__/fixtures/anaconda-test-detailed-export-v4.json @@ -269,20 +269,20 @@ "topSpeed": 187.01, "totalCost": 882362058, "totalDpe": 142.68, - "totalDps": 101.13, + "totalDps": 103.8, "totalEps": 22.71, "totalHps": 677.29, "totalExplDpe": 0, "totalExplDps": 0, "totalExplSDps": 0, "totalHps": 33.62, - "totalKinDpe": 116.29, - "totalKinDps": 16.01, - "totalKinSDps": 12.09, - "totalSDps": 89.99, - "totalThermDpe": 20.44, - "totalThermDps": 53.82, - "totalThermSDps": 53.82, + "totalKinDpe": 117.48, + "totalKinDps": 24.94, + "totalKinSDps": 18.76, + "totalSDps": 91.84, + "totalThermDpe": 21.63, + "totalThermDps": 60.08, + "totalThermSDps": 58.64, "baseShieldStrength": 350, "baseArmour": 945, "hullExplRes": 0.22, diff --git a/__tests__/test-import.js b/__tests__/test-import.js index a6a44dc6..42d6fe06 100644 --- a/__tests__/test-import.js +++ b/__tests__/test-import.js @@ -238,7 +238,7 @@ describe('Import Modal', function() { expect(modal.state.singleBuild).toBe(true); clickProceed(); expect(MockRouter.go.mock.calls.length).toBe(1); - expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/federal_corvette?code=A2putsFklndzsxf50x0x7l28281919040404040402020l06p05sf63c5ifr--v66g2f.AwRj4zNaqA%3D%3D.CwRgDBldUExuBiIlUA%3D%3D.H4sIAAAAAAAAA02SO0sDQRSFbxJ389jgJOsaN%2FGVmPXVKKRQC8FSA9oJWihWWgV%2FgIWFYBNb8RcIWiiIYiF2NqksIqaRoD%2FBQghB41zPFVa3OdzZ890zM3snpBeI6DsEyZgGkbpg5tg2lhzWGbEikN6aSVS0HSL3Ogxo6IvZmdbM9hFsjuickGgn%2B8SGv%2FvJ7DpxIqeCHjb0vJ80GrWIxu5RFmqARnYQEj%2FrMCdesFQzSOeYXvPP1BmGZPeiREa9xWyW0WifwnFX0MMJve4Hd5IQo4I9TcclGrxCUmoO34qVDaK%2BJuiJfD6%2FytZ%2Fj%2FGQAL7fD%2Fyiy8fbcNQdjsXJAFn9DRbyQchZIS9RqZJcGpckt4xjsdKL%2FtndJYjVQJkW8URUVYJTAegLat0IJOKJqCeB0gHoQ6BHgUQ8EdUNZvgghj3tAPmKa1vPQhIqTyp1KHE9AWgKV7Ka8NMinoiywLCrV%2F5Gvolo61ySpMn7xMdwsc3cf4w48w2Is40fwFld9oPzLbyL6CT88QaWoZpMcyDg32Jo0br4EaxDJXk8BT3o%2B7ktGS9B3GU8puS7zJh%2FAHGMT2qjAgAA&bn=Imported%20Federal%20Corvette'); + expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/federal_corvette?code=A2putsFklndzsxf50x0x7l28281919040404040402020l06p05sf63c5ifr--v66g2f.AwRj4zNaqA%3D%3D.CwRgDBldUExuBiIlUA%3D%3D.H4sIAAAAAAAAA02Svy9DURTHT1vvtfoat32eekVV9fm1kBgwSIw0YWYgBqmpMZkMBomFVfwFEoZKhBjE1qWTgegiDX%2BCQdKI1j2%2BR%2FJ4yzfnvu%2FnfO%2B979yQXiCi7xAkbRpEqsLMsRKWHNZpsSKQnppJVLAdIvc6DGiwxexMaWb7GDZHdJ%2BQaCf71Ia%2F88XsOp1EThk9bOh5P2kkahGN3qPM1wANbyOk87zNHH%2FBUs0gnWN61T9TOwfJ7EWJjMcms1lEo30Gx11BD8f1mh%2FcTkCMMvY0HZcoe4Wk5By%2BFcrrRL0N0OOlrd0Ntv57jGoc%2BH4%2F8EqHj3%2FCUXc4FicC5NFvsJBVIWeFvESlpuXSuCS5RRyLlV70z%2B4uQaw6ypSIJ6KOJDgZgFpQ60YgEU9EPQmUCkAfAj0IJOKJqC4wuYMY9rQD5CuubT0LSag8qdShxHUHoElcyWrAT4l4IsoCw65e%2BRv5BqKtC0mSJu8LH8OFT%2Bb%2BE8SZb0CcEn4AZ3TRDx5q4l1EJ%2BCP1bEM1WSaAwH%2FFkOLPoofwTo0LY8nr7O%2B37cp4yWIu4zHlHiXGfMPmat5gqMCAAA%3D&bn=Imported%20Federal%20Corvette'); }); it('imports a valid v4 build', function() { diff --git a/package.json b/package.json index 7738c704..880c6da2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "coriolis_shipyard", - "version": "2.2.9", + "version": "2.2.10", "repository": { "type": "git", "url": "https://github.com/EDCD/coriolis" diff --git a/src/app/components/DamageDealt.jsx b/src/app/components/DamageDealt.jsx index eb27dc20..5d0f27b2 100644 --- a/src/app/components/DamageDealt.jsx +++ b/src/app/components/DamageDealt.jsx @@ -153,7 +153,7 @@ export default class DamageDealt extends TranslatedComponent { } totals.effectiveness = totals.effectiveDps / totalDps; - return {weapons: weapons, totals: totals}; + return { weapons, totals }; } /** diff --git a/src/app/components/DamageReceived.jsx b/src/app/components/DamageReceived.jsx index 7268d5c4..3b254025 100644 --- a/src/app/components/DamageReceived.jsx +++ b/src/app/components/DamageReceived.jsx @@ -93,7 +93,7 @@ export default class DamageReceived extends TranslatedComponent { let weapons = []; for (let grp in Modules.hardpoints) { - if (Modules.hardpoints[grp][0].damage && Modules.hardpoints[grp][0].type) { + if (Modules.hardpoints[grp][0].damage && Modules.hardpoints[grp][0].damagedist) { for (let mId in Modules.hardpoints[grp]) { const m = new Module(Modules.hardpoints[grp][mId]); const classRating = `${m.class}${m.rating}${m.missile ? '/' + m.missile : ''}`; @@ -104,37 +104,35 @@ export default class DamageReceived extends TranslatedComponent { // Effective DPS taking in to account shield resistance let effectivenessShields = 0; - if (m.getDamageType().indexOf('E') != -1) { - effectivenessShields += (1 - ship.shieldExplRes); + if (m.getDamageDist().E) { + effectivenessShields += m.getDamageDist().E * (1 - ship.shieldExplRes); } - if (m.getDamageType().indexOf('K') != -1) { - effectivenessShields += (1 - ship.shieldKinRes); + if (m.getDamageDist().K) { + effectivenessShields += m.getDamageDist().K * (1 - ship.shieldKinRes); } - if (m.getDamageType().indexOf('T') != -1) { - effectivenessShields += (1 - ship.shieldThermRes); + if (m.getDamageDist().T) { + effectivenessShields += m.getDamageDist().T * (1 - ship.shieldThermRes); } - if (m.getDamageType().indexOf('A') != -1) { - effectivenessShields += 1; + if (m.getDamageDist().A) { + effectivenessShields += m.getDamageDist().A; } - effectivenessShields /= m.getDamageType().length; const effectiveDpsShields = baseDps * effectivenessShields; const effectiveSDpsShields = baseSDps * effectivenessShields; // Effective DPS taking in to account hull hardness and resistance let effectivenessHull = 0; - if (m.getDamageType().indexOf('E') != -1) { - effectivenessHull += (1 - ship.hullExplRes); + if (m.getDamageDist().E) { + effectivenessHull += m.getDamageDist().E * (1 - ship.hullExplRes); } - if (m.getDamageType().indexOf('K') != -1) { - effectivenessHull += (1 - ship.hullKinRes); + if (m.getDamageDist().K) { + effectivenessHull += m.getDamageDist().K * (1 - ship.hullKinRes); } - if (m.getDamageType().indexOf('T') != -1) { - effectivenessHull += (1 - ship.hullThermRes); + if (m.getDamageDist().T) { + effectivenessHull += m.getDamageDist().T * (1 - ship.hullThermRes); } - if (m.getDamageType().indexOf('A') != -1) { - effectivenessHull += 1; + if (m.getDamageDist().A) { + effectivenessHull += m.getDamageDist().A; } - effectivenessHull /= m.getDamageType().length; effectivenessHull *= Math.min(m.getPiercing() / ship.hardness, 1); const effectiveDpsHull = baseDps * effectivenessHull; const effectiveSDpsHull = baseSDps * effectivenessHull; diff --git a/src/app/components/HardpointSlot.jsx b/src/app/components/HardpointSlot.jsx index e4d75d6e..f6232568 100644 --- a/src/app/components/HardpointSlot.jsx +++ b/src/app/components/HardpointSlot.jsx @@ -41,7 +41,7 @@ export default class HardpointSlot extends Slot { let classRating = `${m.class}${m.rating}${m.missile ? '/' + m.missile : ''}`; let { drag, drop } = this.props; let { termtip, tooltip } = this.context; - let validMods = Modifications.validity[m.grp] || []; + let validMods = Modifications.modules[m.grp].modifications || []; let showModuleResistances = Persist.showModuleResistances(); // Modifications tooltip shows blueprint and grade, if available @@ -59,9 +59,9 @@ export default class HardpointSlot extends Slot { {m.mount && m.mount == 'F' ? : ''} {m.mount && m.mount == 'G' ? : ''} {m.mount && m.mount == 'T' ? : ''} - {m.getDamageType() && m.getDamageType().match('K') ? : ''} - {m.getDamageType() && m.getDamageType().match('T') ? : ''} - {m.getDamageType() && m.getDamageType().match('E') ? : ''} + {m.getDamageDist() && m.getDamageDist().K ? : ''} + {m.getDamageDist() && m.getDamageDist().T ? : ''} + {m.getDamageDist() && m.getDamageDist().E ? : ''} {classRating} {translate(m.name || m.grp)}{ m.mods && Object.keys(m.mods).length > 0 ? : null } @@ -77,6 +77,7 @@ export default class HardpointSlot extends Slot { { m.getFalloff() ?
{translate('falloff')} {formats.f1(m.getFalloff() / 1000)}{u.km}
: null } { m.getShieldBoost() ?
+{formats.pct1(m.getShieldBoost())}
: null } { m.getAmmo() ?
{translate('ammunition')}: {formats.int(m.getClip())}/{formats.int(m.getAmmo())}
: null } + { m.getShotSpeed() ?
{translate('shotspeed')}: {formats.int(m.getShotSpeed())}{u.mps}
: null } { m.getPiercing() ?
{translate('piercing')}: {formats.int(m.getPiercing())}
: null } { m.getJitter() ?
{translate('jitter')}: {formats.f2(m.getJitter())}°
: null } { showModuleResistances && m.getExplosiveResistance() ?
{translate('explres')}: {formats.pct(m.getExplosiveResistance())}
: null } diff --git a/src/app/components/InternalSlot.jsx b/src/app/components/InternalSlot.jsx index 1bb7bf4b..4ce53f83 100644 --- a/src/app/components/InternalSlot.jsx +++ b/src/app/components/InternalSlot.jsx @@ -23,7 +23,7 @@ export default class InternalSlot extends Slot { let classRating = m.class + m.rating; let { drag, drop, ship } = this.props; let { termtip, tooltip } = this.context; - let validMods = Modifications.validity[m.grp] || []; + let validMods = Modifications.modules[m.grp].modifications || []; let showModuleResistances = Persist.showModuleResistances(); // Modifications tooltip shows blueprint and grade, if available diff --git a/src/app/components/Modification.jsx b/src/app/components/Modification.jsx index 3813681e..c191b96c 100644 --- a/src/app/components/Modification.jsx +++ b/src/app/components/Modification.jsx @@ -13,6 +13,7 @@ export default class Modification extends TranslatedComponent { ship: React.PropTypes.object.isRequired, m: React.PropTypes.object.isRequired, name: React.PropTypes.string.isRequired, + value: React.PropTypes.number.isRequired, onChange: React.PropTypes.func.isRequired }; @@ -24,7 +25,7 @@ export default class Modification extends TranslatedComponent { constructor(props, context) { super(props); this.state = {}; - this.state.value = this.props.m.getModValue(this.props.name) / 100 || 0; + this.state.value = props.value; } /** @@ -61,10 +62,10 @@ export default class Modification extends TranslatedComponent { */ render() { let translate = this.context.language.translate; - let name = this.props.name; + let { m, name } = this.props; - if (name === 'type') { - // We don't show type + if (name === 'damagedist') { + // We don't show damage distribution return null; } @@ -81,7 +82,7 @@ export default class Modification extends TranslatedComponent { return (
{translate(name)}{symbol}
- +
); } diff --git a/src/app/components/ModificationsMenu.jsx b/src/app/components/ModificationsMenu.jsx index 1a56180f..76bf5218 100644 --- a/src/app/components/ModificationsMenu.jsx +++ b/src/app/components/ModificationsMenu.jsx @@ -1,7 +1,8 @@ import React from 'react'; +import * as _ from 'lodash'; import { findDOMNode } from 'react-dom'; import TranslatedComponent from './TranslatedComponent'; -import { stopCtxPropagation } from '../utils/UtilityFunctions'; +import { isEmpty, stopCtxPropagation } from '../utils/UtilityFunctions'; import cn from 'classnames'; import { MountFixed, MountGimballed, MountTurret } from './SvgIcons'; import { Modifications } from 'coriolis-data/dist'; @@ -26,25 +27,177 @@ export default class ModificationsMenu extends TranslatedComponent { constructor(props, context) { super(props); this.state = this._initState(props, context); + + this._toggleBlueprintsMenu = this._toggleBlueprintsMenu.bind(this); + this._rollWorst = this._rollWorst.bind(this); + this._rollRandom = this._rollRandom.bind(this); + this._rollBest = this._rollBest.bind(this); + this._reset = this._reset.bind(this); } /** - * Initiate the list of modifications + * Initialise state * @param {Object} props React Component properties * @param {Object} context React Component context * @return {Object} list: Array of React Components */ _initState(props, context) { let { m, onChange, ship } = props; - let list = []; - for (let modName of Modifications.validity[m.grp]) { - if (Modifications.modifications[modName].type != 'hidden') { - list.push(); + let blueprints = []; + for (const blueprintName in Modifications.modules[m.grp].blueprints) { + for (const grade of Modifications.modules[m.grp].blueprints[blueprintName]) { + const close = this._blueprintSelected.bind(this, Modifications.blueprints[blueprintName].id, grade); + const key = blueprintName + ':' + grade; + blueprints.push(
{Modifications.blueprints[blueprintName].name} grade {grade}
); + } + } + + // Set up the modifications + const modifications = this._setModifications(props); + + const blueprintMenuOpened = false; + + // Set up the specials for this module + // const specials = _selectSpecials(m); + + return { blueprintMenuOpened, blueprints, modifications }; + } + + /** + * Initialise the modifications + * @param {Object} props React Component properties + * @return {Object} list: Array of React Components + */ + _setModifications(props) { + const { m, onChange, ship } = props; + let modifications = []; + for (const modName of Modifications.modules[m.grp].modifications) { + if (Modifications.modifications[modName].type === 'percentage' || Modifications.modifications[modName].type === 'numeric') { + modifications.push(); + } + } + return modifications; + } + + /** + * Toggle the blueprints menu + */ + _toggleBlueprintsMenu() { + const blueprintMenuOpened = !this.state.blueprintMenuOpened; + this.setState({ blueprintMenuOpened }); + } + + /** + * Activated when a blueprint is selected + * @param {int} blueprintId The ID of the selected blueprint + * @param {int} grade The grade of the selected blueprint + */ + _blueprintSelected(blueprintId, grade) { + const { m } = this.props; + const blueprint = Object.assign({}, _.find(Modifications.blueprints, function(o) { return o.id === blueprintId; })); + blueprint.grade = grade; + m.blueprint = blueprint; + + const blueprintMenuOpened = false; + this.setState({ blueprintMenuOpened }); + this.props.onChange(); + } + + /** + * Provide a 'worst' roll within the information we have + */ + _rollWorst() { + const { m, ship } = this.props; + const features = m.blueprint.features[m.blueprint.grade]; + for (const featureName in features) { + if (Modifications.modifications[featureName].method == 'overwrite') { + ship.setModification(m, featureName, features[featureName][1]); + } else { + let value = features[featureName][0]; + if (m.grp == 'sb' && featureName == 'shieldboost') { + // Shield boosters are a special case. Their boost is dependent on their base so we need to calculate the value here + value = ((1 + m.shieldboost) * (1 + value) - 1) / m.shieldboost - 1; + } + + if (Modifications.modifications[featureName].type == 'percentage') { + ship.setModification(m, featureName, value * 10000); + } else if (Modifications.modifications[featureName].type == 'numeric') { + ship.setModification(m, featureName, value * 100); + } + } + } + + this.setState({ modifications: this._setModifications(this.props) }); + this.props.onChange(); + } + + /** + * Provide a random roll within the information we have + */ + _rollRandom() { + const { m, ship } = this.props; + const features = m.blueprint.features[m.blueprint.grade]; + for (const featureName in features) { + if (Modifications.modifications[featureName].method == 'overwrite') { + ship.setModification(m, featureName, features[featureName][1]); + } else { + let value = features[featureName][0] + (Math.random() * (features[featureName][1] - features[featureName][0])); + if (m.grp == 'sb' && featureName == 'shieldboost') { + // Shield boosters are a special case. Their boost is dependent on their base so we need to calculate the value here + value = ((1 + m.shieldboost) * (1 + value) - 1) / m.shieldboost - 1; + } + + if (Modifications.modifications[featureName].type == 'percentage') { + ship.setModification(m, featureName, value * 10000); + } else if (Modifications.modifications[featureName].type == 'numeric') { + ship.setModification(m, featureName, value * 100); + } } } - return { list }; + this.setState({ modifications: this._setModifications(this.props) }); + this.props.onChange(); + } + + /** + * Provide a 'best' roll within the information we have + */ + _rollBest() { + const { m, ship } = this.props; + const features = m.blueprint.features[m.blueprint.grade]; + for (const featureName in features) { + if (Modifications.modifications[featureName].method == 'overwrite') { + ship.setModification(m, featureName, features[featureName][1]); + } else { + let value = features[featureName][1]; + if (m.grp == 'sb' && featureName == 'shieldboost') { + // Shield boosters are a special case. Their boost is dependent on their base so we need to calculate the value here + value = ((1 + m.shieldboost) * (1 + value) - 1) / m.shieldboost - 1; + } + + if (Modifications.modifications[featureName].type == 'percentage') { + ship.setModification(m, featureName, value * 10000); + } else if (Modifications.modifications[featureName].type == 'numeric') { + ship.setModification(m, featureName, value * 100); + } + } + } + + this.setState({ modifications: this._setModifications(this.props) }); + this.props.onChange(); + } + + /** + * Reset modification information + */ + _reset() { + const { m, ship } = this.props; + ship.clearModifications(m); + ship.clearBlueprint(m); + + this.setState({ modifications: this._setModifications(this.props) }); + this.props.onChange(); } /** @@ -52,15 +205,51 @@ export default class ModificationsMenu extends TranslatedComponent { * @return {React.Component} List */ render() { - let { tooltip, termtip } = this.context; + const language = this.context.language; + const translate = language.translate; + const { tooltip, termtip } = this.context; + const { m } = this.props; + const { blueprintMenuOpened } = this.state; + + const _toggleBlueprintsMenu = this._toggleBlueprintsMenu; + const _rollBest = this._rollBest; + const _rollWorst = this._rollWorst; + const _rollRandom = this._rollRandom; + const _reset = this._reset; + + let blueprintLabel; + let haveBlueprint = false; + if (m.blueprint && !isEmpty(m.blueprint)) { + blueprintLabel = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade; + haveBlueprint = true; + } else { + blueprintLabel = translate('PHRASE_SELECT_BLUEPRINT'); + } + return (
e.stopPropagation() } onContextMenu={stopCtxPropagation} - onMouseOver={termtip.bind(null, 'HELP_MODIFICATIONS_MENU')} onMouseOut={tooltip.bind(null, null)} > - {this.state.list} +
{blueprintLabel}
+ { blueprintMenuOpened ? this.state.blueprints : '' } + { haveBlueprint ? + + + + + + + + + + +
{ translate('roll') }: { translate('worst') } { translate('random') } { translate('best') } { translate('reset') }
: '' } + { blueprintMenuOpened ? '' : + + { this.state.modifications } + }
); } diff --git a/src/app/components/StandardSlot.jsx b/src/app/components/StandardSlot.jsx index ebbd5485..d032fc00 100644 --- a/src/app/components/StandardSlot.jsx +++ b/src/app/components/StandardSlot.jsx @@ -46,7 +46,7 @@ export default class StandardSlot extends TranslatedComponent { let m = slot.m; let classRating = m.class + m.rating; let menu; - let validMods = m == null ? [] : (Modifications.validity[m.grp] || []); + let validMods = m == null ? [] : (Modifications.modules[m.grp].modifications || []); let showModuleResistances = Persist.showModuleResistances(); let mass = m.getMass() || m.cargo || m.fuel || 0; diff --git a/src/app/i18n/Language.jsx b/src/app/i18n/Language.jsx index d16b2e1f..4fbac2e4 100644 --- a/src/app/i18n/Language.jsx +++ b/src/app/i18n/Language.jsx @@ -67,6 +67,7 @@ export function getLanguage(langCode) { 'm/s': {translate('m/s')}, // Meters per second '°/s': {translate('°/s')}, // Degrees per second MW: {translate('MW')}, // Mega Watts (same as Mega Joules per second) + mps: {translate('m/s')}, // Metres per second ps: {translate('/s')}, // per second pm: {translate('/min')}, // per minute s: {translate('secs')}, // Seconds diff --git a/src/app/i18n/en.js b/src/app/i18n/en.js index 091cb560..03c96387 100644 --- a/src/app/i18n/en.js +++ b/src/app/i18n/en.js @@ -29,6 +29,11 @@ export const terms = { PHRASE_UNLADEN: 'Ship mass excluding fuel and cargo', PHRASE_UPDATE_RDY: 'Update Available! Click to refresh', PHRASE_ENGAGEMENT_RANGE: 'The distance between your ship and its target', + PHRASE_SELECT_BLUEPRINT: 'Click to select a blueprint', + PHRASE_BLUEPRINT_WORST: 'Worst primary values for this blueprint', + PHRASE_BLUEPRINT_RANDOM: 'Random selection between worst and best primary values for this blueprint', + PHRASE_BLUEPRINT_BEST: 'Best primary values for this blueprint', + PHRASE_BLUEPRINT_RESET: 'Remove all modifications and blueprint', HELP_MODIFICATIONS_MENU: 'Click on a number to enter a new value, or drag along the bar for small changes', @@ -102,6 +107,12 @@ export const terms = { rebuildsperbay: 'Rebuilds per bay', + // Blueprint rolls + worst: 'Worst', + random: 'Random', + best: 'Best', + reset: 'Reset', + // Weapon, offence, defence and movement dpe: 'Damage per MJ of energy', dps: 'Damage per second', @@ -163,6 +174,7 @@ export const terms = { shield: 'Shield', shieldboost: 'Shield boost', shieldreinforcement: 'Shield reinforcement', + shotspeed: 'Shot speed', spinup: 'Spin up time', syscap: 'Systems capacity', sysrate: 'Systems recharge rate', diff --git a/src/app/shipyard/Constants.js b/src/app/shipyard/Constants.js index 35901ee3..a273c578 100755 --- a/src/app/shipyard/Constants.js +++ b/src/app/shipyard/Constants.js @@ -33,6 +33,7 @@ export const ModuleGroupToName = { fi: 'Frame Shift Drive Interdictor', hb: 'Hatch Breaker Limpet Controller', hr: 'Hull Reinforcement Package', + mrp: 'Module Reinforcement Package', rf: 'Refinery', scb: 'Shield Cell Bank', sg: 'Shield Generator', diff --git a/src/app/shipyard/Module.js b/src/app/shipyard/Module.js index 36911b33..7b58e6b4 100755 --- a/src/app/shipyard/Module.js +++ b/src/app/shipyard/Module.js @@ -650,10 +650,18 @@ export default class Module { } /** - * Get the damage type for this module, taking in to account modifications - * @return {string} the damage types for this module; any combination of E T and K + * Get the damage distribution for this module, taking in to account modifications + * @return {string} the damage distribution for this module */ - getDamageType() { - return this.getModValue('type') || this.type; + getDamageDist() { + return this.getModValue('damagedist') || this.damagedist; + } + + /** + * Get the shot speed for this module, taking in to account modifications + * @return {string} the damage distribution for this module + */ + getShotSpeed() { + return this._getModifiedValue('shotspeed'); } } diff --git a/src/app/shipyard/Ship.js b/src/app/shipyard/Ship.js index 1342ff20..88ffb9b0 100755 --- a/src/app/shipyard/Ship.js +++ b/src/app/shipyard/Ship.js @@ -411,6 +411,32 @@ export default class Ship { return this; } + /** + * Clear all modification values for a module + * @param {Number} m The module for which to clear the modifications + */ + clearModifications(m) { + m.mods = {}; + this.updatePowerGenerated() + .updatePowerUsed() + .updateJumpStats() + .recalculateShield() + .recalculateShieldCells() + .recalculateArmour() + .recalculateDps() + .recalculateEps() + .recalculateHps() + .updateMovement(); + } + + /** + * Clear blueprint for a module + * @param {Number} m The module for which to clear the modifications + */ + clearBlueprint(m) { + m.blueprint = {}; + } + /** * Set a modification value * @param {Object} m The module to change @@ -954,20 +980,22 @@ export default class Ship { totalDpe += dpe; totalDps += dps; totalSDps += sdps; - if (slot.m.getDamageType().indexOf('E') != -1) { - totalExplDpe += dpe / slot.m.getDamageType().length; - totalExplDps += dps / slot.m.getDamageType().length; - totalExplSDps += sdps / slot.m.getDamageType().length; - } - if (slot.m.getDamageType().indexOf('K') != -1) { - totalKinDpe += dpe / slot.m.getDamageType().length; - totalKinDps += dps / slot.m.getDamageType().length; - totalKinSDps += sdps / slot.m.getDamageType().length; - } - if (slot.m.getDamageType().indexOf('T') != -1) { - totalThermDpe += dpe / slot.m.getDamageType().length; - totalThermDps += dps / slot.m.getDamageType().length; - totalThermSDps += sdps / slot.m.getDamageType().length; + if (slot.m.getDamageDist()) { + if (slot.m.getDamageDist().E) { + totalExplDpe += dpe * slot.m.getDamageDist().E; + totalExplDps += dps * slot.m.getDamageDist().E; + totalExplSDps += sdps * slot.m.getDamageDist().E; + } + if (slot.m.getDamageDist().K) { + totalKinDpe += dpe * slot.m.getDamageDist().K; + totalKinDps += dps * slot.m.getDamageDist().K; + totalKinSDps += sdps * slot.m.getDamageDist().K; + } + if (slot.m.getDamageDist().T) { + totalThermDpe += dpe * slot.m.getDamageDist().T; + totalThermDps += dps * slot.m.getDamageDist().T; + totalThermSDps += sdps * slot.m.getDamageDist().T; + } } } } @@ -1333,7 +1361,7 @@ export default class Ship { if (this.bulkheads.m && this.bulkheads.m.mods) { for (let modKey in this.bulkheads.m.mods) { // Filter out invalid modifications - if (Modifications.validity['bh'] && Modifications.validity['bh'].indexOf(modKey) != -1) { + if (Modifications.modules['bh'] && Modifications.modules['bh'].modifications.indexOf(modKey) != -1) { bulkheadMods.push({ id: Modifications.modifications[modKey].id, value: this.bulkheads.m.getModValue(modKey) }); } } @@ -1348,7 +1376,7 @@ export default class Ship { if (slot.m && slot.m.mods) { for (let modKey in slot.m.mods) { // Filter out invalid modifications - if (Modifications.validity[slot.m.grp] && Modifications.validity[slot.m.grp].indexOf(modKey) != -1) { + if (Modifications.modules[slot.m.grp] && Modifications.modules[slot.m.grp].modifications.indexOf(modKey) != -1) { slotMods.push({ id: Modifications.modifications[modKey].id, value: slot.m.getModValue(modKey) }); } } @@ -1363,7 +1391,7 @@ export default class Ship { if (slot.m && slot.m.mods) { for (let modKey in slot.m.mods) { // Filter out invalid modifications - if (Modifications.validity[slot.m.grp] && Modifications.validity[slot.m.grp].indexOf(modKey) != -1) { + if (Modifications.modules[slot.m.grp] && Modifications.modules[slot.m.grp].modifications.indexOf(modKey) != -1) { slotMods.push({ id: Modifications.modifications[modKey].id, value: slot.m.getModValue(modKey) }); } } @@ -1378,7 +1406,7 @@ export default class Ship { if (slot.m && slot.m.mods) { for (let modKey in slot.m.mods) { // Filter out invalid modifications - if (Modifications.validity[slot.m.grp] && Modifications.validity[slot.m.grp].indexOf(modKey) != -1) { + if (Modifications.modules[slot.m.grp] && Modifications.modules[slot.m.grp].modifications.indexOf(modKey) != -1) { slotMods.push({ id: Modifications.modifications[modKey].id, value: slot.m.getModValue(modKey) }); } } diff --git a/src/app/utils/SlotFunctions.js b/src/app/utils/SlotFunctions.js index a9481315..1c064c67 100644 --- a/src/app/utils/SlotFunctions.js +++ b/src/app/utils/SlotFunctions.js @@ -153,7 +153,7 @@ export function diffDetails(language, m, mm) { let mPowerGeneration = m.pgen || 0; let mmPowerGeneration = mm ? mm.getPowerGeneration() : 0; - if (mPowerGeneration != mmPowerGeneration) propDiffs.push(
{translate('pgen')}: {diff(formats.round, mPowerGeneration, mmPowerGeneration)}{units.MJ}
); + if (mPowerGeneration != mmPowerGeneration) propDiffs.push(
{translate('pgen')}: {diff(formats.round, mPowerGeneration, mmPowerGeneration)}{units.MJ}
); let mPowerUsage = m.power || 0; let mmPowerUsage = mm ? mm.getPowerUsage() : 0; diff --git a/src/app/utils/UtilityFunctions.js b/src/app/utils/UtilityFunctions.js index 1137af26..4f0e2e7c 100644 --- a/src/app/utils/UtilityFunctions.js +++ b/src/app/utils/UtilityFunctions.js @@ -71,3 +71,15 @@ export function shallowEqual(objA, objB) { export function fromUrlSafe(data) { return data ? data.replace(/-/g, '/').replace(/_/g, '+') : null; } + +/** + * Check if an object is empty + * @param {object} obj the object + * @return {bool} true if the object is empty, otherwise false + */ +export function isEmpty(obj) { + for (let key in obj) { + if (obj.hasOwnProperty(key)) return false; + } + return true; +};