Playing with damage dealt graph

This commit is contained in:
Cmdr McDonald
2017-01-30 13:34:41 +00:00
parent ea3d57399c
commit 76027b8537
2 changed files with 120 additions and 9 deletions

View File

@@ -4,8 +4,11 @@ import { Ships } from 'coriolis-data/dist';
import ShipSelector from './ShipSelector'; import ShipSelector from './ShipSelector';
import { nameComparator } from '../utils/SlotFunctions'; import { nameComparator } from '../utils/SlotFunctions';
import { CollapseSection, ExpandSection, MountFixed, MountGimballed, MountTurret } from './SvgIcons'; import { CollapseSection, ExpandSection, MountFixed, MountGimballed, MountTurret } from './SvgIcons';
import LineChart from '../components/LineChart';
import Slider from '../components/Slider'; import Slider from '../components/Slider';
const DAMAGE_DEALT_COLORS = ['#0088d2', '#ff8c0d', '#D26D00', '#c06400'];
/** /**
* Generates an internationalization friendly weapon comparator that will * Generates an internationalization friendly weapon comparator that will
* sort by specified property (if provided) then by name/group, class, rating * sort by specified property (if provided) then by name/group, class, rating
@@ -47,6 +50,7 @@ export function weaponComparator(translate, propComparator, desc) {
export default class DamageDealt extends TranslatedComponent { export default class DamageDealt extends TranslatedComponent {
static PropTypes = { static PropTypes = {
ship: React.PropTypes.object.isRequired, ship: React.PropTypes.object.isRequired,
chartWidth: React.PropTypes.number.isRequired,
code: React.PropTypes.string.isRequired code: React.PropTypes.string.isRequired
}; };
@@ -63,13 +67,23 @@ export default class DamageDealt extends TranslatedComponent {
this._onShipChange = this._onShipChange.bind(this); this._onShipChange = this._onShipChange.bind(this);
this._onCollapseExpand = this._onCollapseExpand.bind(this); this._onCollapseExpand = this._onCollapseExpand.bind(this);
const ship = this.props.ship;
const against = DamageDealt.DEFAULT_AGAINST;
const range = 0.1667;
const maxRange = 6000;
const maxDps = this._calcMaxDps(ship, against)
const weaponNames = this._weaponNames(ship);
this.state = { this.state = {
predicate: 'n', predicate: 'n',
desc: true, desc: true,
against: DamageDealt.DEFAULT_AGAINST, against,
expanded: false, expanded: false,
range: 0.1667, range,
maxRange: 6000 maxRange,
maxDps,
weaponNames,
calcDpsFunc: this._calcDps.bind(this, ship, against)
}; };
} }
@@ -89,12 +103,84 @@ export default class DamageDealt extends TranslatedComponent {
*/ */
componentWillReceiveProps(nextProps, nextContext) { componentWillReceiveProps(nextProps, nextContext) {
if (nextProps.code != this.props.code) { if (nextProps.code != this.props.code) {
const data = this._calcWeapons(this.props.ship, this.state.against, this.state.range * this.state.maxRange); const data = this._calcWeapons(nextProps.ship, this.state.against, this.state.range * this.state.maxRange);
this.setState({ weapons: data.weapons, totals: data.totals }); const weaponNames = this._weaponNames(nextProps.ship);
this.setState({ weapons: data.weapons,
totals: data.totals,
weaponNames,
calcDpsFunc: this._calcDps.bind(this, nextProps.ship, this.state.against) });
} }
return true; return true;
} }
/**
* Calculate the maximum 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
*/
_calcMaxDps(ship, against) {
let maxDps = 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;
}
}
}
return maxDps;
}
/**
* Calculate the per-weapon DPS for this ship against another ship at a given range
* @param {Object} ship The ship
* @param {Object} against The target
* @param {Object} range The engagement range
* @return {array} The array of weapon DPS
*/
_calcDps(ship, against, range) {
let results = {}
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);
results[i] = thisDps;
}
}
return results;
}
/**
* Obtain the weapon names for this ship
* @param {Object} ship The ship
* @return {array} The weapon names
*/
_weaponNames(ship) {
let names = [];
for (let i =0; i < ship.hardpoints.length; i++) {
if (ship.hardpoints[i].m && ship.hardpoints[i].enabled) {
const m = ship.hardpoints[i].m;
// TODO translate
let name = m.class + m.rating + (m.missile ? '/' + m.missile : '') + ' ' + (m.name || m.grp);
let engineering;
if (m.blueprint && m.blueprint.name) {
engineering = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade;
if (m.blueprint.special && m.blueprint.special.id) {
engineering += ', ' + translate(m.blueprint.special.name);
}
}
if (engineering) {
name = name + ' (' + engineering + ')';
}
names.push(name)
}
}
return names;
}
/** /**
* Calculate the damage dealt by a ship * Calculate the damage dealt by a ship
* @param {Object} ship The ship which will deal the damage * @param {Object} ship The ship which will deal the damage
@@ -193,7 +279,12 @@ export default class DamageDealt extends TranslatedComponent {
_onShipChange(s) { _onShipChange(s) {
const against = Ships[s]; const against = Ships[s];
const data = this._calcWeapons(this.props.ship, against, this.state.range * this.state.maxRange); const data = this._calcWeapons(this.props.ship, against, this.state.range * this.state.maxRange);
this.setState({ against, weapons: data.weapons, totals: data.totals }); const maxDps = this._calcMaxDps(this.props.ship, against)
this.setState({ against,
weapons: data.weapons,
totals: data.totals,
maxDps,
calcDpsFunc: this.props.ship.calcDps.bind(this, this.props.ship, against) });
} }
/** /**
@@ -278,7 +369,10 @@ export default class DamageDealt extends TranslatedComponent {
*/ */
_rangeChange(range) { _rangeChange(range) {
const data = this._calcWeapons(this.props.ship, this.state.against, this.state.range * this.state.maxRange); const data = this._calcWeapons(this.props.ship, this.state.against, this.state.range * this.state.maxRange);
this.setState({ range, weapons: data.weapons, totals: data.totals }); this.setState({ range,
weapons: data.weapons,
totals: data.totals,
calcDpsFunc: this.props.ship.calcDps.bind(this, this.props.ship, against) });
} }
/** /**
@@ -290,6 +384,7 @@ export default class DamageDealt extends TranslatedComponent {
const { formats, translate, units } = language; const { formats, translate, units } = language;
const { expanded, maxRange, range, totals } = this.state; const { expanded, maxRange, range, totals } = this.state;
const sortOrder = this._sortOrder; const sortOrder = this._sortOrder;
const onCollapseExpand = this._onCollapseExpand; const onCollapseExpand = this._onCollapseExpand;
@@ -349,7 +444,23 @@ export default class DamageDealt extends TranslatedComponent {
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table></span> : null } </table>
<div className='group half'>
<h1>{translate('damage')}</h1>
<LineChart
width={this.props.chartWidth}
xMax={6000}
yMax={this.state.maxDps}
xLabel={translate('distance')}
xUnit={translate('m')}
yLabel={translate('damage')}
yUnit={translate('ps')}
series={this.state.weaponNames}
colors={DAMAGE_DEALT_COLORS}
func={this.state.calcDpsFunc}
/>
</div>
</span> : null }
</span> </span>
); );
} }

View File

@@ -423,7 +423,7 @@ export default class OutfittingPage extends Page {
</div> </div>
<div> <div>
<DamageDealt ship={ship} code={code} currentMenu={menu}/> <DamageDealt ship={ship} code={code} chartWidth={chartWidth} currentMenu={menu}/>
</div> </div>
<div> <div>