Add and use range when calculating weapon effectiveness for damage dealt

This commit is contained in:
Cmdr McDonald
2017-01-14 13:10:09 +00:00
parent 53137e0ae1
commit 7f377d6345
3 changed files with 66 additions and 11 deletions

View File

@@ -1,6 +1,8 @@
#2.2.9 #2.2.9
* Use SSL-enabled server for shortlinks * Use SSL-enabled server for shortlinks
* Add falloff for weapons * Add falloff for weapons
* Use falloff when calculating weapon effectiveness in damage dealt
* Add engagement range slider to allow user to see change in weapon effectiveness with range
#2.2.8 #2.2.8
* Fix issue where filling all internals with cargo racks would include restricted slots * Fix issue where filling all internals with cargo racks would include restricted slots

View File

@@ -4,6 +4,7 @@ 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 Slider from '../components/Slider';
/** /**
* Generates an internationalization friendly weapon comparator that will * Generates an internationalization friendly weapon comparator that will
@@ -66,7 +67,9 @@ export default class DamageDealt extends TranslatedComponent {
predicate: 'n', predicate: 'n',
desc: true, desc: true,
against: DamageDealt.DEFAULT_AGAINST, against: DamageDealt.DEFAULT_AGAINST,
expanded: false expanded: false,
range: 0.1667,
maxRange: 6000
}; };
} }
@@ -74,7 +77,7 @@ export default class DamageDealt extends TranslatedComponent {
* Set the initial weapons state * Set the initial weapons state
*/ */
componentWillMount() { componentWillMount() {
const weapons = this._calcWeapons(this.props.ship, this.state.against); const weapons = this._calcWeapons(this.props.ship, this.state.against, this.state.range * this.state.maxRange);
this.setState({ weapons }); this.setState({ weapons });
} }
@@ -86,7 +89,7 @@ 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 weapons = this._calcWeapons(this.props.ship, this.state.against); const weapons = this._calcWeapons(this.props.ship, this.state.against, this.state.range * this.state.maxRange);
this.setState({ weapons }); this.setState({ weapons });
} }
return true; return true;
@@ -96,19 +99,37 @@ export default class DamageDealt extends TranslatedComponent {
* 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
* @param {Object} against The ship against which damage will be dealt * @param {Object} against The ship against which damage will be dealt
* @param {Object} range The engagement range
* @return {boolean} Returns the per-weapon damage * @return {boolean} Returns the per-weapon damage
*/ */
_calcWeapons(ship, against) { _calcWeapons(ship, against, range) {
let weapons = []; // Tidy up the range so that it's to 4 decimal places
range = Math.round(10000 * range) / 10000;
let weapons = [];
for (let i = 0; i < ship.hardpoints.length; i++) { for (let i = 0; i < ship.hardpoints.length; i++) {
if (ship.hardpoints[i].m) { if (ship.hardpoints[i].m) {
const m = ship.hardpoints[i].m; const m = ship.hardpoints[i].m;
if (m.getDamage() && m.grp !== 'po') { if (m.getDamage() && m.grp !== 'po') {
let dropoff = 1;
if (m.getFalloff()) {
// Calculate the dropoff % due to range
if (range > m.getRange()) {
// Weapon is out of range
dropoff = 0;
} else {
const falloff = m.getFalloff();
if (range > falloff) {
const dropoffRange = m.getRange() - falloff;
// Assuming straight-line falloff
dropoff = 1 - (range - falloff) / dropoffRange;
}
}
}
const classRating = `${m.class}${m.rating}${m.missile ? '/' + m.missile : ''}`; const classRating = `${m.class}${m.rating}${m.missile ? '/' + m.missile : ''}`;
const effectiveness = m.getPiercing() >= against.properties.hardness ? 1 : m.getPiercing() / against.properties.hardness; const effectiveness = (m.getPiercing() >= against.properties.hardness ? 1 : m.getPiercing() / against.properties.hardness) * dropoff;
const effectiveDps = m.getDps() * effectiveness; const effectiveDps = m.getDps() * effectiveness * dropoff;
const effectiveSDps = m.getClip() ? (m.getClip() * m.getDps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload()) * effectiveness : effectiveDps; const effectiveSDps = (m.getClip() ? (m.getClip() * m.getDps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload()) * effectiveness : effectiveDps) * dropoff;
weapons.push({ id: i, weapons.push({ id: i,
mount: m.mount, mount: m.mount,
@@ -210,14 +231,23 @@ export default class DamageDealt extends TranslatedComponent {
return rows; return rows;
} }
/**
* Update current range
* @param {number} range Range 0-1
*/
_rangeChange(range) {
const weapons = this._calcWeapons(this.props.ship, this.state.against, this.state.range * this.state.maxRange);
this.setState({ range, weapons });
}
/** /**
* Render damage dealt * Render damage dealt
* @return {React.Component} contents * @return {React.Component} contents
*/ */
render() { render() {
const { language, tooltip, termtip } = this.context; const { language, onWindowResize, sizeRatio, tooltip, termtip } = this.context;
const { formats, translate } = language; const { formats, translate, units } = language;
const { expanded } = this.state; const { expanded, maxRange, range } = this.state;
const sortOrder = this._sortOrder; const sortOrder = this._sortOrder;
const onCollapseExpand = this._onCollapseExpand; const onCollapseExpand = this._onCollapseExpand;
@@ -239,6 +269,27 @@ export default class DamageDealt extends TranslatedComponent {
<tbody> <tbody>
{this._renderRows(translate, formats)} {this._renderRows(translate, formats)}
</tbody> </tbody>
</table>
<table style={{ width: '80%', lineHeight: '1em', backgroundColor: 'transparent', margin: 'auto' }}>
<tbody >
<tr>
<td style={{ verticalAlign: 'top', padding: 0, width: '2.5em' }} onMouseEnter={termtip.bind(null, 'PHRASE_ENGAGEMENT_RANGE')} onMouseLeave={tooltip.bind(null, null)}>{translate('engagement range')}</td>
<td>
<Slider
axis={true}
onChange={this._rangeChange.bind(this)}
axisUnit={translate('m')}
percent={range}
max={maxRange}
scale={sizeRatio}
onResize={onWindowResize}
/>
</td>
<td className='primary' style={{ width: '10em', verticalAlign: 'top', fontSize: '0.9em', textAlign: 'left' }}>
{formats.f2(range * maxRange / 1000)}{units.km}
</td>
</tr>
</tbody>
</table></span> : null } </table></span> : null }
</span> </span>
); );

View File

@@ -28,6 +28,7 @@ export const terms = {
PHRASE_SG_RECOVER: 'Recovery (to 50%) after collapse', PHRASE_SG_RECOVER: 'Recovery (to 50%) after collapse',
PHRASE_UNLADEN: 'Ship mass excluding fuel and cargo', PHRASE_UNLADEN: 'Ship mass excluding fuel and cargo',
PHRASE_UPDATE_RDY: 'Update Available! Click to refresh', PHRASE_UPDATE_RDY: 'Update Available! Click to refresh',
PHRASE_ENGAGEMENT_RANGE: 'The distance between your ship and its target',
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',
@@ -123,6 +124,7 @@ export const terms = {
'yaw': 'Yaw', 'yaw': 'Yaw',
'internal protection': 'Internal protection', 'internal protection': 'Internal protection',
'external protection': 'External protection', 'external protection': 'External protection',
'engagement range': 'Engagement range',
// Modifications // Modifications
ammo: 'Ammunition maximum', ammo: 'Ammunition maximum',