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')}
);
}
}