diff --git a/ChangeLog.md b/ChangeLog.md index 0e821ec8..5f7d1c94 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -13,6 +13,7 @@ * Obey restricted slot rules when adding all for internal slots * Version URLs to handle changes to ship specifications over time * Do not include disabled shield boosters in calculations + * Add 'Damage dealt' section #2.2.5 * Calculate rate of fire for multi-burst weapons diff --git a/src/app/components/DamageDealt.jsx b/src/app/components/DamageDealt.jsx new file mode 100644 index 00000000..f0095013 --- /dev/null +++ b/src/app/components/DamageDealt.jsx @@ -0,0 +1,143 @@ +import React from 'react'; +import cn from 'classnames'; +import TranslatedComponent from './TranslatedComponent'; +import { Ships } from 'coriolis-data/dist'; +import { slotName, slotComparator } from '../utils/SlotFunctions'; +import ShipSelector from './ShipSelector'; + +/** + * Damage against a selected ship + */ +export default class DamageDealt extends TranslatedComponent { + static PropTypes = { + ship: React.PropTypes.object.isRequired, + code: React.PropTypes.string.isRequired + }; + + /** + * Constructor + * @param {Object} props React Component properties + */ + constructor(props) { + super(props); + + this._sort = this._sort.bind(this); + this._onShipChange = this._onShipChange.bind(this); + + this.state = { + predicate: 'n', + desc: true, + against: Ships['anaconda'], + }; + } + + /** + * Triggered when the comparator ship changes + */ + _onShipChange(s) { + this.setState({ against: Ships[s] }); + } + + /** + * Set the sort order and sort + * @param {string} predicate Sort predicate + */ + _sortOrder(predicate) { + let desc = this.state.desc; + + if (predicate == this.state.predicate) { + desc = !desc; + } else { + desc = true; + } + + this._sort(this.props.ship, predicate, desc); + this.setState({ predicate, desc }); + } + + /** + * Sorts the weapon list + * @param {Ship} ship Ship instance + * @param {Ship} against The ship to compare against + * @param {string} predicate Sort predicate + * @param {Boolean} desc Sort order descending + */ + _sort(ship, against, predicate, desc) { + let weaponList = ship.hardpoints; + let comp = slotComparator.bind(null, this.context.language.translate); + + switch (predicate) { + case 'n': comp = comp(null, desc); break; + case 'd': comp = comp((a, b) => a.m.getDps() - b.m.getDps(), desc); break; + case 'e': comp = comp((a, b) => (a.m.getPiercing() > a.m.hardness ? a.m.getDps() : a.m.getDps() * a.m.getPiercing() / a.m.hardness) - (b.m.getPiercing() > b.m.hardness ? b.m.getDps() : b.m.getDps() * b.m.getPiercing() / b.m.hardness), desc); break; + } + + weaponList.sort(comp); + } + + /** + * Render individual rows for hardpoints + * @param {Function} translate Translate function + * @param {Object} formats Localised formats map + * @param {Object} ship Our ship + * @param {Object} against The ship against which to compare + * @return {array} The individual rows + * + */ + _renderRows(translate, formats, ship, against) { + let rows = []; + + for (let hardpoint in ship.hardpoints) { + if (ship.hardpoints[hardpoint].m) { + const m = ship.hardpoints[hardpoint].m; + const classRating = `${m.class}${m.rating}${m.missile ? '/' + m.missile : ''}`; + const effectiveness = m.getPiercing() >= against.properties.hardness ? 1 : m.getPiercing() / against.properties.hardness; + const effectiveDps = m.getDps() * effectiveness; + const effectiveSDps = m.getClip() ? (m.getClip() * m.getDps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload()) * effectiveness : effectiveDps; + + rows.push( + {classRating} {slotName(translate, ship.hardpoints[hardpoint])} + {formats.round1(effectiveDps)} + {formats.round1(effectiveSDps)} + {formats.pct(effectiveness)} + ); + } + } + + + return rows; + } + + /** + * Render damage dealt + * @return {React.Component} contents + */ + render() { + const { language, tooltip, termtip } = this.context; + const { formats, translate } = language; + + const ship = this.props.ship; + const against = this.state.against; + const hardness = against.properties.hardness; + + return ( + +

{translate('damage dealt against')}

+ + + + + + + + + + + + {this._renderRows(translate, formats, ship, against)} + +
{translate('weapon')}{translate('effective dps')}{translate('effective sdps')}{translate('effectiveness')}
+
+ ); + } +} diff --git a/src/app/components/HardpointsSlotSection.jsx b/src/app/components/HardpointsSlotSection.jsx index 8eb212da..51bb79d4 100644 --- a/src/app/components/HardpointsSlotSection.jsx +++ b/src/app/components/HardpointsSlotSection.jsx @@ -133,6 +133,10 @@ export default class HardpointsSlotSection extends SlotSection {
  • +
    {translate('pa')}
    +
    {translate('nl')}