Add movement summary; add standard internal class sizes to shipyard page; fix issue when importing Viper Mk IV

This commit is contained in:
Cmdr McDonald
2016-12-11 21:52:49 +00:00
parent 0dc58bad7e
commit a6a10df39c
13 changed files with 435 additions and 60 deletions

View File

@@ -1,3 +1,10 @@
#2.2.6
* Add pitch/roll/yaw information
* Use combination of pitch, roll and yaw to provide a more useful agility metric
* Add movement summary to outfitting page
* Add standard internal class sizes to shipyard page
* Fix issue when importing Viper Mk IV
#2.2.5
* Calculate rate of fire for multi-burst weapons
* Add note to disable ghostery in error situation

View File

@@ -0,0 +1,30 @@
{
"adder": {
"t3": {"speed": 205, "boost": 298, "pitch": 35.37, "roll": 93.09, "yaw": 13.03},
"t2": {"speed": 209, "boost": 304, "pitch": 36.06, "roll": 94.90, "yaw": 13.29},
"t1": {"speed": 213, "boost": 310, "pitch": 36.80, "roll": 96.84, "yaw": 13.56},
"t0": {"speed": 218, "boost": 317, "pitch": 37.70, "roll": 99.20, "yaw": 13.89},
"t9": {"speed": 220, "boost": 321, "pitch": 38.08, "roll": 100.21, "yaw": 14.03},
"t8": {"speed": 225, "boost": 327, "pitch": 38.86, "roll": 102.26, "yaw": 14.32},
"t7": {"speed": 230, "boost": 334, "pitch": 39.69, "roll": 104.44, "yaw": 14.62},
"t6": {"speed": 234, "boost": 340, "pitch": 40.41, "roll": 106.34, "yaw": 14.89},
"t5": {"speed": 242, "boost": 351, "pitch": 41.71, "roll": 109.78, "yaw": 15.37}
},
"eagle": {
"t2": {"speed": 223, "boost": 325, "pitch": 46.45, "roll": 111.48, "yaw": 16.72},
"t1": {"speed": 229, "boost": 334, "pitch": 47.69, "roll": 114.46, "yaw": 17.17},
"t0": {"speed": 235, "boost": 343, "pitch": 49.00, "roll": 117.60, "yaw": 17.64},
"t9": {"speed": 239, "boost": 349, "pitch": 49.80, "roll": 119.53, "yaw": 17.93},
"t8": {"speed": 243, "boost": 355, "pitch": 50.70, "roll": 121.69, "yaw": 18.25},
"t7": {"speed": 248, "boost": 361, "pitch": 51.62, "roll": 123.89, "yaw": 18.58},
"t6": {"speed": 252, "boost": 367, "pitch": 52.46, "roll": 125.91, "yaw": 18.89},
"t5": {"speed": 259, "boost": 378, "pitch": 53.99, "roll": 129.56, "yaw": 19.43}
},
"hauler": {
"t4": {"speed": 203, "boost": 305, "pitch": 36.61, "roll": 101.71, "yaw": 14.24},
"t3": {"speed": 209, "boost": 314, "pitch": 37.63, "roll": 104.54, "yaw": 14.64},
"t2": {"speed": 216, "boost": 324, "pitch": 38.89, "roll": 108.03, "yaw": 15.12},
"t1": {"speed": 222, "boost": 333, "pitch": 39.97, "roll": 111.02, "yaw": 15.54},
"t0": {"speed": 232, "boost": 348, "pitch": 41.76, "roll": 116.00, "yaw": 16.24}
}
}

View File

@@ -264,22 +264,21 @@
"topBoost": 248.62,
"topSpeed": 186.46,
"totalCost": 882362058,
"totalDpe": 127.26,
"totalDps": 97.74,
"totalDpe": 143.01,
"totalDps": 102.83,
"totalEps": 22.71,
"totalHps": 677.29,
"totalExplDpe": 0,
"totalExplDps": 0,
"totalExplSDps": 0,
"totalHps": 33.62,
"totalKinDpe": 103.97,
"totalKinDps": 28.92,
"totalKinSDps": 21.23,
"totalSDps": 85.77,
"totalThermDpe": 23.29,
"totalThermDps": 68.82,
"totalThermSDps": 64.53,
"agility": 2,
"totalKinDpe": 119.43,
"totalKinDps": 32.51,
"totalKinSDps": 24.79,
"totalSDps": 91.3,
"totalThermDpe": 23.58,
"totalThermDps": 70.32,
"totalThermSDps": 66.51,
"baseShieldStrength": 350,
"baseArmour": 945,
"hullExplRes": 0.78,
@@ -288,6 +287,7 @@
"hullThermRes": 1.37,
"masslock": 23,
"pipSpeed": 0.14,
"pitch": 25,
"moduleCostMultiplier": 1,
"fuelCapacity": 32,
"cargoCapacity": 128,
@@ -297,8 +297,10 @@
"unladenMass": 1179.2,
"powerAvailable": 39.6,
"powerRetracted": 23.33,
"powerDeployed": 34.76,
"powerDeployed": 34.13,
"roll": 60,
"unladenRange": 18.49,
"yaw": 10,
"fullTankRange": 18.12,
"ladenRange": 16.39,
"unladenFastestRange": 73.21,

90
__tests__/test-agility.js Normal file
View File

@@ -0,0 +1,90 @@
import Ship from '../src/app/shipyard/Ship';
import { Ships } from 'coriolis-data/dist';
import * as ModuleUtils from '../src/app/shipyard/ModuleUtils';
describe("Agility", function() {
it("correctly calculates speed", function() {
let agilityData = require('./fixtures/agility-data');
for (let shipId in agilityData) {
for (let thrusterId in agilityData[shipId]) {
const thrusterData = agilityData[shipId][thrusterId];
let shipData = Ships[shipId];
let ship = new Ship(shipId, shipData.properties, shipData.slots);
ship.buildWith(shipData.defaults);
ship.use(ship.standard[1], ModuleUtils.findModule('t', thrusterId));
expect(Math.round(ship.topSpeed)).toBe(thrusterData.speed);
}
}
});
it("correctly calculates boost", function() {
let agilityData = require('./fixtures/agility-data');
for (let shipId in agilityData) {
for (let thrusterId in agilityData[shipId]) {
const thrusterData = agilityData[shipId][thrusterId];
let shipData = Ships[shipId];
let ship = new Ship(shipId, shipData.properties, shipData.slots);
ship.buildWith(shipData.defaults);
// Turn off internals to ensure we have enough power to boost
for (let internal in ship.internal) {
ship.internal[internal].enabled = 0;
}
ship.use(ship.standard[1], ModuleUtils.findModule('t', thrusterId));
expect(Math.round(ship.topBoost)).toBe(thrusterData.boost);
}
}
});
it("correctly calculates pitch", function() {
let agilityData = require('./fixtures/agility-data');
for (let shipId in agilityData) {
for (let thrusterId in agilityData[shipId]) {
const thrusterData = agilityData[shipId][thrusterId];
let shipData = Ships[shipId];
let ship = new Ship(shipId, shipData.properties, shipData.slots);
ship.buildWith(shipData.defaults);
ship.use(ship.standard[1], ModuleUtils.findModule('t', thrusterId));
expect(Math.round(ship.pitches[4] * 100) / 100).toBeCloseTo(thrusterData.pitch, 1);
}
}
});
it("correctly calculates roll", function() {
let agilityData = require('./fixtures/agility-data');
for (let shipId in agilityData) {
for (let thrusterId in agilityData[shipId]) {
const thrusterData = agilityData[shipId][thrusterId];
let shipData = Ships[shipId];
let ship = new Ship(shipId, shipData.properties, shipData.slots);
ship.buildWith(shipData.defaults);
ship.use(ship.standard[1], ModuleUtils.findModule('t', thrusterId));
expect(Math.round(ship.rolls[4] * 100) / 100).toBeCloseTo(thrusterData.roll, 1);
}
}
});
it("correctly calculates yaw", function() {
let agilityData = require('./fixtures/agility-data');
for (let shipId in agilityData) {
for (let thrusterId in agilityData[shipId]) {
const thrusterData = agilityData[shipId][thrusterId];
let shipData = Ships[shipId];
let ship = new Ship(shipId, shipData.properties, shipData.slots);
ship.buildWith(shipData.defaults);
ship.use(ship.standard[1], ModuleUtils.findModule('t', thrusterId));
expect(Math.round(ship.yaws[4] * 100) / 100).toBeCloseTo(thrusterData.yaw, 1);
}
}
});
});

View File

@@ -31,6 +31,7 @@
"jsx"
],
"automock": true,
"bail": false,
"unmockedModulePathPatterns": [
"<rootDir>/node_modules/lodash",
"<rootDir>/node_modules/react",

View File

@@ -0,0 +1,125 @@
import React from 'react';
import cn from 'classnames';
import TranslatedComponent from './TranslatedComponent';
import { DamageKinetic, DamageThermal, DamageExplosive } from './SvgIcons';
/**
* Movement summary
*/
export default class MovementSummary extends TranslatedComponent {
static PropTypes = {
ship: React.PropTypes.object.isRequired
};
/**
* Constructor
* @param {Object} props React Component properties
*/
constructor(props) {
super(props);
}
/**
* Render movement summary
* @return {React.Component} contents
*/
render() {
let ship = this.props.ship;
let { language, tooltip, termtip } = this.context;
let { formats, translate, units } = language;
let hide = tooltip.bind(null, null);
let boostMultiplier = ship.topBoost / ship.topSpeed;
return (
<span>
<h1>{translate('movement summary')}</h1>
<table style={{ marginLeft: 'auto', marginRight: 'auto', lineHeight: '1em', backgroundColor: 'transparent' }}>
<tbody>
<tr>
<td >&nbsp;</td>
<td colSpan='6'>{translate('engine pips')}</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>0</td>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>4B</td>
</tr>
<tr>
<td className='ri'>{translate('speed')} ({units['m/s']})</td>
<td className='ri'>{formats.int(ship.speeds[0])}</td>
<td className='ri'>{formats.int(ship.speeds[1])}</td>
<td className='ri'>{formats.int(ship.speeds[2])}</td>
<td className='ri'>{formats.int(ship.speeds[3])}</td>
<td className='ri'>{formats.int(ship.speeds[4])}</td>
<td className='ri'>{formats.int(ship.speeds[4] * boostMultiplier)}</td>
</tr>
<tr>
<td className='ri'>{translate('pitch')} ({units['°/s']})</td>
<td className='ri'>{formats.int(ship.pitches[0])}</td>
<td className='ri'>{formats.int(ship.pitches[1])}</td>
<td className='ri'>{formats.int(ship.pitches[2])}</td>
<td className='ri'>{formats.int(ship.pitches[3])}</td>
<td className='ri'>{formats.int(ship.pitches[4])}</td>
<td className='ri'>{formats.int(ship.pitches[4] * boostMultiplier)}</td>
</tr>
<tr>
<td className='ri'>{translate('roll')} ({units['°/s']})</td>
<td className='ri'>{formats.int(ship.rolls[0])}</td>
<td className='ri'>{formats.int(ship.rolls[1])}</td>
<td className='ri'>{formats.int(ship.rolls[2])}</td>
<td className='ri'>{formats.int(ship.rolls[3])}</td>
<td className='ri'>{formats.int(ship.rolls[4])}</td>
<td className='ri'>{formats.int(ship.rolls[4] * boostMultiplier)}</td>
</tr>
<tr>
<td className='ri'>{translate('yaw')} ({units['°/s']})</td>
<td className='ri'>{formats.int(ship.yaws[0])}</td>
<td className='ri'>{formats.int(ship.yaws[1])}</td>
<td className='ri'>{formats.int(ship.yaws[2])}</td>
<td className='ri'>{formats.int(ship.yaws[3])}</td>
<td className='ri'>{formats.int(ship.yaws[4])}</td>
<td className='ri'>{formats.int(ship.yaws[4] * boostMultiplier)}</td>
</tr>
</tbody>
</table>
</span>
);
// return (
// <span>
// <h1>{translate('movement summary')}</h1>
// <table className='summary' style={{ marginLeft: 'auto', marginRight: 'auto', lineHeight: '1em', backgroundColor: 'transparent' }}>
// <tbody>
// <tr>
// <td colSpan='4' className='summary'><h2>{translate('normal')}</h2></td>
// </tr>
// <tr>
// <td className='summary'>{translate('speed')} {formats.int(ship.topSpeed)}{units['m/s']}</td>
// <td className='summary'>{translate('pitch')} {formats.f1(ship.pitches[4])}{units['°/s']}</td>
// <td className='summary'>{translate('roll')} {formats.f1(ship.rolls[4])}{units['°/s']}</td>
// <td className='summary'>{translate('yaw')} {formats.f1(ship.yaws[4])}{units['°/s']}</td>
// </tr>
// <tr>
// <td colSpan='4' className='summary'><h2>{translate('boost')}</h2></td>
// </tr>
// <tr>
// <td className='summary'>{translate('speed')} {formats.int(ship.topSpeed * boostMultiplier)}{units['m/s']}</td>
// <td className='summary'>{translate('pitch')} {formats.f1(ship.pitches[4] * boostMultiplier)}{units['°/s']}</td>
// <td className='summary'>{translate('roll')} {formats.f1(ship.rolls[4] * boostMultiplier)}{units['°/s']}</td>
// <td className='summary'>{translate('yaw')} {formats.f1(ship.yaws[4] * boostMultiplier)}{units['°/s']}</td>
// </tr>
// <tr>
// <td colSpan='4' className='summary'><h2>Frame Shift</h2></td>
// </tr>
// <tr>
// <td colSpan='4' className='summary'>Maximum {formats.f2(ship.fullTankRange)} {units.LY}</td>
// </tr>
// </tbody>
// </table>
// </span>
// );
}
}

View File

@@ -65,6 +65,7 @@ export function getLanguage(langCode) {
LY: <u> {translate('LY')}</u>, // Light Years
MJ: <u> {translate('MJ')}</u>, // Mega Joules
'm/s': <u> {translate('m/s')}</u>, // Meters per second
'°/s': <u> {translate('°/s')}</u>, // Degrees per second
MW: <u> {translate('MW')}</u>, // Mega Watts (same as Mega Joules per second)
ps: <u>{translate('/s')}</u>, // per second
pm: <u>{translate('/min')}</u>, // per minute

View File

@@ -94,7 +94,7 @@ export const terms = {
// Unit for seconds
secs: 's',
// Weapon, offence and defence
// Weapon, offence, defence and movement
dpe: 'Damage per MJ of energy',
dps: 'Damage per second',
sdps: 'Sustained damage per second',
@@ -106,6 +106,13 @@ export const terms = {
'damage by': 'Damage by',
'damage from': 'Damage from',
'shield cells': 'Shield cells',
'recovery': 'Recovery',
'recharge': 'Recharge',
'engine pips': 'Engine Pips',
'speed': 'Speed',
'pitch': 'Pitch',
'roll': 'Roll',
'yaw': 'Yaw',
// Modifications
ammo: 'Ammunition maximum',

View File

@@ -16,6 +16,7 @@ import InternalSlotSection from '../components/InternalSlotSection';
import UtilitySlotSection from '../components/UtilitySlotSection';
import OffenceSummary from '../components/OffenceSummary';
import DefenceSummary from '../components/DefenceSummary';
import MovementSummary from '../components/MovementSummary';
import LineChart from '../components/LineChart';
import PowerManagement from '../components/PowerManagement';
import CostSection from '../components/CostSection';
@@ -344,19 +345,7 @@ export default class OutfittingPage extends Page {
</div>
<div className='group third'>
<h1>{translate('speed')}</h1>
<LineChart
width={chartWidth}
xMax={ship.cargoCapacity}
yMax={ship.topBoost + 10}
xUnit={translate('T')}
yUnit={translate('m/s')}
yLabel={translate('speed')}
series={SPEED_SERIES}
colors={SPEED_COLORS}
xLabel={translate('cargo')}
func={state.speedChartFunc}
/>
<MovementSummary ship={ship} code={code}/>
</div>
<div className='group half'>
@@ -402,3 +391,19 @@ export default class OutfittingPage extends Page {
// func={state.jumpRangeChartFunc}
// />
// </div>
// <div className='group third'>
// <h1>{translate('speed')}</h1>
// <LineChart
// width={chartWidth}
// xMax={ship.cargoCapacity}
// yMax={ship.topBoost + 10}
// xUnit={translate('T')}
// yUnit={translate('m/s')}
// yLabel={translate('speed')}
// series={SPEED_SERIES}
// colors={SPEED_COLORS}
// xLabel={translate('cargo')}
// func={state.speedChartFunc}
// />
// </div>

View File

@@ -40,7 +40,9 @@ function shipSummary(shipId, shipData) {
intCount: 0,
maxCargo: 0,
hp: [0, 0, 0, 0, 0], // Utility, Small, Medium, Large, Huge
int: [0, 0, 0, 0, 0, 0, 0, 0] // Sizes 1 - 8
int: [0, 0, 0, 0, 0, 0, 0, 0], // Sizes 1 - 8
standard: shipData.slots.standard,
agility: shipData.properties.pitch + shipData.properties.yaw + shipData.properties.roll
};
Object.assign(summary, shipData.properties);
let ship = new Ship(shipId, shipData.properties, shipData.slots);
@@ -139,7 +141,7 @@ export default class ShipyardPage extends Page {
>
<td className='le'>{s.manufacturer}</td>
<td className='cap'>{translate(SizeMap[s.class])}</td>
<td>{s.agility}</td>
<td className='ri'>{fInt(s.agility)}</td>
<td className='ri'>{fInt(s.speed)}{u['m/s']}</td>
<td className='ri'>{fInt(s.boost)}{u['m/s']}</td>
<td className='ri'>{fInt(s.baseArmour)}</td>
@@ -148,6 +150,12 @@ export default class ShipyardPage extends Page {
<td className='ri'>{fInt(s.topBoost)}{u['m/s']}</td>
<td className='ri'>{fRound(s.maxJumpRange)}{u.LY}</td>
<td className='ri'>{fInt(s.maxCargo)}{u.T}</td>
<td className='cn'>{s.standard[0]}</td>
<td className='cn'>{s.standard[1]}</td>
<td className='cn'>{s.standard[2]}</td>
<td className='cn'>{s.standard[3]}</td>
<td className='cn'>{s.standard[4]}</td>
<td className='cn'>{s.standard[5]}</td>
<td className={cn({ disabled: !s.hp[1] })}>{s.hp[1]}</td>
<td className={cn({ disabled: !s.hp[2] })}>{s.hp[2]}</td>
<td className={cn({ disabled: !s.hp[3] })}>{s.hp[3]}</td>
@@ -260,9 +268,10 @@ export default class ShipyardPage extends Page {
<tr className='main'>
<th rowSpan={2} className='sortable' onClick={sortShips('manufacturer')}>{translate('manufacturer')}</th>
<th rowSpan={2} className='sortable' onClick={sortShips('class')}>{translate('size')}</th>
<th rowSpan={2} className='sortable' onMouseEnter={termtip.bind(null, 'maneuverability')} onMouseLeave={hide} onClick={sortShips('agility')}>{translate('mnv')}</th>
<th rowSpan={2} className='sortable' onClick={sortShips('agility')}>{translate('agility')}</th>
<th colSpan={4}>{translate('base')}</th>
<th colSpan={4}>{translate('max')}</th>
<th colSpan={6}>{translate('core module classes')}</th>
<th colSpan={5} className='sortable' onClick={sortShips('hpCount')}>{translate('hardpoints')}</th>
<th colSpan={8} className='sortable' onClick={sortShips('intCount')}>{translate('internal compartments')}</th>
<th rowSpan={2} className='sortable' onClick={sortShips('hullMass')}>{translate('hull')}</th>
@@ -280,6 +289,13 @@ export default class ShipyardPage extends Page {
<th className='sortable' onClick={sortShips('maxJumpRange')}>{translate('jump')}</th>
<th className='sortable' onClick={sortShips('maxCargo')}>{translate('cargo')}</th>
<th className='sortable lft' onMouseEnter={termtip.bind(null, 'power plant')} onMouseLeave={hide} onClick={sortShips('standard', 0)}>{'pp'}</th>
<th className='sortable' onMouseEnter={termtip.bind(null, 'thrusters')} onMouseLeave={hide} onClick={sortShips('standard', 1)}>{'th'}</th>
<th className='sortable' onMouseEnter={termtip.bind(null, 'frame shift drive')} onMouseLeave={hide} onClick={sortShips('standard', 2)}>{'fsd'}</th>
<th className='sortable' onMouseEnter={termtip.bind(null, 'life support')} onMouseLeave={hide} onClick={sortShips('standard', 3)}>{'ls'}</th>
<th className='sortable' onMouseEnter={termtip.bind(null, 'power distriubtor')} onMouseLeave={hide} onClick={sortShips('standard', 4)}>{'pd'}</th>
<th className='sortable' onMouseEnter={termtip.bind(null, 'sensors')} onMouseLeave={hide} onClick={sortShips('standard', 5)}>{'s'}</th>
<th className='sortable lft' onClick={sortShips('hp',1)}>{translate('S')}</th>
<th className='sortable' onClick={sortShips('hp', 2)}>{translate('M')}</th>
<th className='sortable' onClick={sortShips('hp', 3)}>{translate('L')}</th>

View File

@@ -67,14 +67,35 @@ export function shieldStrength(mass, baseShield, sg, multiplier) {
/**
* Calculate the a ships speed based on mass, and thrusters.
*
* @param {number} mass Current mass of the ship
* @param {number} baseSpeed Base speed m/s for ship
* @param {number} baseBoost Base boost speed m/s for ship
* @param {object} thrusters The Thrusters used
* @param {number} pipSpeed Speed pip multiplier
* @return {object} Approximate speed by pips
* @param {number} mass the mass of the ship
* @param {number} baseSpeed base speed m/s for ship
* @param {object} thrusters The ship's thrusters
* @param {number} engpip the multiplier per pip to engines
* @return {array} Speed by pips
*/
export function speed(mass, baseSpeed, baseBoost, thrusters, pipSpeed) {
export function speed(mass, baseSpeed, thrusters, engpip) {
// thrusters might be a module or a template; handle either here
const minMass = thrusters instanceof Module ? thrusters.getMinMass() : thrusters.minmass;
const optMass = thrusters instanceof Module ? thrusters.getOptMass() : thrusters.optmass;
const maxMass = thrusters instanceof Module ? thrusters.getMaxMass() : thrusters.maxmass;
const minMul = thrusters instanceof Module ? thrusters.getMinMul() : thrusters.minmul;
const optMul = thrusters instanceof Module ? thrusters.getOptMul() : thrusters.optmul;
const maxMul = thrusters instanceof Module ? thrusters.getMaxMul() : thrusters.maxmul;
let results = normValues(minMass, optMass, maxMass, minMul, optMul, maxMul, mass, baseSpeed, engpip);
return results;
}
/**
* Calculate pitch of a ship based on mass and thrusters
* @param {number} mass the mass of the ship
* @param {number} basePitch base pitch of the ship
* @param {object} thrusters the ship's thrusters
* @param {number} engpip the multiplier per pip to engines
* @return {array} Pitch by pips
*/
export function pitch(mass, basePitch, thrusters, engpip) {
// thrusters might be a module or a template; handle either here
let minMass = thrusters instanceof Module ? thrusters.getMinMass() : thrusters.minmass;
let optMass = thrusters instanceof Module ? thrusters.getOptMass() : thrusters.optmass;
@@ -83,16 +104,79 @@ export function speed(mass, baseSpeed, baseBoost, thrusters, pipSpeed) {
let optMul = thrusters instanceof Module ? thrusters.getOptMul() : thrusters.optmul;
let maxMul = thrusters instanceof Module ? thrusters.getMaxMul() : thrusters.maxmul;
let xnorm = Math.min(1, (maxMass - mass) / (maxMass - minMass));
let exponent = Math.log((optMul - minMul) / (maxMul - minMul)) / Math.log(Math.min(1, (maxMass - optMass) / (maxMass - minMass)));
let ynorm = Math.pow(xnorm, exponent);
let mul = minMul + ynorm * (maxMul - minMul);
let speed = baseSpeed * mul;
return {
'0 Pips': speed * (1 - (pipSpeed * 4)),
'2 Pips': speed * (1 - (pipSpeed * 2)),
'4 Pips': speed,
'boost': baseBoost * mul
};
return normValues(minMass, optMass, maxMass, minMul, optMul, maxMul, mass, basePitch, engpip);
}
/**
* Calculate yaw of a ship based on mass and thrusters
* @param {number} mass the mass of the ship
* @param {number} baseYaw base yaw of the ship
* @param {object} thrusters the ship's thrusters
* @param {number} engpip the multiplier per pip to engines
* @return {array} Yaw by pips
*/
export function yaw(mass, baseYaw, thrusters, engpip) {
// thrusters might be a module or a template; handle either here
let minMass = thrusters instanceof Module ? thrusters.getMinMass() : thrusters.minmass;
let optMass = thrusters instanceof Module ? thrusters.getOptMass() : thrusters.optmass;
let maxMass = thrusters instanceof Module ? thrusters.getMaxMass() : thrusters.maxmass;
let minMul = thrusters instanceof Module ? thrusters.getMinMul() : thrusters.minmul;
let optMul = thrusters instanceof Module ? thrusters.getOptMul() : thrusters.optmul;
let maxMul = thrusters instanceof Module ? thrusters.getMaxMul() : thrusters.maxmul;
return normValues(minMass, optMass, maxMass, minMul, optMul, maxMul, mass, baseYaw, engpip);
}
/**
* Calculate roll of a ship based on mass and thrusters
* @param {number} mass the mass of the ship
* @param {number} baseRoll base roll of the ship
* @param {object} thrusters the ship's thrusters
* @param {number} engpip the multiplier per pip to engines
* @return {array} Roll by pips
*/
export function roll(mass, baseRoll, thrusters, engpip) {
// thrusters might be a module or a template; handle either here
let minMass = thrusters instanceof Module ? thrusters.getMinMass() : thrusters.minmass;
let optMass = thrusters instanceof Module ? thrusters.getOptMass() : thrusters.optmass;
let maxMass = thrusters instanceof Module ? thrusters.getMaxMass() : thrusters.maxmass;
let minMul = thrusters instanceof Module ? thrusters.getMinMul() : thrusters.minmul;
let optMul = thrusters instanceof Module ? thrusters.getOptMul() : thrusters.optmul;
let maxMul = thrusters instanceof Module ? thrusters.getMaxMul() : thrusters.maxmul;
return normValues(minMass, optMass, maxMass, minMul, optMul, maxMul, mass, baseRoll, engpip);
}
/**
* Normalise according to FD's calculations and return suitable values
* @param {number} minMass the minimum mass of the thrusters
* @param {number} optMass the optimum mass of the thrusters
* @param {number} maxMass the maximum mass of the thrusters
* @param {number} minMul the minimum multiplier of the thrusters
* @param {number} optMul the optimum multiplier of the thrusters
* @param {number} maxMul the maximum multiplier of the thrusters
* @param {number} mass the mass of the ship
* @param {base} base the base value from which to calculate
* @param {number} engpip the multiplier per pip to engines
* @return {array} values by pips
*/
function normValues(minMass, optMass, maxMass, minMul, optMul, maxMul, mass, base, engpip) {
const xnorm = Math.min(1, (maxMass - mass) / (maxMass - minMass));
const exponent = Math.log((optMul - minMul) / (maxMul - minMul)) / Math.log(Math.min(1, (maxMass - optMass) / (maxMass - minMass)));
const ynorm = Math.pow(xnorm, exponent);
const mul = minMul + ynorm * (maxMul - minMul);
const res = base * mul;
return [res * (1 - (engpip * 4)),
res * (1 - (engpip * 3)),
res * (1 - (engpip * 2)),
res * (1 - (engpip * 1)),
res];
//return {
// '0 Pips': res * (1 - (engpip * 4)),
// '1 Pip': res * (1 - (engpip * 3)),
// '2 Pips': res * (1 - (engpip * 2)),
// '3 Pips': res * (1 - (engpip)),
// '4 Pips': res
//};
}

View File

@@ -188,10 +188,10 @@ export default class Ship {
* Calculate the hypothetical top speeds at cargo and fuel tonnage
* @param {Number} fuel Fuel available in tons
* @param {Number} cargo Cargo in tons
* @return {Object} Speed at pip settings and boost
* @return {array} Speed at pip settings
*/
calcSpeedsWith(fuel, cargo) {
return Calc.speed(this.unladenMass + fuel + cargo, this.speed, this.boost, this.standard[1].m, this.pipSpeed);
return Calc.speed(this.unladenMass + fuel + cargo, this.speed, this.standard[1].m, this.pipSpeed);
}
/**
@@ -432,7 +432,7 @@ export default class Ship {
let newMass = m.getMass();
this.unladenMass = this.unladenMass - oldMass + newMass;
this.ladenMass = this.ladenMass - oldMass + newMass;
this.updateTopSpeed();
this.updateMovement();
this.updateJumpStats();
} else if (name === 'maxfuel') {
m.setModValue(name, value);
@@ -440,13 +440,13 @@ export default class Ship {
} else if (name === 'optmass') {
m.setModValue(name, value);
// Could be for any of thrusters, FSD or shield
this.updateTopSpeed();
this.updateMovement();
this.updateJumpStats();
this.recalculateShield();
} else if (name === 'optmul') {
m.setModValue(name, value);
// Could be for any of thrusters, FSD or shield
this.updateTopSpeed();
this.updateMovement();
this.updateJumpStats();
this.recalculateShield();
} else if (name === 'shieldboost') {
@@ -597,7 +597,7 @@ export default class Ship {
.recalculateDps()
.recalculateEps()
.recalculateHps()
.updateTopSpeed();
.updateMovement();
}
return this.updatePowerPrioritesString().updatePowerEnabledString().updateModificationsString();
@@ -876,7 +876,7 @@ export default class Ship {
if (shieldCellsChange) {
this.recalculateShieldCells();
}
this.updateTopSpeed();
this.updateMovement();
this.updateJumpStats();
}
return this;
@@ -1088,13 +1088,20 @@ export default class Ship {
}
/**
* Update top speed and boost
* Update movement values
* @return {this} The ship instance (for chaining operations)
*/
updateTopSpeed() {
let speeds = Calc.speed(this.unladenMass + this.fuelCapacity, this.speed, this.boost, this.standard[1].m, this.pipSpeed);
this.topSpeed = speeds['4 Pips'];
this.topBoost = this.canBoost() ? speeds.boost : 0;
updateMovement() {
this.speeds = Calc.speed(this.unladenMass + this.fuelCapacity, this.speed, this.standard[1].m, this.pipSpeed);
this.topSpeed = this.speeds[4];
this.topBoost = this.canBoost() ? this.speeds[4] * this.boost / this.speed : 0;
this.pitches = Calc.pitch(this.unladenMass + this.fuelCapacity, this.pitch, this.standard[1].m, this.pipSpeed);
this.rolls = Calc.roll(this.unladenMass + this.fuelCapacity, this.roll, this.standard[1].m, this.pipSpeed);
this.yaws = Calc.yaw(this.unladenMass + this.fuelCapacity, this.yaw, this.standard[1].m, this.pipSpeed);
return this;
}

View File

@@ -33,7 +33,7 @@ const SHIP_FD_NAME_TO_CORIOLIS_NAME = {
'Type7': 'type_7_transport',
'Type9': 'type_9_heavy',
'Viper': 'viper',
'Viper_MKIV': 'viper_mk_iv',
'Viper_MkIV': 'viper_mk_iv',
'Vulture': 'vulture'
};