diff --git a/src/app/components/Boost.jsx b/src/app/components/Boost.jsx index 10e60927..b6803138 100644 --- a/src/app/components/Boost.jsx +++ b/src/app/components/Boost.jsx @@ -1,7 +1,6 @@ import React from 'react'; import TranslatedComponent from './TranslatedComponent'; import { Ships } from 'coriolis-data/dist'; -import ShipSelector from './ShipSelector'; import { nameComparator } from '../utils/SlotFunctions'; import { Pip } from './SvgIcons'; import LineChart from '../components/LineChart'; diff --git a/src/app/components/DamageDealt.jsx b/src/app/components/DamageDealt.jsx deleted file mode 100644 index d1d0fbe6..00000000 --- a/src/app/components/DamageDealt.jsx +++ /dev/null @@ -1,589 +0,0 @@ -import React from 'react'; -import TranslatedComponent from './TranslatedComponent'; -import { Ships } from 'coriolis-data/dist'; -import ShipSelector from './ShipSelector'; -import { nameComparator } from '../utils/SlotFunctions'; -import { CollapseSection, ExpandSection, MountFixed, MountGimballed, MountTurret } from './SvgIcons'; -import LineChart from '../components/LineChart'; -import Slider from '../components/Slider'; -import * as ModuleUtils from '../shipyard/ModuleUtils'; -import Module from '../shipyard/Module'; - -const DAMAGE_DEALT_COLORS = ['#FFFFFF', '#FF0000', '#00FF00', '#7777FF', '#FFFF00', '#FF00FF', '#00FFFF', '#777777']; - -/** - * Generates an internationalization friendly weapon comparator that will - * sort by specified property (if provided) then by name/group, class, rating - * @param {function} translate Translation function - * @param {function} propComparator Optional property comparator - * @param {boolean} desc Use descending order - * @return {function} Comparator function for names - */ -export function weaponComparator(translate, propComparator, desc) { - return (a, b) => { - if (!desc) { // Flip A and B if ascending order - let t = a; - a = b; - b = t; - } - - // If a property comparator is provided use it first - let diff = propComparator ? propComparator(a, b) : nameComparator(translate, a, b); - - if (diff) { - return diff; - } - - // Property matches so sort by name / group, then class, rating - if (a.name === b.name && a.grp === b.grp) { - if(a.class == b.class) { - return a.rating > b.rating ? 1 : -1; - } - return a.class - b.class; - } - - return nameComparator(translate, a, b); - }; -} - -/** - * Damage against a selected ship - */ -export default class DamageDealt extends TranslatedComponent { - static propTypes = { - ship: React.PropTypes.object.isRequired, - code: React.PropTypes.string.isRequired - }; - - static DEFAULT_AGAINST = Ships['anaconda']; - - /** - * Constructor - * @param {Object} props React Component properties - * @param {Object} context React Component context - */ - constructor(props, context) { - super(props); - - this._sort = this._sort.bind(this); - this._onShipChange = this._onShipChange.bind(this); - this._onCollapseExpand = this._onCollapseExpand.bind(this); - - const ship = this.props.ship; - const against = DamageDealt.DEFAULT_AGAINST; - const maxRange = this._calcMaxRange(ship); - const range = 1000 / maxRange; - const maxDps = this._calcMaxSDps(ship, against); - const weaponNames = this._weaponNames(ship, context); - - this.state = { - predicate: 'n', - desc: true, - against, - expanded: false, - range, - maxRange, - maxDps, - weaponNames, - calcHullDpsFunc: this._calcDps.bind(this, context, ship, weaponNames, against, true), - calcShieldsDpsFunc: this._calcDps.bind(this, context, ship, weaponNames, against, false) - }; - } - - /** - * Set the initial weapons state - */ - componentWillMount() { - const data = this._calcWeaponsDps(this.props.ship, this.state.against, this.state.range * this.state.maxRange, true); - this.setState({ weapons: data.weapons, totals: data.totals }); - } - - /** - * Set the updated weapons state if our ship changes - * @param {Object} nextProps Incoming/Next properties - * @param {Object} nextContext Incoming/Next conext - * @return {boolean} Returns true if the component should be rerendered - */ - componentWillReceiveProps(nextProps, nextContext) { - if (nextProps.code != this.props.code) { - const data = this._calcWeaponsDps(nextProps.ship, this.state.against, this.state.range * this.state.maxRange, this.props.hull); - const weaponNames = this._weaponNames(nextProps.ship, nextContext); - const maxRange = this._calcMaxRange(nextProps.ship); - const maxDps = this._calcMaxSDps(nextProps.ship, this.state.against); - this.setState({ weapons: data.weapons, - totals: data.totals, - weaponNames, - maxRange, - maxDps, - calcHullDpsFunc: this._calcDps.bind(this, nextContext, nextProps.ship, weaponNames, this.state.against, true), - calcShieldsDpsFunc: this._calcDps.bind(this, nextContext, nextProps.ship, weaponNames, this.state.against, false) }); - } - return true; - } - - /** - * Calculate the maximum sustained single-weapon DPS for this ship against another ship - * @param {Object} ship The ship - * @param {Object} against The target - * @return {number} The maximum sustained single-weapon DPS - */ - _calcMaxSDps(ship, against) { - let maxSDps = 0; - for (let i = 0; i < ship.hardpoints.length; i++) { - if (ship.hardpoints[i].m && ship.hardpoints[i].enabled) { - const m = ship.hardpoints[i].m; - const thisSDps = m.getClip() ? (m.getClip() * m.getDps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload()) : m.getDps(); - if (thisSDps > maxSDps) { - maxSDps = thisSDps; - } - } - } - return maxSDps; - } - - /** - * Calculate the per-weapon DPS for this ship against another ship at a given range - * @param {Object} context The context - * @param {Object} ship The ship - * @param {Object} weaponNames The names of the weapons for which to calculate DPS - * @param {Object} against The target - * @param {bool} hull true if to calculate against hull, false if to calculate against shields - * @param {Object} range The engagement range - * @return {array} The array of weapon DPS - */ - _calcDps(context, ship, weaponNames, against, hull, range) { - let results = {}; - let weaponNum = 0; - for (let i = 0; i < ship.hardpoints.length; i++) { - if (ship.hardpoints[i].m && ship.hardpoints[i].enabled) { - const m = ship.hardpoints[i].m; - results[weaponNames[weaponNum++]] = this._calcWeaponDps(context, m, against, hull, range); - } - } - return results; - } - - /** - * Calculate the maximum range of a ship's weapons - * @param {Object} ship The ship - * @returns {int} The maximum range, in metres - */ - _calcMaxRange(ship) { - let maxRange = 1000; - for (let i = 0; i < ship.hardpoints.length; i++) { - if (ship.hardpoints[i].maxClass > 0 && ship.hardpoints[i].m && ship.hardpoints[i].enabled) { - const thisRange = ship.hardpoints[i].m.getRange(); - if (thisRange > maxRange) { - maxRange = thisRange; - } - } - } - - return maxRange; - } - - /** - * Obtain the weapon names for this ship - * @param {Object} ship The ship - * @param {Object} context The context - * @return {array} The weapon names - */ - _weaponNames(ship, context) { - const translate = context.language.translate; - let names = []; - let num = 1; - for (let i = 0; i < ship.hardpoints.length; i++) { - if (ship.hardpoints[i].maxClass > 0 && ship.hardpoints[i].m && ship.hardpoints[i].enabled) { - const m = ship.hardpoints[i].m; - let name = '' + num++ + ': ' + m.class + m.rating + (m.missile ? '/' + m.missile : '') + ' ' + translate(m.name || m.grp); - let engineering; - if (m.blueprint && m.blueprint.name) { - engineering = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade; - if (m.blueprint.special && m.blueprint.special.id) { - engineering += ', ' + translate(m.blueprint.special.name); - } - } - if (engineering) { - name = name + ' (' + engineering + ')'; - } - names.push(name); - } - } - return names; - } - - - /** - * Calculate a specific weapon DPS for this ship against another ship at a given range - * @param {Object} context The context - * @param {Object} m The weapon - * @param {Object} against The target - * @param {bool} hull true if to calculate against hull, false if to calculate against shields - * @param {Object} range The engagement range - * @return {number} The weapon DPS - */ - _calcWeaponDps(context, m, against, hull, range) { - const translate = context.language.translate; - let dropoff = 1; - if (m.getFalloff()) { - // Calculate the dropoff % due to range - if (range > m.getRange()) { - // Weapon is out of range - dropoff = 0; - } else { - const falloff = m.getFalloff(); - if (range > falloff) { - const dropoffRange = m.getRange() - falloff; - // Assuming straight-line falloff - dropoff = 1 - (range - falloff) / dropoffRange; - } - } - } - const classRating = `${m.class}${m.rating}${m.missile ? '/' + m.missile : ''}`; - let engineering; - if (m.blueprint && m.blueprint.name) { - engineering = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade; - if (m.blueprint.special && m.blueprint.special.id) { - engineering += ', ' + translate(m.blueprint.special.name); - } - } - const effectivenessShields = dropoff; - const effectiveDpsShields = m.getDps() * effectivenessShields; - const effectiveSDpsShields = (m.getClip() ? (m.getClip() * m.getDps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload()) * effectivenessShields : effectiveDpsShields); - const effectivenessHull = (m.getPiercing() >= against.properties.hardness ? 1 : m.getPiercing() / against.properties.hardness) * dropoff; - const effectiveDpsHull = m.getDps() * effectivenessHull; - const effectiveSDpsHull = (m.getClip() ? (m.getClip() * m.getDps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload()) * effectivenessHull : effectiveDpsHull); - - return hull ? effectiveSDpsHull : effectiveSDpsShields; - } - - /** - * Calculate the damage dealt by a ship - * @param {Object} ship The ship which will deal the damage - * @param {Object} against The ship against which damage will be dealt - * @param {Object} range The engagement range - * @return {object} Returns the per-weapon damage - */ - _calcWeaponsDps(ship, against, range) { - const translate = this.context.language.translate; - - // Tidy up the range so that it's to 4 decimal places - range = Math.round(10000 * range) / 10000; - - // Track totals - let totals = {}; - totals.effectivenessShields = 0; - totals.effectiveDpsShields = 0; - totals.effectiveSDpsShields = 0; - totals.effectivenessHull = 0; - totals.effectiveDpsHull = 0; - totals.effectiveSDpsHull = 0; - let totalDps = 0; - - let weapons = []; - for (let i = 0; i < ship.hardpoints.length; i++) { - if (ship.hardpoints[i].maxClass > 0 && ship.hardpoints[i].m && ship.hardpoints[i].enabled) { - const m = ship.hardpoints[i].m; - if (m.getDamage() && m.grp !== 'po') { - let dropoff = 1; - if (m.getFalloff()) { - // Calculate the dropoff % due to range - if (range > m.getRange()) { - // Weapon is out of range - dropoff = 0; - } else { - const falloff = m.getFalloff(); - if (range > falloff) { - const dropoffRange = m.getRange() - falloff; - // Assuming straight-line falloff - dropoff = 1 - (range - falloff) / dropoffRange; - } - } - } - const classRating = `${m.class}${m.rating}${m.missile ? '/' + m.missile : ''}`; - let engineering; - if (m.blueprint && m.blueprint.name) { - engineering = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade; - if (m.blueprint.special && m.blueprint.special.id >= 0) { - engineering += ', ' + translate(m.blueprint.special.name); - } - } - - // Alter effectiveness as per standard shields (all have the same resistances) - const sg = ModuleUtils.findModule('sg', '3v'); - let effectivenessShields = 0; - if (m.getDamageDist().E) { - effectivenessShields += m.getDamageDist().E * (1 - sg.getExplosiveResistance()); - } - if (m.getDamageDist().K) { - effectivenessShields += m.getDamageDist().K * (1 - sg.getKineticResistance()); - } - if (m.getDamageDist().T) { - effectivenessShields += m.getDamageDist().T * (1 - sg.getThermalResistance()); - } - if (m.getDamageDist().A) { - effectivenessShields += m.getDamageDist().A; - } - effectivenessShields *= dropoff; - const effectiveDpsShields = m.getDps() * effectivenessShields; - const effectiveSDpsShields = (m.getClip() ? (m.getClip() * m.getDps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload()) * effectivenessShields : effectiveDpsShields); - - // Alter effectiveness as per standard hull - const bulkheads = new Module({ template: against.bulkheads }); - let effectivenessHull = 0; - if (m.getDamageDist().E) { - effectivenessHull += m.getDamageDist().E * (1 - bulkheads.getExplosiveResistance()); - } - if (m.getDamageDist().K) { - effectivenessHull += m.getDamageDist().K * (1 - bulkheads.getKineticResistance()); - } - if (m.getDamageDist().T) { - effectivenessHull += m.getDamageDist().T * (1 - bulkheads.getThermalResistance()); - } - if (m.getDamageDist().A) { - effectivenessHull += m.getDamageDist().A; - } - effectivenessHull *= Math.min(m.getPiercing() / against.properties.hardness, 1) * dropoff; - const effectiveDpsHull = m.getDps() * effectivenessHull; - const effectiveSDpsHull = (m.getClip() ? (m.getClip() * m.getDps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload()) * effectivenessHull : effectiveDpsHull); - totals.effectiveDpsShields += effectiveDpsShields; - totals.effectiveSDpsShields += effectiveSDpsShields; - totals.effectiveDpsHull += effectiveDpsHull; - totals.effectiveSDpsHull += effectiveSDpsHull; - totalDps += m.getDps(); - - weapons.push({ id: i, - mount: m.mount, - name: m.name || m.grp, - classRating, - engineering, - effectiveDpsShields, - effectiveSDpsShields, - effectivenessShields, - effectiveDpsHull, - effectiveSDpsHull, - effectivenessHull }); - } - } - } - totals.effectivenessShields = totalDps == 0 ? 0 : totals.effectiveDpsShields / totalDps; - totals.effectivenessHull = totalDps == 0 ? 0 : totals.effectiveDpsHull / totalDps; - - return { weapons, totals }; - } - - /** - * Triggered when the collapse or expand icons are clicked - */ - _onCollapseExpand() { - this.setState({ expanded: !this.state.expanded }); - } - - /** - * Triggered when the ship we compare against changes - * @param {string} s the new ship ID - */ - _onShipChange(s) { - const against = Ships[s]; - const data = this._calcWeaponsDps(this.props.ship, against, this.state.range * this.state.maxRange); - this.setState({ against, - weapons: data.weapons, - totals: data.totals, - calcHullDpsFunc: this._calcDps.bind(this, this.context, this.props.ship, this.state.weaponNames, against, true), - calcShieldsDpsFunc: this._calcDps.bind(this, this.context, this.props.ship, this.state.weaponNames, against, false) }); - } - - /** - * Set the sort order and sort - * @param {string} predicate Sort predicate - */ - _sortOrder(predicate) { - let desc = this.state.desc; - - if (predicate == this.state.predicate) { - desc = !desc; - } else { - desc = true; - } - - this._sort(this.props.ship, predicate, desc); - this.setState({ predicate, desc }); - } - - /** - * Sorts the weapon list - * @param {Ship} ship Ship instance - * @param {string} predicate Sort predicate - * @param {Boolean} desc Sort order descending - */ - _sort(ship, predicate, desc) { - let comp = weaponComparator.bind(null, this.context.language.translate); - - switch (predicate) { - case 'n': comp = comp(null, desc); break; - case 'edpss': comp = comp((a, b) => a.effectiveDpsShields - b.effectiveDpsShields, desc); break; - case 'esdpss': comp = comp((a, b) => a.effectiveSDpsShields - b.effectiveSDpsShields, desc); break; - case 'es': comp = comp((a, b) => a.effectivenessShields - b.effectivenessShields, desc); break; - case 'edpsh': comp = comp((a, b) => a.effectiveDpsHull - b.effectiveDpsHull, desc); break; - case 'esdpsh': comp = comp((a, b) => a.effectiveSDpsHull - b.effectiveSDpsHull, desc); break; - case 'eh': comp = comp((a, b) => a.effectivenessHull - b.effectivenessHull, desc); break; - } - - this.state.weapons.sort(comp); - } - - /** - * Render individual rows for hardpoints - * @param {Function} translate Translate function - * @param {Object} formats Localised formats map - * @return {array} The individual rows - * - */ - _renderRows(translate, formats) { - const { termtip, tooltip } = this.context; - - let rows = []; - - if (this.state.weapons) { - for (let i = 0; i < this.state.weapons.length; i++) { - const weapon = this.state.weapons[i]; - - rows.push( - - {weapon.mount == 'F' ? : null} - {weapon.mount == 'G' ? : null} - {weapon.mount == 'T' ? : null} - {weapon.classRating} {translate(weapon.name)} - {weapon.engineering ? ' (' + weapon.engineering + ')' : null } - - {formats.f1(weapon.effectiveDpsShields)} - {formats.f1(weapon.effectiveSDpsShields)} - {formats.pct(weapon.effectivenessShields)} - {formats.f1(weapon.effectiveDpsHull)} - {formats.f1(weapon.effectiveSDpsHull)} - {formats.pct(weapon.effectivenessHull)} - ); - } - } - - return rows; - } - - /** - * Update current range - * @param {number} range Range 0-1 - */ - _rangeChange(range) { - const data = this._calcWeaponsDps(this.props.ship, this.state.against, this.state.range * this.state.maxRange); - this.setState({ range, - weapons: data.weapons, - totals: data.totals }); - } - - /** - * Render damage dealt - * @return {React.Component} contents - */ - render() { - const { language, onWindowResize, sizeRatio, tooltip, termtip } = this.context; - const { formats, translate, units } = language; - const { against, expanded, maxRange, range, totals } = this.state; - const { ship } = this.props; - - const sortOrder = this._sortOrder; - const onCollapseExpand = this._onCollapseExpand; - - const code = ship.getHardpointsString() + '.' + ship.getModificationsString() + '.' + ship.getPowerEnabledString() + '.' + against.properties.name; - - return ( - -

{translate('damage dealt to')} {expanded ? : }

- {expanded ? - - - - - - - - - - - - - - - - - - - {this._renderRows(translate, formats)} - - - - - - - - - - - - -
{translate('weapon')}{translate('standard shields')}{translate('standard armour')}
{translate('effective dps')}{translate('effective sdps')}{translate('effectiveness')}{translate('effective dps')}{translate('effective sdps')}{translate('effectiveness')}
{translate('total')}{formats.f1(totals.effectiveDpsShields)}{formats.f1(totals.effectiveSDpsShields)}{formats.pct(totals.effectivenessShields)}{formats.f1(totals.effectiveDpsHull)}{formats.f1(totals.effectiveSDpsHull)}{formats.pct(totals.effectivenessHull)}
- - - - - - - - -
{translate('engagement range')} - - - {formats.f2(range * maxRange / 1000)}{units.km} -
-
-

{translate('sustained dps against standard shields')}

- -
-
-

{translate('sustained dps against standard armour')}

- -
-
: null } -
- ); - } -} diff --git a/src/app/components/DamageReceived.jsx b/src/app/components/DamageReceived.jsx deleted file mode 100644 index ec1799ed..00000000 --- a/src/app/components/DamageReceived.jsx +++ /dev/null @@ -1,327 +0,0 @@ -import React from 'react'; -import TranslatedComponent from './TranslatedComponent'; -import { Modules } from 'coriolis-data/dist'; -import { nameComparator } from '../utils/SlotFunctions'; -import { CollapseSection, ExpandSection, MountFixed, MountGimballed, MountTurret } from './SvgIcons'; -import Module from '../shipyard/Module'; -import Slider from '../components/Slider'; - -/** - * Generates an internationalization friendly weapon comparator that will - * sort by specified property (if provided) then by name/group, class, rating - * @param {function} translate Translation function - * @param {function} propComparator Optional property comparator - * @param {boolean} desc Use descending order - * @return {function} Comparator function for names - */ -export function weaponComparator(translate, propComparator, desc) { - return (a, b) => { - if (!desc) { // Flip A and B if ascending order - let t = a; - a = b; - b = t; - } - - // If a property comparator is provided use it first - let diff = propComparator ? propComparator(a, b) : nameComparator(translate, a, b); - - if (diff) { - return diff; - } - - // Property matches so sort by name / group, then class, rating - if (a.name === b.name && a.grp === b.grp) { - if(a.class == b.class) { - return a.rating > b.rating ? 1 : -1; - } - return a.class - b.class; - } - - return nameComparator(translate, a, b); - }; -} - -/** - * Damage received by a selected ship - */ -export default class DamageReceived extends TranslatedComponent { - static propTypes = { - ship: React.PropTypes.object.isRequired, - code: React.PropTypes.string.isRequired - }; - - /** - * Constructor - * @param {Object} props React Component properties - */ - constructor(props) { - super(props); - - this._sort = this._sort.bind(this); - this._onCollapseExpand = this._onCollapseExpand.bind(this); - - this.state = { - predicate: 'n', - desc: true, - expanded: false, - range: 0.1667, - maxRange: 6000 - }; - } - - /** - * Set the initial weapons state - */ - componentWillMount() { - this.setState({ weapons: this._calcWeapons(this.props.ship, this.state.range * this.state.maxRange) }); - } - - /** - * Set the updated weapons state - * @param {Object} nextProps Incoming/Next properties - * @param {Object} nextContext Incoming/Next conext - * @return {boolean} Returns true if the component should be rerendered - */ - componentWillReceiveProps(nextProps, nextContext) { - if (nextProps.code != this.props.code) { - this.setState({ weapons: this._calcWeapons(nextProps.ship, this.state.range * this.state.maxRange) }); - } - return true; - } - - /** - * Calculate the damage received by a ship - * @param {Object} ship The ship which will receive the damage - * @param {Object} range The engagement range - * @return {boolean} Returns the per-weapon damage - */ - _calcWeapons(ship, range) { - // Tidy up the range so that it's to 4 decimal places - range = Math.round(10000 * range) / 10000; - - let weapons = []; - for (let grp in Modules.hardpoints) { - 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]); - let dropoff = 1; - if (m.getFalloff()) { - // Calculate the dropoff % due to range - if (range > m.getRange()) { - // Weapon is out of range - dropoff = 0; - } else { - const falloff = m.getFalloff(); - if (range > falloff) { - const dropoffRange = m.getRange() - falloff; - // Assuming straight-line falloff - dropoff = 1 - (range - falloff) / dropoffRange; - } - } - } - const classRating = `${m.class}${m.rating}${m.missile ? '/' + m.missile : ''}`; - - // Base DPS - const baseDps = m.getDps() * dropoff; - const baseSDps = m.getClip() ? ((m.getClip() * baseDps / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload())) * dropoff : baseDps; - - // Effective DPS taking in to account shield resistance - let effectivenessShields = 0; - if (m.getDamageDist().E) { - effectivenessShields += m.getDamageDist().E * (1 - ship.shieldExplRes); - } - if (m.getDamageDist().K) { - effectivenessShields += m.getDamageDist().K * (1 - ship.shieldKinRes); - } - if (m.getDamageDist().T) { - effectivenessShields += m.getDamageDist().T * (1 - ship.shieldThermRes); - } - if (m.getDamageDist().A) { - effectivenessShields += m.getDamageDist().A; - } - effectivenessShields *= dropoff; - const effectiveDpsShields = baseDps * effectivenessShields; - const effectiveSDpsShields = baseSDps * effectivenessShields; - - // Effective DPS taking in to account hull hardness and resistance - let effectivenessHull = 0; - if (m.getDamageDist().E) { - effectivenessHull += m.getDamageDist().E * (1 - ship.hullExplRes); - } - if (m.getDamageDist().K) { - effectivenessHull += m.getDamageDist().K * (1 - ship.hullKinRes); - } - if (m.getDamageDist().T) { - effectivenessHull += m.getDamageDist().T * (1 - ship.hullThermRes); - } - if (m.getDamageDist().A) { - effectivenessHull += m.getDamageDist().A; - } - effectivenessHull *= Math.min(m.getPiercing() / ship.hardness, 1) * dropoff; - const effectiveDpsHull = baseDps * effectivenessHull; - const effectiveSDpsHull = baseSDps * effectivenessHull; - - weapons.push({ id: m.id, - classRating, - name: m.name || m.grp, - mount: m.mount, - effectiveDpsShields, - effectiveSDpsShields, - effectivenessShields, - effectiveDpsHull, - effectiveSDpsHull, - effectivenessHull }); - } - } - } - - return weapons; - } - - /** - * Triggered when the collapse or expand icons are clicked - */ - _onCollapseExpand() { - this.setState({ expanded: !this.state.expanded }); - } - - /** - * Set the sort order and sort - * @param {string} predicate Sort predicate - */ - _sortOrder(predicate) { - let desc = this.state.desc; - - if (predicate == this.state.predicate) { - desc = !desc; - } else { - desc = true; - } - - this._sort(this.props.ship, predicate, desc); - this.setState({ predicate, desc }); - } - - /** - * Sorts the weapon list - * @param {Ship} ship Ship instance - * @param {string} predicate Sort predicate - * @param {Boolean} desc Sort order descending - */ - _sort(ship, predicate, desc) { - let comp = weaponComparator.bind(null, this.context.language.translate); - - switch (predicate) { - case 'n': comp = comp(null, desc); break; - case 'edpss': comp = comp((a, b) => a.effectiveDpsShields - b.effectiveDpsShields, desc); break; - case 'esdpss': comp = comp((a, b) => a.effectiveSDpsShields - b.effectiveSDpsShields, desc); break; - case 'es': comp = comp((a, b) => a.effectivenessShields - b.effectivenessShields, desc); break; - case 'edpsh': comp = comp((a, b) => a.effectiveDpsHull - b.effectiveDpsHull, desc); break; - case 'esdpsh': comp = comp((a, b) => a.effectiveSDpsHull - b.effectiveSDpsHull, desc); break; - case 'eh': comp = comp((a, b) => a.effectivenessHull - b.effectivenessHull, desc); break; - } - - this.state.weapons.sort(comp); - } - - /** - * Render individual rows for weapons - * @param {Function} translate Translate function - * @param {Object} formats Localised formats map - * @return {array} The individual rows - * - */ - _renderRows(translate, formats) { - const { termtip, tooltip } = this.context; - - let rows = []; - - for (let i = 0; i < this.state.weapons.length; i++) { - const weapon = this.state.weapons[i]; - rows.push( - - {weapon.mount == 'F' ? : null} - {weapon.mount == 'G' ? : null} - {weapon.mount == 'T' ? : null} - {weapon.classRating} {translate(weapon.name)} - - {formats.round1(weapon.effectiveDpsShields)} - {formats.round1(weapon.effectiveSDpsShields)} - {formats.pct(weapon.effectivenessShields)} - {formats.round1(weapon.effectiveDpsHull)} - {formats.round1(weapon.effectiveSDpsHull)} - {formats.pct(weapon.effectivenessHull)} - ); - } - return rows; - } - - /** - * Update current range - * @param {number} range Range 0-1 - */ - _rangeChange(range) { - this.setState({ range, weapons: this._calcWeapons(this.props.ship, this.state.range * this.state.maxRange) }); - } - - /** - * Render damage received - * @return {React.Component} contents - */ - render() { - const { language, onWindowResize, sizeRatio, tooltip, termtip } = this.context; - const { formats, translate, units } = language; - const { expanded, maxRange, range } = this.state; - - const sortOrder = this._sortOrder; - const onCollapseExpand = this._onCollapseExpand; - - return ( - -

{translate('damage received from')} {expanded ? : }

- {expanded ? - - - - - - - - - - - - - - - - - - {this._renderRows(translate, formats)} - -
{translate('weapon')}{translate('against shields')}{translate('against hull')}
{translate('DPS')}{translate('SDPS')}{translate('effectiveness')}{translate('DPS')}{translate('SDPS')}{translate('effectiveness')}
- - - - - - - - -
{translate('engagement range')} - - - {formats.f2(range * maxRange / 1000)}{units.km} -
: null } -
- ); - } -} diff --git a/src/app/components/DefenceSummary.jsx b/src/app/components/DefenceSummary.jsx deleted file mode 100644 index 93b230b0..00000000 --- a/src/app/components/DefenceSummary.jsx +++ /dev/null @@ -1,122 +0,0 @@ -import React from 'react'; -import cn from 'classnames'; -import TranslatedComponent from './TranslatedComponent'; -import { DamageKinetic, DamageThermal, DamageExplosive } from './SvgIcons'; - -/** - * Defence summary - */ -export default class DefenceSummary extends TranslatedComponent { - static propTypes = { - ship: React.PropTypes.object.isRequired - }; - - /** - * Constructor - * @param {Object} props React Component properties - */ - constructor(props) { - super(props); - } - - /** - * Render defence summary - * @return {React.Component} contents - */ - render() { - let ship = this.props.ship; - let { language, tooltip, termtip } = this.context; - let { formats, translate, units } = language; - let hide = tooltip.bind(null, null); - - const shieldGenerator = ship.findShieldGenerator(); - - // Damage values are 1 - resistance values - return ( - -

{translate('defence summary')}

- - - {ship.shield ? - - - : null } - {ship.shield ? - - - - - - : null } - {ship.shield ? - - - - - - : null } - {ship.shield ? - - - - - - : null } - - { ship.shield && ship.shieldCells ? - - - : null } - - - - - - - - - - - - {ship.modulearmour > 0 ? - - - : null } - - {ship.moduleprotection > 0 ? - - - - : null } - -

{translate('shields')}: {formats.int(ship.shield)} {units.MJ}

{translate('recovery')}{formats.time(ship.calcShieldRecovery())}{translate('recharge')}{formats.time(ship.calcShieldRecharge())}
{translate('damage from')} -   - {formats.pct1(1 - ship.shieldExplRes)} - -   - {formats.pct1(1 - ship.shieldKinRes)} - -   - {formats.pct1(1 - ship.shieldThermRes)} -
{translate('total effective shield')} -   - {formats.int((ship.shield + ship.shieldCells) / (1 - ship.shieldExplRes))}{units.MJ} - -   - {formats.int((ship.shield + ship.shieldCells) / (1 - ship.shieldKinRes))}{units.MJ} - -   - {formats.int((ship.shield + ship.shieldCells) / (1 - ship.shieldThermRes))}{units.MJ} -

{translate('shield cells')}: {formats.int(ship.shieldCells)} {units.MJ}

{translate('armour')}: {formats.int(ship.armour)}

{translate('damage from')} -   - {formats.pct1(1 - ship.hullExplRes)} -   - {formats.pct1(1 - ship.hullKinRes)} - -   - {formats.pct1(1 - ship.hullThermRes)} -

{translate('module armour')}: {formats.int(ship.modulearmour)}

{translate('internal protection')} {formats.pct1(ship.moduleprotection)}{translate('external protection')} {formats.pct1(ship.moduleprotection / 2)}
-
- ); - } -} diff --git a/src/app/components/EngineProfile.jsx b/src/app/components/EngineProfile.jsx index 8c9ddf0f..8b90165f 100644 --- a/src/app/components/EngineProfile.jsx +++ b/src/app/components/EngineProfile.jsx @@ -1,7 +1,6 @@ import React from 'react'; import TranslatedComponent from './TranslatedComponent'; import { Ships } from 'coriolis-data/dist'; -import ShipSelector from './ShipSelector'; import { nameComparator } from '../utils/SlotFunctions'; import LineChart from '../components/LineChart'; import Slider from '../components/Slider'; diff --git a/src/app/components/FSDProfile.jsx b/src/app/components/FSDProfile.jsx index 81548632..c3e7bb83 100644 --- a/src/app/components/FSDProfile.jsx +++ b/src/app/components/FSDProfile.jsx @@ -1,7 +1,6 @@ import React from 'react'; import TranslatedComponent from './TranslatedComponent'; import { Ships } from 'coriolis-data/dist'; -import ShipSelector from './ShipSelector'; import { nameComparator } from '../utils/SlotFunctions'; import LineChart from '../components/LineChart'; import Slider from '../components/Slider'; diff --git a/src/app/components/HardpointsSlotSection.jsx b/src/app/components/HardpointSlotSection.jsx similarity index 98% rename from src/app/components/HardpointsSlotSection.jsx rename to src/app/components/HardpointSlotSection.jsx index 51bb79d4..5d697476 100644 --- a/src/app/components/HardpointsSlotSection.jsx +++ b/src/app/components/HardpointSlotSection.jsx @@ -8,7 +8,7 @@ import { stopCtxPropagation } from '../utils/UtilityFunctions'; /** * Hardpoint slot section */ -export default class HardpointsSlotSection extends SlotSection { +export default class HardpointSlotSection extends SlotSection { /** * Constructor diff --git a/src/app/components/JumpRange.jsx b/src/app/components/JumpRange.jsx index 7fc28c36..d1421ec1 100644 --- a/src/app/components/JumpRange.jsx +++ b/src/app/components/JumpRange.jsx @@ -1,7 +1,6 @@ import React from 'react'; import TranslatedComponent from './TranslatedComponent'; import { Ships } from 'coriolis-data/dist'; -import ShipSelector from './ShipSelector'; import { nameComparator } from '../utils/SlotFunctions'; import LineChart from '../components/LineChart'; import Slider from '../components/Slider'; diff --git a/src/app/components/MovementSummary.jsx b/src/app/components/MovementSummary.jsx deleted file mode 100644 index f4c268f1..00000000 --- a/src/app/components/MovementSummary.jsx +++ /dev/null @@ -1,90 +0,0 @@ -import React from 'react'; -import cn from 'classnames'; -import TranslatedComponent from './TranslatedComponent'; - -/** - * Movement summary - */ -export default class MovementSummary extends TranslatedComponent { - static propTypes = { - ship: React.PropTypes.object.isRequired - }; - - /** - * Constructor - * @param {Object} props React Component properties - */ - constructor(props) { - super(props); - } - - /** - * Render movement summary - * @return {React.Component} contents - */ - render() { - let ship = this.props.ship; - let { language, tooltip, termtip } = this.context; - let { formats, translate, units } = language; - let boostMultiplier = ship.topBoost / ship.topSpeed; - - return ( - -

{translate('movement summary')}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 {translate('engine pips')}
 012344B
{translate('speed')} ({units['m/s']}){formats.int(ship.speeds[0])}{formats.int(ship.speeds[1])}{formats.int(ship.speeds[2])}{formats.int(ship.speeds[3])}{formats.int(ship.speeds[4])}{formats.int(ship.speeds[4] * boostMultiplier)}
{translate('pitch')} ({units['°/s']}){formats.int(ship.pitches[0])}{formats.int(ship.pitches[1])}{formats.int(ship.pitches[2])}{formats.int(ship.pitches[3])}{formats.int(ship.pitches[4])}{formats.int(ship.pitches[4] * boostMultiplier)}
{translate('roll')} ({units['°/s']}){formats.int(ship.rolls[0])}{formats.int(ship.rolls[1])}{formats.int(ship.rolls[2])}{formats.int(ship.rolls[3])}{formats.int(ship.rolls[4])}{formats.int(ship.rolls[4] * boostMultiplier)}
{translate('yaw')} ({units['°/s']}){formats.int(ship.yaws[0])}{formats.int(ship.yaws[1])}{formats.int(ship.yaws[2])}{formats.int(ship.yaws[3])}{formats.int(ship.yaws[4])}{formats.int(ship.yaws[4] * boostMultiplier)}
-
- ); - } -} diff --git a/src/app/components/OffenceSummary.jsx b/src/app/components/OffenceSummary.jsx deleted file mode 100644 index d7778a70..00000000 --- a/src/app/components/OffenceSummary.jsx +++ /dev/null @@ -1,73 +0,0 @@ -import React from 'react'; -import cn from 'classnames'; -import TranslatedComponent from './TranslatedComponent'; -import { DamageAbsolute, DamageKinetic, DamageThermal, DamageExplosive } from './SvgIcons'; - -/** - * Offence summary - */ -export default class OffenceSummary extends TranslatedComponent { - static propTypes = { - ship: React.PropTypes.object.isRequired - }; - - /** - * Constructor - * @param {Object} props React Component properties - */ - constructor(props) { - super(props); - } - - /** - * Render offence summary - * @return {React.Component} contents - */ - render() { - let ship = this.props.ship; - let { language, tooltip, termtip } = this.context; - let { formats, translate } = language; - - return ( - -

{translate('offence summary')}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

{translate('dps')}: {formats.f1(ship.totalDps)}

{translate('damage by')} {formats.f1(ship.totalAbsDps)} {formats.f1(ship.totalExplDps)} {formats.f1(ship.totalKinDps)} {formats.f1(ship.totalThermDps)}

{translate('sdps')}: {formats.f1(ship.totalSDps)}

{translate('damage by')} {formats.f1(ship.totalAbsSDps)} {formats.f1(ship.totalExplSDps)} {formats.f1(ship.totalKinSDps)} {formats.f1(ship.totalThermSDps)}

{translate('dpe')}: {formats.f1(ship.totalDpe)}

{translate('damage by')} {formats.f1(ship.totalAbsDpe)} {formats.f1(ship.totalExplDpe)} {formats.f1(ship.totalKinDpe)} {formats.f1(ship.totalThermDpe)}
-
- ); - } -} diff --git a/src/app/components/Pips.jsx b/src/app/components/Pips.jsx index 29051318..08102c40 100644 --- a/src/app/components/Pips.jsx +++ b/src/app/components/Pips.jsx @@ -1,7 +1,6 @@ import React from 'react'; import TranslatedComponent from './TranslatedComponent'; import { Ships } from 'coriolis-data/dist'; -import ShipSelector from './ShipSelector'; import { nameComparator } from '../utils/SlotFunctions'; import { Pip } from './SvgIcons'; import LineChart from '../components/LineChart'; diff --git a/src/app/components/ShipSelector.jsx b/src/app/components/ShipSelector.jsx deleted file mode 100644 index a48ba4a8..00000000 --- a/src/app/components/ShipSelector.jsx +++ /dev/null @@ -1,89 +0,0 @@ -import React from 'react'; -import cn from 'classnames'; -import { Ships } from 'coriolis-data/dist'; -import TranslatedComponent from './TranslatedComponent'; -import { Rocket } from './SvgIcons'; - -/** - * Selector for ships - */ -export default class ShipSelector extends TranslatedComponent { - static propTypes = { - initial: React.PropTypes.object.isRequired, - onChange: React.PropTypes.func.isRequired - }; - - /** - * Constructor - * @param {Object} props React Component properties - */ - constructor(props) { - super(props); - - this.state = { ship : this.props.initial }; - } - - /** - * Generate the ships menu - * @return {React.Component} Menu - */ - _getShipsMenu() { - const _selectShip = this._selectShip; - - let shipList = []; - - for (let s in Ships) { - shipList.push(
{Ships[s].properties.name}
); - } - - return shipList; - } - - /** - * Handle opening the menu - * @param {string} menu The ID of the opened menu - * @param {SyntheticEvent} event Event - */ - _openMenu(menu, event) { - event.stopPropagation(); - if (this.props.currentMenu == menu) { - menu = null; - } - - this.context.openMenu(menu); - } - - /** - * Handle selection of a ship - * @param {string} s The selected ship ID - */ - _selectShip(s) { - this.setState({ ship: Ships[s] }); - - this.context.openMenu(null); - this.props.onChange(s); - } - - /** - * Render ship selector - * @return {React.Component} contents - */ - render() { - const currentMenu = this.props.currentMenu; - const ship = this.state.ship; - - return ( -
-
-
- {ship.properties.name} - {currentMenu == 'wds' ? -
e.stopPropagation() }> - {this._getShipsMenu()} -
: null } -
-
-
- ); - } -} diff --git a/src/app/components/WeaponDamageChart.jsx b/src/app/components/WeaponDamageChart.jsx index 9c04fbef..a2c407b0 100644 --- a/src/app/components/WeaponDamageChart.jsx +++ b/src/app/components/WeaponDamageChart.jsx @@ -1,7 +1,6 @@ import React from 'react'; import TranslatedComponent from './TranslatedComponent'; import { Ships } from 'coriolis-data/dist'; -import ShipSelector from './ShipSelector'; import { nameComparator } from '../utils/SlotFunctions'; import { CollapseSection, ExpandSection, MountFixed, MountGimballed, MountTurret } from './SvgIcons'; import LineChart from '../components/LineChart'; diff --git a/src/app/pages/OutfittingPage.jsx b/src/app/pages/OutfittingPage.jsx index 18dae989..cc3aec70 100644 --- a/src/app/pages/OutfittingPage.jsx +++ b/src/app/pages/OutfittingPage.jsx @@ -14,7 +14,7 @@ import { FloppyDisk, Bin, Switch, Download, Reload, LinkIcon, ShoppingIcon } fro import LZString from 'lz-string'; import ShipSummaryTable from '../components/ShipSummaryTable'; import StandardSlotSection from '../components/StandardSlotSection'; -import HardpointsSlotSection from '../components/HardpointsSlotSection'; +import HardpointSlotSection from '../components/HardpointSlotSection'; import InternalSlotSection from '../components/InternalSlotSection'; import UtilitySlotSection from '../components/UtilitySlotSection'; import Pips from '../components/Pips'; @@ -574,7 +574,7 @@ export default class OutfittingPage extends Page { - + {/* Control of ship and opponent */} diff --git a/src/app/shipyard/Ship.js b/src/app/shipyard/Ship.js index 40a80237..d622254e 100755 --- a/src/app/shipyard/Ship.js +++ b/src/app/shipyard/Ship.js @@ -221,39 +221,6 @@ export default class Ship { return Calc.calcYaw(this.unladenMass + fuel + cargo, this.yaw, this.standard[1].m, this.pipSpeed, eng, this.topBoost / this.topSpeed, boost); } - /** - * Calculate the recovery time after losing or turning on shields - * Thanks to CMDRs Al Gray, GIF, and Nomad Enigma for providing Shield recharge data and formulas - * - * @return {Number} Recovery time in seconds - */ - calcShieldRecovery() { - const shieldGenerator = this.findShieldGenerator(); - if (shieldGenerator) { - const brokenRegenRate = shieldGenerator.getBrokenRegenerationRate(); - // 50% of shield strength / broken recharge rate + 15 second delay before recharge starts - return ((this.shield / 2) / brokenRegenRate) + 15; - } - return 0; - } - - /** - * Calculate the recharge time for a shield going from 50% to 100% - * Thanks to CMDRs Al Gray, GIF, and Nomad Enigma for providing Shield recharge data and formulas - * - * @return {Number} 50 - 100% Recharge time in seconds - */ - calcShieldRecharge() { - const shieldGenerator = this.findShieldGenerator(); - if (shieldGenerator) { - const regenRate = shieldGenerator.getRegenerationRate(); - - // 50% of shield strength / recharge rate - return (this.shield / 2) / regenRate; - } - return 0; - } - /** * Calculate the hypothetical shield strength for the ship using the specified parameters * @param {Object} sg [optional] Shield Generator to use