diff --git a/src/app/components/DamageDealt.jsx b/src/app/components/DamageDealt.jsx index 95b168a0..918c7032 100644 --- a/src/app/components/DamageDealt.jsx +++ b/src/app/components/DamageDealt.jsx @@ -6,6 +6,8 @@ import { nameComparator } from '../utils/SlotFunctions'; import { CollapseSection, ExpandSection, MountFixed, MountGimballed, MountTurret } from './SvgIcons'; import LineChart from '../components/LineChart'; import Slider from '../components/Slider'; +import * as ModuleUtils from '../shipyard/ModuleUtils'; +import Module from '../shipyard/Module'; const DAMAGE_DEALT_COLORS = ['#FFFFFF', '#FF0000', '#00FF00', '#0000FF', '#FFFF00', '#FF00FF', '#00FFFF', '#777777']; @@ -69,9 +71,9 @@ export default class DamageDealt extends TranslatedComponent { const ship = this.props.ship; const against = DamageDealt.DEFAULT_AGAINST; - const range = 0.5; const maxRange = this._calcMaxRange(ship); - const maxDps = this._calcMaxDps(ship, against) + const range = 1000 / maxRange; + const maxDps = this._calcMaxSDps(ship, against) const weaponNames = this._weaponNames(ship, context); this.state = { @@ -106,33 +108,38 @@ export default class DamageDealt extends TranslatedComponent { if (nextProps.code != this.props.code) { const data = this._calcWeaponsDps(nextProps.ship, this.state.against, this.state.range * this.state.maxRange, this.props.hull); const weaponNames = this._weaponNames(nextProps.ship, nextContext); + const maxRange = this._calcMaxRange(nextProps.ship); + const maxDps = this._calcMaxSDps(nextProps.ship, this.state.against) this.setState({ weapons: data.weapons, totals: data.totals, weaponNames, - calcHullDpsFunc: this._calcDps.bind(this, nextContext, nextProps.ship, this.state.weaponNames, this.state.against, true), - calcShieldsDpsFunc: this._calcDps.bind(this, nextContext, nextProps.ship, this.state.weaponNames, this.state.against, false) }); + maxRange, + maxDps, + calcHullDpsFunc: this._calcDps.bind(this, nextContext, nextProps.ship, weaponNames, this.state.against, true), + calcShieldsDpsFunc: this._calcDps.bind(this, nextContext, nextProps.ship, weaponNames, this.state.against, false) }); } return true; } /** - * Calculate the maximum single-weapon DPS for this ship against another ship + * Calculate the maximum sustained single-weapon DPS for this ship against another ship * @param {Object} ship The ship * @param {Object} against The target - * @return {number} The maximum single-weapon DPS + * @return {number} The maximum sustained single-weapon DPS */ - _calcMaxDps(ship, against) { - let maxDps = 0; + _calcMaxSDps(ship, against) { + let maxSDps = 0; for (let i =0; i < ship.hardpoints.length; i++) { if (ship.hardpoints[i].m && ship.hardpoints[i].enabled) { const m = ship.hardpoints[i].m; - const thisDps = m.getDps();// * (m.getPiercing() >= against.properties.hardness ? 1 : m.getPiercing() / against.properties.hardness); - if (thisDps > maxDps) { - maxDps = thisDps; + const thisSDps = m.getClip() ? (m.getClip() * m.getDps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload()) : m.getDps(); + //const thisDps = m.getDps();// * (m.getPiercing() >= against.properties.hardness ? 1 : m.getPiercing() / against.properties.hardness); + if (thisSDps > maxSDps) { + maxSDps = thisSDps; } } } - return maxDps; + return maxSDps; } /** @@ -287,10 +294,42 @@ export default class DamageDealt extends TranslatedComponent { engineering += ', ' + translate(m.blueprint.special.name); } } - const effectivenessShields = dropoff; + + // Alter effectiveness as per standard shields (all have the same resistances) + const sg = ModuleUtils.findModule('sg', '3v'); + let effectivenessShields = 0; + if (m.getDamageDist().E) { + effectivenessShields += m.getDamageDist().E * (1 - sg.getExplosiveResistance()); + } + if (m.getDamageDist().K) { + effectivenessShields += m.getDamageDist().K * (1 - sg.getKineticResistance()); + } + if (m.getDamageDist().T) { + effectivenessShields += m.getDamageDist().T * (1 - sg.getThermalResistance()); + } + if (m.getDamageDist().A) { + effectivenessShields += m.getDamageDist().A; + } + effectivenessShields *= dropoff; const effectiveDpsShields = m.getDps() * effectivenessShields; const effectiveSDpsShields = (m.getClip() ? (m.getClip() * m.getDps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload()) * effectivenessShields : effectiveDpsShields); - const effectivenessHull = (m.getPiercing() >= against.properties.hardness ? 1 : m.getPiercing() / against.properties.hardness) * dropoff; + + // Alter effectiveness as per standard hull + const bulkheads = new Module({template: against.bulkheads}); + let effectivenessHull = 0; + if (m.getDamageDist().E) { + effectivenessHull += m.getDamageDist().E * (1 - bulkheads.getExplosiveResistance()); + } + if (m.getDamageDist().K) { + effectivenessHull += m.getDamageDist().K * (1 - bulkheads.getKineticResistance()); + } + if (m.getDamageDist().T) { + effectivenessHull += m.getDamageDist().T * (1 - bulkheads.getThermalResistance()); + } + if (m.getDamageDist().A) { + effectivenessHull += m.getDamageDist().A; + } + effectivenessHull *= Math.min(m.getPiercing() / against.properties.hardness, 1) * dropoff; const effectiveDpsHull = m.getDps() * effectivenessHull; const effectiveSDpsHull = (m.getClip() ? (m.getClip() * m.getDps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload()) * effectivenessHull : effectiveDpsHull); totals.effectiveDpsShields += effectiveDpsShields; @@ -333,11 +372,9 @@ export default class DamageDealt extends TranslatedComponent { _onShipChange(s) { const against = Ships[s]; const data = this._calcWeaponsDps(this.props.ship, against, this.state.range * this.state.maxRange); - const maxDps = this._calcMaxDps(this.props.ship, against) this.setState({ against, weapons: data.weapons, totals: data.totals, - maxDps, calcHullDpsFunc: this._calcDps.bind(this, this.context, this.props.ship, this.state.weaponNames, against, true), calcShieldsDpsFunc: this._calcDps.bind(this, this.context, this.props.ship, this.state.weaponNames, against, false) }); } @@ -426,9 +463,7 @@ export default class DamageDealt extends TranslatedComponent { const data = this._calcWeaponsDps(this.props.ship, this.state.against, this.state.range * this.state.maxRange); this.setState({ range, weapons: data.weapons, - totals: data.totals, - calcHullDpsFunc: this._calcDps.bind(this, this.context, this.props.ship, this.state.weaponNames, this.state.against, true), - calcShieldsDpsFunc: this._calcDps.bind(this, this.context, this.props.ship, this.state.weaponNames, this.state.against, false) }); + totals: data.totals }); } /** @@ -439,10 +474,13 @@ export default class DamageDealt extends TranslatedComponent { const { language, onWindowResize, sizeRatio, tooltip, termtip } = this.context; const { formats, translate, units } = language; const { expanded, maxRange, range, totals } = this.state; + const { ship } = this.props; const sortOrder = this._sortOrder; const onCollapseExpand = this._onCollapseExpand; + const hStr = ship.getHardpointsString() + '.' + ship.getModificationsString(); + return (

{translate('damage dealt against')} {expanded ? : }

@@ -452,8 +490,8 @@ export default class DamageDealt extends TranslatedComponent { {translate('weapon')} - {translate('shields')} - {translate('armour')} + {translate('standard shields')} + {translate('standard armour')} {translate('effective dps')} @@ -501,33 +539,35 @@ export default class DamageDealt extends TranslatedComponent {
-

{translate('damage against shields')}

+

{translate('damage against standard shields')}

-

{translate('damage against hull')}

+

{translate('damage against standard armour')}

: null } diff --git a/src/app/components/LineChart.jsx b/src/app/components/LineChart.jsx index 4e1ab0a1..39974055 100644 --- a/src/app/components/LineChart.jsx +++ b/src/app/components/LineChart.jsx @@ -10,6 +10,7 @@ const MARGIN = { top: 15, right: 20, bottom: 35, left: 60 }; export default class LineChart extends TranslatedComponent { static defaultProps = { + code: '', xMin: 0, yMin: 0, points: 20, @@ -30,6 +31,7 @@ export default class LineChart extends TranslatedComponent { series: React.PropTypes.array, colors: React.PropTypes.array, points: React.PropTypes.number, + code: React.PropTypes.string, }; /** @@ -42,36 +44,29 @@ export default class LineChart extends TranslatedComponent { this._updateDimensions = this._updateDimensions.bind(this); this._updateSeriesData = this._updateSeriesData.bind(this); + this._updateSeries = this._updateSeries.bind(this); this._tooltip = this._tooltip.bind(this); this._showTip = this._showTip.bind(this); this._hideTip = this._hideTip.bind(this); this._moveTip = this._moveTip.bind(this); - let markerElems = []; - let detailElems = []; + //const data = _updateSeries(this.props); + const series = props.series; + let xScale = d3.scaleLinear(); - let xAxisScale = d3.scaleLinear(); let yScale = d3.scaleLinear(); - let series = props.series; - let seriesLines = []; + let xAxisScale = d3.scaleLinear(); this.xAxis = d3.axisBottom(xAxisScale).tickSizeOuter(0); this.yAxis = d3.axisLeft(yScale).ticks(6).tickSizeOuter(0); - for(let i = 0, l = series ? series.length : 1; i < l; i++) { - let yAccessor = series ? function(d) { return yScale(d[1][this]); }.bind(series[i]) : (d) => yScale(d[1]); - seriesLines.push(d3.line().x((d, i) => xScale(d[0])).y(yAccessor)); - detailElems.push(); - markerElems.push(); - } - this.state = { xScale, xAxisScale, yScale, - seriesLines, - detailElems, - markerElems, + //seriesLines: data.seriesLines, + //detailElems: data.detailElems, + //markerElems: data.markerElems, tipHeight: 2 + (1.2 * (series ? series.length : 0.8)) }; } @@ -165,7 +160,43 @@ export default class LineChart extends TranslatedComponent { } /** - * Update series data generated from props + * Update series generated from props + * @param {Object} props React Component properties + */ + _updateSeries(props, state) { + let { func, xMin, xMax, series, points } = props; + let delta = (xMax - xMin) / points; + let seriesData = new Array(points); + + if (delta) { + seriesData = new Array(points); + for (let i = 0, x = xMin; i < points; i++) { + seriesData[i] = [x, func(x)]; + x += delta; + } + seriesData[points - 1] = [xMax, func(xMax)]; + } else { + let yVal = func(xMin); + seriesData = [[0, yVal], [1, yVal]]; + } + + + const markerElems = []; + const detailElems = []; + const seriesLines = []; + for (let i = 0, l = series ? series.length : 1; i < l; i++) { + const yAccessor = series ? function(d) { return state.yScale(d[1][this]); }.bind(series[i]) : (d) => state.yScale(d[1]); + seriesLines.push(d3.line().x((d, i) => this.state.xScale(d[0])).y(yAccessor)); + detailElems.push(); + markerElems.push(); + } + + this.setState({ markerElems, detailElems, seriesLines, seriesData }); + return { seriesData }; + } + + /** + * Update series and data generated from props * @param {Object} props React Component properties */ _updateSeriesData(props) { @@ -193,7 +224,7 @@ export default class LineChart extends TranslatedComponent { */ componentWillMount() { this._updateDimensions(this.props, this.context.sizeRatio); - this._updateSeriesData(this.props); + this._updateSeries(this.props, this.state); } /** @@ -211,9 +242,12 @@ export default class LineChart extends TranslatedComponent { this._updateDimensions(nextProps, nextContext.sizeRatio); } - if (domainChanged) { - this._updateSeriesData(nextProps); + if (props.code != nextProps.code) { + console.log('Code changed'); } +// if (domainChanged) { + this._updateSeries(nextProps, this.state); +// } } /**