Compare commits

...

30 Commits
23 ... 2.3.4

Author SHA1 Message Date
Cmdr McDonald
1fbba6a5f3 Merge branch 'release/2.3.4' 2017-05-03 17:12:13 +01:00
Cmdr McDonald
d1c0b635b3 Package bump 2017-05-03 17:12:07 +01:00
Cmdr McDonald
060cf75ec4 Handle different specials for dumbfire and seeker missiles 2017-05-03 12:37:49 +01:00
Cmdr McDonald
62e3b70581 Merge branch 'feature/edge' into develop 2017-04-28 07:20:23 -04:00
Cmdr McDonald
4accb901af Bump zlib 2017-04-26 07:58:05 -04:00
Cmdr McDonald
82725e1c5a Fixes 2017-04-25 12:10:44 +01:00
Cmdr McDonald
4dc8ab928c Remove findDOMNode as per warning 2017-04-23 18:50:13 +01:00
Cmdr McDonald
7db76ecba0 Lint fixes 2017-04-23 18:36:20 +01:00
Cmdr McDonald
16a5b2a72a Version bumps 2017-04-23 16:26:16 +01:00
Cmdr McDonald
59a5ba0227 Updaes 2017-04-23 16:06:14 +01:00
Cmdr McDonald
c130b52b7c Fix incorrect height of shipyard ship header 2017-04-21 22:39:07 +01:00
Cmdr McDonald
03f32097e9 Merge branch 'feature/ordering' into develop 2017-04-21 21:38:48 +01:00
Cmdr McDonald
8660dcbd2b Tidy up ordering 2017-04-21 21:38:42 +01:00
Cmdr McDonald
95f358f9d8 Upgrade to React 15.5 2017-04-21 16:07:41 +01:00
Cmdr McDonald
8f944bc4c8 Add racer role 2017-04-21 10:43:39 +01:00
Cmdr McDonald
e9cbe0d952 Bump package version 2017-04-20 15:11:59 +01:00
Cmdr McDonald
684ecfcafd Ensure that stock builds are saved with a code; ignore builds without codes in comparisons 2017-04-20 15:10:03 +01:00
Cmdr McDonald
1516bd4fc0 Fix crash when clearing a speical 2017-04-20 13:17:30 +01:00
Cmdr McDonald
4ea0bbfb93 Merge branch 'release/2.3.3' into develop 2017-04-15 20:46:50 +01:00
Cmdr McDonald
9b6df8ea4f Merge branch 'release/2.3.3' 2017-04-15 20:46:45 +01:00
Cmdr McDonald
9c6f5fb44e Bump version 2017-04-15 20:46:40 +01:00
Cmdr McDonald
c0a732a76b Merge branch 'feature/refit' into develop 2017-04-15 18:11:56 +01:00
Cmdr McDonald
9551b8b5de Add shopping list for refit 2017-04-15 18:11:50 +01:00
Cmdr McDonald
22f83b79af Encode blueprint information event when no active modifications 2017-04-15 18:11:09 +01:00
Cmdr McDonald
0a26f76fb4 Merge branch 'release/2.3.2' into develop 2017-04-14 13:09:55 +01:00
Cmdr McDonald
077f432daf Merge branch 'release/2.3.2' 2017-04-14 13:09:52 +01:00
Cmdr McDonald
e846b4508b Bump version 2017-04-14 11:06:09 +01:00
Cmdr McDonald
3be78885b8 Bump 2017-04-14 10:58:15 +01:00
Cmdr McDonald
e29a4b263d Fix scan time/scan rate confusion 2017-04-13 23:19:27 +01:00
Cmdr McDonald
061ab77de1 Merge branch 'release/23' into develop 2017-04-13 22:26:33 +01:00
64 changed files with 2338 additions and 5260 deletions

View File

@@ -1,3 +1,32 @@
#2.3.4
* Fix crash when removing the special effect from a module
* Ensure comparisons with saved stock ships work correctly
* Add 'Racer' role
* Tidy up shipyard page; remove units from data columns and re-order for legibility
* Allow basic drag/drop functionality in Edge/Internet Explorer 11 browser
* Provide separate special effects for dumbfire and seeker missiles
* Include special effect modifiers in blueprint tooltip
* Use coriolis-data 2.3.4:
* Add missing Long Range blueprint to multi-cannon
* Fix values for thermal load of focused weapon grade 4
* Fix internal module information for power plant blueprints
* Add 'FSD Interrupt' special to dumbfire missile racks; this module now has `specials_S` and `specials_D` keys for specials to differentiate
#2.3.3
* Remove unused blueprint when hitting reset
* Add 'purchase module' external link to EDDB for refit items
* Use coriolis-data 2.3.3:
* Add Felicity Farseer to list of engineers that supply sensor and detailed surface scanner modifications
#2.3.2
* Use scan range for DSS rather than scan time
* Fix companion API import of Dolphin
* Use coriolis-data 2.3.2:
* Separate scan time and scan range
* Add Frontier IDs for new items in 2.3
* Update ownership of module blueprints for sensors and scanners
* Update railgun penetration
#2.3.0
* Make scan time visible on scanners where available
* Update power distributor able-to-boost calculation to take fractional MJ values in to account

View File

@@ -0,0 +1,225 @@
{
"free": false,
"id": 2,
"modules": {
"Armour": {
"module": {
"free": false,
"id": 128049280,
"name": "CobraMkIII_Armour_Grade1",
"on": true,
"priority": 1,
"value": 0
}
},
"FrameShiftDrive": {
"module": {
"free": false,
"id": 128064117,
"name": "Int_Hyperdrive_Size4_Class5",
"on": true,
"priority": 4,
"value": 1610080
}
},
"FuelTank": {
"module": {
"free": false,
"id": 128064349,
"name": "Int_FuelTank_Size4_Class3",
"on": true,
"priority": 1,
"value": 24734
}
},
"LifeSupport": {
"module": {
"free": false,
"id": 128064149,
"name": "Int_LifeSupport_Size3_Class2",
"on": true,
"priority": 0,
"value": 10133
}
},
"MainEngines": {
"module": {
"free": false,
"id": 128064079,
"name": "Int_Engine_Size4_Class2",
"on": true,
"priority": 0,
"value": 59633
}
},
"PaintJob": {
"module": {
"free": false,
"id": 128741033,
"name": "PaintJob_CobraMKIII_Corrosive_05",
"on": true,
"priority": 1,
"value": 0
}
},
"PlanetaryApproachSuite": {
"module": {
"free": false,
"id": 128672317,
"name": "Int_PlanetApproachSuite",
"on": true,
"priority": 1,
"value": 500
}
},
"PowerDistributor": {
"module": {
"free": false,
"id": 128064179,
"name": "Int_PowerDistributor_Size1_Class2",
"on": true,
"priority": 2,
"value": 1293
}
},
"PowerPlant": {
"module": {
"free": false,
"id": 128064037,
"name": "Int_Powerplant_Size2_Class5",
"on": true,
"priority": 1,
"value": 160224
}
},
"Radar": {
"module": {
"free": false,
"id": 128064229,
"name": "Int_Sensors_Size3_Class2",
"on": true,
"priority": 0,
"value": 10133
}
},
"ShipID0": {
"module": {
"free": false,
"id": 128758976,
"name": "Nameplate_ShipID_Black",
"on": true,
"priority": 1,
"value": 0
}
},
"ShipID1": {
"module": {
"free": false,
"id": 128758976,
"name": "Nameplate_ShipID_Black",
"on": true,
"priority": 1,
"value": 0
}
},
"ShipKitBumper": {
"module": {
"free": false,
"id": 128740698,
"name": "CobraMkIII_ShipkitRaider1_Bumper1",
"on": true,
"priority": 1,
"value": 0
}
},
"ShipKitSpoiler": {
"module": {
"free": false,
"id": 128740701,
"name": "CobraMkIII_ShipkitRaider1_Spoiler1",
"on": true,
"priority": 1,
"value": 0
}
},
"ShipKitTail": {
"module": {
"free": false,
"id": 128740705,
"name": "CobraMkIII_ShipkitRaider1_Tail2",
"on": true,
"priority": 1,
"value": 0
}
},
"ShipKitWings": {
"module": {
"free": false,
"id": 128740707,
"name": "CobraMkIII_ShipkitRaider1_Wings1",
"on": true,
"priority": 1,
"value": 0
}
},
"ShipName0": {
"module": {
"free": false,
"id": 128758944,
"name": "Nameplate_Explorer01_Black",
"on": true,
"priority": 1,
"value": 0
}
},
"ShipName1": {
"module": {
"free": false,
"id": 128758944,
"name": "Nameplate_Explorer01_Black",
"on": true,
"priority": 1,
"value": 0
}
},
"Slot01_Size4": {
"module": {
"free": false,
"id": 128666663,
"name": "Int_FuelScoop_Size4_Class3",
"on": true,
"priority": 2,
"value": 178898
}
},
"Slot02_Size4": [],
"Slot03_Size4": [],
"Slot04_Size2": [],
"Slot05_Size2": {
"module": {
"free": false,
"id": 128663561,
"name": "Int_StellarBodyDiscoveryScanner_Advanced",
"on": true,
"priority": 2,
"value": 1545000
}
},
"Slot06_Size2": {
"module": {
"free": false,
"id": 128666634,
"name": "Int_DetailedSurfaceScanner_Tiny",
"on": true,
"priority": 2,
"value": 250000
}
}
},
"name": "CobraMkIII",
"value": {
"hull": 205287,
"modules": 3850628,
"unloaned": 1751109
}
}

View File

@@ -1,8 +1,10 @@
jest.dontMock('../src/app/stores/Persist');
jest.dontMock('../src/app/components/TranslatedComponent');
jest.dontMock('../src/app/components/ModalImport');
jest.unmock('../src/app/stores/Persist');
jest.unmock('../src/app/components/TranslatedComponent');
jest.unmock('../src/app/components/ModalImport');
jest.unmock('prop-types');
import React from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import TU from 'react-testutils-additions';
import Utils from './testUtils';
@@ -264,6 +266,18 @@ describe('Import Modal', function() {
expect(MockRouter.go.mock.calls.length).toBe(1);
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/type_7_transport?code=A0patfFflidasdf5----0404040005050504044d2402.AwRj4yrI.CwRgDBlVK7EiA%3D%3D%3D.&bn=Imported%20Type-7%20Transporter');
});
it('imports a valid companion API build', function() {
const importData = require('./fixtures/companion-api-import-4');
pasteText(JSON.stringify(importData));
expect(modal.state.importValid).toBeTruthy();
expect(modal.state.errorMsg).toEqual(null);
expect(modal.state.singleBuild).toBe(true);
clickProceed();
expect(MockRouter.go.mock.calls.length).toBe(1);
expect(MockRouter.go.mock.calls[0][0]).toBe('outfit/cobra_mk_iii?code=A0p0tdFaldd3sdf4------34---2f2i.AwRj4yKA.CwRgDMYExre1Rcg%3D..EweloBhBGA2EoFMCGBzANokMK6A%3D');
});
});
describe('Import E:D Shipyard Builds', function() {

View File

@@ -1,4 +1,4 @@
jest.dontMock('../src/app/stores/Persist');
jest.unmock('../src/app/stores/Persist');
import React from 'react';
import ReactDOM from 'react-dom';

View File

@@ -1,11 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
const TestUtils = {
createContextProvider: function(context) {
var _contextTypes = {};
Object.keys(context).forEach(function(key) {
_contextTypes[key] = React.PropTypes.any;
_contextTypes[key] = PropTypes.any;
});
return React.createClass({
@@ -21,4 +22,4 @@ const TestUtils = {
};
export default TestUtils;
export default TestUtils;

5877
d3.js vendored

File diff suppressed because it is too large Load Diff

7
d3.min.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
{
"name": "coriolis_shipyard",
"version": "2.3.0",
"version": "2.3.4",
"repository": {
"type": "git",
"url": "https://github.com/EDCD/coriolis"
@@ -24,7 +24,7 @@
"deploy": "npm run lint && npm test && npm run build && npm run rsync"
},
"jest": {
"scriptPreprocessor": "<rootDir>/node_modules/babel-jest",
"transform": {".*": "<rootDir>/node_modules/babel-jest"},
"testRegex": "(/__tests__/test-.*|\\.(test|spec))\\.js$",
"moduleFileExtensions": [
"js",
@@ -37,7 +37,6 @@
"<rootDir>/node_modules/lodash",
"<rootDir>/node_modules/react",
"<rootDir>/node_modules/react-dom",
"<rootDir>/node_modules/react-addons-test-utils",
"<rootDir>/node_modules/react-testutils-additions",
"<rootDir>/node_modules/fbjs",
"<rootDir>/node_modules/fbemitter",
@@ -62,45 +61,46 @@
"babel-preset-es2015": "*",
"babel-preset-react": "*",
"babel-preset-stage-0": "*",
"css-loader": "^0.23.0",
"css-loader": "^0.28.0",
"d3-selection": "1",
"eslint": "2.2.0",
"eslint-plugin-react": "^4.0.0",
"expose-loader": "^0.7.1",
"express": "^4.13.3",
"extract-text-webpack-plugin": "2.0.0",
"file-loader": "^0.8.4",
"eslint": "3.19.0",
"eslint-plugin-react": "^6.10.3",
"expose-loader": "^0.7.3",
"express": "^4.15.2",
"extract-text-webpack-plugin": "2.1.0",
"file-loader": "^0.11.1",
"html-webpack-plugin": "^2.28.0",
"jest-cli": "^16.0.1",
"jsen": "^0.6.0",
"json-loader": "^0.5.3",
"less": "^2.5.3",
"less-loader": "^2.2.1",
"jest-cli": "^19.0.2",
"jsen": "^0.6.4",
"json-loader": "^0.5.4",
"less": "^2.7.2",
"less-loader": "^4.0.3",
"react-addons-perf": "^15.4.2",
"react-addons-test-utils": "^15.0.1",
"react-measure": "^1.4.6",
"react-testutils-additions": "^15.1.0",
"rimraf": "^2.4.3",
"rollup": "0.36",
"rollup-plugin-node-resolve": "2",
"style-loader": "^0.13.0",
"url-loader": "^0.5.6",
"webpack": "^2.2.1",
"webpack-dev-server": "^2.4.1"
"react-measure": "^1.4.7",
"react-testutils-additions": "^15.2.0",
"rimraf": "^2.6.1",
"rollup": "0.41",
"rollup-plugin-node-resolve": "3",
"style-loader": "^0.16.1",
"url-loader": "^0.5.8",
"webpack": "^2.4.1",
"webpack-dev-server": "^2.4.4"
},
"dependencies": {
"babel-polyfill": "*",
"browserify-zlib": "ipfs/browserify-zlib",
"classnames": "^2.2.0",
"browserify-zlib-next": "^1.0.1",
"classnames": "^2.2.5",
"coriolis-data": "EDCD/coriolis-data",
"d3": "4.6.0",
"fbemitter": "^2.0.0",
"lodash": "^4.15.0",
"d3": "4.8.0",
"detect-browser": "^1.7.0",
"fbemitter": "^2.1.1",
"lodash": "^4.17.4",
"lz-string": "^1.4.4",
"react": "^15.0.1",
"react-dom": "^15.0.1",
"prop-types": "^15.5.8",
"react": "^15.5.4",
"react-dom": "^15.5.4",
"react-number-editor": "Athanasius/react-number-editor.git#miggy",
"recharts": "^0.21.2",
"superagent": "^1.4.0"
"recharts": "^0.22.3",
"superagent": "^3.5.2"
}
}

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import Router from './Router';
import { EventEmitter } from 'fbemitter';
import { getLanguage } from './i18n/Language';
@@ -27,18 +28,18 @@ const zlib = require('zlib');
export default class Coriolis extends React.Component {
static childContextTypes = {
closeMenu: React.PropTypes.func.isRequired,
hideModal: React.PropTypes.func.isRequired,
language: React.PropTypes.object.isRequired,
noTouch: React.PropTypes.bool.isRequired,
onCommand: React.PropTypes.func.isRequired,
onWindowResize: React.PropTypes.func.isRequired,
openMenu: React.PropTypes.func.isRequired,
route: React.PropTypes.object.isRequired,
showModal: React.PropTypes.func.isRequired,
sizeRatio: React.PropTypes.number.isRequired,
termtip: React.PropTypes.func.isRequired,
tooltip: React.PropTypes.func.isRequired
closeMenu: PropTypes.func.isRequired,
hideModal: PropTypes.func.isRequired,
language: PropTypes.object.isRequired,
noTouch: PropTypes.bool.isRequired,
onCommand: PropTypes.func.isRequired,
onWindowResize: PropTypes.func.isRequired,
openMenu: PropTypes.func.isRequired,
route: PropTypes.object.isRequired,
showModal: PropTypes.func.isRequired,
sizeRatio: PropTypes.number.isRequired,
termtip: PropTypes.func.isRequired,
tooltip: PropTypes.func.isRequired
};
/**

View File

@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import * as ModuleUtils from '../shipyard/ModuleUtils';
import { findDOMNode } from 'react-dom';
import TranslatedComponent from './TranslatedComponent';
import { stopCtxPropagation } from '../utils/UtilityFunctions';
import cn from 'classnames';
@@ -83,12 +83,12 @@ const CATEGORIES = {
export default class AvailableModulesMenu extends TranslatedComponent {
static propTypes = {
modules: React.PropTypes.oneOfType([React.PropTypes.object, React.PropTypes.array]).isRequired,
onSelect: React.PropTypes.func.isRequired,
diffDetails: React.PropTypes.func,
m: React.PropTypes.object,
shipMass: React.PropTypes.number,
warning: React.PropTypes.func
modules: PropTypes.oneOfType([PropTypes.object, PropTypes.array]).isRequired,
onSelect: PropTypes.func.isRequired,
diffDetails: PropTypes.func,
m: PropTypes.object,
shipMass: PropTypes.number,
warning: PropTypes.func
};
static defaultProps = {
@@ -373,7 +373,7 @@ export default class AvailableModulesMenu extends TranslatedComponent {
*/
componentDidMount() {
if (this.groupElem) { // Scroll to currently selected group
findDOMNode(this).scrollTop = this.groupElem.offsetTop;
this.node.scrollTop = this.groupElem.offsetTop;
}
}
@@ -392,7 +392,7 @@ export default class AvailableModulesMenu extends TranslatedComponent {
*/
render() {
return (
<div
<div ref={node => this.node = node}
className={cn('select', this.props.className)}
onScroll={this._hideDiff}
onClick={(e) => e.stopPropagation() }

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import * as d3 from 'd3';
import TranslatedComponent from './TranslatedComponent';
@@ -45,16 +46,16 @@ export default class BarChart extends TranslatedComponent {
};
static propTypes = {
colors: React.PropTypes.array,
data: React.PropTypes.array.isRequired,
desc: React.PropTypes.bool,
format: React.PropTypes.string.isRequired,
labels: React.PropTypes.array,
predicate: React.PropTypes.string,
properties: React.PropTypes.array,
title: React.PropTypes.string.isRequired,
unit: React.PropTypes.string.isRequired,
width: React.PropTypes.number.isRequired
colors: PropTypes.array,
data: PropTypes.array.isRequired,
desc: PropTypes.bool,
format: PropTypes.string.isRequired,
labels: PropTypes.array,
predicate: PropTypes.string,
properties: PropTypes.array,
title: PropTypes.string.isRequired,
unit: PropTypes.string.isRequired,
width: PropTypes.number.isRequired
};
/**

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent';
import { Ships } from 'coriolis-data/dist';
import { nameComparator } from '../utils/SlotFunctions';
@@ -14,10 +15,10 @@ import Module from '../shipyard/Module';
*/
export default class Boost extends TranslatedComponent {
static propTypes = {
marker: React.PropTypes.string.isRequired,
ship: React.PropTypes.object.isRequired,
boost: React.PropTypes.bool.isRequired,
onChange: React.PropTypes.func.isRequired
marker: PropTypes.string.isRequired,
ship: PropTypes.object.isRequired,
boost: PropTypes.bool.isRequired,
onChange: PropTypes.func.isRequired
};
/**

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent';
import { Ships } from 'coriolis-data/dist';
import Slider from '../components/Slider';
@@ -9,9 +10,9 @@ import Slider from '../components/Slider';
*/
export default class Cargo extends TranslatedComponent {
static propTypes = {
cargo: React.PropTypes.number.isRequired,
cargoCapacity: React.PropTypes.number.isRequired,
onChange: React.PropTypes.func.isRequired
cargo: PropTypes.number.isRequired,
cargoCapacity: PropTypes.number.isRequired,
onChange: PropTypes.func.isRequired
};
/**

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent';
import Link from './Link';
import cn from 'classnames';
@@ -11,11 +12,11 @@ import { outfitURL } from '../utils/UrlGenerators';
export default class ComparisonTable extends TranslatedComponent {
static propTypes = {
facets: React.PropTypes.array.isRequired,
builds: React.PropTypes.array.isRequired,
onSort: React.PropTypes.func.isRequired,
predicate: React.PropTypes.string.isRequired, // Used only to test again prop changes for shouldRender
desc: React.PropTypes.oneOfType([React.PropTypes.bool.isRequired, React.PropTypes.number.isRequired]), // Used only to test again prop changes for shouldRender
facets: PropTypes.array.isRequired,
builds: PropTypes.array.isRequired,
onSort: PropTypes.func.isRequired,
predicate: PropTypes.string.isRequired, // Used only to test again prop changes for shouldRender
desc: PropTypes.oneOfType([PropTypes.bool.isRequired, PropTypes.number.isRequired]), // Used only to test again prop changes for shouldRender
};
/**
@@ -71,21 +72,22 @@ export default class ComparisonTable extends TranslatedComponent {
* @return {React.Component} Table row
*/
_buildRow(build, facets, formats, units) {
let url = outfitURL(build.id, build.toString(), build.buildName);
let cells = [
<td key='s' className='tl'><Link href={url}>{build.name}</Link></td>,
<td key='bn' className='tl'><Link href={url}>{build.buildName}</Link></td>
];
if (build && build.id && build.buildName) {
let url = outfitURL(build.id, build.toString(), build.buildName);
let cells = [
<td key='s' className='tl'><Link href={url}>{build.name}</Link></td>,
<td key='bn' className='tl'><Link href={url}>{build.buildName}</Link></td>
];
for (let f of facets) {
if (f.active) {
for (let p of f.props) {
cells.push(<td key={p}>{formats[f.fmt](build[p])}{f.unit ? units[f.unit] : null}</td>);
for (let f of facets) {
if (f.active) {
for (let p of f.props) {
cells.push(<td key={p}>{formats[f.fmt](build[p])}{f.unit ? units[f.unit] : null}</td>);
}
}
}
return <tr key={build.id + build.buildName} className='tr'>{cells}</tr>;
}
return <tr key={build.id + build.buildName} className='tr'>{cells}</tr>;
}
/**

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import cn from 'classnames';
import { Ships } from 'coriolis-data/dist';
import Persist from '../stores/Persist';
@@ -6,6 +7,7 @@ import Ship from '../shipyard/Ship';
import { Insurance } from '../shipyard/Constants';
import { slotName, slotComparator } from '../utils/SlotFunctions';
import TranslatedComponent from './TranslatedComponent';
import { ShoppingIcon } from '../components/SvgIcons';
/**
* Cost Section
@@ -13,9 +15,9 @@ import TranslatedComponent from './TranslatedComponent';
export default class CostSection extends TranslatedComponent {
static propTypes = {
ship: React.PropTypes.object.isRequired,
code: React.PropTypes.string.isRequired,
buildName: React.PropTypes.string
ship: PropTypes.object.isRequired,
code: PropTypes.string.isRequired,
buildName: PropTypes.string
};
/**
@@ -31,6 +33,7 @@ export default class CostSection extends TranslatedComponent {
this._buildRetrofitShip = this._buildRetrofitShip.bind(this);
this._onBaseRetrofitChange = this._onBaseRetrofitChange.bind(this);
this._defaultRetrofitName = this._defaultRetrofitName.bind(this);
this._eddbShoppingList = this._eddbShoppingList.bind(this);
let data = Ships[props.ship.id]; // Retrieve the basic ship properties, slots and defaults
let retrofitName = this._defaultRetrofitName(props.ship.id, props.buildName);
@@ -325,12 +328,27 @@ export default class CostSection extends TranslatedComponent {
</div>;
}
/**
* Open up a window for EDDB with a shopping list of our retrofit components
*/
_eddbShoppingList() {
const { retrofitCosts } = this.state;
const { ship } = this.props;
// Provide unique list of non-PP module EDDB IDs to buy
const modIds = retrofitCosts.filter(item => item.retroItem.incCost && item.buyId && !item.buyPp).map(item => item.buyId).filter((v, i, a) => a.indexOf(v) === i);
// Open up the relevant URL
window.open('https://eddb.io/station?m=' + modIds.join(','));
}
/**
* Render the retofit tab
* @return {React.Component} Tab contents
*/
_retrofitTab() {
let { retrofitTotal, retrofitCosts, moduleDiscount, retrofitName } = this.state;
const { termtip, tooltip } = this.context;
let { translate, formats, units } = this.context.language;
let int = formats.int;
let rows = [], options = [<option key='stock' value=''>{translate('Stock')}</option>];
@@ -370,7 +388,8 @@ export default class CostSection extends TranslatedComponent {
<tbody>
{rows}
<tr className='ri'>
<td colSpan='4' className='lbl' >{translate('cost')}</td>
<td className='lbl' ><button onClick={this._eddbShoppingList} onMouseOver={termtip.bind(null, 'PHRASE_REFIT_SHOPPING_LIST')} onMouseOut={tooltip.bind(null, null)}><ShoppingIcon className='lg' style={{ fill: 'black' }}/></button></td>
<td colSpan='3' className='lbl' >{translate('cost')}</td>
<td colSpan='2' className={cn('val', retrofitTotal > 0 ? 'warning' : 'secondary-disabled')} style={{ borderBottom:'none' }}>
{int(retrofitTotal)}{units.CR}
</td>
@@ -403,6 +422,8 @@ export default class CostSection extends TranslatedComponent {
if (ship.bulkheads.m.index != retrofitShip.bulkheads.m.index) {
item = {
buyClassRating: ship.bulkheads.m.class + ship.bulkheads.m.rating,
buyId: ship.bulkheads.m.eddbID,
buyPp: ship.bulkheads.m.pp,
buyName: ship.bulkheads.m.name,
sellClassRating: retrofitShip.bulkheads.m.class + retrofitShip.bulkheads.m.rating,
sellName: retrofitShip.bulkheads.m.name,
@@ -424,6 +445,8 @@ export default class CostSection extends TranslatedComponent {
if (modId != retroModId) {
item = { netCost: 0, retroItem: retroSlotGroup[i] };
if (slotGroup[i].m) {
item.buyId = slotGroup[i].m.eddbID,
item.buyPp = slotGroup[i].m.pp,
item.buyName = slotGroup[i].m.name || slotGroup[i].m.grp;
item.buyClassRating = slotGroup[i].m.class + slotGroup[i].m.rating;
item.netCost = slotGroup[i].discountedCost;

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent';
import * as Calc from '../shipyard/Calculations';
import PieChart from './PieChart';
@@ -14,12 +15,12 @@ import VerticalBarChart from './VerticalBarChart';
*/
export default class Defence extends TranslatedComponent {
static propTypes = {
marker: React.PropTypes.string.isRequired,
ship: React.PropTypes.object.isRequired,
opponent: React.PropTypes.object.isRequired,
engagementrange: React.PropTypes.number.isRequired,
sys: React.PropTypes.number.isRequired,
opponentWep: React.PropTypes.number.isRequired
marker: PropTypes.string.isRequired,
ship: PropTypes.object.isRequired,
opponent: PropTypes.object.isRequired,
engagementrange: PropTypes.number.isRequired,
sys: PropTypes.number.isRequired,
opponentWep: PropTypes.number.isRequired
};
/**

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent';
import { Ships } from 'coriolis-data/dist';
import Slider from '../components/Slider';
@@ -9,9 +10,9 @@ import Slider from '../components/Slider';
*/
export default class EngagementRange extends TranslatedComponent {
static propTypes = {
ship: React.PropTypes.object.isRequired,
engagementRange: React.PropTypes.number.isRequired,
onChange: React.PropTypes.func.isRequired
ship: PropTypes.object.isRequired,
engagementRange: PropTypes.number.isRequired,
onChange: PropTypes.func.isRequired
};
/**

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent';
import { Ships } from 'coriolis-data/dist';
import { nameComparator } from '../utils/SlotFunctions';
@@ -13,12 +14,12 @@ import * as Calc from '../shipyard/Calculations';
*/
export default class EngineProfile extends TranslatedComponent {
static propTypes = {
ship: React.PropTypes.object.isRequired,
cargo: React.PropTypes.number.isRequired,
fuel: React.PropTypes.number.isRequired,
eng: React.PropTypes.number.isRequired,
boost: React.PropTypes.bool.isRequired,
marker: React.PropTypes.string.isRequired
ship: PropTypes.object.isRequired,
cargo: PropTypes.number.isRequired,
fuel: PropTypes.number.isRequired,
eng: PropTypes.number.isRequired,
boost: PropTypes.bool.isRequired,
marker: PropTypes.string.isRequired
};
/**

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent';
import { Ships } from 'coriolis-data/dist';
import { nameComparator } from '../utils/SlotFunctions';
@@ -13,10 +14,10 @@ import * as Calc from '../shipyard/Calculations';
*/
export default class FSDProfile extends TranslatedComponent {
static propTypes = {
ship: React.PropTypes.object.isRequired,
cargo: React.PropTypes.number.isRequired,
fuel: React.PropTypes.number.isRequired,
marker: React.PropTypes.string.isRequired
ship: PropTypes.object.isRequired,
cargo: PropTypes.number.isRequired,
fuel: PropTypes.number.isRequired,
marker: PropTypes.string.isRequired
};
/**

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent';
import { Ships } from 'coriolis-data/dist';
import Slider from '../components/Slider';
@@ -9,9 +10,9 @@ import Slider from '../components/Slider';
*/
export default class Fuel extends TranslatedComponent {
static propTypes = {
fuel: React.PropTypes.number.isRequired,
fuelCapacity: React.PropTypes.number.isRequired,
onChange: React.PropTypes.func.isRequired
fuel: PropTypes.number.isRequired,
fuelCapacity: PropTypes.number.isRequired,
onChange: PropTypes.func.isRequired
};
/**

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent';
import { Ships } from 'coriolis-data/dist';
import { nameComparator } from '../utils/SlotFunctions';
@@ -13,8 +14,8 @@ import * as Calc from '../shipyard/Calculations';
*/
export default class JumpRange extends TranslatedComponent {
static propTypes = {
ship: React.PropTypes.object.isRequired,
code: React.PropTypes.string.isRequired
ship: PropTypes.object.isRequired,
code: PropTypes.string.isRequired
};
/**
@@ -42,7 +43,7 @@ export default class JumpRange extends TranslatedComponent {
componentWillReceiveProps(nextProps, nextContext) {
if (nextProps.code != this.props.code) {
this.setState({ fuelLevel: 1,
calcJumpRangeFunc: this._calcJumpRange.bind(this, nextProps.ship) });
calcJumpRangeFunc: this._calcJumpRange.bind(this, nextProps.ship) });
}
return true;
}

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import Measure from 'react-measure';
import * as d3 from 'd3';
import TranslatedComponent from './TranslatedComponent';
@@ -20,21 +21,21 @@ export default class LineChart extends TranslatedComponent {
};
static propTypes = {
func: React.PropTypes.func.isRequired,
xLabel: React.PropTypes.string.isRequired,
xMin: React.PropTypes.number,
xMax: React.PropTypes.number.isRequired,
xUnit: React.PropTypes.string.isRequired,
xMark: React.PropTypes.number,
yLabel: React.PropTypes.string.isRequired,
yMin: React.PropTypes.number,
yMax: React.PropTypes.number.isRequired,
yUnit: React.PropTypes.string,
series: React.PropTypes.array,
colors: React.PropTypes.array,
points: React.PropTypes.number,
aspect: React.PropTypes.number,
code: React.PropTypes.string,
func: PropTypes.func.isRequired,
xLabel: PropTypes.string.isRequired,
xMin: PropTypes.number,
xMax: PropTypes.number.isRequired,
xUnit: PropTypes.string.isRequired,
xMark: PropTypes.number,
yLabel: PropTypes.string.isRequired,
yMin: PropTypes.number,
yMax: PropTypes.number.isRequired,
yUnit: PropTypes.string,
series: PropTypes.array,
colors: PropTypes.array,
points: PropTypes.number,
aspect: PropTypes.number,
code: PropTypes.string,
};
/**

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import Router from '../Router';
import { shallowEqual } from '../utils/UtilityFunctions';
@@ -8,9 +9,9 @@ import { shallowEqual } from '../utils/UtilityFunctions';
export default class Link extends React.Component {
static propTypes = {
children: React.PropTypes.any,
href: React.PropTypes.string.isRequired,
onClick: React.PropTypes.func
children: PropTypes.any,
href: PropTypes.string.isRequired,
onClick: PropTypes.func
};
/**
@@ -56,4 +57,4 @@ export default class Link extends React.Component {
return <a {...this.props} onClick={this.handler}>{this.props.children}</a>;
}
}
}

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent';
import { Ships } from 'coriolis-data/dist';
import Persist from '../stores/Persist';
@@ -22,8 +23,8 @@ function buildComparator(a, b) {
export default class ModalCompare extends TranslatedComponent {
static propTypes = {
onSelect: React.PropTypes.func.isRequired,
builds: React.PropTypes.array
onSelect: PropTypes.func.isRequired,
builds: PropTypes.array
};
static defaultProps = {

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { findDOMNode } from 'react-dom';
import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent';
/**
@@ -8,9 +8,9 @@ import TranslatedComponent from './TranslatedComponent';
export default class ModalExport extends TranslatedComponent {
static propTypes = {
title: React.PropTypes.string,
generator: React.PropTypes.func,
data: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.object, React.PropTypes.array])
title: PropTypes.string,
generator: PropTypes.func,
data: PropTypes.oneOfType([PropTypes.string, PropTypes.object, PropTypes.array])
};
/**
@@ -45,10 +45,9 @@ export default class ModalExport extends TranslatedComponent {
* Focus on textarea and select all
*/
componentDidMount() {
let e = findDOMNode(this.refs.exportField);
if (e) {
e.focus();
e.select();
if (this.exportField) {
this.exportField.focus();
this.exportField.select();
}
}
@@ -68,7 +67,7 @@ export default class ModalExport extends TranslatedComponent {
<h2>{translate(this.props.title || 'Export')}</h2>
{description}
<div>
<textarea className='cb json' ref='exportField' readOnly value={this.state.exportJson} />
<textarea className='cb json' ref={node => this.exportField = node} readOnly value={this.state.exportJson} />
</div>
<button className='r dismiss cap' onClick={this.context.hideModal}>{translate('close')}</button>
</div>;

View File

@@ -1,6 +1,6 @@
/* eslint react/no-danger: 0 */
import PropTypes from 'prop-types';
import React from 'react';
import { findDOMNode } from 'react-dom';
import TranslatedComponent from './TranslatedComponent';
/**
@@ -9,7 +9,7 @@ import TranslatedComponent from './TranslatedComponent';
export default class ModalHelp extends TranslatedComponent {
static propTypes = {
title: React.PropTypes.string
title: PropTypes.string
};
/**
@@ -20,17 +20,6 @@ export default class ModalHelp extends TranslatedComponent {
super(props);
}
/**
* Focus on textarea and select all
*/
componentDidMount() {
const e = findDOMNode(this.refs.exportField);
if (e) {
e.focus();
e.select();
}
}
/**
* Render the modal
* @return {React.Component} Modal Content

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { findDOMNode } from 'react-dom';
import PropTypes from 'prop-types';
import cn from 'classnames';
import TranslatedComponent from './TranslatedComponent';
import Router from '../Router';
@@ -86,7 +86,7 @@ export default class ModalImport extends TranslatedComponent {
static propTypes = {
builds: React.PropTypes.object, // Optional: Import object
builds: PropTypes.object, // Optional: Import object
};
/**
@@ -459,8 +459,8 @@ export default class ModalImport extends TranslatedComponent {
* If textarea is shown focus on mount
*/
componentDidMount() {
if (!this.props.builds && findDOMNode(this.refs.importField)) {
findDOMNode(this.refs.importField).focus();
if (!this.props.builds && this.importField) {
this.importField.focus();
}
}
@@ -476,7 +476,7 @@ export default class ModalImport extends TranslatedComponent {
if (!state.processed) {
importStage = (
<div>
<textarea className='cb json' ref='importField' onChange={this._validateImport} defaultValue={this.state.importString} placeholder={translate('PHRASE_IMPORT')} />
<textarea className='cb json' ref={node => this.importField = node} onChange={this._validateImport} defaultValue={this.state.importString} placeholder={translate('PHRASE_IMPORT')} />
<button id='proceed' className='l cap' onClick={this._process} disabled={!state.importValid} >{translate('proceed')}</button>
<div className='l warning' style={{ marginLeft:'3em' }}>{state.errorMsg}</div>
</div>

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent';
import ShortenUrl from '../utils/ShortenUrl';
@@ -8,7 +9,7 @@ import ShortenUrl from '../utils/ShortenUrl';
export default class ModalPermalink extends TranslatedComponent {
static propTypes = {
url: React.PropTypes.string.isRequired
url: PropTypes.string.isRequired
};
/**

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent';
import cn from 'classnames';
import NumberEditor from 'react-number-editor';
@@ -9,11 +10,11 @@ import NumberEditor from 'react-number-editor';
export default class Modification extends TranslatedComponent {
static propTypes = {
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
ship: PropTypes.object.isRequired,
m: PropTypes.object.isRequired,
name: PropTypes.string.isRequired,
value: PropTypes.number.isRequired,
onChange: PropTypes.func.isRequired
};
/**

View File

@@ -1,11 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
import * as _ from 'lodash';
import TranslatedComponent from './TranslatedComponent';
import { isEmpty, stopCtxPropagation } from '../utils/UtilityFunctions';
import cn from 'classnames';
import { Modifications } from 'coriolis-data/dist';
import Modification from './Modification';
import { getBlueprint, blueprintTooltip } from '../utils/BlueprintFunctions';
import { getBlueprint, blueprintTooltip, setWorst, setBest, setExtreme, setRandom } from '../utils/BlueprintFunctions';
/**
* Modifications menu
@@ -13,10 +14,10 @@ import { getBlueprint, blueprintTooltip } from '../utils/BlueprintFunctions';
export default class ModificationsMenu extends TranslatedComponent {
static propTypes = {
ship: React.PropTypes.object.isRequired,
m: React.PropTypes.object.isRequired,
marker: React.PropTypes.string.isRequired,
onChange: React.PropTypes.func.isRequired
ship: PropTypes.object.isRequired,
m: PropTypes.object.isRequired,
marker: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired
};
/**
@@ -87,10 +88,11 @@ export default class ModificationsMenu extends TranslatedComponent {
const translate = language.translate;
const specials = [];
if (Modifications.modules[m.grp].specials && Modifications.modules[m.grp].specials.length > 0) {
const specialsId = m.missile ? 'specials_' + m.missile : 'specials';
if (Modifications.modules[m.grp][specialsId] && Modifications.modules[m.grp][specialsId].length > 0) {
const close = this._specialSelected.bind(this, null);
specials.push(<div style={{ cursor: 'pointer' }} key={ 'none' } onClick={ close }>{translate('PHRASE_NO_SPECIAL')}</div>);
for (const specialName of Modifications.modules[m.grp].specials) {
for (const specialName of Modifications.modules[m.grp][specialsId]) {
const close = this._specialSelected.bind(this, specialName);
specials.push(<div style={{ cursor: 'pointer' }} key={ specialName } onClick={ close }>{translate(Modifications.specials[specialName].name)}</div>);
}
@@ -130,10 +132,10 @@ export default class ModificationsMenu extends TranslatedComponent {
*/
_blueprintSelected(fdname, grade) {
this.context.tooltip(null);
const { m } = this.props;
const { m, ship } = this.props;
const blueprint = getBlueprint(fdname, m);
blueprint.grade = grade;
m.blueprint = blueprint;
ship.setModuleBlueprint(m, blueprint);
this.setState({ blueprintMenuOpened: false });
this.props.onChange();
@@ -155,50 +157,22 @@ export default class ModificationsMenu extends TranslatedComponent {
this.context.tooltip(null);
const { m, ship } = this.props;
if (m.blueprint) {
if (special === null) {
m.blueprint.special = null;
} else {
m.blueprint.special = Modifications.specials[special];
}
ship.recalculateDps();
ship.recalculateHps();
ship.recalculateEps();
if (special === null) {
ship.clearModuleSpecial(m);
} else {
ship.setModuleSpecial(m, Modifications.specials[special]);
}
this.setState({ specialMenuOpened: false });
this.props.onChange();
}
/**
* Set the result of a roll
* @param {object} ship The ship to which the roll applies
* @param {object} m The module to which the roll applies
* @param {string} featureName The modification feature to which the roll applies
* @param {number} value The value of the roll
*/
_setRollResult(ship, m, featureName, value) {
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);
} else {
ship.setModification(m, featureName, value);
}
}
/**
* Provide a 'worst' roll within the information we have
*/
_rollWorst() {
const { m, ship } = this.props;
ship.clearModifications(m);
const features = m.blueprint.grades[m.blueprint.grade].features;
for (const featureName in features) {
let value = features[featureName][0];
this._setRollResult(ship, m, featureName, value);
}
setWorst(ship, m);
this.props.onChange();
}
@@ -207,13 +181,7 @@ export default class ModificationsMenu extends TranslatedComponent {
*/
_rollRandom() {
const { m, ship } = this.props;
ship.clearModifications(m);
const features = m.blueprint.grades[m.blueprint.grade].features;
for (const featureName in features) {
let value = features[featureName][0] + (Math.random() * (features[featureName][1] - features[featureName][0]));
this._setRollResult(ship, m, featureName, value);
}
setRandom(ship, m);
this.props.onChange();
}
@@ -222,12 +190,7 @@ export default class ModificationsMenu extends TranslatedComponent {
*/
_rollBest() {
const { m, ship } = this.props;
const features = m.blueprint.grades[m.blueprint.grade].features;
for (const featureName in features) {
let value = features[featureName][1];
this._setRollResult(ship, m, featureName, value);
}
setBest(ship, m);
this.props.onChange();
}
@@ -236,29 +199,7 @@ export default class ModificationsMenu extends TranslatedComponent {
*/
_rollExtreme() {
const { m, ship } = this.props;
ship.clearModifications(m);
const features = m.blueprint.grades[m.blueprint.grade].features;
for (const featureName in features) {
let value;
if (Modifications.modifications[featureName].higherbetter) {
// Higher is better, but is this making it better or worse?
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
value = features[featureName][0];
} else {
value = features[featureName][1];
}
} else {
// Higher is worse, but is this making it better or worse?
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
value = features[featureName][1];
} else {
value = features[featureName][0];
}
}
this._setRollResult(ship, m, featureName, value);
}
setExtreme(ship, m);
this.props.onChange();
}
@@ -268,7 +209,7 @@ export default class ModificationsMenu extends TranslatedComponent {
_reset() {
const { m, ship } = this.props;
ship.clearModifications(m);
ship.clearBlueprint(m);
ship.clearModuleBlueprint(m);
this.props.onChange();
}
@@ -294,7 +235,7 @@ export default class ModificationsMenu extends TranslatedComponent {
let blueprintLabel;
let haveBlueprint = false;
let blueprintTt;
if (m.blueprint && !isEmpty(m.blueprint)) {
if (m.blueprint && m.blueprint.name) {
blueprintLabel = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade;
haveBlueprint = true;
blueprintTt = blueprintTooltip(translate, m.blueprint.grades[m.blueprint.grade], Modifications.modules[m.grp].blueprints[m.blueprint.fdname].grades[m.blueprint.grade].engineers, m.grp);

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent';
/**
@@ -6,12 +7,12 @@ import TranslatedComponent from './TranslatedComponent';
*/
export default class Movement extends TranslatedComponent {
static propTypes = {
marker: React.PropTypes.string.isRequired,
ship: React.PropTypes.object.isRequired,
boost: React.PropTypes.bool.isRequired,
eng: React.PropTypes.number.isRequired,
fuel: React.PropTypes.number.isRequired,
cargo: React.PropTypes.number.isRequired
marker: PropTypes.string.isRequired,
ship: PropTypes.object.isRequired,
boost: PropTypes.bool.isRequired,
eng: PropTypes.number.isRequired,
fuel: PropTypes.number.isRequired,
cargo: PropTypes.number.isRequired
};
/**

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent';
import * as Calc from '../shipyard/Calculations';
import PieChart from './PieChart';
@@ -51,12 +52,12 @@ export function weaponComparator(translate, propComparator, desc) {
*/
export default class Offence extends TranslatedComponent {
static propTypes = {
marker: React.PropTypes.string.isRequired,
ship: React.PropTypes.object.isRequired,
opponent: React.PropTypes.object.isRequired,
engagementrange: React.PropTypes.number.isRequired,
wep: React.PropTypes.number.isRequired,
opponentSys: React.PropTypes.number.isRequired
marker: PropTypes.string.isRequired,
ship: PropTypes.object.isRequired,
opponent: PropTypes.object.isRequired,
engagementrange: PropTypes.number.isRequired,
wep: PropTypes.number.isRequired,
opponentSys: PropTypes.number.isRequired
};
/**

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import cn from 'classnames';
import { Ships } from 'coriolis-data/dist';
import Ship from '../shipyard/Ship';
@@ -19,22 +20,22 @@ import WeaponDamageChart from './WeaponDamageChart';
export default class OutfittingSubpages extends TranslatedComponent {
static propTypes = {
ship: React.PropTypes.object.isRequired,
code: React.PropTypes.string.isRequired,
onChange: React.PropTypes.func.isRequired,
buildName: React.PropTypes.string,
sys: React.PropTypes.number.isRequired,
eng: React.PropTypes.number.isRequired,
wep: React.PropTypes.number.isRequired,
cargo: React.PropTypes.number.isRequired,
fuel: React.PropTypes.number.isRequired,
boost: React.PropTypes.bool.isRequired,
engagementRange: React.PropTypes.number.isRequired,
opponent: React.PropTypes.object.isRequired,
opponentBuild: React.PropTypes.string,
opponentSys: React.PropTypes.number.isRequired,
opponentEng: React.PropTypes.number.isRequired,
opponentWep: React.PropTypes.number.isRequired,
ship: PropTypes.object.isRequired,
code: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
buildName: PropTypes.string,
sys: PropTypes.number.isRequired,
eng: PropTypes.number.isRequired,
wep: PropTypes.number.isRequired,
cargo: PropTypes.number.isRequired,
fuel: PropTypes.number.isRequired,
boost: PropTypes.bool.isRequired,
engagementRange: PropTypes.number.isRequired,
opponent: PropTypes.object.isRequired,
opponentBuild: PropTypes.string,
opponentSys: PropTypes.number.isRequired,
opponentEng: PropTypes.number.isRequired,
opponentWep: PropTypes.number.isRequired,
};
/**

View File

@@ -1,4 +1,5 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Measure from 'react-measure';
import * as d3 from 'd3';
@@ -11,7 +12,7 @@ const LABEL_COLOUR = '#000000';
export default class PieChart extends Component {
static propTypes = {
data : React.PropTypes.array.isRequired
data : PropTypes.array.isRequired
};
/**

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent';
import { Ships } from 'coriolis-data/dist';
import { nameComparator } from '../utils/SlotFunctions';
@@ -14,10 +15,10 @@ import Module from '../shipyard/Module';
*/
export default class Pips extends TranslatedComponent {
static propTypes = {
sys: React.PropTypes.number.isRequired,
eng: React.PropTypes.number.isRequired,
wep: React.PropTypes.number.isRequired,
onChange: React.PropTypes.func.isRequired
sys: PropTypes.number.isRequired,
eng: PropTypes.number.isRequired,
wep: PropTypes.number.isRequired,
onChange: PropTypes.func.isRequired
};
/**

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import * as d3 from 'd3';
import cn from 'classnames';
import TranslatedComponent from './TranslatedComponent';
@@ -33,10 +34,10 @@ function bandText(val, index, wattScale) {
export default class PowerBands extends TranslatedComponent {
static propTypes = {
bands: React.PropTypes.array.isRequired,
available: React.PropTypes.number.isRequired,
width: React.PropTypes.number.isRequired,
code: React.PropTypes.string,
bands: PropTypes.array.isRequired,
available: PropTypes.number.isRequired,
width: PropTypes.number.isRequired,
code: PropTypes.string,
};
/**

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { findDOMNode } from 'react-dom';
import PropTypes from 'prop-types';
import cn from 'classnames';
import TranslatedComponent from './TranslatedComponent';
import PowerBands from './PowerBands';
@@ -18,9 +18,9 @@ const POWER = [
*/
export default class PowerManagement extends TranslatedComponent {
static propTypes = {
ship: React.PropTypes.object.isRequired,
code: React.PropTypes.string.isRequired,
onChange: React.PropTypes.func.isRequired
ship: PropTypes.object.isRequired,
code: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired
};
/**
@@ -148,7 +148,7 @@ export default class PowerManagement extends TranslatedComponent {
* Update power bands width from DOM
*/
_updateWidth() {
this.setState({ width: findDOMNode(this).offsetWidth });
this.setState({ width: this.node.offsetWidth });
}
/**
@@ -196,7 +196,7 @@ export default class PowerManagement extends TranslatedComponent {
let sortOrder = this._sortOrder;
return (
<div className='group half' id='componentPriority'>
<div ref={node => this.node = node} className='group half' id='componentPriority'>
<table style={{ width: '100%' }}>
<thead>
<tr className='main'>

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent';
import Ship from '../shipyard/Ship';
import { Ships } from 'coriolis-data/dist';
@@ -12,9 +13,9 @@ import cn from 'classnames';
*/
export default class ShipPicker extends TranslatedComponent {
static propTypes = {
onChange: React.PropTypes.func.isRequired,
ship: React.PropTypes.string.isRequired,
build: React.PropTypes.string
onChange: PropTypes.func.isRequired,
ship: PropTypes.string.isRequired,
build: PropTypes.string
};
static defaultProps = {

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent';
import cn from 'classnames';
import { Warning } from './SvgIcons';
@@ -10,10 +11,10 @@ import * as Calc from '../shipyard/Calculations';
export default class ShipSummaryTable extends TranslatedComponent {
static propTypes = {
ship: React.PropTypes.object.isRequired,
cargo: React.PropTypes.number.isRequired,
fuel: React.PropTypes.number.isRequired,
marker: React.PropTypes.string.isRequired,
ship: PropTypes.object.isRequired,
cargo: PropTypes.number.isRequired,
fuel: PropTypes.number.isRequired,
marker: PropTypes.string.isRequired,
};
/**

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { findDOMNode } from 'react-dom';
import PropTypes from 'prop-types';
const MARGIN_LR = 8; // Left/ Right margin
@@ -16,14 +16,14 @@ export default class Slider extends React.Component {
};
static propTypes = {
axis: React.PropTypes.bool,
axisUnit: React.PropTypes.string,
max: React.PropTypes.number,
min: React.PropTypes.number,
onChange: React.PropTypes.func.isRequired,
onResize: React.PropTypes.func,
percent: React.PropTypes.number.isRequired,
scale: React.PropTypes.number
axis: PropTypes.bool,
axisUnit: PropTypes.string,
max: PropTypes.number,
min: PropTypes.number,
onChange: PropTypes.func.isRequired,
onResize: PropTypes.func,
percent: PropTypes.number.isRequired,
scale: PropTypes.number
};
/**
@@ -100,7 +100,7 @@ export default class Slider extends React.Component {
*/
_updateDimensions() {
this.setState({
outerWidth: findDOMNode(this).getBoundingClientRect().width
outerWidth: this.node.getBoundingClientRect().width
});
}
@@ -144,14 +144,14 @@ export default class Slider extends React.Component {
};
if (!outerWidth) {
return <svg style={style} />;
return <svg style={style} ref={node => this.node = node} />;
}
let margin = MARGIN_LR * scale;
let width = outerWidth - (margin * 2);
let pctPos = width * this.props.percent;
return <svg onMouseUp={this._up} onMouseEnter={this._enter.bind(this)} onMouseMove={this._move} onTouchEnd={this._up} style={style}>
return <svg onMouseUp={this._up} onMouseEnter={this._enter.bind(this)} onMouseMove={this._move} onTouchEnd={this._up} style={style} ref={node => this.node = node}>
<rect className='primary' style={{ opacity: 0.3 }} x={margin} y='0.25em' rx='0.3em' ry='0.3em' width={width} height='0.7em' />
<rect className='primary-disabled' x={margin} y='0.45em' rx='0.15em' ry='0.15em' width={pctPos} height='0.3em' />
<circle className='primary' r={margin} cy='0.6em' cx={pctPos + margin} />

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent';
import cn from 'classnames';
import AvailableModulesMenu from './AvailableModulesMenu';
@@ -13,18 +14,18 @@ import { stopCtxPropagation } from '../utils/UtilityFunctions';
export default class Slot extends TranslatedComponent {
static propTypes = {
availableModules: React.PropTypes.func.isRequired,
onSelect: React.PropTypes.func.isRequired,
onOpen: React.PropTypes.func.isRequired,
maxClass: React.PropTypes.number.isRequired,
selected: React.PropTypes.bool,
m: React.PropTypes.object,
ship: React.PropTypes.object.isRequired,
eligible: React.PropTypes.object,
warning: React.PropTypes.func,
drag: React.PropTypes.func,
drop: React.PropTypes.func,
dropClass: React.PropTypes.string
availableModules: PropTypes.func.isRequired,
onSelect: PropTypes.func.isRequired,
onOpen: PropTypes.func.isRequired,
maxClass: PropTypes.number.isRequired,
selected: PropTypes.bool,
m: PropTypes.object,
ship: PropTypes.object.isRequired,
eligible: PropTypes.object,
warning: PropTypes.func,
drag: PropTypes.func,
drop: PropTypes.func,
dropClass: PropTypes.string
};
/**

View File

@@ -1,9 +1,11 @@
import React from 'react';
import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent';
import { wrapCtxMenu } from '../utils/UtilityFunctions';
import { canMount } from '../utils/SlotFunctions';
import { Equalizer } from '../components/SvgIcons';
import cn from 'classnames';
const browser = require('detect-browser');
/**
* Abstract Slot Section
@@ -11,10 +13,10 @@ import cn from 'classnames';
export default class SlotSection extends TranslatedComponent {
static propTypes = {
ship: React.PropTypes.object.isRequired,
onChange: React.PropTypes.func.isRequired,
code: React.PropTypes.string.isRequired,
togglePwr: React.PropTypes.func
ship: PropTypes.object.isRequired,
onChange: PropTypes.func.isRequired,
code: PropTypes.string.isRequired,
togglePwr: PropTypes.func
};
/**
@@ -75,8 +77,10 @@ export default class SlotSection extends TranslatedComponent {
* @param {Event} e Drag Event
*/
_drag(originSlot, e) {
e.dataTransfer.setData('text/html', e.currentTarget);
e.dataTransfer.effectAllowed = 'all';
if (!browser || (browser.name !== 'edge' && browser.name !== 'ie')) {
e.dataTransfer.setData('text/html', e.currentTarget);
}
e.dataTransfer.effectAllowed = 'copyMove';
this.setState({ originSlot, copy: e.getModifierState('Alt') });
this._close();
}
@@ -93,10 +97,14 @@ export default class SlotSection extends TranslatedComponent {
if (os) {
// Show correct icon
const effect = this.state.copy ? 'copy' : 'move';
e.dataTransfer.dropEffect = os != targetSlot && canMount(this.props.ship, targetSlot, os.m.grp, os.m.class) ? effect : 'none';
if (!browser || (browser.name !== 'edge' && browser.name !== 'ie')) {
e.dataTransfer.dropEffect = os != targetSlot && canMount(this.props.ship, targetSlot, os.m.grp, os.m.class) ? effect : 'none';
}
this.setState({ targetSlot });
} else {
e.dataTransfer.dropEffect = 'none';
if (!browser || (browser.name !== 'edge' && browser.name !== 'ie')) {
e.dataTransfer.dropEffect = 'none';
}
}
}
@@ -106,7 +114,9 @@ export default class SlotSection extends TranslatedComponent {
*/
_dragOverNone(e) {
e.preventDefault();
e.dataTransfer.dropEffect = 'none';
if (!browser || (browser.name !== 'edge' && browser.name !== 'ie')) {
e.dataTransfer.dropEffect = 'none';
}
this.setState({ targetSlot: null });
}

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import cn from 'classnames';
import Persist from '../stores/Persist';
import TranslatedComponent from './TranslatedComponent';
@@ -17,14 +18,14 @@ import { blueprintTooltip } from '../utils/BlueprintFunctions';
export default class StandardSlot extends TranslatedComponent {
static propTypes = {
slot: React.PropTypes.object,
modules: React.PropTypes.array.isRequired,
onSelect: React.PropTypes.func.isRequired,
onOpen: React.PropTypes.func.isRequired,
onChange: React.PropTypes.func.isRequired,
ship: React.PropTypes.object.isRequired,
selected: React.PropTypes.bool,
warning: React.PropTypes.func,
slot: PropTypes.object,
modules: PropTypes.array.isRequired,
onSelect: PropTypes.func.isRequired,
onOpen: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
ship: PropTypes.object.isRequired,
selected: PropTypes.bool,
warning: PropTypes.func,
};
/**

View File

@@ -72,6 +72,15 @@ export default class StandardSlotSection extends SlotSection {
this._close();
}
/**
* Racer role
*/
_optimizeRacer() {
ShipRoles.racer(this.props.ship);
this.props.onChange();
this._close();
}
/**
* Use the specified bulkhead
* @param {Object} bulkhead Bulkhead module details
@@ -220,6 +229,7 @@ export default class StandardSlotSection extends SlotSection {
<li className={cn('lc', { disabled: planetaryDisabled })} onClick={!planetaryDisabled && this._optimizeExplorer.bind(this, true)}>{translate('Planetary Explorer')}</li>
<li className='lc' onClick={this._optimizeMiner.bind(this, false)}>{translate('Miner')}</li>
<li className='lc' onClick={this._optimizeMiner.bind(this, true)}>{translate('Shielded Miner')}</li>
<li className='lc' onClick={this._optimizeRacer.bind(this)}>{translate('Racer')}</li>
</ul>
</div>;
}

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import cn from 'classnames';
import { shallowEqual } from '../utils/UtilityFunctions';
@@ -8,8 +9,8 @@ import { shallowEqual } from '../utils/UtilityFunctions';
class SvgIcon extends React.Component {
static propTypes = {
className: React.PropTypes.any,
style: React.PropTypes.object
className: PropTypes.any,
style: PropTypes.object
};
/**

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent';
/**
@@ -7,8 +8,8 @@ import TranslatedComponent from './TranslatedComponent';
export default class Tooltip extends TranslatedComponent {
static propTypes = {
rect: React.PropTypes.object.isRequired,
options: React.PropTypes.object
rect: PropTypes.object.isRequired,
options: PropTypes.object
};
static defaultProps = {
@@ -127,4 +128,4 @@ export default class Tooltip extends TranslatedComponent {
</div>;
}
}
}

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import { shallowEqual } from '../utils/UtilityFunctions';
/**
@@ -7,15 +8,15 @@ import { shallowEqual } from '../utils/UtilityFunctions';
export default class TranslatedComponent extends React.Component {
static contextTypes = {
language: React.PropTypes.object.isRequired,
sizeRatio: React.PropTypes.number.isRequired,
openMenu: React.PropTypes.func.isRequired,
closeMenu: React.PropTypes.func.isRequired,
showModal: React.PropTypes.func.isRequired,
hideModal: React.PropTypes.func.isRequired,
tooltip: React.PropTypes.func.isRequired,
termtip: React.PropTypes.func.isRequired,
onWindowResize: React.PropTypes.func.isRequired
language: PropTypes.object.isRequired,
sizeRatio: PropTypes.number.isRequired,
openMenu: PropTypes.func.isRequired,
closeMenu: PropTypes.func.isRequired,
showModal: PropTypes.func.isRequired,
hideModal: PropTypes.func.isRequired,
tooltip: PropTypes.func.isRequired,
termtip: PropTypes.func.isRequired,
onWindowResize: PropTypes.func.isRequired
};
/**

View File

@@ -87,14 +87,18 @@ export default class VerticalBarChart extends TranslatedComponent {
/**
* A label that displays the value within the bar of the chart
*/
const ValueLabel = React.createClass({
propTypes: {
class ValueLabel extends React.Component {
static propTypes = {
x: PropTypes.number,
y: PropTypes.number,
payload: PropTypes.object,
value: PropTypes.number
},
};
/**
* Render offence
* @return {React.Component} contents
*/
render() {
const { x, y, payload, value } = this.props;
@@ -104,4 +108,4 @@ const ValueLabel = React.createClass({
<text x={x} y={y} fill="#000000" textAnchor="middle" dy={20} style={{ fontSize: em }}>{value}</text>
);
}
});
};

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent';
import { Ships } from 'coriolis-data/dist';
import { nameComparator } from '../utils/SlotFunctions';
@@ -15,12 +16,12 @@ const DAMAGE_DEALT_COLORS = ['#FFFFFF', '#FF0000', '#00FF00', '#7777FF', '#FFFF0
*/
export default class WeaponDamageChart extends TranslatedComponent {
static propTypes = {
ship: React.PropTypes.object.isRequired,
opponent: React.PropTypes.object.isRequired,
hull: React.PropTypes.bool.isRequired,
engagementRange: React.PropTypes.number.isRequired,
opponentSys: React.PropTypes.number.isRequired,
marker: React.PropTypes.string.isRequired
ship: PropTypes.object.isRequired,
opponent: PropTypes.object.isRequired,
hull: PropTypes.bool.isRequired,
engagementRange: PropTypes.number.isRequired,
opponentSys: PropTypes.number.isRequired,
marker: PropTypes.string.isRequired
};
/**
@@ -59,11 +60,11 @@ export default class WeaponDamageChart extends TranslatedComponent {
const maxRange = this._calcMaxRange(nextProps.ship);
const maxDps = this._calcMaxSDps(nextProps.ship, nextProps.opponent, opponentShields, opponentArmour);
this.setState({ weaponNames,
opponentShields,
opponentArmour,
maxRange,
maxDps,
calcSDpsFunc: this._calcSDps.bind(this, nextProps.ship, weaponNames, nextProps.opponent, opponentShields, opponentArmour, nextProps.hull)
opponentShields,
opponentArmour,
maxRange,
maxDps,
calcSDpsFunc: this._calcSDps.bind(this, nextProps.ship, weaponNames, nextProps.opponent, opponentShields, opponentArmour, nextProps.hull)
});
}
return true;

View File

@@ -38,6 +38,7 @@ export const terms = {
PHRASE_SELECT_SPECIAL: 'Click to select an experimental effect',
PHRASE_NO_SPECIAL: 'No experimental effect',
PHRASE_SHOPPING_LIST: 'Stations that sell this build',
PHRASE_REFIT_SHOPPING_LIST: 'Stations that sell required modules',
PHRASE_TOTAL_EFFECTIVE_SHIELD: 'Total amount of damage that can be taken from each damage type, if using all shield cells',
PHRASE_TIME_TO_LOSE_SHIELDS: 'Shields will hold for',
PHRASE_TIME_TO_RECOVER_SHIELDS: 'Shields will recover in',
@@ -234,6 +235,7 @@ export const terms = {
reload: 'Reload',
rof: 'Rate of fire',
angle: 'Scan angle',
scanrate: 'Scan rate',
scantime: 'Scan time',
shield: 'Shield',
shieldboost: 'Shield boost',

View File

@@ -1,5 +1,4 @@
import React from 'react';
import { findDOMNode } from 'react-dom';
import Page from './Page';
import Router from '../Router';
import cn from 'classnames';
@@ -17,7 +16,7 @@ import ModalImport from '../components/ModalImport';
import { FloppyDisk, Bin, Download, Embed, Rocket, LinkIcon } from '../components/SvgIcons';
import ShortenUrl from '../utils/ShortenUrl';
import { comparisonBBCode } from '../utils/BBCode';
const browser = require('detect-browser');
/**
* Creates a comparator based on the specified predicate
@@ -81,7 +80,9 @@ export default class ComparisonPage extends Page {
newName = name;
for (let shipId in allBuilds) {
for (let buildName in allBuilds[shipId]) {
builds.push(this._createBuild(shipId, buildName, allBuilds[shipId][buildName]));
if (buildName && allBuilds[shipId][buildName]) {
builds.push(this._createBuild(shipId, buildName, allBuilds[shipId][buildName]));
}
}
}
} else {
@@ -226,8 +227,10 @@ export default class ComparisonPage extends Page {
let placeholder = this.placeholder = document.createElement('li');
placeholder.style.width = Math.round(this.dragged.offsetWidth) + 'px';
placeholder.className = 'facet-placeholder';
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/html', e.currentTarget);
if (!browser || (browser.name !== 'edge' && browser.name !== 'ie')) {
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/html', e.currentTarget);
}
}
/**
@@ -381,7 +384,7 @@ export default class ComparisonPage extends Page {
*/
_updateDimensions() {
this.setState({
chartWidth: findDOMNode(this.refs.chartRef).offsetWidth
chartWidth: this.chartRef.offsetWidth
});
}
@@ -496,9 +499,9 @@ export default class ComparisonPage extends Page {
<ComparisonTable builds={builds} facets={facets} onSort={this._sortShips} predicate={predicate} desc={desc} />
{!builds.length ?
<div className='chart' ref={'chartRef'}>{translate('PHRASE_NO_BUILDS')}</div> :
<div className='chart' ref={node => this.chartRef = node}>{translate('PHRASE_NO_BUILDS')}</div> :
facets.filter((f) => f.active).map((f, i) =>
<div key={f.title} className='chart' ref={ i == 0 ? 'chartRef' : null}>
<div key={f.title} className='chart' ref={ i == 0 ? node => this.chartRef = node : null}>
<h3 className='ptr' onClick={this._sortShips.bind(this, f.props[0])}>{translate(f.title)}</h3>
<BarChart
width={chartWidth}

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
/**
* Unexpected Error page / block
@@ -6,12 +7,12 @@ import React from 'react';
export default class ErrorDetails extends React.Component {
static contextTypes = {
route: React.PropTypes.object.isRequired,
language: React.PropTypes.object.isRequired
route: PropTypes.object.isRequired,
language: PropTypes.object.isRequired
};
static propTypes = {
error: React.PropTypes.object.isRequired
error: PropTypes.object.isRequired
};
/**

View File

@@ -1,6 +1,5 @@
import React from 'react';
// import Perf from 'react-addons-perf';
import { findDOMNode } from 'react-dom';
import { Ships } from 'coriolis-data/dist';
import cn from 'classnames';
import Page from './Page';
@@ -308,7 +307,10 @@ export default class OutfittingPage extends Page {
* Save the current build
*/
_saveBuild() {
const { code, buildName, newBuildName, shipId } = this.state;
const { ship, buildName, newBuildName, shipId } = this.state;
// If this is a stock ship the code won't be set, so ensure that we have it
const code = this.state.code || ship.toString();
Persist.saveBuild(shipId, newBuildName, code);
this._updateRoute(shipId, newBuildName, code);

View File

@@ -1,4 +1,5 @@
import React from 'react';
import PropTypes from 'prop-types';
import ErrorDetails from './ErrorDetails';
import { shallowEqual } from '../utils/UtilityFunctions';
@@ -8,22 +9,22 @@ import { shallowEqual } from '../utils/UtilityFunctions';
export default class Page extends React.Component {
static contextTypes = {
closeMenu: React.PropTypes.func.isRequired,
hideModal: React.PropTypes.func.isRequired,
language: React.PropTypes.object.isRequired,
noTouch: React.PropTypes.bool.isRequired,
onCommand: React.PropTypes.func.isRequired,
onWindowResize: React.PropTypes.func.isRequired,
openMenu: React.PropTypes.func.isRequired,
route: React.PropTypes.object.isRequired,
showModal: React.PropTypes.func.isRequired,
sizeRatio: React.PropTypes.number.isRequired,
termtip: React.PropTypes.func.isRequired,
tooltip: React.PropTypes.func.isRequired
closeMenu: PropTypes.func.isRequired,
hideModal: PropTypes.func.isRequired,
language: PropTypes.object.isRequired,
noTouch: PropTypes.bool.isRequired,
onCommand: PropTypes.func.isRequired,
onWindowResize: PropTypes.func.isRequired,
openMenu: PropTypes.func.isRequired,
route: PropTypes.object.isRequired,
showModal: PropTypes.func.isRequired,
sizeRatio: PropTypes.number.isRequired,
termtip: PropTypes.func.isRequired,
tooltip: PropTypes.func.isRequired
};
static propTypes = {
currentMenu: React.PropTypes.any
currentMenu: PropTypes.any
};
/**

View File

@@ -54,7 +54,18 @@ function shipSummary(shipId, shipData) {
summary.retailCost = ship.totalCost; // Record Stock/Default/retail cost
ship.optimizeMass({ pd: '1D' }); // Optimize Mass with 1D PD for maximum possible jump range
summary.maxJumpRange = ship.unladenRange; // Record Jump Range
ship.optimizeMass({ th: ship.standard[1].maxClass + 'A', fsd: '2D', ft: '1C' }); // Optmize mass with Max Thrusters
// Best thrusters
let th;
if (ship.standard[1].maxClass === 3) {
th = 'tz';
} else if (ship.standard[1].maxClass === 2) {
th = 'u0';
} else {
th = ship.standard[1].maxClass + 'A';
}
ship.optimizeMass({ th, fsd: '2D', ft: '1C' }); // Optmize mass with Max Thrusters
summary.topSpeed = ship.topSpeed;
summary.topBoost = ship.topBoost;
summary.baseArmour = ship.armour;
@@ -139,19 +150,22 @@ export default class ShipyardPage extends Page {
className={cn({ highlighted: noTouch && this.state.shipId === s.id })}
onMouseEnter={noTouch && this._highlightShip.bind(this, s.id)}
>
<td className='le'>{s.manufacturer}</td>
<td className='cap'>{translate(SizeMap[s.class])}</td>
<td className='ri'>{s.manufacturer}</td>
<td className='ri'>{fInt(s.retailCost)}</td>
<td className='ri cap'>{translate(SizeMap[s.class])}</td>
<td className='ri'>{fInt(s.crew)}</td>
<td className='ri'>{s.masslock}</td>
<td className='ri'>{fInt(s.agility)}</td>
<td className='ri'>{fInt(s.hardness)}</td>
<td className='ri'>{fInt(s.crew)}</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.hullMass)}</td>
<td className='ri'>{fInt(s.speed)}</td>
<td className='ri'>{fInt(s.boost)}</td>
<td className='ri'>{fInt(s.baseArmour)}</td>
<td className='ri'>{fInt(s.baseShieldStrength)}{u.MJ}</td>
<td className='ri'>{fInt(s.topSpeed)}{u['m/s']}</td>
<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='ri'>{fInt(s.baseShieldStrength)}</td>
<td className='ri'>{fInt(s.topSpeed)}</td>
<td className='ri'>{fInt(s.topBoost)}</td>
<td className='ri'>{fRound(s.maxJumpRange)}</td>
<td className='ri'>{fInt(s.maxCargo)}</td>
<td className='cn'>{s.standard[0]}</td>
<td className='cn'>{s.standard[1]}</td>
<td className='cn'>{s.standard[2]}</td>
@@ -171,9 +185,6 @@ export default class ShipyardPage extends Page {
<td className={cn({ disabled: !s.int[5] })}>{s.int[5]}</td>
<td className={cn({ disabled: !s.int[6] })}>{s.int[6]}</td>
<td className={cn({ disabled: !s.int[7] })}>{s.int[7]}</td>
<td className='ri'>{fInt(s.hullMass)}{u.T}</td>
<td>{s.masslock}</td>
<td className='ri'>{fInt(s.retailCost)}{u.CR}</td>
</tr>;
}
@@ -236,7 +247,7 @@ export default class ShipyardPage extends Page {
let detailRows = new Array(shipSummaries.length);
for (let s of shipSummaries) {
detailRows[i] = this._shipRowElement(s, translate, units, fInt, fRound);
detailRows[i] = this._shipRowElement(s, translate, units, fInt, formats.f1);
shipRows[i] = (
<tr
key={i}
@@ -255,8 +266,14 @@ export default class ShipyardPage extends Page {
<div style={{ whiteSpace: 'nowrap', margin: '0 auto', fontSize: '0.8em', position: 'relative', display: 'inline-block', maxWidth: '100%' }}>
<table style={{ width: '12em', position: 'absolute', zIndex: 1 }}>
<thead>
<tr>
<th className='le rgt'>&nbsp;</th>
</tr>
<tr className='main'>
<th style={{ height: '2.6em', padding: '2px 0.4em 1px' }} className='sortable le rgt' onClick={sortShips('name')}>{translate('ship')}</th>
<th className='sortable le rgt' onClick={sortShips('name')}>{translate('ship')}</th>
</tr>
<tr>
<th className='le rgt invisible'>{units['m/s']}</th>
</tr>
</thead>
<tbody onMouseLeave={this._highlightShip.bind(this, null)}>
@@ -267,21 +284,23 @@ export default class ShipyardPage extends Page {
<table style={{ marginLeft: 'calc(12em - 1px)', zIndex: 0 }}>
<thead>
<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' onClick={sortShips('agility')}>{translate('agility')}</th>
<th rowSpan={2} className='sortable' onClick={sortShips('hardness')}>{translate('hardness')}</th>
<th rowSpan={2} className='sortable' onClick={sortShips('crew')}>{translate('crew')}</th>
<th rowSpan={3} className='sortable' onClick={sortShips('manufacturer')}>{translate('manufacturer')}</th>
<th>&nbsp;</th>
<th rowSpan={3} className='sortable' onClick={sortShips('class')}>{translate('size')}</th>
<th rowSpan={3} className='sortable' onClick={sortShips('crew')}>{translate('crew')}</th>
<th rowSpan={3} className='sortable' onMouseEnter={termtip.bind(null, 'mass lock factor')} onMouseLeave={hide} onClick={sortShips('masslock')} >{translate('MLF')}</th>
<th rowSpan={3} className='sortable' onClick={sortShips('agility')}>{translate('agility')}</th>
<th rowSpan={3} className='sortable' onMouseEnter={termtip.bind(null, 'hardness')} onMouseLeave={hide} onClick={sortShips('hardness')}>{translate('hrd')}</th>
<th>&nbsp;</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>
<th rowSpan={2} className='sortable' onMouseEnter={termtip.bind(null, 'mass lock factor')} onMouseLeave={hide} onClick={sortShips('masslock')} >{translate('MLF')}</th>
<th rowSpan={2} className='sortable' onClick={sortShips('retailCost')}>{translate('cost')}</th>
<th className='lft' colSpan={6}></th>
<th className='lft' colSpan={5}></th>
<th className='lft' colSpan={8}></th>
</tr>
<tr>
<th className='sortable lft' onClick={sortShips('retailCost')}>{translate('cost')}</th>
<th className='sortable lft' onClick={sortShips('hullMass')}>{translate('hull')}</th>
<th className='sortable lft' onClick={sortShips('speed')}>{translate('speed')}</th>
<th className='sortable' onClick={sortShips('boost')}>{translate('boost')}</th>
<th className='sortable' onClick={sortShips('baseArmour')}>{translate('armour')}</th>
@@ -292,6 +311,21 @@ 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='lft' colSpan={6}>{translate('core module classes')}</th>
<th colSpan={5} className='sortable lft' onClick={sortShips('hpCount')}>{translate('hardpoints')}</th>
<th colSpan={8} className='sortable lft' onClick={sortShips('intCount')}>{translate('internal compartments')}</th>
</tr>
<tr>
<th className='sortable lft' onClick={sortShips('retailCost')}>{units.CR}</th>
<th className='sortable lft' onClick={sortShips('hullMass')}>{units.T}</th>
<th className='sortable lft' onClick={sortShips('speed')}>{units['m/s']}</th>
<th className='sortable' onClick={sortShips('boost')}>{units['m/s']}</th>
<th>&nbsp;</th>
<th className='sortable' onClick={sortShips('baseShieldStrength')}>{units.MJ}</th>
<th className='sortable lft' onClick={sortShips('topSpeed')}>{units['m/s']}</th>
<th className='sortable' onClick={sortShips('topBoost')}>{units['m/s']}</th>
<th className='sortable' onClick={sortShips('maxJumpRange')}>{units.LY}</th>
<th className='sortable' onClick={sortShips('maxCargo')}>{units.T}</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>

View File

@@ -168,10 +168,10 @@ function normValues(minMass, optMass, maxMass, minMul, optMul, maxMul, mass, bas
const res = base * mul;
return [res * (1 - (engpip * 4)),
res * (1 - (engpip * 3)),
res * (1 - (engpip * 2)),
res * (1 - (engpip * 1)),
res];
res * (1 - (engpip * 3)),
res * (1 - (engpip * 2)),
res * (1 - (engpip * 1)),
res];
}
/**

View File

@@ -105,115 +105,115 @@ export const BulkheadNames = [
* @type {Array}
*/
export const ShipFacets = [
{ // 0
title: 'agility',
props: ['topPitch', 'topRoll', 'topYaw'],
lbls: ['pitch', 'roll', 'yaw'],
fmt: 'f1',
i: 0
},
{ // 1
title: 'speed',
props: ['topSpeed', 'topBoost'],
lbls: ['thrusters', 'boost'],
unit: 'm/s',
fmt: 'int',
i: 1
},
{ // 2
title: 'armour',
props: ['armour'],
fmt: 'int',
i: 2
},
{ // 3
title: 'shields',
props: ['shield'],
unit: 'MJ',
fmt: 'int',
i: 3
},
{ // 4
title: 'jump range',
props: ['unladenRange', 'fullTankRange', 'ladenRange'],
lbls: ['max', 'full tank', 'laden'],
unit: 'LY',
fmt: 'round',
i: 4
},
{ // 5
title: 'mass',
props: ['unladenMass', 'ladenMass'],
lbls: ['unladen', 'laden'],
unit: 'T',
fmt: 'round',
i: 5
},
{ // 6
title: 'cargo',
props: ['cargoCapacity'],
unit: 'T',
fmt: 'int',
i: 6
},
{ // 7
title: 'fuel',
props: ['fuelCapacity'],
unit: 'T',
fmt: 'int',
i: 7
},
{ // 8
title: 'power',
props: ['powerRetracted', 'powerDeployed', 'powerAvailable'],
lbls: ['retracted', 'deployed', 'available'],
unit: 'MW',
fmt: 'f2',
i: 8
},
{ // 9
title: 'cost',
props: ['totalCost'],
unit: 'CR',
fmt: 'int',
i: 9
},
{ // 10
title: 'fastest range',
props: ['unladenFastestRange', 'ladenFastestRange'],
lbls: ['unladen', 'laden'],
unit: 'LY',
fmt: 'round',
i: 10
},
{ // 11
title: 'DPS',
props: ['totalDps', 'totalExplDps', 'totalKinDps', 'totalThermDps'],
lbls: ['total', 'explosive', 'kinetic', 'thermal'],
fmt: 'round',
i: 11
},
{ // 14
title: 'Sustained DPS',
props: ['totalSDps', 'totalExplSDps', 'totalKinSDps', 'totalThermSDps'],
lbls: ['total', 'explosive', 'kinetic', 'thermal'],
fmt: 'round',
i: 14
},
{ // 12
title: 'EPS',
props: ['totalEps'],
lbls: ['EPS'],
fmt: 'round',
i: 12
},
{ // 13
title: 'HPS',
props: ['totalHps'],
lbls: ['HPS'],
fmt: 'round',
i: 13
}
{ // 0
title: 'agility',
props: ['topPitch', 'topRoll', 'topYaw'],
lbls: ['pitch', 'roll', 'yaw'],
fmt: 'f1',
i: 0
},
{ // 1
title: 'speed',
props: ['topSpeed', 'topBoost'],
lbls: ['thrusters', 'boost'],
unit: 'm/s',
fmt: 'int',
i: 1
},
{ // 2
title: 'armour',
props: ['armour'],
fmt: 'int',
i: 2
},
{ // 3
title: 'shields',
props: ['shield'],
unit: 'MJ',
fmt: 'int',
i: 3
},
{ // 4
title: 'jump range',
props: ['unladenRange', 'fullTankRange', 'ladenRange'],
lbls: ['max', 'full tank', 'laden'],
unit: 'LY',
fmt: 'round',
i: 4
},
{ // 5
title: 'mass',
props: ['unladenMass', 'ladenMass'],
lbls: ['unladen', 'laden'],
unit: 'T',
fmt: 'round',
i: 5
},
{ // 6
title: 'cargo',
props: ['cargoCapacity'],
unit: 'T',
fmt: 'int',
i: 6
},
{ // 7
title: 'fuel',
props: ['fuelCapacity'],
unit: 'T',
fmt: 'int',
i: 7
},
{ // 8
title: 'power',
props: ['powerRetracted', 'powerDeployed', 'powerAvailable'],
lbls: ['retracted', 'deployed', 'available'],
unit: 'MW',
fmt: 'f2',
i: 8
},
{ // 9
title: 'cost',
props: ['totalCost'],
unit: 'CR',
fmt: 'int',
i: 9
},
{ // 10
title: 'fastest range',
props: ['unladenFastestRange', 'ladenFastestRange'],
lbls: ['unladen', 'laden'],
unit: 'LY',
fmt: 'round',
i: 10
},
{ // 11
title: 'DPS',
props: ['totalDps', 'totalExplDps', 'totalKinDps', 'totalThermDps'],
lbls: ['total', 'explosive', 'kinetic', 'thermal'],
fmt: 'round',
i: 11
},
{ // 14
title: 'Sustained DPS',
props: ['totalSDps', 'totalExplSDps', 'totalKinSDps', 'totalThermSDps'],
lbls: ['total', 'explosive', 'kinetic', 'thermal'],
fmt: 'round',
i: 14
},
{ // 12
title: 'EPS',
props: ['totalEps'],
lbls: ['EPS'],
fmt: 'round',
i: 12
},
{ // 13
title: 'HPS',
props: ['totalHps'],
lbls: ['HPS'],
fmt: 'round',
i: 13
}
];
/**

View File

@@ -119,12 +119,11 @@ export default class ModuleSet {
/**
* Find the lightest Power Distributor that provides sufficient
* energy to boost.
* @param {number} boostEnergy [description]
* @param {number} boostEnergy The energy that is required to boost
* @return {Object} Power Distributor
*/
lightestPowerDist(boostEnergy) {
let pd = this.standard[4][0];
for (let p of this.standard[4]) {
if (p.mass < pd.mass && p.engcap > boostEnergy) {
pd = p;

View File

@@ -429,11 +429,45 @@ export default class Ship {
}
/**
* Clear blueprint for a module
* @param {Number} m The module for which to clear the modifications
* Set blueprint for a module
* @param {Object} m The module for which to set the blueprint
* @param {Object} bp The blueprint
*/
clearBlueprint(m) {
setModuleBlueprint(m, bp) {
m.blueprint = bp;
this.updateModificationsString();
}
/**
* Clear blueprint for a module
* @param {Object} m The module for which to clear the blueprint
*/
clearModuleBlueprint(m) {
m.blueprint = {};
this.updateModificationsString();
}
/**
* Set special for a module
* @param {Object} m The module for which to set the blueprint
* @param {Object} special The special
*/
setModuleSpecial(m, special) {
if (m.blueprint) {
m.blueprint.special = special;
}
this.recalculateDps().recalculateHps().recalculateEps();
}
/**
* Clear special for a module
* @param {Object} m The module for which to clear the blueprint
*/
clearModuleSpecial(m) {
if (m.blueprint) {
m.blueprint.special = null;
}
this.recalculateDps().recalculateHps().recalculateEps();
}
/**
@@ -673,6 +707,11 @@ export default class Ship {
* @return {this} The current ship instance for chaining
*/
buildFrom(serializedString) {
if (!serializedString) {
// Empty serialized string; nothing to do
return this;
}
let standard = new Array(this.standard.length),
hardpoints = new Array(this.hardpoints.length),
internal = new Array(this.internal.length),
@@ -1445,16 +1484,20 @@ export default class Ship {
// Now work out the size of the binary buffer from our modifications array
let bufsize = 0;
for (let slot of slots) {
if (slot.length > 0) {
// Length is 1 for the slot ID, 10 for the blueprint name and grade, 5 for each modification, and 1 for the end marker
bufsize = bufsize + 1 + 10 + (5 * slot.length) + 1;
}
}
for (let special of specials) {
if (special) {
// Length is 5 for each special
bufsize += 5;
for (let i = 0; i < slots.length; i++) {
if (slots[i].length > 0 || (blueprints[i] && blueprints[i].id)) {
// Length is 1 for the slot ID, 5 for each modification, 1 for the end marker of the modifications and 1 for the end marker of the slot
bufsize = bufsize + 1 + (5 * slots[i].length) + 1 + 1;
if (blueprints[i] && blueprints[i].id) {
// Additional 10 for the blueprint and grade
bufsize += 10;
}
if (specials[i]) {
// Additional 5 for each special
bufsize += 5;
}
}
}
@@ -1465,7 +1508,7 @@ export default class Ship {
let curpos = 0;
let i = 0;
for (let slot of slots) {
if (slot.length > 0) {
if (slot.length > 0 || (blueprints[i] && blueprints[i].id)) {
buffer.writeInt8(i, curpos++);
if (blueprints[i] && blueprints[i].id) {
buffer.writeInt8(MODIFICATION_ID_BLUEPRINT, curpos++);
@@ -1675,6 +1718,11 @@ export default class Ship {
.use(standard[4], pd) // Power Distributor
.use(standard[6], ft); // Fuel Tank
// Turn off nearly everything
if (m.fsdDisabled) this.setSlotEnabled(this.standard[2], false);
if (m.pdDisabled) this.setSlotEnabled(this.standard[4], false);
if (m.sDisabled) this.setSlotEnabled(this.standard[5], false);
// Thrusters and Powerplant must be determined after all other ModuleUtils are mounted
// Loop at least once to determine absolute lightest PD and TH
do {

View File

@@ -294,3 +294,88 @@ export function miner(ship, shielded) {
ship.useLightestStandard(standardOpts);
}
/**
* Racer Role
* @param {Ship} ship Ship instance
*/
export function racer(ship) {
let standardOpts = {},
usedSlots = [],
sgSlot,
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
// Cargo hatch can be disabled
ship.setSlotEnabled(ship.cargoHatch, false);
// Shield generator
const shieldOrder = [1, 2, 3, 4, 5, 6, 7, 8];
const shieldInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.sg)
.filter(a => a.maxClass >= sg.class)
.sort((a,b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass));
for (let i = 0; i < shieldInternals.length; i++) {
if (canMount(ship, shieldInternals[i], 'sg')) {
ship.use(shieldInternals[i], sg);
usedSlots.push(shieldInternals[i]);
sgSlot = shieldInternals[i];
break;
}
}
// Empty the hardpoints
for (let s of ship.hardpoints) {
ship.use(s, null);
}
// Empty the internals
for (let i = ship.internal.length; i--;) {
let slot = ship.internal[i];
if (usedSlots.indexOf(slot) == -1) {
ship.use(slot, null);
}
}
// Best thrusters
if (ship.standard[1].maxClass === 3) {
standardOpts.th = 'tz';
} else if (ship.standard[1].maxClass === 2) {
standardOpts.th = 'u0';
} else {
standardOpts.th = ship.standard[1].maxClass + 'A';
}
// Best power distributor for more boosting
standardOpts.pd = ship.standard[4].maxClass + 'A';
// Smallest possible FSD drive
standardOpts.fsd = '2D';
// Minimal fuel tank
standardOpts.ft = '1C';
// Disable nearly everything
standardOpts.fsdDisabled = true;
standardOpts.sDisabled = true;
standardOpts.pdDisabled = true;
standardOpts.lsDisabled = true;
ship.useLightestStandard(standardOpts);
// Apply engineering to each module
// ship.standard[1].m.blueprint = getBlueprint('Engine_Dirty', ship.standard[0]);
// ship.standard[1].m.blueprint.grade = 5;
// setBest(ship, ship.standard[1].m);
// ship.standard[3].m.blueprint = getBlueprint('LifeSupport_LightWeight', ship.standard[3]);
// ship.standard[3].m.blueprint.grade = 4;
// setBest(ship, ship.standard[3].m);
// ship.standard[4].m.blueprint = getBlueprint('PowerDistributor_PriorityEngines', ship.standard[4]);
// ship.standard[4].m.blueprint.grade = 3;
// setBest(ship, ship.standard[4].m);
// ship.standard[5].m.blueprint = getBlueprint('Sensor_Sensor_LightWeight', ship.standard[5]);
// ship.standard[5].m.blueprint.grade = 5;
// setBest(ship, ship.standard[5].m);
}

View File

@@ -87,6 +87,36 @@ export function blueprintTooltip(translate, blueprint, engineers, grp, m) {
);
}
}
// We also add in any benefits from specials that aren't covered above
if (m.blueprint && m.blueprint.special) {
for (const feature in Modifications.modifierActions[m.blueprint.special.edname]) {
if (!blueprint.features[feature] && !m.mods.feature) {
const featureDef = Modifications.modifications[feature];
let symbol = '';
if (feature === 'jitter') {
symbol = '°';
} else if (featureDef.type === 'percentage') {
symbol = '%';
}
let current = m.getModValue(feature);
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
current = Math.round(current / 10) / 10;
} else if (featureDef.type === 'numeric') {
current /= 100;
}
const currentIsBeneficial = isValueBeneficial(feature, current);
effects.push(
<tr key={feature}>
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
<td>&nbsp;</td>
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{current}{symbol}</td>
<td>&nbsp;</td>
</tr>
);
}
}
}
}
let components;
if (!m) {
@@ -227,3 +257,110 @@ export function getBlueprint(name, module) {
}
return blueprint;
}
/**
* Provide 'worst' primary modifications
* @param {Object} ship The ship for which to perform the modifications
* @param {Object} m The module for which to perform the modifications
*/
export function setWorst(ship, m) {
ship.clearModifications(m);
const features = m.blueprint.grades[m.blueprint.grade].features;
for (const featureName in features) {
const value = features[featureName][0];
_setValue(ship, m, featureName, value);
}
}
/**
* Provide 'best' primary modifications
* @param {Object} ship The ship for which to perform the modifications
* @param {Object} m The module for which to perform the modifications
*/
export function setBest(ship, m) {
ship.clearModifications(m);
const features = m.blueprint.grades[m.blueprint.grade].features;
for (const featureName in features) {
const value = features[featureName][1];
_setValue(ship, m, featureName, value);
}
}
/**
* Provide 'extreme' primary modifications
* @param {Object} ship The ship for which to perform the modifications
* @param {Object} m The module for which to perform the modifications
*/
export function setExtreme(ship, m) {
ship.clearModifications(m);
const features = m.blueprint.grades[m.blueprint.grade].features;
for (const featureName in features) {
let value;
if (Modifications.modifications[featureName].higherbetter) {
// Higher is better, but is this making it better or worse?
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
value = features[featureName][0];
} else {
value = features[featureName][1];
}
} else {
// Higher is worse, but is this making it better or worse?
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
value = features[featureName][1];
} else {
value = features[featureName][0];
}
}
_setValue(ship, m, featureName, value);
}
}
/**
* Provide 'random' primary modifications
* @param {Object} ship The ship for which to perform the modifications
* @param {Object} m The module for which to perform the modifications
*/
export function setRandom(ship, m) {
ship.clearModifications(m);
// Pick a single value for our randomness
const mult = Math.random();
const features = m.blueprint.grades[m.blueprint.grade].features;
for (const featureName in features) {
let value;
if (Modifications.modifications[featureName].higherbetter) {
// Higher is better, but is this making it better or worse?
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
value = features[featureName][1] + ((features[featureName][0] - features[featureName][1]) * mult);
} else {
value = features[featureName][0] + ((features[featureName][1] - features[featureName][0]) * mult);
}
} else {
// Higher is worse, but is this making it better or worse?
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
value = features[featureName][0] + ((features[featureName][1] - features[featureName][0]) * mult);
} else {
value = features[featureName][1] + ((features[featureName][0] - features[featureName][1]) * mult);
}
}
_setValue(ship, m, featureName, value);
}
}
/**
* Set a modification feature value
* @param {Object} ship The ship for which to perform the modifications
* @param {Object} m The module for which to perform the modifications
* @param {string} featureName The feature being set
* @param {number} value The value being set for the feature
*/
function _setValue(ship, m, featureName, value) {
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);
} else {
ship.setModification(m, featureName, value);
}
}

View File

@@ -17,6 +17,7 @@ const SHIP_FD_NAME_TO_CORIOLIS_NAME = {
'Cutter': 'imperial_cutter',
'DiamondBackXL': 'diamondback_explorer',
'DiamondBack': 'diamondback',
'Dolphin': 'dolphin',
'Eagle': 'eagle',
'Empire_Courier': 'imperial_courier',
'Empire_Eagle': 'imperial_eagle',

View File

@@ -37,6 +37,10 @@ thead {
&.rgt {
border-right: 1px solid @primary-bg;
}
&.invisible {
color: @primary-disabled;
}
}
}

View File

@@ -18,6 +18,7 @@ CopyDirPlugin.prototype.apply = function(compiler) {
};
module.exports = {
cache: true,
entry: {
app: ['babel-polyfill', path.resolve(__dirname, 'src/app/index')],
lib: ['d3', 'react', 'react-dom', 'classnames', 'fbemitter', 'lz-string']
@@ -76,7 +77,7 @@ module.exports = {
rules: [
{ test: /\.css$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader'}) },
{ test: /\.less$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader',use: 'css-loader!less-loader'}) },
{ test: /\.(js|jsx)$/, loaders: [ 'babel-loader' ], include: path.join(__dirname, 'src') },
{ test: /\.(js|jsx)$/, loader: 'babel-loader?cacheDirectory=true', include: path.join(__dirname, 'src') },
{ test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff' },
{ test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff' },
{ test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/octet-stream' },