mirror of
https://github.com/EDCD/coriolis.git
synced 2025-12-08 14:33:22 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
99c0bfcee1 | ||
|
|
37bfc700e9 | ||
|
|
fcf0494df6 | ||
|
|
20ba6eb822 | ||
|
|
0e2c0349e0 | ||
|
|
c49e2cff03 | ||
|
|
d79313bfbe | ||
|
|
fd404b5155 | ||
|
|
49e72146b4 | ||
|
|
9b534b62c8 | ||
|
|
0be59af9b0 | ||
|
|
029ba63aa5 | ||
|
|
99e9e0c76f | ||
|
|
5bbc6e1cbe | ||
|
|
1e5f66e528 | ||
|
|
cdb837a25a |
12
ChangeLog.md
12
ChangeLog.md
@@ -1,3 +1,15 @@
|
||||
#2.2.10
|
||||
* Fix detailed export of module reinforcement packages
|
||||
* Use damagedist for exact breakdown of weapons that have more than one type of damage
|
||||
* Use new-style modification validity data
|
||||
* Provide ability to select engineering blueprint and roll sample values for them
|
||||
* Use coriolis-data 2.2.10:
|
||||
* Fix incorrect base shield values for Cutter and Corvette
|
||||
* Update weapons to have %-based damage distributions
|
||||
* Remove power draw for detailed surface scanner - although shown in outfitting it is not part of active power
|
||||
* Fix incorrect names for lightweight and kinetic armour
|
||||
* Add engineering blueprints
|
||||
|
||||
#2.2.9
|
||||
* Use SSL-enabled server for shortlinks
|
||||
* Add falloff for weapons
|
||||
|
||||
@@ -269,20 +269,20 @@
|
||||
"topSpeed": 187.01,
|
||||
"totalCost": 882362058,
|
||||
"totalDpe": 142.68,
|
||||
"totalDps": 101.13,
|
||||
"totalDps": 103.8,
|
||||
"totalEps": 22.71,
|
||||
"totalHps": 677.29,
|
||||
"totalExplDpe": 0,
|
||||
"totalExplDps": 0,
|
||||
"totalExplSDps": 0,
|
||||
"totalHps": 33.62,
|
||||
"totalKinDpe": 116.29,
|
||||
"totalKinDps": 16.01,
|
||||
"totalKinSDps": 12.09,
|
||||
"totalSDps": 89.99,
|
||||
"totalThermDpe": 20.44,
|
||||
"totalThermDps": 53.82,
|
||||
"totalThermSDps": 53.82,
|
||||
"totalKinDpe": 117.48,
|
||||
"totalKinDps": 24.94,
|
||||
"totalKinSDps": 18.76,
|
||||
"totalSDps": 91.84,
|
||||
"totalThermDpe": 21.63,
|
||||
"totalThermDps": 60.08,
|
||||
"totalThermSDps": 58.64,
|
||||
"baseShieldStrength": 350,
|
||||
"baseArmour": 945,
|
||||
"hullExplRes": 0.22,
|
||||
|
||||
@@ -238,7 +238,7 @@ describe('Import Modal', function() {
|
||||
expect(modal.state.singleBuild).toBe(true);
|
||||
clickProceed();
|
||||
expect(MockRouter.go.mock.calls.length).toBe(1);
|
||||
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/federal_corvette?code=A2putsFklndzsxf50x0x7l28281919040404040402020l06p05sf63c5ifr--v66g2f.AwRj4zNaqA%3D%3D.CwRgDBldUExuBiIlUA%3D%3D.H4sIAAAAAAAAA02SO0sDQRSFbxJ389jgJOsaN%2FGVmPXVKKRQC8FSA9oJWihWWgV%2FgIWFYBNb8RcIWiiIYiF2NqksIqaRoD%2FBQghB41zPFVa3OdzZ890zM3snpBeI6DsEyZgGkbpg5tg2lhzWGbEikN6aSVS0HSL3Ogxo6IvZmdbM9hFsjuickGgn%2B8SGv%2FvJ7DpxIqeCHjb0vJ80GrWIxu5RFmqARnYQEj%2FrMCdesFQzSOeYXvPP1BmGZPeiREa9xWyW0WifwnFX0MMJve4Hd5IQo4I9TcclGrxCUmoO34qVDaK%2BJuiJfD6%2FytZ%2Fj%2FGQAL7fD%2Fyiy8fbcNQdjsXJAFn9DRbyQchZIS9RqZJcGpckt4xjsdKL%2FtndJYjVQJkW8URUVYJTAegLat0IJOKJqCeB0gHoQ6BHgUQ8EdUNZvgghj3tAPmKa1vPQhIqTyp1KHE9AWgKV7Ka8NMinoiywLCrV%2F5Gvolo61ySpMn7xMdwsc3cf4w48w2Is40fwFld9oPzLbyL6CT88QaWoZpMcyDg32Jo0br4EaxDJXk8BT3o%2B7ktGS9B3GU8puS7zJh%2FAHGMT2qjAgAA&bn=Imported%20Federal%20Corvette');
|
||||
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/federal_corvette?code=A2putsFklndzsxf50x0x7l28281919040404040402020l06p05sf63c5ifr--v66g2f.AwRj4zNaqA%3D%3D.CwRgDBldUExuBiIlUA%3D%3D.H4sIAAAAAAAAA02Svy9DURTHT1vvtfoat32eekVV9fm1kBgwSIw0YWYgBqmpMZkMBomFVfwFEoZKhBjE1qWTgegiDX%2BCQdKI1j2%2BR%2FJ4yzfnvu%2FnfO%2B979yQXiCi7xAkbRpEqsLMsRKWHNZpsSKQnppJVLAdIvc6DGiwxexMaWb7GDZHdJ%2BQaCf71Ia%2F88XsOp1EThk9bOh5P2kkahGN3qPM1wANbyOk87zNHH%2FBUs0gnWN61T9TOwfJ7EWJjMcms1lEo30Gx11BD8f1mh%2FcTkCMMvY0HZcoe4Wk5By%2BFcrrRL0N0OOlrd0Ntv57jGoc%2BH4%2F8EqHj3%2FCUXc4FicC5NFvsJBVIWeFvESlpuXSuCS5RRyLlV70z%2B4uQaw6ypSIJ6KOJDgZgFpQ60YgEU9EPQmUCkAfAj0IJOKJqC4wuYMY9rQD5CuubT0LSag8qdShxHUHoElcyWrAT4l4IsoCw65e%2BRv5BqKtC0mSJu8LH8OFT%2Bb%2BE8SZb0CcEn4AZ3TRDx5q4l1EJ%2BCP1bEM1WSaAwH%2FFkOLPoofwTo0LY8nr7O%2B37cp4yWIu4zHlHiXGfMPmat5gqMCAAA%3D&bn=Imported%20Federal%20Corvette');
|
||||
});
|
||||
|
||||
it('imports a valid v4 build', function() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "coriolis_shipyard",
|
||||
"version": "2.2.9",
|
||||
"version": "2.2.10",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/EDCD/coriolis"
|
||||
|
||||
@@ -153,7 +153,7 @@ export default class DamageDealt extends TranslatedComponent {
|
||||
}
|
||||
totals.effectiveness = totals.effectiveDps / totalDps;
|
||||
|
||||
return {weapons: weapons, totals: totals};
|
||||
return { weapons, totals };
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -93,7 +93,7 @@ export default class DamageReceived extends TranslatedComponent {
|
||||
let weapons = [];
|
||||
|
||||
for (let grp in Modules.hardpoints) {
|
||||
if (Modules.hardpoints[grp][0].damage && Modules.hardpoints[grp][0].type) {
|
||||
if (Modules.hardpoints[grp][0].damage && Modules.hardpoints[grp][0].damagedist) {
|
||||
for (let mId in Modules.hardpoints[grp]) {
|
||||
const m = new Module(Modules.hardpoints[grp][mId]);
|
||||
const classRating = `${m.class}${m.rating}${m.missile ? '/' + m.missile : ''}`;
|
||||
@@ -104,37 +104,35 @@ export default class DamageReceived extends TranslatedComponent {
|
||||
|
||||
// Effective DPS taking in to account shield resistance
|
||||
let effectivenessShields = 0;
|
||||
if (m.getDamageType().indexOf('E') != -1) {
|
||||
effectivenessShields += (1 - ship.shieldExplRes);
|
||||
if (m.getDamageDist().E) {
|
||||
effectivenessShields += m.getDamageDist().E * (1 - ship.shieldExplRes);
|
||||
}
|
||||
if (m.getDamageType().indexOf('K') != -1) {
|
||||
effectivenessShields += (1 - ship.shieldKinRes);
|
||||
if (m.getDamageDist().K) {
|
||||
effectivenessShields += m.getDamageDist().K * (1 - ship.shieldKinRes);
|
||||
}
|
||||
if (m.getDamageType().indexOf('T') != -1) {
|
||||
effectivenessShields += (1 - ship.shieldThermRes);
|
||||
if (m.getDamageDist().T) {
|
||||
effectivenessShields += m.getDamageDist().T * (1 - ship.shieldThermRes);
|
||||
}
|
||||
if (m.getDamageType().indexOf('A') != -1) {
|
||||
effectivenessShields += 1;
|
||||
if (m.getDamageDist().A) {
|
||||
effectivenessShields += m.getDamageDist().A;
|
||||
}
|
||||
effectivenessShields /= m.getDamageType().length;
|
||||
const effectiveDpsShields = baseDps * effectivenessShields;
|
||||
const effectiveSDpsShields = baseSDps * effectivenessShields;
|
||||
|
||||
// Effective DPS taking in to account hull hardness and resistance
|
||||
let effectivenessHull = 0;
|
||||
if (m.getDamageType().indexOf('E') != -1) {
|
||||
effectivenessHull += (1 - ship.hullExplRes);
|
||||
if (m.getDamageDist().E) {
|
||||
effectivenessHull += m.getDamageDist().E * (1 - ship.hullExplRes);
|
||||
}
|
||||
if (m.getDamageType().indexOf('K') != -1) {
|
||||
effectivenessHull += (1 - ship.hullKinRes);
|
||||
if (m.getDamageDist().K) {
|
||||
effectivenessHull += m.getDamageDist().K * (1 - ship.hullKinRes);
|
||||
}
|
||||
if (m.getDamageType().indexOf('T') != -1) {
|
||||
effectivenessHull += (1 - ship.hullThermRes);
|
||||
if (m.getDamageDist().T) {
|
||||
effectivenessHull += m.getDamageDist().T * (1 - ship.hullThermRes);
|
||||
}
|
||||
if (m.getDamageType().indexOf('A') != -1) {
|
||||
effectivenessHull += 1;
|
||||
if (m.getDamageDist().A) {
|
||||
effectivenessHull += m.getDamageDist().A;
|
||||
}
|
||||
effectivenessHull /= m.getDamageType().length;
|
||||
effectivenessHull *= Math.min(m.getPiercing() / ship.hardness, 1);
|
||||
const effectiveDpsHull = baseDps * effectivenessHull;
|
||||
const effectiveSDpsHull = baseSDps * effectivenessHull;
|
||||
|
||||
@@ -41,7 +41,7 @@ export default class HardpointSlot extends Slot {
|
||||
let classRating = `${m.class}${m.rating}${m.missile ? '/' + m.missile : ''}`;
|
||||
let { drag, drop } = this.props;
|
||||
let { termtip, tooltip } = this.context;
|
||||
let validMods = Modifications.validity[m.grp] || [];
|
||||
let validMods = Modifications.modules[m.grp].modifications || [];
|
||||
let showModuleResistances = Persist.showModuleResistances();
|
||||
|
||||
// Modifications tooltip shows blueprint and grade, if available
|
||||
@@ -59,9 +59,9 @@ export default class HardpointSlot extends Slot {
|
||||
{m.mount && m.mount == 'F' ? <span onMouseOver={termtip.bind(null, 'fixed')} onMouseOut={tooltip.bind(null, null)}><MountFixed /></span> : ''}
|
||||
{m.mount && m.mount == 'G' ? <span onMouseOver={termtip.bind(null, 'gimballed')} onMouseOut={tooltip.bind(null, null)}><MountGimballed /></span> : ''}
|
||||
{m.mount && m.mount == 'T' ? <span onMouseOver={termtip.bind(null, 'turreted')} onMouseOut={tooltip.bind(null, null)}><MountTurret /></span> : ''}
|
||||
{m.getDamageType() && m.getDamageType().match('K') ? <span onMouseOver={termtip.bind(null, 'kinetic')} onMouseOut={tooltip.bind(null, null)}><DamageKinetic /></span> : ''}
|
||||
{m.getDamageType() && m.getDamageType().match('T') ? <span onMouseOver={termtip.bind(null, 'thermal')} onMouseOut={tooltip.bind(null, null)}><DamageThermal /></span> : ''}
|
||||
{m.getDamageType() && m.getDamageType().match('E') ? <span onMouseOver={termtip.bind(null, 'explosive')} onMouseOut={tooltip.bind(null, null)}><DamageExplosive /></span> : ''}
|
||||
{m.getDamageDist() && m.getDamageDist().K ? <span onMouseOver={termtip.bind(null, 'kinetic')} onMouseOut={tooltip.bind(null, null)}><DamageKinetic /></span> : ''}
|
||||
{m.getDamageDist() && m.getDamageDist().T ? <span onMouseOver={termtip.bind(null, 'thermal')} onMouseOut={tooltip.bind(null, null)}><DamageThermal /></span> : ''}
|
||||
{m.getDamageDist() && m.getDamageDist().E ? <span onMouseOver={termtip.bind(null, 'explosive')} onMouseOut={tooltip.bind(null, null)}><DamageExplosive /></span> : ''}
|
||||
{classRating} {translate(m.name || m.grp)}{ m.mods && Object.keys(m.mods).length > 0 ? <span className='r' onMouseOver={termtip.bind(null, modTT)} onMouseOut={tooltip.bind(null, null)}><Modified /></span> : null }
|
||||
</div>
|
||||
|
||||
@@ -77,6 +77,7 @@ export default class HardpointSlot extends Slot {
|
||||
{ m.getFalloff() ? <div className={'l'}>{translate('falloff')} {formats.f1(m.getFalloff() / 1000)}{u.km}</div> : null }
|
||||
{ m.getShieldBoost() ? <div className={'l'}>+{formats.pct1(m.getShieldBoost())}</div> : null }
|
||||
{ m.getAmmo() ? <div className={'l'}>{translate('ammunition')}: {formats.int(m.getClip())}/{formats.int(m.getAmmo())}</div> : null }
|
||||
{ m.getShotSpeed() ? <div className={'l'}>{translate('shotspeed')}: {formats.int(m.getShotSpeed())}{u.mps}</div> : null }
|
||||
{ m.getPiercing() ? <div className={'l'}>{translate('piercing')}: {formats.int(m.getPiercing())}</div> : null }
|
||||
{ m.getJitter() ? <div className={'l'}>{translate('jitter')}: {formats.f2(m.getJitter())}°</div> : null }
|
||||
{ showModuleResistances && m.getExplosiveResistance() ? <div className='l'>{translate('explres')}: {formats.pct(m.getExplosiveResistance())}</div> : null }
|
||||
|
||||
@@ -23,7 +23,7 @@ export default class InternalSlot extends Slot {
|
||||
let classRating = m.class + m.rating;
|
||||
let { drag, drop, ship } = this.props;
|
||||
let { termtip, tooltip } = this.context;
|
||||
let validMods = Modifications.validity[m.grp] || [];
|
||||
let validMods = Modifications.modules[m.grp].modifications || [];
|
||||
let showModuleResistances = Persist.showModuleResistances();
|
||||
|
||||
// Modifications tooltip shows blueprint and grade, if available
|
||||
|
||||
@@ -13,6 +13,7 @@ export default class Modification extends TranslatedComponent {
|
||||
ship: React.PropTypes.object.isRequired,
|
||||
m: React.PropTypes.object.isRequired,
|
||||
name: React.PropTypes.string.isRequired,
|
||||
value: React.PropTypes.number.isRequired,
|
||||
onChange: React.PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
@@ -24,7 +25,7 @@ export default class Modification extends TranslatedComponent {
|
||||
constructor(props, context) {
|
||||
super(props);
|
||||
this.state = {};
|
||||
this.state.value = this.props.m.getModValue(this.props.name) / 100 || 0;
|
||||
this.state.value = props.value;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,10 +62,10 @@ export default class Modification extends TranslatedComponent {
|
||||
*/
|
||||
render() {
|
||||
let translate = this.context.language.translate;
|
||||
let name = this.props.name;
|
||||
let { m, name } = this.props;
|
||||
|
||||
if (name === 'type') {
|
||||
// We don't show type
|
||||
if (name === 'damagedist') {
|
||||
// We don't show damage distribution
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React from 'react';
|
||||
import * as _ from 'lodash';
|
||||
import { findDOMNode } from 'react-dom';
|
||||
import TranslatedComponent from './TranslatedComponent';
|
||||
import { stopCtxPropagation } from '../utils/UtilityFunctions';
|
||||
import { isEmpty, stopCtxPropagation } from '../utils/UtilityFunctions';
|
||||
import cn from 'classnames';
|
||||
import { MountFixed, MountGimballed, MountTurret } from './SvgIcons';
|
||||
import { Modifications } from 'coriolis-data/dist';
|
||||
@@ -26,25 +27,178 @@ export default class ModificationsMenu extends TranslatedComponent {
|
||||
constructor(props, context) {
|
||||
super(props);
|
||||
this.state = this._initState(props, context);
|
||||
|
||||
this._toggleBlueprintsMenu = this._toggleBlueprintsMenu.bind(this);
|
||||
this._rollWorst = this._rollWorst.bind(this);
|
||||
this._rollRandom = this._rollRandom.bind(this);
|
||||
this._rollBest = this._rollBest.bind(this);
|
||||
this._reset = this._reset.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate the list of modifications
|
||||
* Initialise state
|
||||
* @param {Object} props React Component properties
|
||||
* @param {Object} context React Component context
|
||||
* @return {Object} list: Array of React Components
|
||||
*/
|
||||
_initState(props, context) {
|
||||
let { m, onChange, ship } = props;
|
||||
let list = [];
|
||||
|
||||
for (let modName of Modifications.validity[m.grp]) {
|
||||
if (Modifications.modifications[modName].type != 'hidden') {
|
||||
list.push(<Modification key={ modName } ship={ ship } m={ m } name={ modName } onChange={ onChange }/>);
|
||||
let blueprints = [];
|
||||
for (const blueprintName in Modifications.modules[m.grp].blueprints) {
|
||||
for (const grade of Modifications.modules[m.grp].blueprints[blueprintName]) {
|
||||
const close = this._blueprintSelected.bind(this, Modifications.blueprints[blueprintName].id, grade);
|
||||
const key = blueprintName + ':' + grade;
|
||||
blueprints.push(<div style={{ cursor: 'pointer' }} key={ key } onClick={ close }>{Modifications.blueprints[blueprintName].name} grade {grade}</div>);
|
||||
}
|
||||
}
|
||||
|
||||
return { list };
|
||||
// Set up the modifications
|
||||
const modifications = this._setModifications(props);
|
||||
|
||||
const blueprintMenuOpened = false;
|
||||
|
||||
// Set up the specials for this module
|
||||
// const specials = _selectSpecials(m);
|
||||
|
||||
return { blueprintMenuOpened, blueprints, modifications };
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the modifications
|
||||
* @param {Object} props React Component properties
|
||||
* @return {Object} list: Array of React Components
|
||||
*/
|
||||
_setModifications(props) {
|
||||
const { m, onChange, ship } = props;
|
||||
let modifications = [];
|
||||
for (const modName of Modifications.modules[m.grp].modifications) {
|
||||
if (Modifications.modifications[modName].type === 'percentage' || Modifications.modifications[modName].type === 'numeric') {
|
||||
const key = modName + (m.getModValue(modName) / 100 || 0);
|
||||
modifications.push(<Modification key={ key } ship={ ship } m={ m } name={ modName } value={ m.getModValue(modName) / 100 || 0 } onChange={ onChange }/>);
|
||||
}
|
||||
}
|
||||
return modifications;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the blueprints menu
|
||||
*/
|
||||
_toggleBlueprintsMenu() {
|
||||
const blueprintMenuOpened = !this.state.blueprintMenuOpened;
|
||||
this.setState({ blueprintMenuOpened });
|
||||
}
|
||||
|
||||
/**
|
||||
* Activated when a blueprint is selected
|
||||
* @param {int} blueprintId The ID of the selected blueprint
|
||||
* @param {int} grade The grade of the selected blueprint
|
||||
*/
|
||||
_blueprintSelected(blueprintId, grade) {
|
||||
const { m } = this.props;
|
||||
const blueprint = Object.assign({}, _.find(Modifications.blueprints, function(o) { return o.id === blueprintId; }));
|
||||
blueprint.grade = grade;
|
||||
m.blueprint = blueprint;
|
||||
|
||||
const blueprintMenuOpened = false;
|
||||
this.setState({ blueprintMenuOpened });
|
||||
this.props.onChange();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a 'worst' roll within the information we have
|
||||
*/
|
||||
_rollWorst() {
|
||||
const { m, ship } = this.props;
|
||||
const features = m.blueprint.features[m.blueprint.grade];
|
||||
for (const featureName in features) {
|
||||
if (Modifications.modifications[featureName].method == 'overwrite') {
|
||||
ship.setModification(m, featureName, features[featureName][1]);
|
||||
} else {
|
||||
let value = features[featureName][0];
|
||||
if (m.grp == 'sb' && featureName == 'shieldboost') {
|
||||
// Shield boosters are a special case. Their boost is dependent on their base so we need to calculate the value here
|
||||
value = ((1 + m.shieldboost) * (1 + value) - 1) / m.shieldboost - 1;
|
||||
}
|
||||
|
||||
if (Modifications.modifications[featureName].type == 'percentage') {
|
||||
ship.setModification(m, featureName, value * 10000);
|
||||
} else if (Modifications.modifications[featureName].type == 'numeric') {
|
||||
ship.setModification(m, featureName, value * 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({ modifications: this._setModifications(this.props) });
|
||||
this.props.onChange();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a random roll within the information we have
|
||||
*/
|
||||
_rollRandom() {
|
||||
const { m, ship } = this.props;
|
||||
const features = m.blueprint.features[m.blueprint.grade];
|
||||
for (const featureName in features) {
|
||||
if (Modifications.modifications[featureName].method == 'overwrite') {
|
||||
ship.setModification(m, featureName, features[featureName][1]);
|
||||
} else {
|
||||
let value = features[featureName][0] + (Math.random() * (features[featureName][1] - features[featureName][0]));
|
||||
if (m.grp == 'sb' && featureName == 'shieldboost') {
|
||||
// Shield boosters are a special case. Their boost is dependent on their base so we need to calculate the value here
|
||||
value = ((1 + m.shieldboost) * (1 + value) - 1) / m.shieldboost - 1;
|
||||
}
|
||||
|
||||
if (Modifications.modifications[featureName].type == 'percentage') {
|
||||
ship.setModification(m, featureName, value * 10000);
|
||||
} else if (Modifications.modifications[featureName].type == 'numeric') {
|
||||
ship.setModification(m, featureName, value * 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({ modifications: this._setModifications(this.props) });
|
||||
this.props.onChange();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a 'best' roll within the information we have
|
||||
*/
|
||||
_rollBest() {
|
||||
const { m, ship } = this.props;
|
||||
const features = m.blueprint.features[m.blueprint.grade];
|
||||
for (const featureName in features) {
|
||||
if (Modifications.modifications[featureName].method == 'overwrite') {
|
||||
ship.setModification(m, featureName, features[featureName][1]);
|
||||
} else {
|
||||
let value = features[featureName][1];
|
||||
if (m.grp == 'sb' && featureName == 'shieldboost') {
|
||||
// Shield boosters are a special case. Their boost is dependent on their base so we need to calculate the value here
|
||||
value = ((1 + m.shieldboost) * (1 + value) - 1) / m.shieldboost - 1;
|
||||
}
|
||||
|
||||
if (Modifications.modifications[featureName].type == 'percentage') {
|
||||
ship.setModification(m, featureName, value * 10000);
|
||||
} else if (Modifications.modifications[featureName].type == 'numeric') {
|
||||
ship.setModification(m, featureName, value * 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({ modifications: this._setModifications(this.props) });
|
||||
this.props.onChange();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset modification information
|
||||
*/
|
||||
_reset() {
|
||||
const { m, ship } = this.props;
|
||||
ship.clearModifications(m);
|
||||
ship.clearBlueprint(m);
|
||||
|
||||
this.setState({ modifications: this._setModifications(this.props) });
|
||||
this.props.onChange();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,15 +206,51 @@ export default class ModificationsMenu extends TranslatedComponent {
|
||||
* @return {React.Component} List
|
||||
*/
|
||||
render() {
|
||||
let { tooltip, termtip } = this.context;
|
||||
const language = this.context.language;
|
||||
const translate = language.translate;
|
||||
const { tooltip, termtip } = this.context;
|
||||
const { m } = this.props;
|
||||
const { blueprintMenuOpened } = this.state;
|
||||
|
||||
const _toggleBlueprintsMenu = this._toggleBlueprintsMenu;
|
||||
const _rollBest = this._rollBest;
|
||||
const _rollWorst = this._rollWorst;
|
||||
const _rollRandom = this._rollRandom;
|
||||
const _reset = this._reset;
|
||||
|
||||
let blueprintLabel;
|
||||
let haveBlueprint = false;
|
||||
if (m.blueprint && !isEmpty(m.blueprint)) {
|
||||
blueprintLabel = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade;
|
||||
haveBlueprint = true;
|
||||
} else {
|
||||
blueprintLabel = translate('PHRASE_SELECT_BLUEPRINT');
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn('select', this.props.className)}
|
||||
onClick={(e) => e.stopPropagation() }
|
||||
onContextMenu={stopCtxPropagation}
|
||||
onMouseOver={termtip.bind(null, 'HELP_MODIFICATIONS_MENU')} onMouseOut={tooltip.bind(null, null)}
|
||||
>
|
||||
{this.state.list}
|
||||
<div className={ cn('section-menu', { selected: true })} style={{ cursor: 'pointer' }} onClick={_toggleBlueprintsMenu}>{blueprintLabel}</div>
|
||||
{ blueprintMenuOpened ? this.state.blueprints : '' }
|
||||
{ haveBlueprint ?
|
||||
<table style={{ width: '100%', backgroundColor: 'transparent' }}>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td> { translate('roll') }: </td>
|
||||
<td style={{ cursor: 'pointer' }} onClick={_rollWorst} onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_WORST')} onMouseOut={tooltip.bind(null, null)}> { translate('worst') } </td>
|
||||
<td style={{ cursor: 'pointer' }} onClick={_rollRandom} onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_RANDOM')} onMouseOut={tooltip.bind(null, null)}> { translate('random') } </td>
|
||||
<td style={{ cursor: 'pointer' }} onClick={_rollBest}onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_BEST')} onMouseOut={tooltip.bind(null, null)}> { translate('best') } </td>
|
||||
<td style={{ cursor: 'pointer' }} onClick={_reset}onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_RESET')} onMouseOut={tooltip.bind(null, null)}> { translate('reset') } </td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table> : '' }
|
||||
{ blueprintMenuOpened ? '' :
|
||||
<span onMouseOver={termtip.bind(null, 'HELP_MODIFICATIONS_MENU')} onMouseOut={tooltip.bind(null, null)} >
|
||||
{ this.state.modifications }
|
||||
</span> }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ export default class StandardSlot extends TranslatedComponent {
|
||||
let m = slot.m;
|
||||
let classRating = m.class + m.rating;
|
||||
let menu;
|
||||
let validMods = m == null ? [] : (Modifications.validity[m.grp] || []);
|
||||
let validMods = m == null ? [] : (Modifications.modules[m.grp].modifications || []);
|
||||
let showModuleResistances = Persist.showModuleResistances();
|
||||
let mass = m.getMass() || m.cargo || m.fuel || 0;
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ export function getLanguage(langCode) {
|
||||
'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)
|
||||
mps: <u>{translate('m/s')}</u>, // Metres per second
|
||||
ps: <u>{translate('/s')}</u>, // per second
|
||||
pm: <u>{translate('/min')}</u>, // per minute
|
||||
s: <u>{translate('secs')}</u>, // Seconds
|
||||
|
||||
@@ -29,6 +29,11 @@ export const terms = {
|
||||
PHRASE_UNLADEN: 'Ship mass excluding fuel and cargo',
|
||||
PHRASE_UPDATE_RDY: 'Update Available! Click to refresh',
|
||||
PHRASE_ENGAGEMENT_RANGE: 'The distance between your ship and its target',
|
||||
PHRASE_SELECT_BLUEPRINT: 'Click to select a blueprint',
|
||||
PHRASE_BLUEPRINT_WORST: 'Worst primary values for this blueprint',
|
||||
PHRASE_BLUEPRINT_RANDOM: 'Random selection between worst and best primary values for this blueprint',
|
||||
PHRASE_BLUEPRINT_BEST: 'Best primary values for this blueprint',
|
||||
PHRASE_BLUEPRINT_RESET: 'Remove all modifications and blueprint',
|
||||
|
||||
HELP_MODIFICATIONS_MENU: 'Click on a number to enter a new value, or drag along the bar for small changes',
|
||||
|
||||
@@ -102,6 +107,12 @@ export const terms = {
|
||||
|
||||
rebuildsperbay: 'Rebuilds per bay',
|
||||
|
||||
// Blueprint rolls
|
||||
worst: 'Worst',
|
||||
random: 'Random',
|
||||
best: 'Best',
|
||||
reset: 'Reset',
|
||||
|
||||
// Weapon, offence, defence and movement
|
||||
dpe: 'Damage per MJ of energy',
|
||||
dps: 'Damage per second',
|
||||
@@ -163,6 +174,7 @@ export const terms = {
|
||||
shield: 'Shield',
|
||||
shieldboost: 'Shield boost',
|
||||
shieldreinforcement: 'Shield reinforcement',
|
||||
shotspeed: 'Shot speed',
|
||||
spinup: 'Spin up time',
|
||||
syscap: 'Systems capacity',
|
||||
sysrate: 'Systems recharge rate',
|
||||
|
||||
@@ -33,6 +33,7 @@ export const ModuleGroupToName = {
|
||||
fi: 'Frame Shift Drive Interdictor',
|
||||
hb: 'Hatch Breaker Limpet Controller',
|
||||
hr: 'Hull Reinforcement Package',
|
||||
mrp: 'Module Reinforcement Package',
|
||||
rf: 'Refinery',
|
||||
scb: 'Shield Cell Bank',
|
||||
sg: 'Shield Generator',
|
||||
|
||||
@@ -650,10 +650,18 @@ export default class Module {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the damage type for this module, taking in to account modifications
|
||||
* @return {string} the damage types for this module; any combination of E T and K
|
||||
* Get the damage distribution for this module, taking in to account modifications
|
||||
* @return {string} the damage distribution for this module
|
||||
*/
|
||||
getDamageType() {
|
||||
return this.getModValue('type') || this.type;
|
||||
getDamageDist() {
|
||||
return this.getModValue('damagedist') || this.damagedist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the shot speed for this module, taking in to account modifications
|
||||
* @return {string} the damage distribution for this module
|
||||
*/
|
||||
getShotSpeed() {
|
||||
return this._getModifiedValue('shotspeed');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -411,6 +411,32 @@ export default class Ship {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all modification values for a module
|
||||
* @param {Number} m The module for which to clear the modifications
|
||||
*/
|
||||
clearModifications(m) {
|
||||
m.mods = {};
|
||||
this.updatePowerGenerated()
|
||||
.updatePowerUsed()
|
||||
.updateJumpStats()
|
||||
.recalculateShield()
|
||||
.recalculateShieldCells()
|
||||
.recalculateArmour()
|
||||
.recalculateDps()
|
||||
.recalculateEps()
|
||||
.recalculateHps()
|
||||
.updateMovement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear blueprint for a module
|
||||
* @param {Number} m The module for which to clear the modifications
|
||||
*/
|
||||
clearBlueprint(m) {
|
||||
m.blueprint = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a modification value
|
||||
* @param {Object} m The module to change
|
||||
@@ -954,20 +980,22 @@ export default class Ship {
|
||||
totalDpe += dpe;
|
||||
totalDps += dps;
|
||||
totalSDps += sdps;
|
||||
if (slot.m.getDamageType().indexOf('E') != -1) {
|
||||
totalExplDpe += dpe / slot.m.getDamageType().length;
|
||||
totalExplDps += dps / slot.m.getDamageType().length;
|
||||
totalExplSDps += sdps / slot.m.getDamageType().length;
|
||||
}
|
||||
if (slot.m.getDamageType().indexOf('K') != -1) {
|
||||
totalKinDpe += dpe / slot.m.getDamageType().length;
|
||||
totalKinDps += dps / slot.m.getDamageType().length;
|
||||
totalKinSDps += sdps / slot.m.getDamageType().length;
|
||||
}
|
||||
if (slot.m.getDamageType().indexOf('T') != -1) {
|
||||
totalThermDpe += dpe / slot.m.getDamageType().length;
|
||||
totalThermDps += dps / slot.m.getDamageType().length;
|
||||
totalThermSDps += sdps / slot.m.getDamageType().length;
|
||||
if (slot.m.getDamageDist()) {
|
||||
if (slot.m.getDamageDist().E) {
|
||||
totalExplDpe += dpe * slot.m.getDamageDist().E;
|
||||
totalExplDps += dps * slot.m.getDamageDist().E;
|
||||
totalExplSDps += sdps * slot.m.getDamageDist().E;
|
||||
}
|
||||
if (slot.m.getDamageDist().K) {
|
||||
totalKinDpe += dpe * slot.m.getDamageDist().K;
|
||||
totalKinDps += dps * slot.m.getDamageDist().K;
|
||||
totalKinSDps += sdps * slot.m.getDamageDist().K;
|
||||
}
|
||||
if (slot.m.getDamageDist().T) {
|
||||
totalThermDpe += dpe * slot.m.getDamageDist().T;
|
||||
totalThermDps += dps * slot.m.getDamageDist().T;
|
||||
totalThermSDps += sdps * slot.m.getDamageDist().T;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1333,7 +1361,7 @@ export default class Ship {
|
||||
if (this.bulkheads.m && this.bulkheads.m.mods) {
|
||||
for (let modKey in this.bulkheads.m.mods) {
|
||||
// Filter out invalid modifications
|
||||
if (Modifications.validity['bh'] && Modifications.validity['bh'].indexOf(modKey) != -1) {
|
||||
if (Modifications.modules['bh'] && Modifications.modules['bh'].modifications.indexOf(modKey) != -1) {
|
||||
bulkheadMods.push({ id: Modifications.modifications[modKey].id, value: this.bulkheads.m.getModValue(modKey) });
|
||||
}
|
||||
}
|
||||
@@ -1348,7 +1376,7 @@ export default class Ship {
|
||||
if (slot.m && slot.m.mods) {
|
||||
for (let modKey in slot.m.mods) {
|
||||
// Filter out invalid modifications
|
||||
if (Modifications.validity[slot.m.grp] && Modifications.validity[slot.m.grp].indexOf(modKey) != -1) {
|
||||
if (Modifications.modules[slot.m.grp] && Modifications.modules[slot.m.grp].modifications.indexOf(modKey) != -1) {
|
||||
slotMods.push({ id: Modifications.modifications[modKey].id, value: slot.m.getModValue(modKey) });
|
||||
}
|
||||
}
|
||||
@@ -1363,7 +1391,7 @@ export default class Ship {
|
||||
if (slot.m && slot.m.mods) {
|
||||
for (let modKey in slot.m.mods) {
|
||||
// Filter out invalid modifications
|
||||
if (Modifications.validity[slot.m.grp] && Modifications.validity[slot.m.grp].indexOf(modKey) != -1) {
|
||||
if (Modifications.modules[slot.m.grp] && Modifications.modules[slot.m.grp].modifications.indexOf(modKey) != -1) {
|
||||
slotMods.push({ id: Modifications.modifications[modKey].id, value: slot.m.getModValue(modKey) });
|
||||
}
|
||||
}
|
||||
@@ -1378,7 +1406,7 @@ export default class Ship {
|
||||
if (slot.m && slot.m.mods) {
|
||||
for (let modKey in slot.m.mods) {
|
||||
// Filter out invalid modifications
|
||||
if (Modifications.validity[slot.m.grp] && Modifications.validity[slot.m.grp].indexOf(modKey) != -1) {
|
||||
if (Modifications.modules[slot.m.grp] && Modifications.modules[slot.m.grp].modifications.indexOf(modKey) != -1) {
|
||||
slotMods.push({ id: Modifications.modifications[modKey].id, value: slot.m.getModValue(modKey) });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ export function diffDetails(language, m, mm) {
|
||||
|
||||
let mPowerGeneration = m.pgen || 0;
|
||||
let mmPowerGeneration = mm ? mm.getPowerGeneration() : 0;
|
||||
if (mPowerGeneration != mmPowerGeneration) propDiffs.push(<div key='pgen'>{translate('pgen')}: <span className={diffClass(mPowerGeneration, mmPowerGeneration, true)}>{diff(formats.round, mPowerGeneration, mmPowerGeneration)}{units.MJ}</span></div>);
|
||||
if (mPowerGeneration != mmPowerGeneration) propDiffs.push(<div key='pgen'>{translate('pgen')}: <span className={diffClass(mPowerGeneration, mmPowerGeneration)}>{diff(formats.round, mPowerGeneration, mmPowerGeneration)}{units.MJ}</span></div>);
|
||||
|
||||
let mPowerUsage = m.power || 0;
|
||||
let mmPowerUsage = mm ? mm.getPowerUsage() : 0;
|
||||
|
||||
@@ -71,3 +71,15 @@ export function shallowEqual(objA, objB) {
|
||||
export function fromUrlSafe(data) {
|
||||
return data ? data.replace(/-/g, '/').replace(/_/g, '+') : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an object is empty
|
||||
* @param {object} obj the object
|
||||
* @return {bool} true if the object is empty, otherwise false
|
||||
*/
|
||||
export function isEmpty(obj) {
|
||||
for (let key in obj) {
|
||||
if (obj.hasOwnProperty(key)) return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user