mirror of
https://github.com/EDCD/coriolis.git
synced 2025-12-10 07:05:35 +00:00
Working on shield recovery calculation
This commit is contained in:
@@ -113,10 +113,10 @@ export default class BattleCentre extends TranslatedComponent {
|
|||||||
const { sys, eng, wep, cargo, fuel, boost, engagementRange, opponent } = this.state;
|
const { sys, eng, wep, cargo, fuel, boost, engagementRange, opponent } = this.state;
|
||||||
const { ship } = this.props;
|
const { ship } = this.props;
|
||||||
|
|
||||||
// Markers are used to propagate state changes without requiring a deep comparison of the ship
|
// Markers are used to propagate state changes without requiring a deep comparison of the ship, as that takes a long time
|
||||||
const pipsMarker = '' + ship.canBoost();
|
const pipsMarker = '' + ship.canBoost();
|
||||||
const movementMarker = '' + ship.topSpeed + ':' + ship.pitch + ':' + ship.roll + ':' + ship.yaw + ':' + ship.canBoost();
|
const movementMarker = '' + ship.topSpeed + ':' + ship.pitch + ':' + ship.roll + ':' + ship.yaw + ':' + ship.canBoost();
|
||||||
const shieldMarker = '' + ship.shield + ':' + ship.shieldCells + ':' + ship.shieldExplRes + ':' + ship.shieldKinRes + ':' + ship.shieldThermRes + ':' + ship.armour;
|
const shieldMarker = '' + ship.shield + ':' + ship.shieldCells + ':' + ship.shieldExplRes + ':' + ship.shieldKinRes + ':' + ship.shieldThermRes + ':' + ship.armour + ship.standard[4].m.getSystemsCapacity() + ':' + ship.standard[4].m.getSystemsRechargeRate();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ export default class Defence extends TranslatedComponent {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
const { shield, armour, shielddamage } = this._calcMetrics(props.ship, props.opponent, props.sys);
|
const { shield, armour, shielddamage, armourdamage } = this._calcMetrics(props.ship, props.opponent, props.sys);
|
||||||
this.state = { shield, armour, shielddamage };
|
this.state = { shield, armour, shielddamage, armourdamage };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,8 +40,8 @@ export default class Defence extends TranslatedComponent {
|
|||||||
*/
|
*/
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
if (this.props.marker != nextProps.marker || this.props.sys != nextProps.sys) {
|
if (this.props.marker != nextProps.marker || this.props.sys != nextProps.sys) {
|
||||||
const { shield, armour, shielddamage } = this._calcMetrics(nextProps.ship, nextProps.opponent, nextProps.sys);
|
const { shield, armour, shielddamage, armourdamage } = this._calcMetrics(nextProps.ship, nextProps.opponent, nextProps.sys);
|
||||||
this.setState({ shield, armour, shielddamage });
|
this.setState({ shield, armour, shielddamage, armourdamage });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,11 +97,49 @@ export default class Defence extends TranslatedComponent {
|
|||||||
|
|
||||||
const generatorStrength = Calc.shieldStrength(ship.hullMass, ship.baseShieldStrength, shieldGenerator, 1);
|
const generatorStrength = Calc.shieldStrength(ship.hullMass, ship.baseShieldStrength, shieldGenerator, 1);
|
||||||
const boostersStrength = generatorStrength * boost;
|
const boostersStrength = generatorStrength * boost;
|
||||||
|
|
||||||
|
// Recover time is the time taken to go from 0 to 50%. It includes a 15-second wait before shields start to recover
|
||||||
|
// Note that the shields use the broken regeneration rate to define how much energy goes in to the shields, and the normal
|
||||||
|
// regeneration rate to define how much energy is taken from the SYS capacitor
|
||||||
|
const shieldToRecover = (generatorStrength + boostersStrength) / 2;
|
||||||
|
const powerDistributor = ship.standard[4].m;
|
||||||
|
// Our initial regeneration comes from the SYS capacitor store, which is replenished as it goes
|
||||||
|
const capacitorDrain = shieldGenerator.getRegenerationRate() - powerDistributor.getSystemsRechargeRate() * (sys / 4);
|
||||||
|
console.log(`shieldToRecover is ${shieldToRecover}`);
|
||||||
|
console.log(`Regeneration rate is ${shieldGenerator.getRegenerationRate()}`);
|
||||||
|
console.log(`Power distributor recharge is ${powerDistributor.getSystemsRechargeRate() * sys / 4}`);
|
||||||
|
console.log(`capacitor drain is ${capacitorDrain}`);
|
||||||
|
const capacitorLifetime = powerDistributor.getSystemsCapacity() / capacitorDrain;
|
||||||
|
|
||||||
|
console.log(`Need to recover ${shieldToRecover}`);
|
||||||
|
console.log(`SYS contains ${powerDistributor.getSystemsCapacity()} and recharges at ${powerDistributor.getSystemsRechargeRate() * (sys / 4)}`);
|
||||||
|
let recover = 15;
|
||||||
|
if (capacitorDrain <= 0 || shieldToRecover < capacitorLifetime * shieldGenerator.getBrokenRegenerationRate()) {
|
||||||
|
// We can recover the entire shield from the capacitor store
|
||||||
|
recover += shieldToRecover / shieldGenerator.getBrokenRegenerationRate();
|
||||||
|
console.log(`We can recover the entire shield before the capacitor drains - takes ${recover}`);
|
||||||
|
} else {
|
||||||
|
// We can recover some of the shield from the capacitor store
|
||||||
|
recover += capacitorLifetime;
|
||||||
|
console.log(`We can recover ${capacitorLifetime * shieldGenerator.getBrokenRegenerationRate()} before capacitor is empty`);
|
||||||
|
console.log(`Sys is ${sys}`);
|
||||||
|
const remainingShieldToRecover = shieldToRecover - capacitorLifetime * shieldGenerator.getBrokenRegenerationRate();
|
||||||
|
if (sys === 0) {
|
||||||
|
// No system pips so will never recover shields
|
||||||
|
console.log(`Cannot recover shields`);
|
||||||
|
recover = Math.Inf;
|
||||||
|
} else {
|
||||||
|
// Recover remaining shields at the rate of the power distributor's recharge
|
||||||
|
recover += remainingShieldToRecover / (powerDistributor.getSystemsRechargeRate() * sys / 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
shield = {
|
shield = {
|
||||||
generator: generatorStrength,
|
generator: generatorStrength,
|
||||||
boosters: boostersStrength,
|
boosters: boostersStrength,
|
||||||
cells: ship.shieldCells,
|
cells: ship.shieldCells,
|
||||||
total: generatorStrength + boostersStrength + ship.shieldCells
|
total: generatorStrength + boostersStrength + ship.shieldCells,
|
||||||
|
recover
|
||||||
};
|
};
|
||||||
|
|
||||||
// Shield resistances have three components: the shield generator, the shield boosters and the SYS pips.
|
// Shield resistances have three components: the shield generator, the shield boosters and the SYS pips.
|
||||||
@@ -149,8 +187,8 @@ export default class Defence extends TranslatedComponent {
|
|||||||
const armourBulkheads = ship.baseArmour + (ship.baseArmour * ship.bulkheads.m.getHullBoost());
|
const armourBulkheads = ship.baseArmour + (ship.baseArmour * ship.bulkheads.m.getHullBoost());
|
||||||
let armourReinforcement = 0;
|
let armourReinforcement = 0;
|
||||||
|
|
||||||
let modulearmour = 0;
|
let moduleArmour = 0;
|
||||||
let moduleprotection = 1;
|
let moduleProtection = 1;
|
||||||
|
|
||||||
let hullExplDmg = 1;
|
let hullExplDmg = 1;
|
||||||
let hullKinDmg = 1;
|
let hullKinDmg = 1;
|
||||||
@@ -168,11 +206,11 @@ export default class Defence extends TranslatedComponent {
|
|||||||
hullThermDmg = hullThermDmg * (1 - slot.m.getThermalResistance());
|
hullThermDmg = hullThermDmg * (1 - slot.m.getThermalResistance());
|
||||||
}
|
}
|
||||||
if (slot.m && slot.m.grp == 'mrp') {
|
if (slot.m && slot.m.grp == 'mrp') {
|
||||||
modulearmour += slot.m.getIntegrity();
|
moduleArmour += slot.m.getIntegrity();
|
||||||
moduleprotection = moduleprotection * (1 - slot.m.getProtection());
|
moduleProtection = moduleProtection * (1 - slot.m.getProtection());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
moduleprotection = 1 - moduleprotection;
|
moduleProtection = 1 - moduleProtection;
|
||||||
|
|
||||||
// Apply diminishing returns
|
// Apply diminishing returns
|
||||||
hullExplDmg = hullExplDmg > 0.7 ? hullExplDmg : 0.7 - (0.7 - hullExplDmg) / 2;
|
hullExplDmg = hullExplDmg > 0.7 ? hullExplDmg : 0.7 - (0.7 - hullExplDmg) / 2;
|
||||||
@@ -182,12 +220,11 @@ export default class Defence extends TranslatedComponent {
|
|||||||
const armour = {
|
const armour = {
|
||||||
bulkheads: armourBulkheads,
|
bulkheads: armourBulkheads,
|
||||||
reinforcement: armourReinforcement,
|
reinforcement: armourReinforcement,
|
||||||
modulearmour: modulearmour,
|
modulearmour: moduleArmour,
|
||||||
moduleprotection: moduleprotection,
|
moduleprotection: moduleProtection,
|
||||||
total: armourBulkheads + armourReinforcement
|
total: armourBulkheads + armourReinforcement
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Armour resistances have two components: bulkheads and HRPs
|
// Armour resistances have two components: bulkheads and HRPs
|
||||||
// We re-cast these as damage percentages
|
// We re-cast these as damage percentages
|
||||||
armour.absolute = {
|
armour.absolute = {
|
||||||
@@ -214,7 +251,15 @@ export default class Defence extends TranslatedComponent {
|
|||||||
total: (1 - ship.bulkheads.m.getThermalResistance()) * hullThermDmg
|
total: (1 - ship.bulkheads.m.getThermalResistance()) * hullThermDmg
|
||||||
};
|
};
|
||||||
|
|
||||||
return { shield, armour, shielddamage };
|
const armourdamage = {
|
||||||
|
absolutesdps: opponentSDps.absolute *= armour.absolute.total,
|
||||||
|
explosivesdps: opponentSDps.explosive *= armour.explosive.total,
|
||||||
|
kineticsdps: opponentSDps.kinetic *= armour.kinetic.total,
|
||||||
|
thermalsdps: opponentSDps.thermal *= armour.thermal.total
|
||||||
|
};
|
||||||
|
armourdamage.totalsdps = armourdamage.absolutesdps + armourdamage.explosivesdps + armourdamage.kineticsdps + armourdamage.thermalsdps;
|
||||||
|
|
||||||
|
return { shield, armour, shielddamage, armourdamage };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -234,7 +279,7 @@ export default class Defence extends TranslatedComponent {
|
|||||||
const { ship, sys } = this.props;
|
const { ship, sys } = this.props;
|
||||||
const { language, tooltip, termtip } = this.context;
|
const { language, tooltip, termtip } = this.context;
|
||||||
const { formats, translate, units } = language;
|
const { formats, translate, units } = language;
|
||||||
const { shield, armour, shielddamage } = this.state;
|
const { shield, armour, shielddamage, armourdamage } = this.state;
|
||||||
|
|
||||||
const shieldSourcesData = [];
|
const shieldSourcesData = [];
|
||||||
const effectiveShieldData = [];
|
const effectiveShieldData = [];
|
||||||
@@ -284,7 +329,6 @@ export default class Defence extends TranslatedComponent {
|
|||||||
shieldDamageTakenData.push({ value: Math.round(shield.kinetic.total * 100), label: translate('kinetic') });
|
shieldDamageTakenData.push({ value: Math.round(shield.kinetic.total * 100), label: translate('kinetic') });
|
||||||
shieldDamageTakenData.push({ value: Math.round(shield.thermal.total * 100), label: translate('thermal') });
|
shieldDamageTakenData.push({ value: Math.round(shield.thermal.total * 100), label: translate('thermal') });
|
||||||
|
|
||||||
console.log(`max effective shields are ${shield.absolute.max}/${shield.explosive.max}/${shield.kinetic.max}/${shield.thermal.max}`);
|
|
||||||
maxEffectiveShield = Math.max(shield.total / shield.absolute.max, shield.total / shield.explosive.max, shield.total / shield.kinetic.max, shield.total / shield.thermal.max);
|
maxEffectiveShield = Math.max(shield.total / shield.absolute.max, shield.total / shield.explosive.max, shield.total / shield.kinetic.max, shield.total / shield.thermal.max);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,17 +373,16 @@ console.log(`max effective shields are ${shield.absolute.max}/${shield.explosive
|
|||||||
armourDamageTakenData.push({ value: Math.round(armour.kinetic.total * 100), label: translate('kinetic') });
|
armourDamageTakenData.push({ value: Math.round(armour.kinetic.total * 100), label: translate('kinetic') });
|
||||||
armourDamageTakenData.push({ value: Math.round(armour.thermal.total * 100), label: translate('thermal') });
|
armourDamageTakenData.push({ value: Math.round(armour.thermal.total * 100), label: translate('thermal') });
|
||||||
|
|
||||||
// TODO versions of ship.calcShieldRecovery() and ship.calcShieldRecharge() that take account of SYS pips
|
|
||||||
return (
|
return (
|
||||||
<span id='defence'>
|
<span id='defence'>
|
||||||
{shield.total ? <span>
|
{shield.total ? <span>
|
||||||
<div className='group quarter'>
|
<div className='group quarter'>
|
||||||
<h2>{translate('shield metrics')}</h2>
|
<h2>{translate('shield metrics')}</h2>
|
||||||
<br/>
|
<br/>
|
||||||
<h2 onMouseOver={termtip.bind(null, <div>{shieldTooltipDetails}</div>)} onMouseOut={tooltip.bind(null, null)} className='summary'>{translate('raw shield strength')}: {formats.int(shield.total)}{units.MJ}</h2>
|
<h2 onMouseOver={termtip.bind(null, <div>{shieldTooltipDetails}</div>)} onMouseOut={tooltip.bind(null, null)} className='summary'>{translate('raw shield strength')}<br/>{formats.int(shield.total)}{units.MJ}</h2>
|
||||||
<h2 onMouseOver={termtip.bind(null, translate('TT_TIME_TO_LOSE_SHIELDS'))} onMouseOut={tooltip.bind(null, null)}>{translate('PHRASE_TIME_TO_LOSE_SHIELDS')} {formats.time(shield.total / shielddamage.totalsdps)}</h2>
|
<h2 onMouseOver={termtip.bind(null, translate('TT_TIME_TO_LOSE_SHIELDS'))} onMouseOut={tooltip.bind(null, null)}>{translate('PHRASE_TIME_TO_LOSE_SHIELDS')}<br/>{formats.time(shield.total / shielddamage.totalsdps)}</h2>
|
||||||
<h2 onMouseOver={termtip.bind(null, translate('PHRASE_SG_RECOVER'))} onMouseOut={tooltip.bind(null, null)}>{translate('PHRASE_TIME_TO_RECOVER_SHIELDS')} {formats.time(ship.calcShieldRecovery())}</h2>
|
<h2 onMouseOver={termtip.bind(null, translate('PHRASE_SG_RECOVER'))} onMouseOut={tooltip.bind(null, null)}>{translate('PHRASE_TIME_TO_RECOVER_SHIELDS')}<br/>{formats.time(shield.recover)}</h2>
|
||||||
<h2 onMouseOver={termtip.bind(null, translate('PHRASE_SG_RECHARGE'))} onMouseOut={tooltip.bind(null, null)}>{translate('PHRASE_TIME_TO_RECHARGE_SHIELDS')} {formats.time(ship.calcShieldRecharge())}</h2>
|
<h2 onMouseOver={termtip.bind(null, translate('PHRASE_SG_RECHARGE'))} onMouseOut={tooltip.bind(null, null)}>{translate('PHRASE_TIME_TO_RECHARGE_SHIELDS')}<br/>{formats.time(ship.calcShieldRecharge())}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className='group quarter'>
|
<div className='group quarter'>
|
||||||
<h2 onMouseOver={termtip.bind(null, translate('PHRASE_SHIELD_SOURCES'))} onMouseOut={tooltip.bind(null, null)}>{translate('shield sources')}</h2>
|
<h2 onMouseOver={termtip.bind(null, translate('PHRASE_SHIELD_SOURCES'))} onMouseOut={tooltip.bind(null, null)}>{translate('shield sources')}</h2>
|
||||||
@@ -357,6 +400,11 @@ console.log(`max effective shields are ${shield.absolute.max}/${shield.explosive
|
|||||||
|
|
||||||
<div className='group quarter'>
|
<div className='group quarter'>
|
||||||
<h2>{translate('armour metrics')}</h2>
|
<h2>{translate('armour metrics')}</h2>
|
||||||
|
<h2 onMouseOver={termtip.bind(null, <div>{armourTooltipDetails}</div>)} onMouseOut={tooltip.bind(null, null)} className='summary'>{translate('raw armour strength')}<br/>{formats.int(armour.total)}</h2>
|
||||||
|
<h2 onMouseOver={termtip.bind(null, translate('TT_TIME_TO_LOSE_ARMOUR'))} onMouseOut={tooltip.bind(null, null)}>{translate('PHRASE_TIME_TO_LOSE_ARMOUR')}<br/>{formats.time(armour.total / armourdamage.totalsdps)}</h2>
|
||||||
|
<h2 onMouseOver={termtip.bind(null, translate('TT_MODULE_ARMOUR'))} onMouseOut={tooltip.bind(null, null)}>{translate('raw module armour')}<br/>{formats.int(armour.modulearmour)}</h2>
|
||||||
|
<h2 onMouseOver={termtip.bind(null, translate('TT_MODULE_PROTECTION_EXTERNAL'))} onMouseOut={tooltip.bind(null, null)}>{translate('PHRASE_MODULE_PROTECTION_EXTERNAL')}<br/>{formats.pct1(armour.moduleprotection / 2)}</h2>
|
||||||
|
<h2 onMouseOver={termtip.bind(null, translate('TT_MODULE_PROTECTION_INTERNAL'))} onMouseOut={tooltip.bind(null, null)}>{translate('PHRASE_MODULE_PROTECTION_INTERNAL')}<br/>{formats.pct1(armour.moduleprotection)}</h2>
|
||||||
<br/>
|
<br/>
|
||||||
</div>
|
</div>
|
||||||
<div className='group quarter'>
|
<div className='group quarter'>
|
||||||
|
|||||||
@@ -45,8 +45,15 @@ export const terms = {
|
|||||||
PHRASE_SHIELD_SOURCES: 'Breakdown of the supply of shield energy',
|
PHRASE_SHIELD_SOURCES: 'Breakdown of the supply of shield energy',
|
||||||
PHRASE_EFFECTIVE_SHIELD: 'Effective shield strength against different damage types',
|
PHRASE_EFFECTIVE_SHIELD: 'Effective shield strength against different damage types',
|
||||||
PHRASE_DAMAGE_TAKEN: '% of raw damage taken for 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',
|
||||||
|
PHRASE_MODULE_PROTECTION_INTERNAL: 'Protection for all other modules',
|
||||||
|
|
||||||
TT_TIME_TO_LOSE_SHIELDS: 'Against sustained fire from all opponent\'s 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',
|
||||||
|
TT_MODULE_PROTECTION_EXTERNAL: 'Percentage of damage diverted from hardpoints to module reinforcement packages',
|
||||||
|
TT_MODULE_PROTECTION_INTERNAL: 'Percentage of damage diverted from non-hardpoint modules to module reinforcement packages',
|
||||||
|
|
||||||
HELP_MODIFICATIONS_MENU: 'Click on a number to enter a new value, or drag along the bar for small changes',
|
HELP_MODIFICATIONS_MENU: 'Click on a number to enter a new value, or drag along the bar for small changes',
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user