diff --git a/src/app/components/Defence.jsx b/src/app/components/Defence.jsx index 902e1bea..56a1bafc 100644 --- a/src/app/components/Defence.jsx +++ b/src/app/components/Defence.jsx @@ -55,6 +55,8 @@ export default class Defence extends TranslatedComponent { const { formats, translate, units } = language; const { shield, armour, shielddamage, armourdamage } = this.state; + const pd = ship.standard[4].m; + const shieldSourcesData = []; const effectiveShieldData = []; const shieldDamageTakenData = []; @@ -153,7 +155,7 @@ export default class Defence extends TranslatedComponent {

{translate('shield metrics')}


{shieldTooltipDetails})} 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(shield.total / shielddamage.totalsdps)}

+

{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()))}

{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)}

@@ -174,7 +176,7 @@ export default class Defence extends TranslatedComponent {

{translate('armour metrics')}

{armourTooltipDetails}

)} 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(armour.total / armourdamage.totalsdps)}

+

{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()))}

{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)}

diff --git a/src/app/components/Offence.jsx b/src/app/components/Offence.jsx index d3272c53..52e0791c 100644 --- a/src/app/components/Offence.jsx +++ b/src/app/components/Offence.jsx @@ -135,6 +135,8 @@ export default class Offence extends TranslatedComponent { 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); @@ -147,10 +149,13 @@ export default class Offence extends TranslatedComponent { 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; @@ -212,6 +217,9 @@ export default class Offence extends TranslatedComponent { armourSDpsData.push({ value: Math.round(kineticArmourSDps), label: translate('kinetic') }); armourSDpsData.push({ value: Math.round(thermalArmourSDps), label: translate('thermal') }); + const timeToDepleteShields = Calc.timeToDeplete(opponentShields.total, totalShieldsSDps, totalSEps, pd.getWeaponsCapacity(), pd.getWeaponsRechargeRate() * (wep / 4)); + const timeToDepleteArmour = Calc.timeToDeplete(opponentArmour.total, totalArmourSDps, totalSEps, pd.getWeaponsCapacity(), pd.getWeaponsRechargeRate() * (wep / 4)); + return (
@@ -236,8 +244,8 @@ export default class Offence extends TranslatedComponent {

{translate('shield damage')}

-

{translate('PHRASE_TIME_TO_REMOVE_SHIELDS')}
{totalShieldsSDps == 0 ? translate('never') : formats.time(opponentShields.total / totalShieldsSDps)}

-

{translate('PHRASE_TIME_TO_REMOVE_ARMOUR')}
{totalArmourSDps == 0 ? translate('never') : formats.time(opponentArmour.total / totalArmourSDps)}

+

{translate('PHRASE_TIME_TO_REMOVE_SHIELDS')}
{timeToDepleteShields === Infinity ? translate('never') : formats.time(timeToDepleteShields)}

+

{translate('PHRASE_TIME_TO_REMOVE_ARMOUR')}
{timeToDepleteArmour === Infinity ? translate('never') : formats.time(timeToDepleteArmour)}

{translate('shield damage sources')}

diff --git a/src/app/i18n/en.js b/src/app/i18n/en.js index ad969a1b..cf986c7b 100644 --- a/src/app/i18n/en.js +++ b/src/app/i18n/en.js @@ -44,6 +44,8 @@ export const terms = { PHRASE_TIME_TO_RECHARGE_SHIELDS: 'Shields will recharge in', PHRASE_SHIELD_SOURCES: 'Breakdown of the supply of shield energy', PHRASE_EFFECTIVE_SHIELD: 'Effective shield strength against different damage types', + PHRASE_ARMOUR_SOURCES: 'Breakdown of the supply of armour', + PHRASE_EFFECTIVE_ARMOUR: 'Effective armour strength against different damage types', PHRASE_DAMAGE_TAKEN: '% of raw damage taken for different damage types', PHRASE_TIME_TO_LOSE_ARMOUR: 'Armour will hold for', PHRASE_MODULE_PROTECTION_EXTERNAL: 'Protection for hardpoints', @@ -51,6 +53,10 @@ export const terms = { PHRASE_SHIELD_DAMAGE: 'Breakdown of sources for sustained DPS against shields', PHRASE_ARMOUR_DAMAGE: 'Breakdown of sources for sustained DPS against armour', + PHRASE_TIME_TO_REMOVE_SHIELDS: 'Will remove shields in', + TT_TIME_TO_REMOVE_SHIELDS: 'With sustained fire by all weapons', + PHRASE_TIME_TO_REMOVE_ARMOUR: 'Will remove armour in', + TT_TIME_TO_REMOVE_ARMOUR: 'With sustained fire by all weapons', TT_TIME_TO_LOSE_SHIELDS: 'Against sustained fire from all opponent\'s weapons', TT_TIME_TO_LOSE_ARMOUR: 'Against sustained fire from all opponent\'s weapons', TT_MODULE_ARMOUR: 'Armour protecting against module damage', diff --git a/src/app/shipyard/Calculations.js b/src/app/shipyard/Calculations.js index ea77c8a0..183ec30e 100644 --- a/src/app/shipyard/Calculations.js +++ b/src/app/shipyard/Calculations.js @@ -551,7 +551,8 @@ export function defenceMetrics(ship, opponent, sys, engagementrange) { explosivesdps: sustainedDps.shieldsdps.explosive, kineticsdps: sustainedDps.shieldsdps.kinetic, thermalsdps: sustainedDps.shieldsdps.thermal, - totalsdps: sustainedDps.shieldsdps.absolute + sustainedDps.shieldsdps.explosive + sustainedDps.shieldsdps.kinetic + sustainedDps.shieldsdps.thermal + totalsdps: sustainedDps.shieldsdps.absolute + sustainedDps.shieldsdps.explosive + sustainedDps.shieldsdps.kinetic + sustainedDps.shieldsdps.thermal, + totalseps: sustainedDps.eps } : {}; const armourdamage = { @@ -559,7 +560,8 @@ export function defenceMetrics(ship, opponent, sys, engagementrange) { explosivesdps: sustainedDps.armoursdps.explosive, kineticsdps: sustainedDps.armoursdps.kinetic, thermalsdps: sustainedDps.armoursdps.thermal, - totalsdps: sustainedDps.armoursdps.absolute + sustainedDps.armoursdps.explosive + sustainedDps.armoursdps.kinetic + sustainedDps.armoursdps.thermal + totalsdps: sustainedDps.armoursdps.absolute + sustainedDps.armoursdps.explosive + sustainedDps.armoursdps.kinetic + sustainedDps.armoursdps.thermal, + totalseps: sustainedDps.eps }; return { shield, armour, shielddamage, armourdamage }; @@ -603,6 +605,7 @@ export function offenceMetrics(ship, opponent, wep, engagementrange) { classRating, engineering, sdps: weaponSustainedDps.damage, + seps: weaponSustainedDps.eps, effectiveness: weaponSustainedDps.effectiveness }); } @@ -682,6 +685,8 @@ export function _sustainedDps(ship, opponent, opponentShields, opponentArmour, e thermal: 0 }; + let eps = 0; + for (let i = 0; i < ship.hardpoints.length; i++) { if (ship.hardpoints[i].m && ship.hardpoints[i].enabled && ship.hardpoints[i].maxClass > 0) { const m = ship.hardpoints[i].m; @@ -694,10 +699,11 @@ export function _sustainedDps(ship, opponent, opponentShields, opponentArmour, e armoursdps.explosive += sustainedDps.damage.armour.explosive; armoursdps.kinetic += sustainedDps.damage.armour.kinetic; armoursdps.thermal += sustainedDps.damage.armour.thermal; + eps += sustainedDps.eps; } } - return { shieldsdps, armoursdps }; + return { shieldsdps, armoursdps, eps }; } /** @@ -712,6 +718,7 @@ export function _sustainedDps(ship, opponent, opponentShields, opponentArmour, e export function _weaponSustainedDps(m, opponent, opponentShields, opponentArmour, engagementrange) { const opponentHasShields = opponentShields.generator ? true : false; const weapon = { + eps: 0, damage: { shields: { absolute: 0, @@ -742,6 +749,9 @@ export function _weaponSustainedDps(m, opponent, opponentShields, opponentArmour } }; + // EPS + weapon.eps = m.getClip() ? (m.getClip() * m.getEps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload()) : m.getEps(); + // Initial sustained DPS let sDps = m.getClip() ? (m.getClip() * m.getDps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload()) : m.getDps(); @@ -822,3 +832,26 @@ export function timeToDrainWep(ship, wep) { return initialCharge / drainPerSecond; } } + +/** + * Calculate the time to deplete an amount of shields or armour + */ +export function timeToDeplete(amount, dps, eps, capacity, recharge) { + const drainPerSecond = eps - recharge; + if (drainPerSecond <= 0) { + // Simple result + return amount / dps; + } else { + // We are draining the capacitor, but can we deplete before we run out + const timeToDrain = capacity / drainPerSecond; + const depletedBeforeDrained = dps * timeToDrain; + if (depletedBeforeDrained >= amount) { + return amount / dps; + } else { + const restToDeplete = amount - depletedBeforeDrained; + // We delete the rest at the reduced rate + const reducedDps = dps * (recharge / eps); + return timeToDrain + (restToDeplete / reducedDps); + } + } +}