import React from 'react'; import PropTypes from 'prop-types'; import TranslatedComponent from './TranslatedComponent'; import * as Calc from '../shipyard/Calculations'; import PieChart from './PieChart'; import VerticalBarChart from './VerticalBarChart'; /** * Defence information * Shield information consists of four panels: * - textual information (time to lose shields etc.) * - breakdown of shield sources (pie chart) * - comparison of shield resistances (bar chart) * - effective shield (bar chart) */ export default class Defence extends TranslatedComponent { static propTypes = { marker: PropTypes.string.isRequired, ship: PropTypes.object.isRequired, opponent: PropTypes.object.isRequired, engagementrange: PropTypes.number.isRequired, sys: PropTypes.number.isRequired, opponentWep: PropTypes.number.isRequired }; /** * Constructor * @param {Object} props React Component properties */ constructor(props) { super(props); const { shield, armour, shielddamage, armourdamage } = Calc.defenceMetrics(props.ship, props.opponent, props.sys, props.opponentWep, props.engagementrange); this.state = { shield, armour, shielddamage, armourdamage }; } /** * 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.sys != nextProps.sys) { const { shield, armour, shielddamage, armourdamage } = Calc.defenceMetrics(nextProps.ship, nextProps.opponent, nextProps.sys, nextProps.opponentWep, nextProps.engagementrange); this.setState({ shield, armour, shielddamage, armourdamage }); } return true; } /** * Render defence * @return {React.Component} contents */ render() { const { opponent, sys, opponentWep } = this.props; const { language, tooltip, termtip } = this.context; const { formats, translate, units } = language; const { shield, armour, shielddamage, armourdamage } = this.state; const pd = opponent.standard[4].m; const shieldSourcesData = []; const effectiveShieldData = []; const shieldDamageTakenData = []; const shieldSourcesTt = []; const shieldDamageTakenAbsoluteTt = []; const shieldDamageTakenExplosiveTt = []; const shieldDamageTakenKineticTt = []; const shieldDamageTakenThermalTt = []; const effectiveShieldAbsoluteTt = []; const effectiveShieldExplosiveTt = []; const effectiveShieldKineticTt = []; const effectiveShieldThermalTt = []; let maxEffectiveShield = 0; if (shield.total) { shieldSourcesData.push({ value: Math.round(shield.generator), label: translate('generator') }); shieldSourcesData.push({ value: Math.round(shield.boosters), label: translate('boosters') }); shieldSourcesData.push({ value: Math.round(shield.cells), label: translate('cells') }); shieldSourcesData.push({ value: Math.round(shield.addition), label: translate('shield addition') }); if (shield.generator > 0) { shieldSourcesTt.push(
{translate('generator') + ' ' + formats.int(shield.generator)}{units.MJ}
); effectiveShieldAbsoluteTt.push(
{translate('generator') + ' ' + formats.int(shield.generator)}{units.MJ}
); effectiveShieldExplosiveTt.push(
{translate('generator') + ' ' + formats.int(shield.generator)}{units.MJ}
); effectiveShieldKineticTt.push(
{translate('generator') + ' ' + formats.int(shield.generator)}{units.MJ}
); effectiveShieldThermalTt.push(
{translate('generator') + ' ' + formats.int(shield.generator)}{units.MJ}
); if (shield.boosters > 0) { shieldSourcesTt.push(
{translate('boosters') + ' ' + formats.int(shield.boosters)}{units.MJ}
); effectiveShieldAbsoluteTt.push(
{translate('boosters') + ' ' + formats.int(shield.boosters)}{units.MJ}
); effectiveShieldExplosiveTt.push(
{translate('boosters') + ' ' + formats.int(shield.boosters)}{units.MJ}
); effectiveShieldKineticTt.push(
{translate('boosters') + ' ' + formats.int(shield.boosters)}{units.MJ}
); effectiveShieldThermalTt.push(
{translate('boosters') + ' ' + formats.int(shield.boosters)}{units.MJ}
); } if (shield.cells > 0) { shieldSourcesTt.push(
{translate('cells') + ' ' + formats.int(shield.cells)}{units.MJ}
); effectiveShieldAbsoluteTt.push(
{translate('cells') + ' ' + formats.int(shield.cells)}{units.MJ}
); effectiveShieldExplosiveTt.push(
{translate('cells') + ' ' + formats.int(shield.cells)}{units.MJ}
); effectiveShieldKineticTt.push(
{translate('cells') + ' ' + formats.int(shield.cells)}{units.MJ}
); effectiveShieldThermalTt.push(
{translate('cells') + ' ' + formats.int(shield.cells)}{units.MJ}
); } // Add effective shield from resistances const rawMj = shield.generator + shield.boosters + shield.cells; const explosiveMj = rawMj / (shield.explosive.base) - rawMj; if (explosiveMj != 0) effectiveShieldExplosiveTt.push(
{translate('resistance') + ' ' + formats.int(explosiveMj)}{units.MJ}
); const kineticMj = rawMj / (shield.kinetic.base) - rawMj; if (kineticMj != 0) effectiveShieldKineticTt.push(
{translate('resistance') + ' ' + formats.int(kineticMj)}{units.MJ}
); const thermalMj = rawMj / (shield.thermal.base) - rawMj; if (thermalMj != 0) effectiveShieldThermalTt.push(
{translate('resistance') + ' ' + formats.int(thermalMj)}{units.MJ}
); // Add effective shield from power distributor SYS pips if (shield.absolute.sys != 1) { effectiveShieldAbsoluteTt.push(
{translate('power distributor') + ' ' + formats.int(rawMj / shield.absolute.total - rawMj)}{units.MJ}
); effectiveShieldExplosiveTt.push(
{translate('power distributor') + ' ' + formats.int(rawMj / shield.explosive.total - rawMj / shield.explosive.base)}{units.MJ}
); effectiveShieldKineticTt.push(
{translate('power distributor') + ' ' + formats.int(rawMj / shield.kinetic.total - rawMj / shield.kinetic.base)}{units.MJ}
); effectiveShieldThermalTt.push(
{translate('power distributor') + ' ' + formats.int(rawMj / shield.thermal.total - rawMj / shield.thermal.base)}{units.MJ}
); } } shieldDamageTakenAbsoluteTt.push(
{translate('generator') + ' ' + formats.pct1(shield.absolute.generator)}
); shieldDamageTakenAbsoluteTt.push(
{translate('boosters') + ' ' + formats.pct1(shield.absolute.boosters)}
); shieldDamageTakenAbsoluteTt.push(
{translate('power distributor') + ' ' + formats.pct1(shield.absolute.sys)}
); shieldDamageTakenExplosiveTt.push(
{translate('generator') + ' ' + formats.pct1(shield.explosive.generator)}
); shieldDamageTakenExplosiveTt.push(
{translate('boosters') + ' ' + formats.pct1(shield.explosive.boosters)}
); shieldDamageTakenExplosiveTt.push(
{translate('power distributor') + ' ' + formats.pct1(shield.explosive.sys)}
); shieldDamageTakenKineticTt.push(
{translate('generator') + ' ' + formats.pct1(shield.kinetic.generator)}
); shieldDamageTakenKineticTt.push(
{translate('boosters') + ' ' + formats.pct1(shield.kinetic.boosters)}
); shieldDamageTakenKineticTt.push(
{translate('power distributor') + ' ' + formats.pct1(shield.kinetic.sys)}
); shieldDamageTakenThermalTt.push(
{translate('generator') + ' ' + formats.pct1(shield.thermal.generator)}
); shieldDamageTakenThermalTt.push(
{translate('boosters') + ' ' + formats.pct1(shield.thermal.boosters)}
); shieldDamageTakenThermalTt.push(
{translate('power distributor') + ' ' + formats.pct1(shield.thermal.sys)}
); const effectiveAbsoluteShield = shield.total / shield.absolute.total; effectiveShieldData.push({ value: Math.round(effectiveAbsoluteShield), label: translate('absolute'), tooltip: effectiveShieldAbsoluteTt }); const effectiveExplosiveShield = shield.total / shield.explosive.total; effectiveShieldData.push({ value: Math.round(effectiveExplosiveShield), label: translate('explosive'), tooltip: effectiveShieldExplosiveTt }); const effectiveKineticShield = shield.total / shield.kinetic.total; effectiveShieldData.push({ value: Math.round(effectiveKineticShield), label: translate('kinetic'), tooltip: effectiveShieldKineticTt }); const effectiveThermalShield = shield.total / shield.thermal.total; effectiveShieldData.push({ value: Math.round(effectiveThermalShield), label: translate('thermal'), tooltip: effectiveShieldThermalTt }); shieldDamageTakenData.push({ value: Math.round(shield.absolute.total * 100), label: translate('absolute'), tooltip: shieldDamageTakenAbsoluteTt }); shieldDamageTakenData.push({ value: Math.round(shield.explosive.total * 100), label: translate('explosive'), tooltip: shieldDamageTakenExplosiveTt }); shieldDamageTakenData.push({ value: Math.round(shield.kinetic.total * 100), label: translate('kinetic'), tooltip: shieldDamageTakenKineticTt }); shieldDamageTakenData.push({ value: Math.round(shield.thermal.total * 100), label: translate('thermal'), tooltip: shieldDamageTakenThermalTt }); maxEffectiveShield = Math.max(shield.total / shield.absolute.max, shield.total / shield.explosive.max, shield.total / shield.kinetic.max, shield.total / shield.thermal.max); } const armourSourcesData = []; armourSourcesData.push({ value: Math.round(armour.bulkheads), label: translate('bulkheads') }); armourSourcesData.push({ value: Math.round(armour.reinforcement), label: translate('reinforcement') }); const armourSourcesTt = []; const effectiveArmourAbsoluteTt = []; const effectiveArmourExplosiveTt = []; const effectiveArmourKineticTt = []; const effectiveArmourThermalTt = []; const effectiveArmourCausticTt = []; if (armour.bulkheads > 0) { armourSourcesTt.push(
{translate('bulkheads') + ' ' + formats.int(armour.bulkheads)}
); effectiveArmourAbsoluteTt.push(
{translate('bulkheads') + ' ' + formats.int(armour.bulkheads)}
); effectiveArmourExplosiveTt.push(
{translate('bulkheads') + ' ' + formats.int(armour.bulkheads)}
); effectiveArmourKineticTt.push(
{translate('bulkheads') + ' ' + formats.int(armour.bulkheads)}
); effectiveArmourThermalTt.push(
{translate('bulkheads') + ' ' + formats.int(armour.bulkheads)}
); effectiveArmourCausticTt.push(
{translate('bulkheads') + ' ' + formats.int(armour.bulkheads)}
); if (armour.reinforcement > 0) { armourSourcesTt.push(
{translate('reinforcement') + ' ' + formats.int(armour.reinforcement)}
); effectiveArmourAbsoluteTt.push(
{translate('reinforcement') + ' ' + formats.int(armour.reinforcement)}
); effectiveArmourExplosiveTt.push(
{translate('reinforcement') + ' ' + formats.int(armour.reinforcement)}
); effectiveArmourKineticTt.push(
{translate('reinforcement') + ' ' + formats.int(armour.reinforcement)}
); effectiveArmourThermalTt.push(
{translate('reinforcement') + ' ' + formats.int(armour.reinforcement)}
); effectiveArmourCausticTt.push(
{translate('reinforcement') + ' ' + formats.int(armour.reinforcement)}
); } } const rawArmour = armour.bulkheads + armour.reinforcement; const armourDamageTakenTt = []; armourDamageTakenTt.push(
{translate('bulkheads') + ' ' + formats.pct1(armour.absolute.bulkheads)}
); armourDamageTakenTt.push(
{translate('reinforcement') + ' ' + formats.pct1(armour.absolute.reinforcement)}
); const armourDamageTakenExplosiveTt = []; armourDamageTakenExplosiveTt.push(
{translate('bulkheads') + ' ' + formats.pct1(armour.explosive.bulkheads)}
); armourDamageTakenExplosiveTt.push(
{translate('reinforcement') + ' ' + formats.pct1(armour.explosive.reinforcement)}
); if (armour.explosive.total != 1) effectiveArmourExplosiveTt.push(
{translate('resistance') + ' ' + formats.int(rawArmour / armour.explosive.total - rawArmour)}
); const armourDamageTakenKineticTt = []; armourDamageTakenKineticTt.push(
{translate('bulkheads') + ' ' + formats.pct1(armour.kinetic.bulkheads)}
); armourDamageTakenKineticTt.push(
{translate('reinforcement') + ' ' + formats.pct1(armour.kinetic.reinforcement)}
); if (armour.kinetic.total != 1) effectiveArmourKineticTt.push(
{translate('resistance') + ' ' + formats.int(rawArmour / armour.kinetic.total - rawArmour)}
); const armourDamageTakenThermalTt = []; armourDamageTakenThermalTt.push(
{translate('bulkheads') + ' ' + formats.pct1(armour.thermal.bulkheads)}
); armourDamageTakenThermalTt.push(
{translate('reinforcement') + ' ' + formats.pct1(armour.thermal.reinforcement)}
); if (armour.thermal.total != 1) effectiveArmourThermalTt.push(
{translate('resistance') + ' ' + formats.int(rawArmour / armour.thermal.total - rawArmour)}
); const armourDamageTakenCausticTt = []; armourDamageTakenCausticTt.push(
{translate('bulkheads') + ' ' + formats.pct1(armour.caustic.bulkheads)}
); armourDamageTakenCausticTt.push(
{translate('reinforcement') + ' ' + formats.pct1(armour.caustic.reinforcement)}
); if (armour.thermal.total != 1) effectiveArmourCausticTt.push(
{translate('resistance') + ' ' + formats.int(rawArmour / armour.caustic.total - rawArmour)}
); const effectiveArmourData = []; const effectiveAbsoluteArmour = armour.total / armour.absolute.total; effectiveArmourData.push({ value: Math.round(effectiveAbsoluteArmour), label: translate('absolute'), tooltip: effectiveArmourAbsoluteTt }); const effectiveExplosiveArmour = armour.total / armour.explosive.total; effectiveArmourData.push({ value: Math.round(effectiveExplosiveArmour), label: translate('explosive'), tooltip: effectiveArmourExplosiveTt }); const effectiveKineticArmour = armour.total / armour.kinetic.total; effectiveArmourData.push({ value: Math.round(effectiveKineticArmour), label: translate('kinetic'), tooltip: effectiveArmourKineticTt }); const effectiveThermalArmour = armour.total / armour.thermal.total; effectiveArmourData.push({ value: Math.round(effectiveThermalArmour), label: translate('thermal'), tooltip: effectiveArmourThermalTt }); const effectiveCausticArmour = armour.total / armour.caustic.total; effectiveArmourData.push({ value: Math.round(effectiveCausticArmour), label: translate('caustic'), tooltip: effectiveArmourCausticTt }); const armourDamageTakenData = []; armourDamageTakenData.push({ value: Math.round(armour.absolute.total * 100), label: translate('absolute'), tooltip: armourDamageTakenTt }); armourDamageTakenData.push({ value: Math.round(armour.explosive.total * 100), label: translate('explosive'), tooltip: armourDamageTakenExplosiveTt }); armourDamageTakenData.push({ value: Math.round(armour.kinetic.total * 100), label: translate('kinetic'), tooltip: armourDamageTakenKineticTt }); armourDamageTakenData.push({ value: Math.round(armour.thermal.total * 100), label: translate('thermal'), tooltip: armourDamageTakenThermalTt }); armourDamageTakenData.push({ value: Math.round(armour.caustic.total * 100), label: translate('caustic'), tooltip: armourDamageTakenCausticTt }); return ( {shield.total ?

{translate('shield metrics')}


{shieldSourcesTt}

)} onMouseOut={tooltip.bind(null, null)} className='summary'>{translate('raw shield strength')}
{formats.int(shield.total)}{units.MJ}

{translate('PHRASE_TIME_TO_LOSE_SHIELDS')}
{shielddamage.totalsdps == 0 ? translate('ever') : formats.time(Calc.timeToDeplete(shield.total, shielddamage.totalsdps, shielddamage.totalseps, pd.getWeaponsCapacity(), pd.getWeaponsRechargeRate() * opponentWep / 4))}

{translate('PHRASE_TIME_TO_RECOVER_SHIELDS')}
{shield.recover === Math.Inf ? translate('never') : formats.time(shield.recover)}

{translate('PHRASE_TIME_TO_RECHARGE_SHIELDS')}
{shield.recharge === Math.Inf ? translate('never') : formats.time(shield.recharge)}

{translate('shield sources')}

{translate('damage taken')}(%)

{translate('effective shield')}(MJ)

: null }

{translate('armour metrics')}

{armourSourcesTt}

)} onMouseOut={tooltip.bind(null, null)} className='summary'>{translate('raw armour strength')}
{formats.int(armour.total)}

{translate('PHRASE_TIME_TO_LOSE_ARMOUR')}
{armourdamage.totalsdps == 0 ? translate('ever') : formats.time(Calc.timeToDeplete(armour.total, armourdamage.totalsdps, armourdamage.totalseps, pd.getWeaponsCapacity(), pd.getWeaponsRechargeRate() * opponentWep / 4))}

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

{translate('PHRASE_MODULE_PROTECTION_EXTERNAL')}
{formats.pct1(armour.moduleprotection / 2)}

{translate('PHRASE_MODULE_PROTECTION_INTERNAL')}
{formats.pct1(armour.moduleprotection)}


{translate('armour sources')}

{translate('damage taken')}(%)

{translate('effective armour')}

); } }