import React from 'react'; import TranslatedComponent from './TranslatedComponent'; import * as Calc from '../shipyard/Calculations'; import PieChart from './PieChart'; import { nameComparator } from '../utils/SlotFunctions'; import { MountFixed, MountGimballed, MountTurret } from './SvgIcons'; import VerticalBarChart from './VerticalBarChart'; /** * 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); }; } /** * Offence information * Offence information consists of four panels: * - textual information (time to drain cap, time to take down shields etc.) * - breakdown of damage sources (pie chart) * - comparison of shield resistances (table chart) * - effective sustained DPS of weapons (bar chart) */ export default class Offence extends TranslatedComponent { static propTypes = { marker: React.PropTypes.string.isRequired, ship: React.PropTypes.object.isRequired, opponent: React.PropTypes.object.isRequired, engagementrange: React.PropTypes.number.isRequired, wep: React.PropTypes.number.isRequired, opponentSys: React.PropTypes.number.isRequired }; /** * Constructor * @param {Object} props React Component properties */ constructor(props) { super(props); this._sort = this._sort.bind(this); const damage = Calc.offenceMetrics(props.ship, props.opponent, props.wep, props.opponentSys, props.engagementrange); this.state = { predicate: 'n', desc: true, damage }; } /** * Update the state if our properties change * @param {Object} nextProps Incoming/Next properties * @return {boolean} Returns true if the component should be rerendered */ componentWillReceiveProps(nextProps) { if (this.props.marker != nextProps.marker || this.props.eng != nextProps.eng) { const damage = Calc.offenceMetrics(nextProps.ship, nextProps.opponent, nextProps.wep, nextProps.opponentSys, nextProps.engagementrange); this.setState({ damage }); } return true; } /** * 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(predicate, desc); this.setState({ predicate, desc }); } /** * Sorts the weapon list * @param {string} predicate Sort predicate * @param {Boolean} desc Sort order descending */ _sort(predicate, desc) { let comp = weaponComparator.bind(null, this.context.language.translate); switch (predicate) { case 'n': comp = comp(null, desc); break; case 'esdpss': comp = comp((a, b) => a.sdps.shields.total - b.sdps.shields.total, desc); break; case 'es': comp = comp((a, b) => a.effectiveness.shields.total - b.effectiveness.shields.total, desc); break; case 'esdpsh': comp = comp((a, b) => a.sdps.armour.total - b.sdps.armour.total, desc); break; case 'eh': comp = comp((a, b) => a.effectiveness.armour.total - b.effectiveness.armour.total, desc); break; } this.state.damage.sort(comp); } /** * Render offence * @return {React.Component} contents */ render() { const { ship, opponent, wep, engagementrange } = this.props; const { language, tooltip, termtip } = this.context; const { formats, translate, units } = language; const { damage } = this.state; const sortOrder = this._sortOrder; const pd = ship.standard[4].m; const opponentShields = Calc.shieldMetrics(opponent, 4); const opponentArmour = Calc.armourMetrics(opponent); const timeToDrain = Calc.timeToDrainWep(ship, wep); let absoluteShieldsSDps = 0; let explosiveShieldsSDps = 0; let kineticShieldsSDps = 0; let thermalShieldsSDps = 0; let absoluteArmourSDps = 0; let explosiveArmourSDps = 0; let kineticArmourSDps = 0; let thermalArmourSDps = 0; let totalSEps = 0; const rows = []; for (let i = 0; i < damage.length; i++) { const weapon = damage[i]; totalSEps += weapon.seps; absoluteShieldsSDps += weapon.sdps.shields.absolute; explosiveShieldsSDps += weapon.sdps.shields.explosive; kineticShieldsSDps += weapon.sdps.shields.kinetic; thermalShieldsSDps += weapon.sdps.shields.thermal; absoluteArmourSDps += weapon.sdps.armour.absolute; explosiveArmourSDps += weapon.sdps.armour.explosive; kineticArmourSDps += weapon.sdps.armour.kinetic; thermalArmourSDps += weapon.sdps.armour.thermal; const effectivenessShieldsTooltipDetails = []; effectivenessShieldsTooltipDetails.push(
| {translate('weapon')} | {translate('opponent\'s shields')} | {translate('opponent\'s armour')} | ||
|---|---|---|---|---|
| {'sdps'} | {'eft'} | {'sdps'} | {'eft'} | |