Compare commits

..

13 Commits

Author SHA1 Message Date
willyb321
1d544099f6 Merge branch 'release/2.9.15' 2018-05-30 07:43:16 +10:00
willyb321
49a6c5f2c4 Merge branch 'release/2.9.14' 2018-05-29 07:03:18 +10:00
willyb321
298eaa8b4b Merge remote-tracking branch 'origin/develop' 2018-05-03 10:58:46 +10:00
willyb321
7b87038a8c Merge branch 'develop' 2018-05-03 07:39:08 +10:00
willyb321
fdc9171c69 Merge branch 'release/2.9.13' 2018-05-03 07:14:53 +10:00
willyb321
f43bd100e6 Merge branch 'release/2.9.12' 2018-04-28 12:16:21 +10:00
willyb321
fbba0e3ea5 Merge branch 'release/2.9.11' 2018-04-26 09:21:01 +10:00
willyb321
b15695128f Merge branch 'release/release/v2.9.10' 2018-04-25 20:00:47 +10:00
willyb321
0870b90443 Merge branch 'release/2.9.8' 2018-04-23 07:38:34 +10:00
willyb321
48ccab152b Merge branch 'release/2.9.7' 2018-04-22 12:27:20 +10:00
willyb321
f3bc900f16 Merge branch 'release/2.9.6' 2018-04-22 07:00:47 +10:00
willyb321
ec148847a9 Merge branch 'develop' 2018-04-21 11:39:19 +10:00
willyb321
0474af912a Merge branch 'release/2.9.5' 2018-04-21 11:05:29 +10:00
35 changed files with 1840 additions and 2274 deletions

View File

@@ -5,7 +5,7 @@
"jsx": true, "jsx": true,
"classes": true, "classes": true,
"modules": true "modules": true
} },
}, },
"env": { "env": {
"browser": true, "browser": true,
@@ -33,6 +33,7 @@
"ClassDeclaration": true "ClassDeclaration": true
} }
}], }],
"no-console": 2,
"brace-style": [2, "1tbs", { "allowSingleLine": true }], "brace-style": [2, "1tbs", { "allowSingleLine": true }],
"comma-style": [2, "last"], "comma-style": [2, "last"],
"indent": [2, 2, { "SwitchCase": 1, "VariableDeclarator": 2 }], "indent": [2, 2, { "SwitchCase": 1, "VariableDeclarator": 2 }],

View File

@@ -8,8 +8,7 @@ cache:
directories: directories:
- node_modules - node_modules
before_install: before_script:
- git clone https://github.com/EDCD/coriolis-data.git ../coriolis-data
script: script:
- npm run lint - npm run lint

11
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{ {
"name": "coriolis_shipyard", "name": "coriolis_shipyard",
"version": "2.9.16", "version": "2.9.15",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@@ -10760,15 +10760,6 @@
"prop-types": "^15.5.10" "prop-types": "^15.5.10"
} }
}, },
"react-ga": {
"version": "2.5.3",
"resolved": "https://registry.npmjs.org/react-ga/-/react-ga-2.5.3.tgz",
"integrity": "sha512-25wvPv1PVLDLhw1gEYP33h0V2sJHahKMfUCAxhq8JPYmNQwx1fcjJAkJk+WmSqGN93lHLhExDkxy3SQizQnx3A==",
"requires": {
"prop-types": "^15.6.0",
"react": "^15.6.2 || ^16.0"
}
},
"react-measure": { "react-measure": {
"version": "1.4.7", "version": "1.4.7",
"resolved": "https://registry.npmjs.org/react-measure/-/react-measure-1.4.7.tgz", "resolved": "https://registry.npmjs.org/react-measure/-/react-measure-1.4.7.tgz",

View File

@@ -1,6 +1,6 @@
{ {
"name": "coriolis_shipyard", "name": "coriolis_shipyard",
"version": "2.9.16", "version": "2.9.15",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/EDCD/coriolis" "url": "https://github.com/EDCD/coriolis"
@@ -109,7 +109,6 @@
"prop-types": "^15.5.8", "prop-types": "^15.5.8",
"react": "^15.5.4", "react": "^15.5.4",
"react-dom": "^15.5.4", "react-dom": "^15.5.4",
"react-ga": "^2.5.3",
"react-number-editor": "Athanasius/react-number-editor.git#miggy", "react-number-editor": "Athanasius/react-number-editor.git#miggy",
"recharts": "^0.22.3", "recharts": "^0.22.3",
"superagent": "^3.5.2" "superagent": "^3.5.2"

View File

@@ -93,8 +93,8 @@ export default class Coriolis extends React.Component {
// Need to decode and gunzip the data, then build the ship // Need to decode and gunzip the data, then build the ship
const data = zlib.inflate(new Buffer(r.params.data, 'base64'), { to: 'string' }); const data = zlib.inflate(new Buffer(r.params.data, 'base64'), { to: 'string' });
const json = JSON.parse(data); const json = JSON.parse(data);
console.info('Ship import data: '); console.log('Ship import data: ');
console.info(json); console.log(json);
let ship; let ship;
if (json && json.modules) { if (json && json.modules) {
ship = CompanionApiUtils.shipFromJson(json); ship = CompanionApiUtils.shipFromJson(json);
@@ -356,7 +356,7 @@ export default class Coriolis extends React.Component {
<div className="right cap"> <div className="right cap">
<a href="https://github.com/EDCD/coriolis" target="_blank" title="Coriolis Github Project">{window.CORIOLIS_VERSION} - {window.CORIOLIS_DATE}</a> <a href="https://github.com/EDCD/coriolis" target="_blank" title="Coriolis Github Project">{window.CORIOLIS_VERSION} - {window.CORIOLIS_DATE}</a>
<br/> <br/>
<a href={'https://github.com/EDCD/coriolis/compare/edcd:develop@{' + window.CORIOLIS_DATE + '}...edcd:develop'} target="_blank" title={'Coriolis Commits since' + window.CORIOLIS_DATE}>Commits since last release ({window.CORIOLIS_DATE})</a> <a href={"https://github.com/EDCD/coriolis/compare/edcd:develop@{" + window.CORIOLIS_DATE + "}...edcd:develop"} target="_blank" title={"Coriolis Commits since" + window.CORIOLIS_DATE}>Commits since last release ({window.CORIOLIS_DATE})</a>
</div> </div>
</footer> </footer>
</div>; </div>;

View File

@@ -1,6 +1,5 @@
import Persist from './stores/Persist'; import Persist from './stores/Persist';
import ReactGA from 'react-ga';
ReactGA.initialize('UA-55840909-18');
let standalone = undefined; let standalone = undefined;
/** /**
@@ -258,7 +257,9 @@ Route.prototype.match = function(path, params) {
* @param {string} path Path to track * @param {string} path Path to track
*/ */
function gaTrack(path) { function gaTrack(path) {
ReactGA.pageview(path); if (window.ga) {
window.ga('send', 'pageview', path);
}
} }
/** /**

View File

@@ -210,7 +210,7 @@ export default class AvailableModulesMenu extends TranslatedComponent {
} }
} }
let trackingFocus = false; let trackingFocus = false;
return { list, currentGroup, trackingFocus }; return { list, currentGroup, trackingFocus};
} }
/** /**
@@ -222,8 +222,6 @@ export default class AvailableModulesMenu extends TranslatedComponent {
* @param {function} onSelect Select/Mount callback * @param {function} onSelect Select/Mount callback
* @param {string} grp Group name * @param {string} grp Group name
* @param {Array} modules Available modules * @param {Array} modules Available modules
* @param {string} firstSlotId id of first slot item
* @param {string} lastSlotId id of last slot item
* @return {React.Component} Available Module Group contents * @return {React.Component} Available Module Group contents
*/ */
_buildGroup(translate, mountedModule, warningFunc, mass, onSelect, grp, modules, firstSlotId, lastSlotId) { _buildGroup(translate, mountedModule, warningFunc, mass, onSelect, grp, modules, firstSlotId, lastSlotId) {
@@ -242,7 +240,7 @@ export default class AvailableModulesMenu extends TranslatedComponent {
let m = sortedModules[i]; let m = sortedModules[i];
let mount = null; let mount = null;
let disabled = false; let disabled = false;
prevName = m.name; prevName = m.name
if (ModuleUtils.isShieldGenerator(m.grp)) { if (ModuleUtils.isShieldGenerator(m.grp)) {
// Shield generators care about maximum hull mass // Shield generators care about maximum hull mass
disabled = mass > m.maxmass; disabled = mass > m.maxmass;
@@ -369,13 +367,14 @@ export default class AvailableModulesMenu extends TranslatedComponent {
* @param {Function} select Select module callback * @param {Function} select Select module callback
* @param {SyntheticEvent} event Event * @param {SyntheticEvent} event Event
*/ */
_keyDown(select, event) { _keyDown(select, event) {
let className = event.currentTarget.attributes['class'].value; var className = event.currentTarget.attributes['class'].value;
if (event.key == 'Enter' && className.indexOf('disabled') < 0 && className.indexOf('active') < 0) { if (event.key == 'Enter' && className.indexOf('disabled') < 0 && className.indexOf('active') < 0) {
select(); select();
return; return
} }
let elemId = event.currentTarget.attributes['data-id'].value; var elemId = event.currentTarget.attributes['data-id'].value;
if (className.indexOf('disabled') < 0 && event.key == 'Tab') { if (className.indexOf('disabled') < 0 && event.key == 'Tab') {
if (event.shiftKey && elemId == this.firstSlotId) { if (event.shiftKey && elemId == this.firstSlotId) {
event.preventDefault(); event.preventDefault();
@@ -392,11 +391,10 @@ export default class AvailableModulesMenu extends TranslatedComponent {
/** /**
* Key Up * Key Up
* @param {Function} select Select module callback *
* @param {SytheticEvent} event Event
*/ */
_keyUp(select,event) { _keyUp(select,event) {
// nothing here yet //nothing here yet
} }
/** /**
@@ -465,11 +463,11 @@ export default class AvailableModulesMenu extends TranslatedComponent {
this.slotItems[this.firstSlotId].focus(); this.slotItems[this.firstSlotId].focus();
} }
} }
/**
* Handle focus if the component updates
*
*/
componentWillUnmount() { componentWillUnmount() {
/**
* Set focus to slot element ref (if we have one) after modules component unmounts
*/
if(this.props.slotDiv) { if(this.props.slotDiv) {
this.props.slotDiv.focus(); this.props.slotDiv.focus();
} }
@@ -489,6 +487,7 @@ export default class AvailableModulesMenu extends TranslatedComponent {
* @return {React.Component} List * @return {React.Component} List
*/ */
render() { render() {
console.log("Tracking focus? " + this.state.trackingFocus);
return ( return (
<div ref={node => this.node = node} <div ref={node => this.node = node}
className={cn('select', this.props.className)} className={cn('select', this.props.className)}

View File

@@ -17,25 +17,14 @@ export default class HardpointSlotSection extends SlotSection {
*/ */
constructor(props, context) { constructor(props, context) {
super(props, context, 'hardpoints', 'hardpoints'); super(props, context, 'hardpoints', 'hardpoints');
this._empty = this._empty.bind(this);
this.selectedRefId = null;
this.firstRefId = 'emptyall';
this.lastRefId = 'nl-F';
}
/** this._empty = this._empty.bind(this);
* Handle focus when component updates
* @param {Object} prevProps React Component properties
*/
componentDidUpdate(prevProps) {
this._handleSectionFocus(prevProps,this.firstRefId, this.lastRefId);
} }
/** /**
* Empty all slots * Empty all slots
*/ */
_empty() { _empty() {
this.selectedRefId = 'emptyall';
this.props.ship.emptyWeapons(); this.props.ship.emptyWeapons();
this.props.onChange(); this.props.onChange();
this._close(); this._close();
@@ -48,7 +37,6 @@ export default class HardpointSlotSection extends SlotSection {
* @param {SyntheticEvent} event Event * @param {SyntheticEvent} event Event
*/ */
_fill(group, mount, event) { _fill(group, mount, event) {
this.selectedRefId = group + '-' + mount;
this.props.ship.useWeapon(group, mount, null, event.getModifierState('Alt')); this.props.ship.useWeapon(group, mount, null, event.getModifierState('Alt'));
this.props.onChange(); this.props.onChange();
this._close(); this._close();
@@ -107,52 +95,52 @@ export default class HardpointSlotSection extends SlotSection {
return <div className='select hardpoint' onClick={(e) => e.stopPropagation()} onContextMenu={stopCtxPropagation}> return <div className='select hardpoint' onClick={(e) => e.stopPropagation()} onContextMenu={stopCtxPropagation}>
<ul> <ul>
<li className='lc' tabIndex='0' onClick={this._empty} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['emptyall'] = smRef}>{translate('empty all')}</li> <li className='lc' onClick={this._empty}>{translate('empty all')}</li>
<li className='optional-hide' style={{ textAlign: 'center', marginTop: '1em' }}>{translate('PHRASE_ALT_ALL')}</li> <li className='optional-hide' style={{ textAlign: 'center', marginTop: '1em' }}>{translate('PHRASE_ALT_ALL')}</li>
</ul> </ul>
<div className='select-group cap'>{translate('pl')}</div> <div className='select-group cap'>{translate('pl')}</div>
<ul> <ul>
<li className='c' tabIndex='0' onClick={_fill.bind(this, 'pl', 'F')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['pl-F'] = smRef}><MountFixed className='lg'/></li> <li className='c' onClick={_fill.bind(this, 'pl', 'F')}><MountFixed className='lg'/></li>
<li className='c' tabIndex='0' onClick={_fill.bind(this, 'pl', 'G')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['pl-G'] = smRef}><MountGimballed className='lg'/></li> <li className='c' onClick={_fill.bind(this, 'pl', 'G')}><MountGimballed className='lg'/></li>
<li className='c' tabIndex='0' onClick={_fill.bind(this, 'pl', 'T')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['pl-T'] = smRef}><MountTurret className='lg'/></li> <li className='c' onClick={_fill.bind(this, 'pl', 'T')}><MountTurret className='lg'/></li>
</ul> </ul>
<div className='select-group cap'>{translate('ul')}</div> <div className='select-group cap'>{translate('ul')}</div>
<ul> <ul>
<li className='c' tabIndex='0' onClick={_fill.bind(this, 'ul', 'F')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['ul-F'] = smRef}><MountFixed className='lg'/></li> <li className='c' onClick={_fill.bind(this, 'ul', 'F')}><MountFixed className='lg'/></li>
<li className='c' tabIndex='0' onClick={_fill.bind(this, 'ul', 'G')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['ul-G'] = smRef}><MountGimballed className='lg'/></li> <li className='c' onClick={_fill.bind(this, 'ul', 'G')}><MountGimballed className='lg'/></li>
<li className='c' tabIndex='0' onClick={_fill.bind(this, 'ul', 'T')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['ul-T'] = smRef}><MountTurret className='lg'/></li> <li className='c' onClick={_fill.bind(this, 'ul', 'T')}><MountTurret className='lg'/></li>
</ul> </ul>
<div className='select-group cap'>{translate('bl')}</div> <div className='select-group cap'>{translate('bl')}</div>
<ul> <ul>
<li className='c' tabIndex='0' onClick={_fill.bind(this, 'bl', 'F')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['bl-F'] = smRef}><MountFixed className='lg'/></li> <li className='c' onClick={_fill.bind(this, 'bl', 'F')}><MountFixed className='lg'/></li>
<li className='c' tabIndex='0' onClick={_fill.bind(this, 'bl', 'G')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['bl-G'] = smRef}><MountGimballed className='lg'/></li> <li className='c' onClick={_fill.bind(this, 'bl', 'G')}><MountGimballed className='lg'/></li>
<li className='c' tabIndex='0' onClick={_fill.bind(this, 'bl', 'T')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['bl-T'] = smRef}><MountTurret className='lg'/></li> <li className='c' onClick={_fill.bind(this, 'bl', 'T')}><MountTurret className='lg'/></li>
</ul> </ul>
<div className='select-group cap'>{translate('mc')}</div> <div className='select-group cap'>{translate('mc')}</div>
<ul> <ul>
<li className='c' tabIndex='0' onClick={_fill.bind(this, 'mc', 'F')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['mc-F'] = smRef}><MountFixed className='lg'/></li> <li className='c' onClick={_fill.bind(this, 'mc', 'F')}><MountFixed className='lg'/></li>
<li className='c' tabIndex='0' onClick={_fill.bind(this, 'mc', 'G')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['mc-G'] = smRef}><MountGimballed className='lg'/></li> <li className='c' onClick={_fill.bind(this, 'mc', 'G')}><MountGimballed className='lg'/></li>
<li className='c' tabIndex='0' onClick={_fill.bind(this, 'mc', 'T')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['mc-T'] = smRef}><MountTurret className='lg'/></li> <li className='c' onClick={_fill.bind(this, 'mc', 'T')}><MountTurret className='lg'/></li>
</ul> </ul>
<div className='select-group cap'>{translate('c')}</div> <div className='select-group cap'>{translate('c')}</div>
<ul> <ul>
<li className='c' tabIndex='0' onClick={_fill.bind(this, 'c', 'F')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['c-F'] = smRef}><MountFixed className='lg'/></li> <li className='c' onClick={_fill.bind(this, 'c', 'F')}><MountFixed className='lg'/></li>
<li className='c' tabIndex='0' onClick={_fill.bind(this, 'c', 'G')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['c-G'] = smRef}><MountGimballed className='lg'/></li> <li className='c' onClick={_fill.bind(this, 'c', 'G')}><MountGimballed className='lg'/></li>
<li className='c' tabIndex='0' onClick={_fill.bind(this, 'c', 'T')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['c-T'] = smRef}><MountTurret className='lg'/></li> <li className='c' onClick={_fill.bind(this, 'c', 'T')}><MountTurret className='lg'/></li>
</ul> </ul>
<div className='select-group cap'>{translate('fc')}</div> <div className='select-group cap'>{translate('fc')}</div>
<ul> <ul>
<li className='c' tabIndex='0' onClick={_fill.bind(this, 'fc', 'F')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['fc-F'] = smRef}><MountFixed className='lg'/></li> <li className='c' onClick={_fill.bind(this, 'fc', 'F')}><MountFixed className='lg'/></li>
<li className='c' tabIndex='0' onClick={_fill.bind(this, 'fc', 'G')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['fc-G'] = smRef}><MountGimballed className='lg'/></li> <li className='c' onClick={_fill.bind(this, 'fc', 'G')}><MountGimballed className='lg'/></li>
<li className='c' tabIndex='0' onClick={_fill.bind(this, 'fc', 'T')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['fc-T'] = smRef}><MountTurret className='lg'/></li> <li className='c' onClick={_fill.bind(this, 'fc', 'T')}><MountTurret className='lg'/></li>
</ul> </ul>
<div className='select-group cap'>{translate('pa')}</div> <div className='select-group cap'>{translate('pa')}</div>
<ul> <ul>
<li className='lc' tabIndex='0' onClick={_fill.bind(this, 'pa', 'F')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['pa-F'] = smRef}>{translate('pa')}</li> <li className='lc' onClick={_fill.bind(this, 'pa', 'F')}>{translate('pa')}</li>
</ul> </ul>
<div className='select-group cap'>{translate('nl')}</div> <div className='select-group cap'>{translate('nl')}</div>
<ul> <ul>
<li className='lc' tabIndex='0' onClick={_fill.bind(this, 'nl', 'F')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['nl-F'] = smRef}>{translate('nl')}</li> <li className='lc' onClick={_fill.bind(this, 'nl', 'F')}>{translate('nl')}</li>
</ul> </ul>
</div>; </div>;
} }

View File

@@ -505,8 +505,8 @@ export default class Header extends TranslatedComponent {
return ( return (
<header> <header>
{this.props.appCacheUpdate && <div id="app-update" onClick={() => window.location.reload() }>{translate('PHRASE_UPDATE_RDY')}</div>} {this.props.appCacheUpdate && <div id="app-update" onClick={() => window.location.reload() }>{translate('PHRASE_UPDATE_RDY')}</div>}
{this.props.appCacheUpdate ? <a className={'view-changes'} href={'https://github.com/EDCD/coriolis/compare/edcd:develop@{' + window.CORIOLIS_DATE + '}...edcd:develop'} target="_blank"> {this.props.appCache ? <a className={"view-changes"} href={"https://github.com/EDCD/coriolis/compare/edcd:develop@{" + window.CORIOLIS_DATE + "}...edcd:develop"} target="_blank">
{'View Release Changes'} {"View Release Changes"}
</a> : null} </a> : null}
<Link className='l' href='/' style={{ marginRight: '1em' }} title='Home'><CoriolisLogo className='icon xl' /></Link> <Link className='l' href='/' style={{ marginRight: '1em' }} title='Home'><CoriolisLogo className='icon xl' /></Link>

View File

@@ -21,6 +21,8 @@ export default class InternalSlot extends Slot {
* @param {Object} u Localized Units Map * @param {Object} u Localized Units Map
* @return {React.Component} Slot contents * @return {React.Component} Slot contents
*/ */
_getSlotDetails(m, enabled, translate, formats, u) { _getSlotDetails(m, enabled, translate, formats, u) {
if (m) { if (m) {
let classRating = m.class + m.rating; let classRating = m.class + m.rating;

View File

@@ -18,6 +18,7 @@ export default class InternalSlotSection extends SlotSection {
*/ */
constructor(props, context) { constructor(props, context) {
super(props, context, 'internal', 'optional internal'); super(props, context, 'internal', 'optional internal');
this._empty = this._empty.bind(this); this._empty = this._empty.bind(this);
this._fillWithCargo = this._fillWithCargo.bind(this); this._fillWithCargo = this._fillWithCargo.bind(this);
this._fillWithCells = this._fillWithCells.bind(this); this._fillWithCells = this._fillWithCells.bind(this);
@@ -28,24 +29,12 @@ export default class InternalSlotSection extends SlotSection {
this._fillWithFirstClassCabins = this._fillWithFirstClassCabins.bind(this); this._fillWithFirstClassCabins = this._fillWithFirstClassCabins.bind(this);
this._fillWithBusinessClassCabins = this._fillWithBusinessClassCabins.bind(this); this._fillWithBusinessClassCabins = this._fillWithBusinessClassCabins.bind(this);
this._fillWithEconomyClassCabins = this._fillWithEconomyClassCabins.bind(this); this._fillWithEconomyClassCabins = this._fillWithEconomyClassCabins.bind(this);
this.selectedRefId = null;
this.firstRefId = 'emptyall';
this.lastRefId = this.sectionRefArr['pcq'] ? 'pcq' : 'pcm';
}
/**
* Handle focus when component updates
* @param {Object} prevProps React Component properties
*/
componentDidUpdate(prevProps) {
this._handleSectionFocus(prevProps,this.firstRefId, this.lastRefId);
} }
/** /**
* Empty all slots * Empty all slots
*/ */
_empty() { _empty() {
this.selectedRefId = 'emptyall';
this.props.ship.emptyInternal(); this.props.ship.emptyInternal();
this.props.onChange(); this.props.onChange();
this._close(); this._close();
@@ -56,7 +45,6 @@ export default class InternalSlotSection extends SlotSection {
* @param {SyntheticEvent} event Event * @param {SyntheticEvent} event Event
*/ */
_fillWithCargo(event) { _fillWithCargo(event) {
this.selectedRefId = 'cargo';
let clobber = event.getModifierState('Alt'); let clobber = event.getModifierState('Alt');
let ship = this.props.ship; let ship = this.props.ship;
ship.internal.forEach((slot) => { ship.internal.forEach((slot) => {
@@ -73,7 +61,6 @@ export default class InternalSlotSection extends SlotSection {
* @param {SyntheticEvent} event Event * @param {SyntheticEvent} event Event
*/ */
_fillWithFuelTanks(event) { _fillWithFuelTanks(event) {
this.selectedRefId = 'ft';
let clobber = event.getModifierState('Alt'); let clobber = event.getModifierState('Alt');
let ship = this.props.ship; let ship = this.props.ship;
ship.internal.forEach((slot) => { ship.internal.forEach((slot) => {
@@ -90,7 +77,6 @@ export default class InternalSlotSection extends SlotSection {
* @param {SyntheticEvent} event Event * @param {SyntheticEvent} event Event
*/ */
_fillWithLuxuryCabins(event) { _fillWithLuxuryCabins(event) {
this.selectedRefId = 'pcq';
let clobber = event.getModifierState('Alt'); let clobber = event.getModifierState('Alt');
let ship = this.props.ship; let ship = this.props.ship;
ship.internal.forEach((slot) => { ship.internal.forEach((slot) => {
@@ -107,7 +93,6 @@ export default class InternalSlotSection extends SlotSection {
* @param {SyntheticEvent} event Event * @param {SyntheticEvent} event Event
*/ */
_fillWithFirstClassCabins(event) { _fillWithFirstClassCabins(event) {
this.selectedRefId = 'pcm';
let clobber = event.getModifierState('Alt'); let clobber = event.getModifierState('Alt');
let ship = this.props.ship; let ship = this.props.ship;
ship.internal.forEach((slot) => { ship.internal.forEach((slot) => {
@@ -124,7 +109,6 @@ export default class InternalSlotSection extends SlotSection {
* @param {SyntheticEvent} event Event * @param {SyntheticEvent} event Event
*/ */
_fillWithBusinessClassCabins(event) { _fillWithBusinessClassCabins(event) {
this.selectedRefId = 'pci';
let clobber = event.getModifierState('Alt'); let clobber = event.getModifierState('Alt');
let ship = this.props.ship; let ship = this.props.ship;
ship.internal.forEach((slot) => { ship.internal.forEach((slot) => {
@@ -141,7 +125,6 @@ export default class InternalSlotSection extends SlotSection {
* @param {SyntheticEvent} event Event * @param {SyntheticEvent} event Event
*/ */
_fillWithEconomyClassCabins(event) { _fillWithEconomyClassCabins(event) {
this.selectedRefId = 'pce';
let clobber = event.getModifierState('Alt'); let clobber = event.getModifierState('Alt');
let ship = this.props.ship; let ship = this.props.ship;
ship.internal.forEach((slot) => { ship.internal.forEach((slot) => {
@@ -158,7 +141,6 @@ export default class InternalSlotSection extends SlotSection {
* @param {SyntheticEvent} event Event * @param {SyntheticEvent} event Event
*/ */
_fillWithCells(event) { _fillWithCells(event) {
this.selectedRefId = 'scb';
let clobber = event.getModifierState('Alt'); let clobber = event.getModifierState('Alt');
let ship = this.props.ship; let ship = this.props.ship;
let chargeCap = 0; // Capacity of single activation let chargeCap = 0; // Capacity of single activation
@@ -178,7 +160,6 @@ export default class InternalSlotSection extends SlotSection {
* @param {SyntheticEvent} event Event * @param {SyntheticEvent} event Event
*/ */
_fillWithArmor(event) { _fillWithArmor(event) {
this.selectedRefId = 'hr';
let clobber = event.getModifierState('Alt'); let clobber = event.getModifierState('Alt');
let ship = this.props.ship; let ship = this.props.ship;
ship.internal.forEach((slot) => { ship.internal.forEach((slot) => {
@@ -195,7 +176,6 @@ export default class InternalSlotSection extends SlotSection {
* @param {SyntheticEvent} event Event * @param {SyntheticEvent} event Event
*/ */
_fillWithModuleReinforcementPackages(event) { _fillWithModuleReinforcementPackages(event) {
this.selectedRefId = 'mrp';
let clobber = event.getModifierState('Alt'); let clobber = event.getModifierState('Alt');
let ship = this.props.ship; let ship = this.props.ship;
ship.internal.forEach((slot) => { ship.internal.forEach((slot) => {
@@ -260,16 +240,16 @@ export default class InternalSlotSection extends SlotSection {
_getSectionMenu(translate, ship) { _getSectionMenu(translate, ship) {
return <div className='select' onClick={e => e.stopPropagation()} onContextMenu={stopCtxPropagation}> return <div className='select' onClick={e => e.stopPropagation()} onContextMenu={stopCtxPropagation}>
<ul> <ul>
<li className='lc' tabIndex='0' onClick={this._empty} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['emptyall'] = smRef}>{translate('empty all')}</li> <li className='lc' onClick={this._empty}>{translate('empty all')}</li>
<li className='lc' tabIndex='0' onClick={this._fillWithCargo} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['cargo'] = smRef}>{translate('cargo')}</li> <li className='lc' onClick={this._fillWithCargo}>{translate('cargo')}</li>
<li className='lc' tabIndex='0' onClick={this._fillWithCells} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['scb'] = smRef}>{translate('scb')}</li> <li className='lc' onClick={this._fillWithCells}>{translate('scb')}</li>
<li className='lc' tabIndex='0' onClick={this._fillWithArmor} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['hr'] = smRef}>{translate('hr')}</li> <li className='lc' onClick={this._fillWithArmor}>{translate('hr')}</li>
<li className='lc' tabIndex='0' onClick={this._fillWithModuleReinforcementPackages} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['mrp'] = smRef}>{translate('mrp')}</li> <li className='lc' onClick={this._fillWithModuleReinforcementPackages}>{translate('mrp')}</li>
<li className='lc' tabIndex='0' onClick={this._fillWithFuelTanks} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['ft'] = smRef}>{translate('ft')}</li> <li className='lc' onClick={this._fillWithFuelTanks}>{translate('ft')}</li>
<li className='lc' tabIndex='0' onClick={this._fillWithEconomyClassCabins} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['pce'] = smRef}>{translate('pce')}</li> <li className='lc' onClick={this._fillWithEconomyClassCabins}>{translate('pce')}</li>
<li className='lc' tabIndex='0' onClick={this._fillWithBusinessClassCabins} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['pci'] = smRef}>{translate('pci')}</li> <li className='lc' onClick={this._fillWithBusinessClassCabins}>{translate('pci')}</li>
<li className='lc' tabIndex='0' onClick={this._fillWithFirstClassCabins} onKeyDown={ship.luxuryCabins ? '' : this._keyDown} ref={smRef => this.sectionRefArr['pcm'] = smRef}>{translate('pcm')}</li> <li className='lc' onClick={this._fillWithFirstClassCabins}>{translate('pcm')}</li>
{ ship.luxuryCabins ? <li className='lc' tabIndex='0' onClick={this._fillWithLuxuryCabins} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['pcq'] = smRef}>{translate('pcq')}</li> : ''} { ship.luxuryCabins ? <li className='lc' onClick={this._fillWithLuxuryCabins}>{translate('pcq')}</li> : ''}
<li className='optional-hide' style={{ textAlign: 'center', marginTop: '1em' }}>{translate('PHRASE_ALT_ALL')}</li> <li className='optional-hide' style={{ textAlign: 'center', marginTop: '1em' }}>{translate('PHRASE_ALT_ALL')}</li>
</ul> </ul>
</div>; </div>;

View File

@@ -50,7 +50,6 @@ export default class ModalPermalink extends TranslatedComponent {
<h3 >{translate('shortened')}</h3> <h3 >{translate('shortened')}</h3>
<input value={this.state.shortenedUrl} readOnly size={25} onFocus={ (e) => e.target.select() }/> <input value={this.state.shortenedUrl} readOnly size={25} onFocus={ (e) => e.target.select() }/>
<br/><br/> <br/><br/>
<p>s.orbis.zone is the new URL shortener domain, old eddp.co urls are considered end of life and could go down at any moment. Sorry for any inconvenience.</p>
<button className={'r dismiss cap'} onClick={this.context.hideModal}>{translate('close')}</button> <button className={'r dismiss cap'} onClick={this.context.hideModal}>{translate('close')}</button>
</div>; </div>;
} }

View File

@@ -1,120 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent';
import ShortenUrl from '../utils/ShortenUrl';
import Persist from '../stores/Persist';
/**
* Permalink modal
*/
export default class ModalShoppingList extends TranslatedComponent {
static propTypes = {
ship: PropTypes.object.isRequired
};
/**
* Constructor
* @param {Object} props React Component properties
*/
constructor(props) {
super(props);
this.state = {
matsList: '',
mats: {},
matsPerGrade: Persist.getRolls()
};
}
/**
* React component did mount
*/
componentDidMount() {
this.renderMats();
}
/**
* Convert mats object to string
*/
renderMats() {
const ship = this.props.ship;
let mats = {};
for (const module of ship.costList) {
if (module.type === 'SHIP') {
continue;
}
if (module.m && module.m.blueprint) {
if (!module.m.blueprint.grade || !module.m.blueprint.grades) {
continue;
}
for (const g in module.m.blueprint.grades) {
if (g > module.m.blueprint.grade) {
continue;
}
for (const i in module.m.blueprint.grades[g].components) {
if (mats[i]) {
mats[i] += module.m.blueprint.grades[g].components[i] * this.state.matsPerGrade[g];
} else {
mats[i] = module.m.blueprint.grades[g].components[i] * this.state.matsPerGrade[g];
}
}
}
}
}
let matsString = '';
for (const i in mats) {
if (!mats.hasOwnProperty(i)) {
continue;
}
if (mats[i] === 0) {
delete mats[i];
continue;
}
matsString += `${i}: ${mats[i]}\n`;
}
this.setState({ matsList: matsString, mats });
}
/**
* Handler for changing roll amounts
* @param {SyntheticEvent} e React Event
*/
changeHandler(e) {
let grade = e.target.id;
let newState = this.state.matsPerGrade;
newState[grade] = parseInt(e.target.value);
this.setState({ matsPerGrade: newState });
Persist.setRolls(newState);
this.renderMats();
}
/**
* Render the modal
* @return {React.Component} Modal Content
*/
render() {
let translate = this.context.language.translate;
this.changeHandler = this.changeHandler.bind(this);
return <div className='modal' onClick={ (e) => e.stopPropagation() }>
<h2>{translate('PHRASE_SHOPPING_MATS')}</h2>
<label>Grade 1 rolls </label>
<input id={1} type={'number'} min={0} defaultValue={this.state.matsPerGrade[1]} onChange={this.changeHandler} />
<br/>
<label>Grade 2 rolls </label>
<input id={2} type={'number'} min={0} defaultValue={this.state.matsPerGrade[2]} onChange={this.changeHandler} />
<br/>
<label>Grade 3 rolls </label>
<input id={3} type={'number'} min={0} value={this.state.matsPerGrade[3]} onChange={this.changeHandler} />
<br/>
<label>Grade 4 rolls </label>
<input id={4} type={'number'} min={0} value={this.state.matsPerGrade[4]} onChange={this.changeHandler} />
<br/>
<label>Grade 5 rolls </label>
<input id={5} type={'number'} min={0} value={this.state.matsPerGrade[5]} onChange={this.changeHandler} />
<div>
<textarea className='cb json' readOnly value={this.state.matsList} />
</div>
<button className={'r dismiss cap'} onClick={this.context.hideModal}>{translate('close')}</button>
</div>;
}
}

View File

@@ -13,7 +13,7 @@ import {
getPercent, getPercent,
setRandom, setRandom,
specialToolTip specialToolTip
} from '../utils/BlueprintFunctions'; } from '../utils/BlueprintFunctions'
/** /**
* Modifications menu * Modifications menu
@@ -43,15 +43,15 @@ export default class ModificationsMenu extends TranslatedComponent {
this._rollBest = this._rollBest.bind(this); this._rollBest = this._rollBest.bind(this);
this._rollWorst = this._rollWorst.bind(this); this._rollWorst = this._rollWorst.bind(this);
this._reset = this._reset.bind(this); this._reset = this._reset.bind(this);
this._keyDown = this._keyDown.bind(this); this._keyDown = this._keyDown.bind(this);
this.modItems = [];// Array to hold various element refs (<li>, <div>, <ul>, etc.) this.modItems = [];// Array to hold various element refs (<li>, <div>, <ul>, etc.)
this.firstModId = null; this.firstModId = null;
this.firstBPLabel = null;// First item in mod menu this.firstBPLabel = null;// First item in mod menu
this.lastModId = null; this.lastModId = null;
this.selectedModId = null; this.lastNeId = null;//Last number editor id. Used to set focus to last number editor when shift-tab pressed on first element in mod menu.
this.selectedSpecialId = null; this.modValDidChange = false; //used to determine if component update was caused by change in modification value.
this.lastNeId = null;// Last number editor id. Used to set focus to last number editor when shift-tab pressed on first element in mod menu.
this.modValDidChange = false; // used to determine if component update was caused by change in modification value.
this._handleModChange = this._handleModChange.bind(this); this._handleModChange = this._handleModChange.bind(this);
this.state = { this.state = {
@@ -83,13 +83,14 @@ export default class ModificationsMenu extends TranslatedComponent {
const close = this._blueprintSelected.bind(this, blueprintName, grade); const close = this._blueprintSelected.bind(this, blueprintName, grade);
const key = blueprintName + ':' + grade; const key = blueprintName + ':' + grade;
const tooltipContent = blueprintTooltip(translate, blueprint.grades[grade], Modifications.modules[m.grp].blueprints[blueprintName].grades[grade].engineers, m.grp); const tooltipContent = blueprintTooltip(translate, blueprint.grades[grade], Modifications.modules[m.grp].blueprints[blueprintName].grades[grade].engineers, m.grp);
if (classes.indexOf('active') >= 0) this.selectedModId = key;
blueprintGrades.unshift(<li key={key} tabIndex="0" data-id={key} className={classes} style={{ width: '2em' }} onMouseOver={termtip.bind(null, tooltipContent)} onMouseOut={tooltip.bind(null, null)} onClick={close} onKeyDown={this._keyDown} ref={modItem => this.modItems[key] = modItem}>{grade}</li>); blueprintGrades.unshift(<li key={key} tabIndex="0" data-id={key} className={classes} style={{ width: '2em' }} onMouseOver={termtip.bind(null, tooltipContent)} onMouseOut={tooltip.bind(null, null)} onClick={close} onKeyDown={this._keyDown} ref={modItem => this.modItems[key] = modItem}>{grade}</li>);
} }
if (blueprintGrades) { if (blueprintGrades) {
const thisLen = blueprintGrades.length; const thisLen = blueprintGrades.length;
if (this.firstModId == null) this.firstModId = blueprintGrades[0].key; if (this.firstModId == null) this.firstModId = blueprintGrades[0].key;
this.lastModId = blueprintGrades[thisLen - 1].key; this.lastModId = blueprintGrades[thisLen-1].key;
blueprints.push(<div key={blueprint.name} className={'select-group cap'}>{translate(blueprint.name)}</div>); blueprints.push(<div key={blueprint.name} className={'select-group cap'}>{translate(blueprint.name)}</div>);
blueprints.push(<ul key={blueprintName}>{blueprintGrades}</ul>); blueprints.push(<ul key={blueprintName}>{blueprintGrades}</ul>);
} }
@@ -99,12 +100,14 @@ export default class ModificationsMenu extends TranslatedComponent {
/** /**
* Key down - select module on Enter key, move to next/previous module on Tab/Shift-Tab, close on Esc * Key down - select module on Enter key, move to next/previous module on Tab/Shift-Tab, close on Esc
* @param {Function} select Select module callback
* @param {SyntheticEvent} event Event * @param {SyntheticEvent} event Event
* *
*/ */
_keyDown(event) { _keyDown(event) {
let className = null; var className = null;
let elemId = null; var elemId = null;
if (event.currentTarget.attributes['class']) className = event.currentTarget.attributes['class'].value; if (event.currentTarget.attributes['class']) className = event.currentTarget.attributes['class'].value;
if (event.currentTarget.attributes['data-id']) elemId = event.currentTarget.attributes['data-id'].value; if (event.currentTarget.attributes['data-id']) elemId = event.currentTarget.attributes['data-id'].value;
@@ -113,24 +116,25 @@ export default class ModificationsMenu extends TranslatedComponent {
if (elemId != null) { if (elemId != null) {
this.modItems[elemId].click(); this.modItems[elemId].click();
} else { } else {
event.currentTarget.click(); event.currentTarget.click();
} }
return; return
} }
if (event.key == 'Tab') { if (event.key == 'Tab') {
// Shift-Tab //Shift-Tab
if(event.shiftKey) { if(event.shiftKey) {
if (elemId == this.firstModId && elemId != null) { if (elemId == this.firstModId && elemId != null) {
// Initial modification menu // Initial modification menu
event.preventDefault(); event.preventDefault();
this.modItems[this.lastModId].focus(); this.modItems[this.lastModId].focus();
return; return;
} else if (event.currentTarget.className.indexOf('button-inline-menu') >= 0 && event.currentTarget.previousElementSibling == null && this.lastNeId != null && this.modItems[this.lastNeId] != null) { } else if (event.currentTarget.className.indexOf("button-inline-menu") >= 0 && event.currentTarget.previousElementSibling == null && this.lastNeId != null && this.modItems[this.lastNeId] != null) {
// shift-tab on first element in modifications menu. set focus to last number editor field if open // shift-tab on first element in modifications menu. set focus to last number editor field if open
event.preventDefault(); event.preventDefault();
this.modItems[this.lastNeId].lastChild.focus(); this.modItems[this.lastNeId].lastChild.focus();
return; return;
} else if (event.currentTarget.className.indexOf('button-inline-menu') >= 0 && event.currentTarget.previousElementSibling == null) { } else if (event.currentTarget.className.indexOf("button-inline-menu") >= 0 && event.currentTarget.previousElementSibling == null) {
// shift-tab on button-inline-menu with no number editor // shift-tab on button-inline-menu with no number editor
event.preventDefault(); event.preventDefault();
event.currentTarget.parentElement.lastElementChild.focus(); event.currentTarget.parentElement.lastElementChild.focus();
@@ -141,7 +145,7 @@ export default class ModificationsMenu extends TranslatedComponent {
event.preventDefault(); event.preventDefault();
this.modItems[this.firstModId].focus(); this.modItems[this.firstModId].focus();
return; return;
} else if (event.currentTarget.className.indexOf('button-inline-menu') >= 0 && event.currentTarget.nextSibling == null && event.currentTarget.nodeName != 'TD') { } else if (event.currentTarget.className.indexOf("button-inline-menu") >= 0 && event.currentTarget.nextSibling == null && event.currentTarget.nodeName != "TD") {
// Experimental menu // Experimental menu
event.preventDefault(); event.preventDefault();
event.currentTarget.parentElement.firstElementChild.focus(); event.currentTarget.parentElement.firstElementChild.focus();
@@ -150,6 +154,7 @@ export default class ModificationsMenu extends TranslatedComponent {
event.preventDefault(); event.preventDefault();
this.modItems[this.firstBPLabel].focus(); this.modItems[this.firstBPLabel].focus();
} }
} }
} }
} }
@@ -162,6 +167,7 @@ export default class ModificationsMenu extends TranslatedComponent {
* @return {Object} list: Array of React Components * @return {Object} list: Array of React Components
*/ */
_renderSpecials(props, context) { _renderSpecials(props, context) {
const { m } = props; const { m } = props;
const { language, tooltip, termtip } = context; const { language, tooltip, termtip } = context;
const translate = language.translate; const translate = language.translate;
@@ -177,7 +183,6 @@ export default class ModificationsMenu extends TranslatedComponent {
const classes = cn('button-inline-menu', { const classes = cn('button-inline-menu', {
active: m.blueprint && m.blueprint.special && m.blueprint.special.edname == specialName active: m.blueprint && m.blueprint.special && m.blueprint.special.edname == specialName
}); });
if (classes.indexOf('active') >= 0) this.selectedSpecialId = specialName;
const close = this._specialSelected.bind(this, specialName); const close = this._specialSelected.bind(this, specialName);
if (m.blueprint && m.blueprint.name) { if (m.blueprint && m.blueprint.name) {
let tmp = {}; let tmp = {};
@@ -195,6 +200,7 @@ export default class ModificationsMenu extends TranslatedComponent {
} }
} }
} }
console.log("_renderSpecials. specials: %O", specials);
return specials; return specials;
} }
@@ -213,6 +219,7 @@ export default class ModificationsMenu extends TranslatedComponent {
modifications.push(<Modification key={ key } ship={ ship } m={ m } name={ modName } value={ m.getModValue(modName) / 100 || 0 } onChange={ onChange } onKeyDown={ this._keyDown } modItems={ this.modItems } handleModChange = {this._handleModChange} />); modifications.push(<Modification key={ key } ship={ ship } m={ m } name={ modName } value={ m.getModValue(modName) / 100 || 0 } onChange={ onChange } onKeyDown={ this._keyDown } modItems={ this.modItems } handleModChange = {this._handleModChange} />);
} }
} }
console.log("_renderModifications. modItems: %O", this.modItems);
return modifications; return modifications;
} }
@@ -312,9 +319,13 @@ export default class ModificationsMenu extends TranslatedComponent {
_rollWorst() { _rollWorst() {
const { m, ship } = this.props; const { m, ship } = this.props;
setPercent(ship, m, 0); setPercent(ship, m, 0);
// this will change the values in the modifications. Set modDidChange to true to prevent focus change when component updates // this will change the values in the modifications. Set modDidChange to true to prevent focus change when component updates
this._handleModChange(true); this._handleModChange(true);
this.props.onChange(); this.props.onChange();
} }
/** /**
@@ -324,24 +335,21 @@ export default class ModificationsMenu extends TranslatedComponent {
const { m, ship } = this.props; const { m, ship } = this.props;
ship.clearModifications(m); ship.clearModifications(m);
ship.clearModuleBlueprint(m); ship.clearModuleBlueprint(m);
this.selectedModId = null;
this.selectedSpecialId = null;
this.props.onChange(); this.props.onChange();
} }
/** /**
* set mod did change boolean * set mod did change boolean
* @param {boolean} b Boolean to determine if a change has been made to a module
*/ */
_handleModChange(b) { _handleModChange(b) {
this.modValDidChange = b; this.modValDidChange = b;
} }
/**
* Set focus on first element in modifications menu
* after it first mounts
*/
componentDidMount() { componentDidMount() {
/**
* Set focus on first element in modifications menu
* after it first mounts
*/
let firstEleCn = this.modItems['modMainDiv'].children.length > 0 ? this.modItems['modMainDiv'].children[0].className : null; let firstEleCn = this.modItems['modMainDiv'].children.length > 0 ? this.modItems['modMainDiv'].children[0].className : null;
if (firstEleCn.indexOf('select-group cap') >= 0) { if (firstEleCn.indexOf('select-group cap') >= 0) {
this.modItems['modMainDiv'].children[1].firstElementChild.focus(); this.modItems['modMainDiv'].children[1].firstElementChild.focus();
@@ -350,21 +358,14 @@ export default class ModificationsMenu extends TranslatedComponent {
} }
} }
/**
* Set focus on first element in modifications menu
* if component updates, unless update is due to value change
* in a modification
*/
componentDidUpdate() { componentDidUpdate() {
/**
* Set focus on first element in modifications menu
* if component updates, unless update is due to value change
* in a modification
*/
if (!this.modValDidChange) { if (!this.modValDidChange) {
if (this.modItems['modMainDiv'].children.length > 0) { if (this.modItems['modMainDiv'].children.length > 0) {
if (this.modItems[this.selectedModId]) {
this.modItems[this.selectedModId].focus();
return;
} else if (this.modItems[this.selectedSpecialId]) {
this.modItems[this.selectedSpecialId].focus();
return;
}
let firstEleCn = this.modItems['modMainDiv'].children[0].className; let firstEleCn = this.modItems['modMainDiv'].children[0].className;
if (firstEleCn.indexOf('button-inline-menu') >= 0) { if (firstEleCn.indexOf('button-inline-menu') >= 0) {
this.modItems['modMainDiv'].firstElementChild.focus(); this.modItems['modMainDiv'].firstElementChild.focus();
@@ -373,15 +374,14 @@ export default class ModificationsMenu extends TranslatedComponent {
} }
} }
} else { } else {
this._handleModChange(false);// Need to reset if component update due to value change this._handleModChange(false);//Need to reset if component update due to value change
} }
} }
/**
* set focus to the modification menu icon after mod menu is unmounted.
*/
componentWillUnmount() { componentWillUnmount() {
if (this.props.modButton) { if (this.props.modButton) {
this.props.modButton.focus(); this.props.modButton.focus();// set focus to the modification menu icon after mod menu is unmounted.
} }
} }
@@ -407,7 +407,7 @@ export default class ModificationsMenu extends TranslatedComponent {
let haveBlueprint = false; let haveBlueprint = false;
let blueprintTt; let blueprintTt;
let blueprintCv; let blueprintCv;
// TODO: Fix this to actually find the correct blueprint. //TODO: Fix this to actually find the correct blueprint.
if (!m.blueprint || !m.blueprint.name || !m.blueprint.fdname || !Modifications.modules[m.grp].blueprints || !Modifications.modules[m.grp].blueprints[m.blueprint.fdname]) { if (!m.blueprint || !m.blueprint.name || !m.blueprint.fdname || !Modifications.modules[m.grp].blueprints || !Modifications.modules[m.grp].blueprints[m.blueprint.fdname]) {
this.props.ship.clearModuleBlueprint(m); this.props.ship.clearModuleBlueprint(m);
this.props.ship.clearModuleSpecial(m); this.props.ship.clearModuleSpecial(m);
@@ -440,7 +440,7 @@ export default class ModificationsMenu extends TranslatedComponent {
const showReset = !blueprintMenuOpened && (!specialMenuOpened || !specials.length) && haveBlueprint; const showReset = !blueprintMenuOpened && (!specialMenuOpened || !specials.length) && haveBlueprint;
const showMods = !blueprintMenuOpened && (!specialMenuOpened || !specials.length) && haveBlueprint; const showMods = !blueprintMenuOpened && (!specialMenuOpened || !specials.length) && haveBlueprint;
if (haveBlueprint) { if (haveBlueprint) {
this.firstBPLabel = blueprintLabel; this.firstBPLabel = blueprintLabel
} else { } else {
this.firstBPLabel = 'selectBP'; this.firstBPLabel = 'selectBP';
} }
@@ -464,8 +464,8 @@ export default class ModificationsMenu extends TranslatedComponent {
<tbody> <tbody>
{ showRolls ? { showRolls ?
<tr> <tr>
<td tabIndex="0" className={ cn('section-menu button-inline-menu', { active: false }) }> { translate('roll') }: </td> <td tabIndex="0" className={ cn('section-menu button-inline-menu', {active: false})}> { translate('roll') }: </td>
<td tabIndex="0" className={ cn('section-menu button-inline-menu', { active: blueprintCv === 0 }) } style={{ cursor: 'pointer' }} onClick={_rollWorst} onKeyDown={ this._keyDown } onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_WORST')} onMouseOut={tooltip.bind(null, null)}> { translate('0%') } </td> <td tabIndex="0" className={ cn('section-menu button-inline-menu', { active: blueprintCv === 0 })} style={{ cursor: 'pointer' }} onClick={_rollWorst} onKeyDown={ this._keyDown } onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_WORST')} onMouseOut={tooltip.bind(null, null)}> { translate('0%') } </td>
<td tabIndex="0" className={ cn('section-menu button-inline-menu', { active: blueprintCv === 50 })} style={{ cursor: 'pointer' }} onClick={_rollFifty} onKeyDown={ this._keyDown } onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_FIFTY')} onMouseOut={tooltip.bind(null, null)}> { translate('50%') } </td> <td tabIndex="0" className={ cn('section-menu button-inline-menu', { active: blueprintCv === 50 })} style={{ cursor: 'pointer' }} onClick={_rollFifty} onKeyDown={ this._keyDown } onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_FIFTY')} onMouseOut={tooltip.bind(null, null)}> { translate('50%') } </td>
<td tabIndex="0" className={ cn('section-menu button-inline-menu', { active: blueprintCv === 100 })} style={{ cursor: 'pointer' }} onClick={_rollFull} onKeyDown={ this._keyDown } onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_BEST')} onMouseOut={tooltip.bind(null, null)}> { translate('100%') } </td> <td tabIndex="0" className={ cn('section-menu button-inline-menu', { active: blueprintCv === 100 })} style={{ cursor: 'pointer' }} onClick={_rollFull} onKeyDown={ this._keyDown } onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_BEST')} onMouseOut={tooltip.bind(null, null)}> { translate('100%') } </td>
<td tabIndex="0" className={ cn('section-menu button-inline-menu', { active: blueprintCv === null || blueprintCv % 50 != 0 })} style={{ cursor: 'pointer' }} onClick={_rollRandom} onKeyDown={ this._keyDown } onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_RANDOM')} onMouseOut={tooltip.bind(null, null)}> { translate('random') } </td> <td tabIndex="0" className={ cn('section-menu button-inline-menu', { active: blueprintCv === null || blueprintCv % 50 != 0 })} style={{ cursor: 'pointer' }} onClick={_rollRandom} onKeyDown={ this._keyDown } onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_RANDOM')} onMouseOut={tooltip.bind(null, null)}> { translate('random') } </td>

View File

@@ -18,16 +18,12 @@ export default class ShipSummaryTable extends TranslatedComponent {
pips: PropTypes.object.isRequired pips: PropTypes.object.isRequired
}; };
/**
* The ShipSummaryTable constructor
* @param {Object} props The props
*/
constructor(props) { constructor(props) {
super(props); super(props)
this.didContextChange = this.didContextChange.bind(this); this.didContextChange = this.didContextChange.bind(this);
this.state = { this.state = {
shieldColour: 'blue' shieldColour: 'blue'
}; }
} }
/** /**
@@ -51,7 +47,6 @@ export default class ShipSummaryTable extends TranslatedComponent {
const canBoost = ship.canBoost(cargo, ship.fuelCapacity); const canBoost = ship.canBoost(cargo, ship.fuelCapacity);
const boostTooltip = canBoost ? 'TT_SUMMARY_BOOST' : canThrust ? 'TT_SUMMARY_BOOST_NONFUNCTIONAL' : 'TT_SUMMARY_SPEED_NONFUNCTIONAL'; const boostTooltip = canBoost ? 'TT_SUMMARY_BOOST' : canThrust ? 'TT_SUMMARY_BOOST_NONFUNCTIONAL' : 'TT_SUMMARY_SPEED_NONFUNCTIONAL';
const sgMetrics = Calc.shieldMetrics(ship, pips.sys || 2); const sgMetrics = Calc.shieldMetrics(ship, pips.sys || 2);
const shipBoost = canBoost ? Calc.calcBoost(ship) : 'No Boost';
const armourMetrics = Calc.armourMetrics(ship); const armourMetrics = Calc.armourMetrics(ship);
let shieldColour = 'blue'; let shieldColour = 'blue';
if (shieldGenerator && shieldGenerator.m.grp === 'psg') { if (shieldGenerator && shieldGenerator.m.grp === 'psg') {
@@ -61,7 +56,7 @@ export default class ShipSummaryTable extends TranslatedComponent {
} }
this.state = { this.state = {
shieldColour shieldColour
}; }
return <div id='summary'> return <div id='summary'>
<table className={'summaryTable'}> <table className={'summaryTable'}>
<thead> <thead>
@@ -82,7 +77,6 @@ export default class ShipSummaryTable extends TranslatedComponent {
<th onMouseEnter={termtip.bind(null, 'hull hardness', { cap: 0 })} onMouseLeave={hide} rowSpan={2}>{translate('hrd')}</th> <th onMouseEnter={termtip.bind(null, 'hull hardness', { cap: 0 })} onMouseLeave={hide} rowSpan={2}>{translate('hrd')}</th>
<th rowSpan={2}>{translate('crew')}</th> <th rowSpan={2}>{translate('crew')}</th>
<th onMouseEnter={termtip.bind(null, 'mass lock factor', { cap: 0 })} onMouseLeave={hide} rowSpan={2}>{translate('MLF')}</th> <th onMouseEnter={termtip.bind(null, 'mass lock factor', { cap: 0 })} onMouseLeave={hide} rowSpan={2}>{translate('MLF')}</th>
<th onMouseEnter={termtip.bind(null, 'TT_SUMMARY_BOOST_TIME', { cap: 0 })} onMouseLeave={hide} rowSpan={2}>{translate('boost time')}</th>
</tr> </tr>
<tr> <tr>
<th className='lft'>{translate('max')}</th> <th className='lft'>{translate('max')}</th>
@@ -119,7 +113,6 @@ export default class ShipSummaryTable extends TranslatedComponent {
<td>{int(ship.hardness)}</td> <td>{int(ship.hardness)}</td>
<td>{ship.crew}</td> <td>{ship.crew}</td>
<td>{ship.masslock}</td> <td>{ship.masslock}</td>
<td>{shipBoost !== 'No Boost' ? formats.time(shipBoost) : 'No Boost'}</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@@ -147,8 +140,8 @@ export default class ShipSummaryTable extends TranslatedComponent {
<td>{int(ship.shieldThermRes * 100) + '%'}</td> <td>{int(ship.shieldThermRes * 100) + '%'}</td>
<td>{int(sgMetrics && sgMetrics.generator ? sgMetrics.total / sgMetrics.absolute.total : 0)}</td> <td>{int(sgMetrics && sgMetrics.generator ? sgMetrics.total / sgMetrics.absolute.total : 0)}</td>
<td>{int(sgMetrics && sgMetrics.generator ? sgMetrics.total / sgMetrics.explosive.total : 0)}</td> <td>{int(sgMetrics && sgMetrics.generator ? sgMetrics.total / sgMetrics.explosive.total : 0)}</td>
<td>{int(sgMetrics && sgMetrics.generator ? sgMetrics.total / sgMetrics.kinetic.total : 0)}</td> <td>{int(sgMetrics && sgMetrics.generator ? sgMetrics.total / sgMetrics.kinetic.total : 0 )}</td>
<td>{int(sgMetrics && sgMetrics.generator ? sgMetrics.total / sgMetrics.thermal.total : 0)}</td> <td>{int(sgMetrics && sgMetrics.generator ? sgMetrics.total / sgMetrics.thermal.total : 0 )}</td>
<td>{sgMetrics && sgMetrics.recover ? formats.time(sgMetrics.recover) : 0}</td> <td>{sgMetrics && sgMetrics.recover ? formats.time(sgMetrics.recover) : 0}</td>
<td>{sgMetrics && sgMetrics.recharge ? formats.time(sgMetrics.recharge) : 0}</td> <td>{sgMetrics && sgMetrics.recharge ? formats.time(sgMetrics.recharge) : 0}</td>
</tr> </tr>

View File

@@ -17,12 +17,12 @@ export default class Slider extends React.Component {
static propTypes = { static propTypes = {
axis: PropTypes.bool, axis: PropTypes.bool,
axisUnit: PropTypes.string,// units (T, M, etc.) axisUnit: PropTypes.string,//units (T, M, etc.)
max: PropTypes.number, max: PropTypes.number,
min: PropTypes.number, min: PropTypes.number,
onChange: PropTypes.func.isRequired,// function which determins percent value onChange: PropTypes.func.isRequired,// function which determins percent value
onResize: PropTypes.func, onResize: PropTypes.func,
percent: PropTypes.number.isRequired,// value of slider percent: PropTypes.number.isRequired,//value of slider
scale: PropTypes.number scale: PropTypes.number
}; };
@@ -51,6 +51,7 @@ export default class Slider extends React.Component {
* @param {SyntheticEvent} event Event * @param {SyntheticEvent} event Event
*/ */
_down(event) { _down(event) {
let rect = event.currentTarget.getBoundingClientRect(); let rect = event.currentTarget.getBoundingClientRect();
this.left = rect.left; this.left = rect.left;
this.width = rect.width; this.width = rect.width;
@@ -94,26 +95,28 @@ export default class Slider extends React.Component {
case 'Enter': case 'Enter':
event.preventDefault(); event.preventDefault();
this.sliderInputBox._setDisplay('block'); this.sliderInputBox._setDisplay('block');
//this.enterTimer = setTimeout(() => this.sliderInputBox.sliderVal.focus(), 10);
return; return;
default: default:
return; return;
} }
} }
/** /**
* Key down handler * Key down handler
* increment slider position by +/- 1 when right/left arrow key is pressed or held * increment slider position by +/- 1 when right/left arrow key is pressed or held
* @param {Event} event Keyboard even * @param {Event} event
*/ */
_keydown(event) { _keydown(event) {
let newVal = this.props.percent * this.props.max;
switch (event.key) { switch (event.key) {
case 'ArrowRight': case 'ArrowRight':
newVal += 1; var newVal = this.props.percent*this.props.max + 1;
if (newVal <= this.props.max) this.props.onChange(newVal / this.props.max); if (newVal <= this.props.max) this.props.onChange(newVal/this.props.max);
return; return;
case 'ArrowLeft': case 'ArrowLeft':
newVal -= 1; var newVal = this.props.percent*this.props.max - 1;
if (newVal >= 0) this.props.onChange(newVal / this.props.max); if (newVal >= 0) this.props.onChange(newVal/this.props.max);
return; return;
default: default:
return; return;
@@ -129,11 +132,6 @@ export default class Slider extends React.Component {
this.touchStartTimer = setTimeout(() => this.sliderInputBox._setDisplay('block'), 1500); this.touchStartTimer = setTimeout(() => this.sliderInputBox._setDisplay('block'), 1500);
} }
/**
* Touch end handler
* @param {Event} event DOM Event
*
*/
_touchend(event) { _touchend(event) {
this.sliderInputBox.sliderVal.focus(); this.sliderInputBox.sliderVal.focus();
clearTimeout(this.touchStartTimer); clearTimeout(this.touchStartTimer);
@@ -183,6 +181,7 @@ export default class Slider extends React.Component {
*/ */
componentDidMount() { componentDidMount() {
this._updateDimensions(); this._updateDimensions();
} }
/** /**
@@ -201,17 +200,21 @@ export default class Slider extends React.Component {
render() { render() {
let outerWidth = this.state.outerWidth; let outerWidth = this.state.outerWidth;
let { axis, axisUnit, min, max, scale } = this.props; let { axis, axisUnit, min, max, scale } = this.props;
let style = { let style = {
width: '100%', width: '100%',
height: axis ? '2.5em' : '1.5em', height: axis ? '2.5em' : '1.5em',
boxSizing: 'border-box' boxSizing: 'border-box'
}; };
if (!outerWidth) { if (!outerWidth) {
return <svg style={style} ref={node => this.node = node} />; return <svg style={style} ref={node => this.node = node} />;
} }
let margin = MARGIN_LR * scale; let margin = MARGIN_LR * scale;
let width = outerWidth - (margin * 2); let width = outerWidth - (margin * 2);
let pctPos = width * this.props.percent; let pctPos = width * this.props.percent;
return <div><svg return <div><svg
onMouseUp={this._up} onMouseEnter={this._enter.bind(this)} onMouseMove={this._move} onKeyUp={this._keyup} onKeyDown={this._keydown} style={style} ref={node => this.node = node} tabIndex="0"> onMouseUp={this._up} onMouseEnter={this._enter.bind(this)} onMouseMove={this._move} onKeyUp={this._keyup} onKeyDown={this._keydown} style={style} ref={node => this.node = node} tabIndex="0">
<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' style={{ opacity: 0.3 }} x={margin} y='0.25em' rx='0.3em' ry='0.3em' width={width} height='0.7em' />
@@ -230,136 +233,110 @@ export default class Slider extends React.Component {
axisUnit={this.props.axisUnit} axisUnit={this.props.axisUnit}
scale={this.props.scale} scale={this.props.scale}
max={this.props.max} max={this.props.max}
/> />
</div>; </div>;
} }
} }
/** /**
* New component to add keyboard support for sliders - works on all devices (desktop, iOS, Android) * New component to add keyboard support for sliders - works on all devices (desktop, iOS, Android)
**/ **/
class TextInputBox extends React.Component { class TextInputBox extends React.Component {
static propTypes = { static propTypes = {
axisUnit: PropTypes.string,// units (T, M, etc.) axisUnit: PropTypes.string,//units (T, M, etc.)
max: PropTypes.number, max: PropTypes.number,
onChange: PropTypes.func.isRequired,// function which determins percent value onChange: PropTypes.func.isRequired,// function which determins percent value
percent: PropTypes.number.isRequired,// value of slider percent: PropTypes.number.isRequired,//value of slider
scale: PropTypes.number scale: PropTypes.number
}; };
/**
* Determine if the user is still dragging
* @param {Object} props React Component properties
*/
constructor(props) { constructor(props) {
super(props); super(props);
this._handleFocus = this._handleFocus.bind(this); this._handleFocus = this._handleFocus.bind(this);
this._handleBlur = this._handleBlur.bind(this); this._handleBlur = this._handleBlur.bind(this);
this._handleChange = this._handleChange.bind(this); this._handleChange = this._handleChange.bind(this);
this._keyup = this._keyup.bind(this); //this._keydown = this._keydown.bind(this);
this.state = this._getInitialState(); this._keyup = this._keyup.bind(this);
} this.state = this._getInitialState();
/** this.percent = this.props.percent;
* Update input value if slider changes will change props/state this.max = this.props.max;
* @param {Object} nextProps React Component properites this.state.inputValue = this.percent * this.max;
* @param {Object} nextState React Component state values
*/
componentWillReceiveProps(nextProps, nextState) {
let nextValue = nextProps.percent * nextProps.max;
// See https://stackoverflow.com/questions/32414308/updating-state-on-props-change-in-react-form
if (nextValue !== this.state.inputValue && nextValue <= nextProps.max) {
this.setState({ inputValue: nextValue });
} }
}
/** componentWillReceiveProps(nextProps, nextState) {
* Update slider textbox visibility/values if changes are made to slider var nextValue = nextProps.percent * nextProps.max;
* @param {Object} prevProps React Component properites // See https://stackoverflow.com/questions/32414308/updating-state-on-props-change-in-react-form
* @param {Object} prevState React Component state values if (nextValue !== this.state.inputValue && nextValue <= nextProps.max) {
*/ this.setState({ inputValue: nextValue });
componentDidUpdate(prevProps, prevState) { }
if (prevState.divStyle.display == 'none' && this.state.divStyle.display == 'block') {
this.enterTimer = setTimeout(() => this.sliderVal.focus(), 10);
} }
if (prevProps.max !== this.props.max && this.state.inputValue > this.props.max) { componentDidUpdate(prevProps, prevState) {
// they chose a different module
this.setState({ inputValue: this.props.max }); if (prevState.divStyle.display == 'none' && this.state.divStyle.display == 'block') {
this.enterTimer = setTimeout(() => this.sliderVal.focus(), 10);
}
if (prevProps.max !== this.props.max && this.state.inputValue > this.props.max) {
// they chose a different module
this.setState({ inputValue: this.props.max });
}
if (this.state.inputValue != prevState.inputValue && prevProps.max == this.props.max) {
this.props.onChange(this.state.inputValue/this.props.max);
}
} }
if (this.state.inputValue != prevState.inputValue && prevProps.max == this.props.max) {
this.props.onChange(this.state.inputValue / this.props.max); _getInitialState() {
return {
divStyle: {display:'none'},
inputStyle: {width:'4em'},
labelStyle: {marginLeft: '.1em'},
maxLength:5,
size:5,
min:0,
tabIndex:-1,
type:'number',
readOnly: true
}
} }
}
/** _setDisplay(val) {
* Set initial state for the textbox.
* We may want to rethink this to
* try and make it a stateless component
* @returns {object} React state object with initial values set
*/
_getInitialState() {
return {
divStyle: { display:'none' },
inputStyle: { width:'4em' },
labelStyle: { marginLeft: '.1em' },
maxLength:5,
size:5,
min:0,
tabIndex:-1,
type:'number',
readOnly: true,
inputValue: this.props.percent * this.props.max
};
}
/**
*
* @param {string} val block or none
*/
_setDisplay(val) {
this.setState({
divStyle: { display:val }
});
}
/**
* Update the input value
* when textbox gets focus
*/
_handleFocus() {
this.setState({
inputValue:this._getValue()
});
}
/**
* Update inputValue when textbox loses focus
*/
_handleBlur() {
this._setDisplay('none');
if (this.state.inputValue !== '') {
this.props.onChange(this.state.inputValue / this.props.max);
} else {
this.setState({ this.setState({
inputValue: this.props.percent * this.props.max divStyle: {display:val}
}); });
} }
}
/** _handleFocus() {
* Get the value in the text box this.setState({
* @returns {number} inputValue Value of the input box inputValue:this._getValue()
*/ });
_getValue() {
return this.state.inputValue;
}
/**
* Update and set limits on input box
* values depending on what user
* has selected
*
* @param {SyntheticEvent} event ReactJs onChange event
*/
_handleChange(event) {
if (event.target.value < 0) {
this.setState({ inputValue: 0 });
} else if (event.target.value <= this.props.max) {
this.setState({ inputValue: event.target.value });
} else {
this.setState({ inputValue: this.props.max });
} }
}
_handleBlur() {
this._setDisplay('none');
if (this.state.inputValue !== '') {
this.props.onChange(this.state.inputValue/this.props.max);
} else {
this.state.inputValue = this.props.percent * this.props.max;
}
}
_getValue() {
return this.state.inputValue;
}
_handleChange(event) {
if (event.target.value < 0) {
this.setState({inputValue: 0});
} else if (event.target.value <= this.props.max) {
this.setState({inputValue: event.target.value});
} else {
this.setState({inputValue: this.props.max});
}
}
/** /**
* Key up handler for input field. * Key up handler for input field.
* If user hits Enter key, blur/close the input field * If user hits Enter key, blur/close the input field
@@ -373,14 +350,12 @@ class TextInputBox extends React.Component {
default: default:
return; return;
} }
}
/** }
* Get the value in the text box
* @return {React.Component} Text Input component for Slider render() {
*/ let { axisUnit, onChange, percent, scale } = this.props;
render() { return <div style={this.state.divStyle}><input style={this.state.inputStyle} value={this._getValue()} min={this.state.min} max={this.props.max} onChange={this._handleChange} onKeyUp={this._keyup} tabIndex={this.state.tabIndex} maxLength={this.state.maxLength} size={this.state.size} onBlur={() => {this._handleBlur()}} onFocus={() => {this._handleFocus()}} type={this.state.type} ref={(ip) => this.sliderVal = ip}/><text className="primary upp" style={this.state.labelStyle}>{this.props.axisUnit}</text></div>;
let { axisUnit, onChange, percent, scale } = this.props; }
return <div style={this.state.divStyle}><input style={this.state.inputStyle} value={this._getValue()} min={this.state.min} max={this.props.max} onChange={this._handleChange} onKeyUp={this._keyup} tabIndex={this.state.tabIndex} maxLength={this.state.maxLength} size={this.state.size} onBlur={() => {this._handleBlur();}} onFocus={() => {this._handleFocus();}} type={this.state.type} ref={(ip) => this.sliderVal = ip}/><text className="primary upp" style={this.state.labelStyle}>{this.props.axisUnit}</text></div>; }
}
}

View File

@@ -85,10 +85,13 @@ export default class Slot extends TranslatedComponent {
*/ */
_keyDown(event) { _keyDown(event) {
if (event.key == 'Enter') { if (event.key == 'Enter') {
if(event.target.className == 'r') { if(event.target.className == 'r') {
this._toggleModifications(); console.log("Slot: Enter key pressed on mod icon");
} this._toggleModifications();
this.props.onOpen(event); } else {
console.log("Slot: Enter key pressed on: %O", event.target);
}
this.props.onOpen(event);
} }
} }
/** /**

View File

@@ -18,8 +18,7 @@ export default class SlotSection extends TranslatedComponent {
onCargoChange: PropTypes.func.isRequired, onCargoChange: PropTypes.func.isRequired,
onFuelChange: PropTypes.func.isRequired, onFuelChange: PropTypes.func.isRequired,
code: PropTypes.string.isRequired, code: PropTypes.string.isRequired,
togglePwr: PropTypes.func, togglePwr: PropTypes.func
sectionMenuRefs: PropTypes.object
}; };
/** /**
@@ -33,10 +32,7 @@ export default class SlotSection extends TranslatedComponent {
super(props); super(props);
this.sectionId = sectionId; this.sectionId = sectionId;
this.sectionName = sectionName; this.sectionName = sectionName;
this.ssHeadRef = null;
this.sectionRefArr = this.props.sectionMenuRefs[this.sectionId] = [];
this.sectionRefArr['selectedRef'] = null;
this._getSlots = this._getSlots.bind(this); this._getSlots = this._getSlots.bind(this);
this._selectModule = this._selectModule.bind(this); this._selectModule = this._selectModule.bind(this);
this._getSectionMenu = this._getSectionMenu.bind(this); this._getSectionMenu = this._getSectionMenu.bind(this);
@@ -44,8 +40,6 @@ export default class SlotSection extends TranslatedComponent {
this._drop = this._drop.bind(this); this._drop = this._drop.bind(this);
this._dragOverNone = this._dragOverNone.bind(this); this._dragOverNone = this._dragOverNone.bind(this);
this._close = this._close.bind(this); this._close = this._close.bind(this);
this._keyDown = this._keyDown.bind(this);
this._handleSectionFocus = this._handleSectionFocus.bind(this);
this.state = {}; this.state = {};
} }
@@ -53,59 +47,7 @@ export default class SlotSection extends TranslatedComponent {
// _getSlots() // _getSlots()
// _getSectionMenu() // _getSectionMenu()
// _contextMenu() // _contextMenu()
// componentDidUpdate(prevProps)
/**
* TODO: May either need to send the function to be triggered when Enter key is pressed, or else
* may need a separate keyDown handler for each subclass (StandardSlotSection, HardpointSlotSection, etc.)
* ex: _keyDown(_keyDownfn, event)
*
* @param {SyntheticEvent} event KeyDown event
*/
_keyDown(event) {
if (event.key == 'Enter') {
event.stopPropagation();
if (event.currentTarget.nodeName === 'H1') {
this._openMenu(this.sectionName, event);
} else {
event.currentTarget.click();
}
return;
}
if (event.key == 'Tab') {
if (event.shiftKey) {
if ((event.currentTarget === this.sectionRefArr[this.firstRefId]) && this.sectionRefArr[this.lastRefId]) {
event.preventDefault();
this.sectionRefArr[this.lastRefId].focus();
}
} else {
if ((event.currentTarget === this.sectionRefArr[this.lastRefId]) && this.sectionRefArr[this.firstRefId]) {
event.preventDefault();
this.sectionRefArr[this.firstRefId].focus();
}
}
}
}
/**
* Set focus on appropriate Slot Section Menu element
* @param {Object} focusPrevProps prevProps for componentDidUpdate() from ...SlotSection.jsx
* @param {String} firstRef id of the first ref in ...SlotSection.jsx
* @param {String} lastRef id of the last ref in ...SlotSection.jsx
*
*/
_handleSectionFocus(focusPrevProps, firstRef, lastRef) {
if (this.selectedRefId !== null && this.sectionRefArr[this.selectedRefId]) {
// set focus on the previously selected option for the currently open section menu
this.sectionRefArr[this.selectedRefId].focus();
} else if (this.sectionRefArr[firstRef] && this.sectionRefArr[firstRef] != null) {
// set focus on the first option in the currently open section menu if none have been selected previously
this.sectionRefArr[firstRef].focus();
} else if (this.props.currentMenu == null && focusPrevProps.currentMenu == this.sectionName && this.sectionRefArr['ssHeadRef']) {
// set focus on the section menu header when section menu is closed
this.sectionRefArr['ssHeadRef'].focus();
}
}
/** /**
* Open a menu * Open a menu
* @param {string} menu Menu name * @param {string} menu Menu name
@@ -283,7 +225,7 @@ export default class SlotSection extends TranslatedComponent {
return ( return (
<div id={this.sectionId} className={'group'} onDragLeave={this._dragOverNone}> <div id={this.sectionId} className={'group'} onDragLeave={this._dragOverNone}>
<div className={cn('section-menu', { selected: sectionMenuOpened })} onClick={open} onContextMenu={ctx}> <div className={cn('section-menu', { selected: sectionMenuOpened })} onClick={open} onContextMenu={ctx}>
<h1 tabIndex="0" onKeyDown={this._keyDown} ref={ssHead => this.sectionRefArr['ssHeadRef'] = ssHead}>{translate(this.sectionName)} <Equalizer/></h1> <h1>{translate(this.sectionName)} <Equalizer/></h1>
{sectionMenuOpened ? this._getSectionMenu(translate, this.props.ship) : null } {sectionMenuOpened ? this._getSectionMenu(translate, this.props.ship) : null }
</div> </div>
{this._getSlots()} {this._getSlots()}

View File

@@ -39,16 +39,13 @@ export default class StandardSlot extends TranslatedComponent {
this.modButton = null; this.modButton = null;
this.slotDiv = null; this.slotDiv = null;
} }
/**
* Handle Enter key _keyDown(event) {
* @param {SyntheticEvent} event KeyDown event
*/
_keyDown(event) {
if (event.key == 'Enter') { if (event.key == 'Enter') {
if(event.target.className == 'r') { if(event.target.className == 'r') {
this._toggleModifications(); this._toggleModifications();
} }
this.props.onOpen(event); this.props.onOpen(event);
} }
} }
@@ -64,9 +61,6 @@ export default class StandardSlot extends TranslatedComponent {
let classRating = m.class + m.rating; let classRating = m.class + m.rating;
let menu; let menu;
let validMods = m == null || !Modifications.modules[m.grp] ? [] : (Modifications.modules[m.grp].modifications || []); let validMods = m == null || !Modifications.modules[m.grp] ? [] : (Modifications.modules[m.grp].modifications || []);
if (m && m.name && m.name === 'Guardian Hybrid Power Plant') {
validMods = [];
}
let showModuleResistances = Persist.showModuleResistances(); let showModuleResistances = Persist.showModuleResistances();
let mass = m.getMass() || m.cargo || m.fuel || 0; let mass = m.getMass() || m.cargo || m.fuel || 0;
@@ -154,6 +148,7 @@ export default class StandardSlot extends TranslatedComponent {
* Toggle the modifications flag when selecting the modifications icon * Toggle the modifications flag when selecting the modifications icon
*/ */
_toggleModifications() { _toggleModifications() {
this._modificationsSelected = !this._modificationsSelected; this._modificationsSelected = !this._modificationsSelected;
} }
} }

View File

@@ -20,23 +20,12 @@ export default class StandardSlotSection extends SlotSection {
super(props, context, 'standard', 'core internal'); super(props, context, 'standard', 'core internal');
this._optimizeStandard = this._optimizeStandard.bind(this); this._optimizeStandard = this._optimizeStandard.bind(this);
this._selectBulkhead = this._selectBulkhead.bind(this); this._selectBulkhead = this._selectBulkhead.bind(this);
this.selectedRefId = null;
this.firstRefId = 'maxjump';
this.lastRefId = 'racer';
}
/**
* Handle focus if the component updates
* @param {Object} prevProps React Component properties
*/
componentDidUpdate(prevProps) {
this._handleSectionFocus(prevProps,this.firstRefId, this.lastRefId);
} }
/** /**
* Use the lightest/optimal available standard modules * Use the lightest/optimal available standard modules
*/ */
_optimizeStandard() { _optimizeStandard() {
this.selectedRefId = 'maxjump';
this.props.ship.useLightestStandard(); this.props.ship.useLightestStandard();
this.props.onChange(); this.props.onChange();
this.props.onCargoChange(this.props.ship.cargoCapacity); this.props.onCargoChange(this.props.ship.cargoCapacity);
@@ -50,8 +39,6 @@ export default class StandardSlotSection extends SlotSection {
* @param {integer} bulkheadIndex Bulkhead to use see Constants.BulkheadNames * @param {integer} bulkheadIndex Bulkhead to use see Constants.BulkheadNames
*/ */
_multiPurpose(shielded, bulkheadIndex) { _multiPurpose(shielded, bulkheadIndex) {
this.selectedRefId = 'multipurpose';
if (bulkheadIndex === 2) this.selectedRefId = 'combat';
ShipRoles.multiPurpose(this.props.ship, shielded, bulkheadIndex); ShipRoles.multiPurpose(this.props.ship, shielded, bulkheadIndex);
this.props.onChange(); this.props.onChange();
this.props.onCargoChange(this.props.ship.cargoCapacity); this.props.onCargoChange(this.props.ship.cargoCapacity);
@@ -64,7 +51,6 @@ export default class StandardSlotSection extends SlotSection {
* @param {Boolean} shielded True if shield generator should be included * @param {Boolean} shielded True if shield generator should be included
*/ */
_optimizeCargo(shielded) { _optimizeCargo(shielded) {
this.selectedRefId = 'trader';
ShipRoles.trader(this.props.ship, shielded); ShipRoles.trader(this.props.ship, shielded);
this.props.onChange(); this.props.onChange();
this.props.onCargoChange(this.props.ship.cargoCapacity); this.props.onCargoChange(this.props.ship.cargoCapacity);
@@ -77,7 +63,6 @@ export default class StandardSlotSection extends SlotSection {
* @param {Boolean} shielded True if shield generator should be included * @param {Boolean} shielded True if shield generator should be included
*/ */
_optimizeMiner(shielded) { _optimizeMiner(shielded) {
this.selectedRefId = 'miner';
ShipRoles.miner(this.props.ship, shielded); ShipRoles.miner(this.props.ship, shielded);
this.props.onChange(); this.props.onChange();
this.props.onCargoChange(this.props.ship.cargoCapacity); this.props.onCargoChange(this.props.ship.cargoCapacity);
@@ -90,8 +75,6 @@ export default class StandardSlotSection extends SlotSection {
* @param {Boolean} planetary True if Planetary Vehicle Hangar (PVH) should be included * @param {Boolean} planetary True if Planetary Vehicle Hangar (PVH) should be included
*/ */
_optimizeExplorer(planetary) { _optimizeExplorer(planetary) {
this.selectedRefId = 'explorer';
if (planetary) this.selectedRefId = 'planetary';
ShipRoles.explorer(this.props.ship, planetary); ShipRoles.explorer(this.props.ship, planetary);
this.props.onChange(); this.props.onChange();
this.props.onCargoChange(this.props.ship.cargoCapacity); this.props.onCargoChange(this.props.ship.cargoCapacity);
@@ -103,7 +86,6 @@ export default class StandardSlotSection extends SlotSection {
* Racer role * Racer role
*/ */
_optimizeRacer() { _optimizeRacer() {
this.selectedRefId = 'racer';
ShipRoles.racer(this.props.ship); ShipRoles.racer(this.props.ship);
this.props.onChange(); this.props.onChange();
this.props.onCargoChange(this.props.ship.cargoCapacity); this.props.onCargoChange(this.props.ship.cargoCapacity);
@@ -247,17 +229,17 @@ export default class StandardSlotSection extends SlotSection {
let planetaryDisabled = this.props.ship.internal.length < 4; let planetaryDisabled = this.props.ship.internal.length < 4;
return <div className='select' onClick={(e) => e.stopPropagation()} onContextMenu={stopCtxPropagation}> return <div className='select' onClick={(e) => e.stopPropagation()} onContextMenu={stopCtxPropagation}>
<ul> <ul>
<li className='lc' tabIndex="0" onClick={this._optimizeStandard} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['maxjump'] = smRef}>{translate('Maximize Jump Range')}</li> <li className='lc' onClick={this._optimizeStandard}>{translate('Maximize Jump Range')}</li>
</ul> </ul>
<div className='select-group cap'>{translate('roles')}</div> <div className='select-group cap'>{translate('roles')}</div>
<ul> <ul>
<li className='lc' tabIndex="0" onClick={this._multiPurpose.bind(this, false, 0)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['multipurpose'] = smRef}>{translate('Multi-purpose')}</li> <li className='lc' onClick={this._multiPurpose.bind(this, false, 0)}>{translate('Multi-purpose')}</li>
<li className='lc' tabIndex="0" onClick={this._multiPurpose.bind(this, true, 2)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['combat'] = smRef}>{translate('Combat')}</li> <li className='lc' onClick={this._multiPurpose.bind(this, true, 2)}>{translate('Combat')}</li>
<li className='lc' tabIndex="0" onClick={this._optimizeCargo.bind(this, true)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['trader'] = smRef}>{translate('Trader')}</li> <li className='lc' onClick={this._optimizeCargo.bind(this, true)}>{translate('Trader')}</li>
<li className='lc' tabIndex="0" onClick={this._optimizeExplorer.bind(this, false)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['explorer'] = smRef}>{translate('Explorer')}</li> <li className='lc' onClick={this._optimizeExplorer.bind(this, false)}>{translate('Explorer')}</li>
<li className={cn('lc', { disabled: planetaryDisabled })} tabIndex={planetaryDisabled ? '' : '0'} onClick={!planetaryDisabled && this._optimizeExplorer.bind(this, true)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['planetary'] = smRef}>{translate('Planetary Explorer')}</li> <li className={cn('lc', { disabled: planetaryDisabled })} onClick={!planetaryDisabled && this._optimizeExplorer.bind(this, true)}>{translate('Planetary Explorer')}</li>
<li className='lc' tabIndex="0" onClick={this._optimizeMiner.bind(this, true)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['miner'] = smRef}>{translate('Miner')}</li> <li className='lc' onClick={this._optimizeMiner.bind(this, true)}>{translate('Miner')}</li>
<li className='lc' tabIndex="0" onClick={this._optimizeRacer.bind(this)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['racer'] = smRef}>{translate('Racer')}</li> <li className='lc' onClick={this._optimizeRacer.bind(this)}>{translate('Racer')}</li>
</ul> </ul>
</div>; </div>;
} }

View File

@@ -228,72 +228,6 @@ export class LinkIcon extends SvgIcon {
} }
} }
/**
* Material
*/
export class MatIcon extends SvgIcon {
/**
* Generate the SVG
* @return {React.Component} SVG Contents
*/
svg() {
return<g xmlns="http://www.w3.org/2000/svg">
<path fill="#FF7100" d="M 24.86,4.18
C 24.86,4.18 17.17,7.82 17.17,7.82
17.17,7.82 15.35,14.55 15.35,14.55
15.35,14.55 24.70,9.75 24.70,9.75
24.70,9.75 24.86,4.18 24.86,4.18 Z
M 32.21,17.45
C 32.21,17.45 26.41,11.18 26.41,11.18
26.41,11.18 19.51,11.51 19.51,11.51
19.51,11.51 26.92,19.01 26.92,19.01
26.92,19.01 32.21,17.45 32.21,17.45 Z
M 21.99,28.62
C 21.99,28.62 26.10,21.10 26.10,21.10
26.10,21.10 23.66,14.57 23.66,14.57
23.66,14.57 18.89,24.01 18.89,24.01
18.89,24.01 21.99,28.62 21.99,28.62 Z
M 8.33,22.24
C 8.33,22.24 16.67,23.87 16.67,23.87
16.67,23.87 22.06,19.51 22.06,19.51
22.06,19.51 11.70,17.84 11.70,17.84
11.70,17.84 8.33,22.24 8.33,22.24 Z
M 10.11,7.14
C 10.11,7.14 11.15,15.66 11.15,15.66
11.15,15.66 16.92,19.49 16.92,19.49
16.92,19.49 15.29,9.02 15.29,9.02
15.29,9.02 10.11,7.14 10.11,7.14 Z
M 27.69,2.67
C 27.69,2.67 35.89,16.00 35.89,16.00
35.89,16.00 27.69,29.33 27.69,29.33
27.69,29.33 11.31,29.33 11.31,29.33
11.31,29.33 3.11,16.00 3.11,16.00
3.11,16.00 11.31,2.67 11.31,2.67
11.31,2.67 27.67,2.67 27.67,2.67M 29.16,0.00
C 29.16,0.00 27.69,0.00 27.69,0.00
27.69,0.00 11.31,0.00 11.31,0.00
11.31,0.00 9.84,0.00 9.84,0.00
9.84,0.00 9.06,1.25 9.06,1.25
9.06,1.25 0.87,14.57 0.87,14.57
0.87,14.57 0.00,15.98 0.00,15.98
0.00,15.98 0.87,17.39 0.87,17.39
0.87,17.39 9.06,30.73 9.06,30.73
9.06,30.73 9.84,32.00 9.84,32.00
9.84,32.00 11.31,32.00 11.31,32.00
11.31,32.00 27.69,32.00 27.69,32.00
27.69,32.00 29.16,32.00 29.16,32.00
29.16,32.00 29.94,30.73 29.94,30.73
29.94,30.73 38.13,17.39 38.13,17.39
38.13,17.39 39.00,15.98 39.00,15.98
39.00,15.98 38.13,14.57 38.13,14.57
38.13,14.57 29.94,1.25 29.94,1.25
29.94,1.25 29.16,0.00 29.16,0.00
29.16,0.00 29.16,0.00 29.16,0.00 Z" />
</g>;
}
}
/** /**
* Shopping icon (dollar sign) * Shopping icon (dollar sign)
*/ */

View File

@@ -17,23 +17,12 @@ export default class UtilitySlotSection extends SlotSection {
constructor(props, context) { constructor(props, context) {
super(props, context, 'utility', 'utility mounts'); super(props, context, 'utility', 'utility mounts');
this._empty = this._empty.bind(this); this._empty = this._empty.bind(this);
this.selectedRefId = null;
this.firstRefId = 'emptyall';
this.lastRefId = 'po';
}
/**
* Handle focus if the component updates
* @param {Object} prevProps React Component properties
*/
componentDidUpdate(prevProps) {
this._handleSectionFocus(prevProps,this.firstRefId, this.lastRefId);
} }
/** /**
* Empty all utility slots and close the menu * Empty all utility slots and close the menu
*/ */
_empty() { _empty() {
this.selectedRefId = this.firstRefId;
this.props.ship.emptyUtility(); this.props.ship.emptyUtility();
this.props.onChange(); this.props.onChange();
this._close(); this._close();
@@ -47,9 +36,6 @@ export default class UtilitySlotSection extends SlotSection {
* @param {Synthetic} event Event * @param {Synthetic} event Event
*/ */
_use(group, rating, name, event) { _use(group, rating, name, event) {
this.selectedRefId = group;
if (rating !== null) this.selectedRefId += '-' + rating;
this.props.ship.useUtility(group, rating, name, event.getModifierState('Alt')); this.props.ship.useUtility(group, rating, name, event.getModifierState('Alt'));
this.props.onChange(); this.props.onChange();
this._close(); this._close();
@@ -108,28 +94,28 @@ export default class UtilitySlotSection extends SlotSection {
return <div className='select' onClick={(e) => e.stopPropagation()} onContextMenu={stopCtxPropagation}> return <div className='select' onClick={(e) => e.stopPropagation()} onContextMenu={stopCtxPropagation}>
<ul> <ul>
<li className='lc' tabIndex='0' onClick={this._empty} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['emptyall'] = smRef}>{translate('empty all')}</li> <li className='lc' onClick={this._empty}>{translate('empty all')}</li>
<li className='optional-hide' style={{ textAlign: 'center', marginTop: '1em' }}>{translate('PHRASE_ALT_ALL')}</li> <li className='optional-hide' style={{ textAlign: 'center', marginTop: '1em' }}>{translate('PHRASE_ALT_ALL')}</li>
</ul> </ul>
<div className='select-group cap'>{translate('sb')}</div> <div className='select-group cap'>{translate('sb')}</div>
<ul> <ul>
<li className='c' tabIndex='0' onClick={_use.bind(this, 'sb', 'A', null)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['sb-A'] = smRef}>A</li> <li className='c' onClick={_use.bind(this, 'sb', 'A', null)}>A</li>
<li className='c' tabIndex='0' onClick={_use.bind(this, 'sb', 'B', null)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['sb-B'] = smRef}>B</li> <li className='c' onClick={_use.bind(this, 'sb', 'B', null)}>B</li>
<li className='c' tabIndex='0' onClick={_use.bind(this, 'sb', 'C', null)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['sb-C'] = smRef}>C</li> <li className='c' onClick={_use.bind(this, 'sb', 'C', null)}>C</li>
<li className='c' tabIndex='0' onClick={_use.bind(this, 'sb', 'D', null)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['sb-D'] = smRef}>D</li> <li className='c' onClick={_use.bind(this, 'sb', 'D', null)}>D</li>
<li className='c' tabIndex='0' onClick={_use.bind(this, 'sb', 'E', null)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['sb-E'] = smRef}>E</li> <li className='c' onClick={_use.bind(this, 'sb', 'E', null)}>E</li>
</ul> </ul>
<div className='select-group cap'>{translate('hs')}</div> <div className='select-group cap'>{translate('hs')}</div>
<ul> <ul>
<li className='lc' tabIndex='0' onClick={_use.bind(this, 'hs', null, 'Heat Sink Launcher')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['hs'] = smRef}>{translate('Heat Sink Launcher')}</li> <li className='lc' onClick={_use.bind(this, 'hs', null, 'Heat Sink Launcher')}>{translate('Heat Sink Launcher')}</li>
</ul> </ul>
<div className='select-group cap'>{translate('ch')}</div> <div className='select-group cap'>{translate('ch')}</div>
<ul> <ul>
<li className='lc' tabIndex='0' onClick={_use.bind(this, 'ch', null, 'Chaff Launcher')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['ch'] = smRef}>{translate('Chaff Launcher')}</li> <li className='lc' onClick={_use.bind(this, 'ch', null, 'Chaff Launcher')}>{translate('Chaff Launcher')}</li>
</ul> </ul>
<div className='select-group cap'>{translate('po')}</div> <div className='select-group cap'>{translate('po')}</div>
<ul> <ul>
<li className='lc' tabIndex='0' onClick={_use.bind(this, 'po', null, 'Point Defence')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['po'] = smRef}>{translate('Point Defence')}</li> <li className='lc' onClick={_use.bind(this, 'po', null, 'Point Defence')}>{translate('Point Defence')}</li>
</ul> </ul>
</div>; </div>;
} }

View File

@@ -25,7 +25,6 @@
"PHRASE_SELECT_SPECIAL": "Click to select an experimental effect", "PHRASE_SELECT_SPECIAL": "Click to select an experimental effect",
"PHRASE_NO_SPECIAL": "No experimental effect", "PHRASE_NO_SPECIAL": "No experimental effect",
"PHRASE_SHOPPING_LIST": "Stations that sell this build", "PHRASE_SHOPPING_LIST": "Stations that sell this build",
"PHRASE_SHOPPING_MATS": "Materials needed for this build",
"PHRASE_REFIT_SHOPPING_LIST": "Stations that sell required modules", "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_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_LOSE_SHIELDS": "Shields will hold for",
@@ -61,7 +60,6 @@
"TT_SUMMARY_SPEED": "With full fuel tank and 4 pips to ENG", "TT_SUMMARY_SPEED": "With full fuel tank and 4 pips to ENG",
"TT_SUMMARY_SPEED_NONFUNCTIONAL": "Thrusters powered off or over maximum mass with full fuel and cargo loads", "TT_SUMMARY_SPEED_NONFUNCTIONAL": "Thrusters powered off or over maximum mass with full fuel and cargo loads",
"TT_SUMMARY_BOOST": "With full fuel tank and 4 pips to ENG", "TT_SUMMARY_BOOST": "With full fuel tank and 4 pips to ENG",
"TT_SUMMARY_BOOST_TIME": "Time between each boost with 4 pips to ENG",
"TT_SUMMARY_BOOST_NONFUNCTIONAL": "Power distributor not able to supply enough power to boost", "TT_SUMMARY_BOOST_NONFUNCTIONAL": "Power distributor not able to supply enough power to boost",
"TT_SUMMARY_SHIELDS": "Raw shield strength, including boosters", "TT_SUMMARY_SHIELDS": "Raw shield strength, including boosters",
"TT_SUMMARY_SHIELDS_SCB": "Raw shield strength, including boosters and SCBs", "TT_SUMMARY_SHIELDS_SCB": "Raw shield strength, including boosters and SCBs",
@@ -180,7 +178,6 @@
"internal protection": "Internal protection", "internal protection": "Internal protection",
"external protection": "External protection", "external protection": "External protection",
"engagement range": "Engagement range", "engagement range": "Engagement range",
"boost time": "Boost time",
"total": "Total", "total": "Total",
"ammo": "Ammunition maximum", "ammo": "Ammunition maximum",
"boot": "Boot time", "boot": "Boot time",

View File

@@ -9,7 +9,7 @@ import * as Utils from '../utils/UtilityFunctions';
import Ship from '../shipyard/Ship'; import Ship from '../shipyard/Ship';
import { toDetailedBuild } from '../shipyard/Serializer'; import { toDetailedBuild } from '../shipyard/Serializer';
import { outfitURL } from '../utils/UrlGenerators'; import { outfitURL } from '../utils/UrlGenerators';
import { FloppyDisk, Bin, Switch, Download, Reload, LinkIcon, ShoppingIcon, MatIcon } from '../components/SvgIcons'; import { FloppyDisk, Bin, Switch, Download, Reload, LinkIcon, ShoppingIcon } from '../components/SvgIcons';
import LZString from 'lz-string'; import LZString from 'lz-string';
import ShipSummaryTable from '../components/ShipSummaryTable'; import ShipSummaryTable from '../components/ShipSummaryTable';
import StandardSlotSection from '../components/StandardSlotSection'; import StandardSlotSection from '../components/StandardSlotSection';
@@ -25,7 +25,6 @@ import EngagementRange from '../components/EngagementRange';
import OutfittingSubpages from '../components/OutfittingSubpages'; import OutfittingSubpages from '../components/OutfittingSubpages';
import ModalExport from '../components/ModalExport'; import ModalExport from '../components/ModalExport';
import ModalPermalink from '../components/ModalPermalink'; import ModalPermalink from '../components/ModalPermalink';
import ModalShoppingList from '../components/ModalShoppingList';
/** /**
* Document Title Generator * Document Title Generator
@@ -59,7 +58,6 @@ export default class OutfittingPage extends Page {
this._fuelUpdated = this._fuelUpdated.bind(this); this._fuelUpdated = this._fuelUpdated.bind(this);
this._opponentUpdated = this._opponentUpdated.bind(this); this._opponentUpdated = this._opponentUpdated.bind(this);
this._engagementRangeUpdated = this._engagementRangeUpdated.bind(this); this._engagementRangeUpdated = this._engagementRangeUpdated.bind(this);
this._sectionMenuRefs = {};
} }
/** /**
@@ -507,13 +505,6 @@ export default class OutfittingPage extends Page {
window.open('https://eddb.io/station?s=' + shipId + '&m=' + modIds.join(',')); window.open('https://eddb.io/station?s=' + shipId + '&m=' + modIds.join(','));
} }
/**
* Generates the shopping list
*/
_genShoppingList() {
this.context.showModal(<ModalShoppingList ship={this.state.ship}/>);
}
/** /**
* Handle Key Down * Handle Key Down
* @param {Event} e Keyboard Event * @param {Event} e Keyboard Event
@@ -563,19 +554,10 @@ export default class OutfittingPage extends Page {
const shipSummaryMarker = `${ship.name}${_sStr}${_iStr}${_hStr}${_pStr}${_mStr}${ship.ladenMass}${cargo}${fuel}`; const shipSummaryMarker = `${ship.name}${_sStr}${_iStr}${_hStr}${_pStr}${_mStr}${ship.ladenMass}${cargo}${fuel}`;
const requirements = Ships[ship.id].requirements; const requirements = Ships[ship.id].requirements;
let requirementElements = []; var requirementElements = [];
/**
* Render the requirements for a ship / etc
* @param {string} className Class names
* @param {string} textKey The key for translating
* @param {String} tooltipTextKey Tooltip key
*/
function renderRequirement(className, textKey, tooltipTextKey) { function renderRequirement(className, textKey, tooltipTextKey) {
if (textKey.startsWith('empire') || textKey.startsWith('federation')) { requirementElements.push(<div key={textKey} className={className} onMouseEnter={termtip.bind(null, tooltipTextKey)} onMouseLeave={hide}>{translate(textKey)}</div>);
requirementElements.push(<div key={textKey} className={className} onMouseEnter={termtip.bind(null, tooltipTextKey)} onMouseLeave={hide}><a href={textKey.startsWith('empire') ? 'http://elite-dangerous.wikia.com/wiki/Empire/Ranks' : 'http://elite-dangerous.wikia.com/wiki/Federation/Ranks'} target="_blank" rel="noopener">{translate(textKey)}</a></div>);
} else {
requirementElements.push(<div key={textKey} className={className} onMouseEnter={termtip.bind(null, tooltipTextKey)} onMouseLeave={hide}>{translate(textKey)}</div>);
}
} }
if (requirements) { if (requirements) {
@@ -616,18 +598,15 @@ export default class OutfittingPage extends Page {
<button onClick={this._genShortlink} onMouseOver={termtip.bind(null, 'shortlink')} onMouseOut={hide}> <button onClick={this._genShortlink} onMouseOver={termtip.bind(null, 'shortlink')} onMouseOut={hide}>
<LinkIcon className='lg' /> <LinkIcon className='lg' />
</button> </button>
<button onClick={this._genShoppingList} onMouseOver={termtip.bind(null, 'PHRASE_SHOPPING_MATS')} onMouseOut={hide}>
<MatIcon className='lg' />
</button>
</div> </div>
</div> </div>
{/* Main tables */} {/* Main tables */}
<ShipSummaryTable ship={ship} fuel={fuel} cargo={cargo} marker={shipSummaryMarker} pips={{ sys: this.state.sys, wep: this.state.wep, eng: this.state.eng }} /> <ShipSummaryTable ship={ship} fuel={fuel} cargo={cargo} marker={shipSummaryMarker} pips={{sys: this.state.sys, wep: this.state.wep, eng: this.state.eng}} />
<StandardSlotSection ship={ship} fuel={fuel} cargo={cargo} code={standardSlotMarker} onChange={shipUpdated} onCargoChange={this._cargoUpdated} onFuelChange={this._fuelUpdated} currentMenu={menu} sectionMenuRefs={this._sectionMenuRefs}/> <StandardSlotSection ship={ship} fuel={fuel} cargo={cargo} code={standardSlotMarker} onChange={shipUpdated} onCargoChange={this._cargoUpdated} onFuelChange={this._fuelUpdated} currentMenu={menu} />
<InternalSlotSection ship={ship} code={internalSlotMarker} onChange={shipUpdated} onCargoChange={this._cargoUpdated} onFuelChange={this._fuelUpdated} currentMenu={menu} sectionMenuRefs={this._sectionMenuRefs}/> <InternalSlotSection ship={ship} code={internalSlotMarker} onChange={shipUpdated} onCargoChange={this._cargoUpdated} onFuelChange={this._fuelUpdated} currentMenu={menu} />
<HardpointSlotSection ship={ship} code={hardpointsSlotMarker} onChange={shipUpdated} onCargoChange={this._cargoUpdated} onFuelChange={this._fuelUpdated} currentMenu={menu} sectionMenuRefs={this._sectionMenuRefs}/> <HardpointSlotSection ship={ship} code={hardpointsSlotMarker} onChange={shipUpdated} onCargoChange={this._cargoUpdated} onFuelChange={this._fuelUpdated} currentMenu={menu} />
<UtilitySlotSection ship={ship} code={hardpointsSlotMarker} onChange={shipUpdated} onCargoChange={this._cargoUpdated} onFuelChange={this._fuelUpdated} currentMenu={menu} sectionMenuRefs={this._sectionMenuRefs}/> <UtilitySlotSection ship={ship} code={hardpointsSlotMarker} onChange={shipUpdated} onCargoChange={this._cargoUpdated} onFuelChange={this._fuelUpdated} currentMenu={menu} />
{/* Control of ship and opponent */} {/* Control of ship and opponent */}
<div className='group quarter'> <div className='group quarter'>

View File

@@ -274,11 +274,11 @@ export default class ShipyardPage extends Page {
for (let s of shipSummaries) { for (let s of shipSummaries) {
let shipSortValue = s[shipPredicate]; let shipSortValue = s[shipPredicate];
if(shipPredicateIndex != undefined) { if( shipPredicateIndex != undefined ) {
shipSortValue = shipSortValue[shipPredicateIndex]; shipSortValue = shipSortValue[shipPredicateIndex];
} }
if(shipSortValue != lastShipSortValue) { if( shipSortValue != lastShipSortValue ) {
backgroundHighlight = !backgroundHighlight; backgroundHighlight = !backgroundHighlight;
lastShipSortValue = shipSortValue; lastShipSortValue = shipSortValue;
} }

View File

@@ -45,9 +45,9 @@ export function totalJumpRange(mass, fsd, fuel) {
* @param {number} baseShield Base Shield strength MJ for ship * @param {number} baseShield Base Shield strength MJ for ship
* @param {object} sg The shield generator used * @param {object} sg The shield generator used
* @param {number} multiplier Shield multiplier for ship (1 + shield boosters if any) * @param {number} multiplier Shield multiplier for ship (1 + shield boosters if any)
* @return {number} Approximate shield strengh in MJ * @return {number} Approximate shield strengh in MJ
*/ */
export function shieldStrength(mass, baseShield, sg, multiplier) { export function shieldStrength(mass, baseShield, sg, multiplier, ship) {
// sg might be a module or a template; handle either here // sg might be a module or a template; handle either here
let minMass = sg instanceof Module ? sg.getMinMass() : sg.minmass; let minMass = sg instanceof Module ? sg.getMinMass() : sg.minmass;
let optMass = sg instanceof Module ? sg.getOptMass() : sg.optmass; let optMass = sg instanceof Module ? sg.getOptMass() : sg.optmass;
@@ -55,6 +55,17 @@ export function shieldStrength(mass, baseShield, sg, multiplier) {
let minMul = sg instanceof Module ? sg.getMinMul() : sg.minmul; let minMul = sg instanceof Module ? sg.getMinMul() : sg.minmul;
let optMul = sg instanceof Module ? sg.getOptMul() : sg.optmul; let optMul = sg instanceof Module ? sg.getOptMul() : sg.optmul;
let maxMul = sg instanceof Module ? sg.getMaxMul() : sg.maxmul; let maxMul = sg instanceof Module ? sg.getMaxMul() : sg.maxmul;
if (ship) {
for (const i of ship.hardpoints) {
if (!i.maxClass) {
if (i.grp === 'sb' || (i.m && i.m.grp === 'sb')) {
if (!isNaN(i.m.getModValue('optmul'))) {
optMul += i.m.getModValue('optmul') / 10000;
}
}
}
}
}
let xnorm = Math.min(1, (maxMass - mass) / (maxMass - minMass)); let xnorm = Math.min(1, (maxMass - mass) / (maxMass - minMass));
let exponent = Math.log((optMul - minMul) / (maxMul - minMul)) / Math.log(Math.min(1, (maxMass - optMass) / (maxMass - minMass))); let exponent = Math.log((optMul - minMul) / (maxMul - minMul)) / Math.log(Math.min(1, (maxMass - optMass) / (maxMass - minMass)));
let ynorm = Math.pow(xnorm, exponent); let ynorm = Math.pow(xnorm, exponent);
@@ -350,7 +361,7 @@ export function shieldMetrics(ship, sys) {
boosterKinDmg = boosterKinDmg > 0.7 ? boosterKinDmg : 0.7 - (0.7 - boosterKinDmg) / 2; boosterKinDmg = boosterKinDmg > 0.7 ? boosterKinDmg : 0.7 - (0.7 - boosterKinDmg) / 2;
boosterThermDmg = boosterThermDmg > 0.7 ? boosterThermDmg : 0.7 - (0.7 - boosterThermDmg) / 2; boosterThermDmg = boosterThermDmg > 0.7 ? boosterThermDmg : 0.7 - (0.7 - boosterThermDmg) / 2;
const generatorStrength = this.shieldStrength(ship.hullMass, ship.baseShieldStrength, shieldGenerator, 1); const generatorStrength = this.shieldStrength(ship.hullMass, ship.baseShieldStrength, shieldGenerator, 1, ship);
const boostersStrength = generatorStrength * boost; const boostersStrength = generatorStrength * boost;
// Recover time is the time taken to go from 0 to 50%. It includes a 16-second wait before shields start to recover // Recover time is the time taken to go from 0 to 50%. It includes a 16-second wait before shields start to recover
@@ -452,19 +463,6 @@ export function shieldMetrics(ship, sys) {
return shield; return shield;
} }
/**
* Calculate time from one boost to another
* @return {number} Boost frequency in seconds
* @param ship
*/
export function calcBoost(ship) {
if (!ship.boostEnergy || !ship.standard[4] || !ship.standard[4].m) {
return undefined;
}
return ship.boostEnergy / ship.standard[4].m.engrate;
}
/** /**
* Calculate armour metrics * Calculate armour metrics
* @param {Object} ship The ship * @param {Object} ship The ship

View File

@@ -136,7 +136,7 @@ export default class Module {
if (modification.type === 'percentage') { if (modification.type === 'percentage') {
modValue = this.getModValue(name) / 10000; modValue = this.getModValue(name) / 10000;
} else if (modification.type === 'numeric') { } else if (modification.type === 'numeric') {
modValue = this.getModValue(name) / 100; modValue = this.getModValue(name)/ 100;
} else { } else {
modValue = this.getModValue(name); modValue = this.getModValue(name);
} }

View File

@@ -241,7 +241,7 @@ export default class Ship {
} }
// TODO Not accurate if the ship has modified shield boosters // TODO Not accurate if the ship has modified shield boosters
return Calc.shieldStrength(this.hullMass, this.baseShieldStrength, sg, 1 + (multiplierDelta || 0)); return Calc.shieldStrength(this.hullMass, this.baseShieldStrength, sg, 1 + (multiplierDelta || 0), this);
} }
/** /**

View File

@@ -1,5 +1,5 @@
import * as ModuleUtils from './ModuleUtils'; import * as ModuleUtils from './ModuleUtils'
import { canMount } from '../utils/SlotFunctions'; import { canMount } from '../utils/SlotFunctions'
/** /**
* Standard / typical role for multi-purpose or combat (if shielded with better bulkheads) * Standard / typical role for multi-purpose or combat (if shielded with better bulkheads)
@@ -7,20 +7,20 @@ import { canMount } from '../utils/SlotFunctions';
* @param {Boolean} shielded True if shield generator should be included * @param {Boolean} shielded True if shield generator should be included
* @param {integer} bulkheadIndex Bulkhead to use see Constants.BulkheadNames * @param {integer} bulkheadIndex Bulkhead to use see Constants.BulkheadNames
*/ */
export function multiPurpose(ship, shielded, bulkheadIndex) { export function multiPurpose (ship, shielded, bulkheadIndex) {
ship.useStandard('A') ship.useStandard('A')
.use(ship.standard[3], ModuleUtils.standard(3, ship.standard[3].maxClass + 'D')) // D Life Support .use(ship.standard[3], ModuleUtils.standard(3, ship.standard[3].maxClass + 'D')) // D Life Support
.use(ship.standard[5], ModuleUtils.standard(5, ship.standard[5].maxClass + 'D')) // D Sensors .use(ship.standard[5], ModuleUtils.standard(5, ship.standard[5].maxClass + 'D')) // D Sensors
.useBulkhead(bulkheadIndex); .useBulkhead(bulkheadIndex)
if (shielded) { if (shielded) {
ship.internal.some(function(slot) { ship.internal.some(function (slot) {
if (canMount(ship, slot, 'sg')) { // Assuming largest slot can hold an eligible shield if (canMount(ship, slot, 'sg')) { // Assuming largest slot can hold an eligible shield
ship.use(slot, ModuleUtils.findInternal('sg', slot.maxClass, 'A')); ship.use(slot, ModuleUtils.findInternal('sg', slot.maxClass, 'A'))
ship.setSlotEnabled(slot, true); ship.setSlotEnabled(slot, true)
return true; return true
} }
}); })
} }
} }
@@ -30,51 +30,51 @@ export function multiPurpose(ship, shielded, bulkheadIndex) {
* @param {Boolean} shielded True if shield generator should be included * @param {Boolean} shielded True if shield generator should be included
* @param {Object} standardOpts [Optional] Standard module optional overrides * @param {Object} standardOpts [Optional] Standard module optional overrides
*/ */
export function trader(ship, shielded, standardOpts) { export function trader (ship, shielded, standardOpts) {
let usedSlots = []; let usedSlots = []
let bstCount = 2; let bstCount = 2
let sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass); let sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass)
ship.useStandard('A') ship.useStandard('A')
.use(ship.standard[3], ModuleUtils.standard(3, ship.standard[3].maxClass + 'D')) // D Life Support .use(ship.standard[3], ModuleUtils.standard(3, ship.standard[3].maxClass + 'D')) // D Life Support
.use(ship.standard[1], ModuleUtils.standard(1, ship.standard[1].maxClass + 'D')) // D Life Support .use(ship.standard[1], ModuleUtils.standard(1, ship.standard[1].maxClass + 'D')) // D Life Support
.use(ship.standard[4], ModuleUtils.standard(4, ship.standard[4].maxClass + 'D')) // D Life Support .use(ship.standard[4], ModuleUtils.standard(4, ship.standard[4].maxClass + 'D')) // D Life Support
.use(ship.standard[5], ModuleUtils.standard(5, ship.standard[5].maxClass + 'D')); // D Sensors .use(ship.standard[5], ModuleUtils.standard(5, ship.standard[5].maxClass + 'D')) // D Sensors
const shieldOrder = [1, 2, 3, 4, 5, 6, 7, 8]; const shieldOrder = [1, 2, 3, 4, 5, 6, 7, 8]
const shieldInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const shieldInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.sg) .filter(a => (!a.eligible) || a.eligible.sg)
.filter(a => a.maxClass >= sg.class) .filter(a => a.maxClass >= sg.class)
.sort((a, b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass)); .sort((a, b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass))
shieldInternals.some(function(slot) { shieldInternals.some(function (slot) {
if (canMount(ship, slot, 'sg')) { // Assuming largest slot can hold an eligible shield if (canMount(ship, slot, 'sg')) { // Assuming largest slot can hold an eligible shield
const shield = ModuleUtils.findInternal('sg', slot.maxClass, 'A'); const shield = ModuleUtils.findInternal('sg', slot.maxClass, 'A')
if (shield && shield.maxmass > ship.hullMass) { if (shield && shield.maxmass > ship.hullMass) {
ship.use(slot, shield); ship.use(slot, shield)
ship.setSlotEnabled(slot, true); ship.setSlotEnabled(slot, true)
usedSlots.push(slot); usedSlots.push(slot)
return true; return true
} }
} }
}); })
// Fill the empty internals with cargo racks // Fill the empty internals with cargo racks
for (let i = ship.internal.length; i--;) { for (let i = ship.internal.length; i--;) {
let slot = ship.internal[i]; let slot = ship.internal[i]
if (usedSlots.indexOf(slot) == -1 && canMount(ship, slot, 'cr')) { if (usedSlots.indexOf(slot) == -1 && canMount(ship, slot, 'cr')) {
ship.use(slot, ModuleUtils.findInternal('cr', slot.maxClass, 'E')); ship.use(slot, ModuleUtils.findInternal('cr', slot.maxClass, 'E'))
} }
} }
// Empty the hardpoints // Empty the hardpoints
for (let s of ship.hardpoints) { for (let s of ship.hardpoints) {
ship.use(s, null); ship.use(s, null)
} }
for (let s of ship.hardpoints) { for (let s of ship.hardpoints) {
if (s.maxClass == 0 && bstCount) { // Mount up to 2 boosters if (s.maxClass == 0 && bstCount) { // Mount up to 2 boosters
ship.use(s, ModuleUtils.hardpoints('04')); ship.use(s, ModuleUtils.hardpoints('04'))
bstCount--; bstCount--
} else { } else {
ship.use(s, null); ship.use(s, null)
} }
} }
// ship.useLightestStandard(standardOpts); // ship.useLightestStandard(standardOpts);
@@ -85,127 +85,127 @@ export function trader(ship, shielded, standardOpts) {
* @param {Ship} ship Ship instance * @param {Ship} ship Ship instance
* @param {Boolean} planetary True if Planetary Vehicle Hangar (PVH) should be included * @param {Boolean} planetary True if Planetary Vehicle Hangar (PVH) should be included
*/ */
export function explorer(ship, planetary) { export function explorer (ship, planetary) {
let standardOpts = { ppRating: 'A' }, let standardOpts = {ppRating: 'A'},
heatSinkCount = 2, // Fit 2 heat sinks if possible heatSinkCount = 2, // Fit 2 heat sinks if possible
usedSlots = [], usedSlots = [],
sgSlot, sgSlot,
fuelScoopSlot, fuelScoopSlot,
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass); sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass)
if (!planetary) { // Non-planetary explorers don't really need to boost if (!planetary) { // Non-planetary explorers don't really need to boost
standardOpts.pd = '1D'; standardOpts.pd = '1D'
} }
// Cargo hatch can be disabled // Cargo hatch can be disabled
ship.setSlotEnabled(ship.cargoHatch, false); ship.setSlotEnabled(ship.cargoHatch, false)
// Advanced Discovery Scanner - class 1 or higher // Advanced Discovery Scanner - class 1 or higher
const adsOrder = [1, 2, 3, 4, 5, 6, 7, 8]; const adsOrder = [1, 2, 3, 4, 5, 6, 7, 8]
const adsInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const adsInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.sc) .filter(a => (!a.eligible) || a.eligible.sc)
.sort((a, b) => adsOrder.indexOf(a.maxClass) - adsOrder.indexOf(b.maxClass)); .sort((a, b) => adsOrder.indexOf(a.maxClass) - adsOrder.indexOf(b.maxClass))
for (let i = 0; i < adsInternals.length; i++) { for (let i = 0; i < adsInternals.length; i++) {
if (canMount(ship, adsInternals[i], 'sc')) { if (canMount(ship, adsInternals[i], 'sc')) {
ship.use(adsInternals[i], ModuleUtils.internal('2f')); ship.use(adsInternals[i], ModuleUtils.internal('2f'))
usedSlots.push(adsInternals[i]); usedSlots.push(adsInternals[i])
break; break
} }
} }
if (planetary) { if (planetary) {
// Planetary Vehicle Hangar - class 2 or higher // Planetary Vehicle Hangar - class 2 or higher
const pvhOrder = [2, 3, 4, 5, 6, 7, 8, 1]; const pvhOrder = [2, 3, 4, 5, 6, 7, 8, 1]
const pvhInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const pvhInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.pv) .filter(a => (!a.eligible) || a.eligible.pv)
.sort((a, b) => pvhOrder.indexOf(a.maxClass) - pvhOrder.indexOf(b.maxClass)); .sort((a, b) => pvhOrder.indexOf(a.maxClass) - pvhOrder.indexOf(b.maxClass))
for (let i = 0; i < pvhInternals.length; i++) { for (let i = 0; i < pvhInternals.length; i++) {
if (canMount(ship, pvhInternals[i], 'pv')) { if (canMount(ship, pvhInternals[i], 'pv')) {
// Planetary Vehical Hangar only has even classes // Planetary Vehical Hangar only has even classes
const pvhClass = pvhInternals[i].maxClass % 2 === 1 ? pvhInternals[i].maxClass - 1 : pvhInternals[i].maxClass; const pvhClass = pvhInternals[i].maxClass % 2 === 1 ? pvhInternals[i].maxClass - 1 : pvhInternals[i].maxClass
ship.use(pvhInternals[i], ModuleUtils.findInternal('pv', pvhClass, 'G')); // G is lower mass ship.use(pvhInternals[i], ModuleUtils.findInternal('pv', pvhClass, 'G')) // G is lower mass
ship.setSlotEnabled(pvhInternals[i], false); // Disable power for Planetary Vehical Hangar ship.setSlotEnabled(pvhInternals[i], false) // Disable power for Planetary Vehical Hangar
usedSlots.push(pvhInternals[i]); usedSlots.push(pvhInternals[i])
break; break
} }
} }
} }
// Shield generator // Shield generator
const shieldOrder = [1, 2, 3, 4, 5, 6, 7, 8]; const shieldOrder = [1, 2, 3, 4, 5, 6, 7, 8]
const shieldInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const shieldInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.sg) .filter(a => (!a.eligible) || a.eligible.sg)
.filter(a => a.maxClass >= sg.class) .filter(a => a.maxClass >= sg.class)
.sort((a, b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass)); .sort((a, b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass))
for (let i = 0; i < shieldInternals.length; i++) { for (let i = 0; i < shieldInternals.length; i++) {
if (canMount(ship, shieldInternals[i], 'sg')) { if (canMount(ship, shieldInternals[i], 'sg')) {
ship.use(shieldInternals[i], sg); ship.use(shieldInternals[i], sg)
usedSlots.push(shieldInternals[i]); usedSlots.push(shieldInternals[i])
sgSlot = shieldInternals[i]; sgSlot = shieldInternals[i]
break; break
} }
} }
// Detailed Surface Scanner // Detailed Surface Scanner
const dssOrder = [1, 2, 3, 4, 5, 6, 7, 8]; const dssOrder = [1, 2, 3, 4, 5, 6, 7, 8]
const dssInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const dssInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.sc) .filter(a => (!a.eligible) || a.eligible.sc)
.sort((a, b) => dssOrder.indexOf(a.maxClass) - dssOrder.indexOf(b.maxClass)); .sort((a, b) => dssOrder.indexOf(a.maxClass) - dssOrder.indexOf(b.maxClass))
for (let i = 0; i < dssInternals.length; i++) { for (let i = 0; i < dssInternals.length; i++) {
if (canMount(ship, dssInternals[i], 'sc')) { if (canMount(ship, dssInternals[i], 'sc')) {
ship.use(dssInternals[i], ModuleUtils.internal('2i')); ship.use(dssInternals[i], ModuleUtils.internal('2i'))
usedSlots.push(dssInternals[i]); usedSlots.push(dssInternals[i])
break; break
} }
} }
// Fuel scoop - best possible // Fuel scoop - best possible
const fuelScoopOrder = [8, 7, 6, 5, 4, 3, 2, 1]; const fuelScoopOrder = [8, 7, 6, 5, 4, 3, 2, 1]
const fuelScoopInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const fuelScoopInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.fs) .filter(a => (!a.eligible) || a.eligible.fs)
.sort((a, b) => fuelScoopOrder.indexOf(a.maxClass) - fuelScoopOrder.indexOf(b.maxClass)); .sort((a, b) => fuelScoopOrder.indexOf(a.maxClass) - fuelScoopOrder.indexOf(b.maxClass))
for (let i = 0; i < fuelScoopInternals.length; i++) { for (let i = 0; i < fuelScoopInternals.length; i++) {
if (canMount(ship, fuelScoopInternals[i], 'fs')) { if (canMount(ship, fuelScoopInternals[i], 'fs')) {
ship.use(fuelScoopInternals[i], ModuleUtils.findInternal('fs', fuelScoopInternals[i].maxClass, 'A')); ship.use(fuelScoopInternals[i], ModuleUtils.findInternal('fs', fuelScoopInternals[i].maxClass, 'A'))
usedSlots.push(fuelScoopInternals[i]); usedSlots.push(fuelScoopInternals[i])
fuelScoopSlot = fuelScoopInternals[i]; fuelScoopSlot = fuelScoopInternals[i]
break; break
} }
} }
// AFMUs - fill as they are 0-weight // AFMUs - fill as they are 0-weight
const afmuOrder = [8, 7, 6, 5, 4, 3, 2, 1]; const afmuOrder = [8, 7, 6, 5, 4, 3, 2, 1]
const afmuInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const afmuInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.pc) .filter(a => (!a.eligible) || a.eligible.pc)
.sort((a, b) => afmuOrder.indexOf(a.maxClass) - afmuOrder.indexOf(b.maxClass)); .sort((a, b) => afmuOrder.indexOf(a.maxClass) - afmuOrder.indexOf(b.maxClass))
for (let i = 0; i < afmuInternals.length; i++) { for (let i = 0; i < afmuInternals.length; i++) {
if (canMount(ship, afmuInternals[i], 'am')) { if (canMount(ship, afmuInternals[i], 'am')) {
ship.use(afmuInternals[i], ModuleUtils.findInternal('am', afmuInternals[i].maxClass, 'A')); ship.use(afmuInternals[i], ModuleUtils.findInternal('am', afmuInternals[i].maxClass, 'A'))
usedSlots.push(afmuInternals[i]); usedSlots.push(afmuInternals[i])
ship.setSlotEnabled(afmuInternals[i], false); // Disable power for AFM Unit ship.setSlotEnabled(afmuInternals[i], false) // Disable power for AFM Unit
} }
} }
for (let s of ship.hardpoints) { for (let s of ship.hardpoints) {
if (s.maxClass == 0 && heatSinkCount) { // Mount up to 2 heatsinks if (s.maxClass == 0 && heatSinkCount) { // Mount up to 2 heatsinks
ship.use(s, ModuleUtils.hardpoints('02')); ship.use(s, ModuleUtils.hardpoints('02'))
ship.setSlotEnabled(s, heatSinkCount == 2); // Only enable a single Heatsink ship.setSlotEnabled(s, heatSinkCount == 2) // Only enable a single Heatsink
heatSinkCount--; heatSinkCount--
} else { } else {
ship.use(s, null); ship.use(s, null)
} }
} }
if (sgSlot && fuelScoopSlot) { if (sgSlot && fuelScoopSlot) {
// The SG and Fuel scoop to not need to be powered at the same time // The SG and Fuel scoop to not need to be powered at the same time
if (sgSlot.m.getPowerUsage() > fuelScoopSlot.m.getPowerUsage()) { // The Shield generator uses the most power if (sgSlot.m.getPowerUsage() > fuelScoopSlot.m.getPowerUsage()) { // The Shield generator uses the most power
ship.setSlotEnabled(fuelScoopSlot, false); ship.setSlotEnabled(fuelScoopSlot, false)
} else { // The Fuel scoop uses the most power } else { // The Fuel scoop uses the most power
ship.setSlotEnabled(sgSlot, false); ship.setSlotEnabled(sgSlot, false)
} }
} }
ship.useLightestStandard(standardOpts); ship.useLightestStandard(standardOpts)
} }
/** /**
@@ -213,188 +213,188 @@ export function explorer(ship, planetary) {
* @param {Ship} ship Ship instance * @param {Ship} ship Ship instance
* @param {Boolean} shielded True if shield generator should be included * @param {Boolean} shielded True if shield generator should be included
*/ */
export function miner(ship, shielded) { export function miner (ship, shielded) {
shielded = true; shielded = true
let standardOpts = { ppRating: 'A' }, let standardOpts = {ppRating: 'A'},
miningLaserCount = 2, miningLaserCount = 2,
usedSlots = [], usedSlots = [],
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass); sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass)
// Cargo hatch should be enabled // Cargo hatch should be enabled
ship.setSlotEnabled(ship.cargoHatch, true); ship.setSlotEnabled(ship.cargoHatch, true)
// Largest possible refinery // Largest possible refinery
const refineryOrder = [4, 5, 6, 7, 8, 3, 2, 1]; const refineryOrder = [4, 5, 6, 7, 8, 3, 2, 1]
const refineryInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const refineryInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.rf) .filter(a => (!a.eligible) || a.eligible.rf)
.sort((a, b) => refineryOrder.indexOf(a.maxClass) - refineryOrder.indexOf(b.maxClass)); .sort((a, b) => refineryOrder.indexOf(a.maxClass) - refineryOrder.indexOf(b.maxClass))
for (let i = 0; i < refineryInternals.length; i++) { for (let i = 0; i < refineryInternals.length; i++) {
if (canMount(ship, refineryInternals[i], 'rf')) { if (canMount(ship, refineryInternals[i], 'rf')) {
ship.use(refineryInternals[i], ModuleUtils.findInternal('rf', Math.min(refineryInternals[i].maxClass, 4), 'A')); ship.use(refineryInternals[i], ModuleUtils.findInternal('rf', Math.min(refineryInternals[i].maxClass, 4), 'A'))
usedSlots.push(refineryInternals[i]); usedSlots.push(refineryInternals[i])
break; break
} }
} }
// Prospector limpet controller - 3A if possible // Prospector limpet controller - 3A if possible
const prospectorOrder = [3, 4, 5, 6, 7, 8, 2, 1]; const prospectorOrder = [3, 4, 5, 6, 7, 8, 2, 1]
const prospectorInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const prospectorInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.pc) .filter(a => (!a.eligible) || a.eligible.pc)
.sort((a, b) => prospectorOrder.indexOf(a.maxClass) - prospectorOrder.indexOf(b.maxClass)); .sort((a, b) => prospectorOrder.indexOf(a.maxClass) - prospectorOrder.indexOf(b.maxClass))
for (let i = 0; i < prospectorInternals.length; i++) { for (let i = 0; i < prospectorInternals.length; i++) {
if (canMount(ship, prospectorInternals[i], 'pc')) { if (canMount(ship, prospectorInternals[i], 'pc')) {
// Prospector only has odd classes // Prospector only has odd classes
const prospectorClass = prospectorInternals[i].maxClass % 2 === 0 ? prospectorInternals[i].maxClass - 1 : prospectorInternals[i].maxClass; const prospectorClass = prospectorInternals[i].maxClass % 2 === 0 ? prospectorInternals[i].maxClass - 1 : prospectorInternals[i].maxClass
ship.use(prospectorInternals[i], ModuleUtils.findInternal('pc', prospectorClass, 'A')); ship.use(prospectorInternals[i], ModuleUtils.findInternal('pc', prospectorClass, 'A'))
usedSlots.push(prospectorInternals[i]); usedSlots.push(prospectorInternals[i])
break; break
} }
} }
// Shield generator if required // Shield generator if required
if (shielded) { if (shielded) {
const shieldOrder = [1, 2, 3, 4, 5, 6, 7, 8]; const shieldOrder = [1, 2, 3, 4, 5, 6, 7, 8]
const shieldInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const shieldInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.sg) .filter(a => (!a.eligible) || a.eligible.sg)
.filter(a => a.maxClass >= sg.class) .filter(a => a.maxClass >= sg.class)
.sort((a, b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass)); .sort((a, b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass))
for (let i = 0; i < shieldInternals.length; i++) { for (let i = 0; i < shieldInternals.length; i++) {
if (canMount(ship, shieldInternals[i], 'sg')) { if (canMount(ship, shieldInternals[i], 'sg')) {
ship.use(shieldInternals[i], sg); ship.use(shieldInternals[i], sg)
usedSlots.push(shieldInternals[i]); usedSlots.push(shieldInternals[i])
break; break
} }
} }
} }
// Dual mining lasers of highest possible class; remove anything else // Dual mining lasers of highest possible class; remove anything else
const miningLaserOrder = [2, 3, 4, 1, 0]; const miningLaserOrder = [2, 3, 4, 1, 0]
const miningLaserHardpoints = ship.hardpoints.concat().sort(function(a, b) { const miningLaserHardpoints = ship.hardpoints.concat().sort(function (a, b) {
return miningLaserOrder.indexOf(a.maxClass) - miningLaserOrder.indexOf(b.maxClass); return miningLaserOrder.indexOf(a.maxClass) - miningLaserOrder.indexOf(b.maxClass)
}); })
for (let s of miningLaserHardpoints) { for (let s of miningLaserHardpoints) {
if (s.maxClass >= 1 && miningLaserCount) { if (s.maxClass >= 1 && miningLaserCount) {
ship.use(s, ModuleUtils.hardpoints(s.maxClass >= 2 ? '2m' : '2l')); ship.use(s, ModuleUtils.hardpoints(s.maxClass >= 2 ? '2m' : '2l'))
miningLaserCount--; miningLaserCount--
} else { } else {
ship.use(s, null); ship.use(s, null)
} }
} }
// Number of collector limpets required to be active is a function of the size of the ship and the power of the lasers // Number of collector limpets required to be active is a function of the size of the ship and the power of the lasers
const miningLaserDps = ship.hardpoints.filter(h => h.m != null) const miningLaserDps = ship.hardpoints.filter(h => h.m != null)
.reduce(function(a, b) { .reduce(function (a, b) {
return a + b.m.getDps(); return a + b.m.getDps()
}, 0); }, 0)
// Find out how many internal slots we have, and their potential cargo size // Find out how many internal slots we have, and their potential cargo size
const potentialCargo = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const potentialCargo = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.cr) .filter(a => (!a.eligible) || a.eligible.cr)
.map(b => Math.pow(2, b.maxClass)); .map(b => Math.pow(2, b.maxClass))
// One collector for each 1.25 DPS, multiply by 1.25 for medium ships and 1.5 for large ships as they have further to travel // One collector for each 1.25 DPS, multiply by 1.25 for medium ships and 1.5 for large ships as they have further to travel
// 0 if we only have 1 cargo slot, otherwise minium of 1 and maximum of 6 (excluding size modifier) // 0 if we only have 1 cargo slot, otherwise minium of 1 and maximum of 6 (excluding size modifier)
const sizeModifier = ship.class == 2 ? 1.2 : ship.class == 3 ? 1.5 : 1; const sizeModifier = ship.class == 2 ? 1.2 : ship.class == 3 ? 1.5 : 1
let collectorLimpetsRequired = potentialCargo.length == 1 ? 0 : Math.ceil(sizeModifier * Math.min(6, Math.floor(miningLaserDps / 1.25))); let collectorLimpetsRequired = potentialCargo.length == 1 ? 0 : Math.ceil(sizeModifier * Math.min(6, Math.floor(miningLaserDps / 1.25)))
if (collectorLimpetsRequired > 0) { if (collectorLimpetsRequired > 0) {
const collectorOrder = [1, 2, 3, 4, 5, 6, 7, 8]; const collectorOrder = [1, 2, 3, 4, 5, 6, 7, 8]
const collectorInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const collectorInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.cc) .filter(a => (!a.eligible) || a.eligible.cc)
.sort((a, b) => collectorOrder.indexOf(a.maxClass) - collectorOrder.indexOf(b.maxClass)); .sort((a, b) => collectorOrder.indexOf(a.maxClass) - collectorOrder.indexOf(b.maxClass))
// Always keep at least 2 slots free for cargo racks (1 for shielded) // Always keep at least 2 slots free for cargo racks (1 for shielded)
for (let i = 0; i < collectorInternals.length - (shielded ? 1 : 2) && collectorLimpetsRequired > 0; i++) { for (let i = 0; i < collectorInternals.length - (shielded ? 1 : 2) && collectorLimpetsRequired > 0; i++) {
if (canMount(ship, collectorInternals[i], 'cc')) { if (canMount(ship, collectorInternals[i], 'cc')) {
// Collector only has odd classes // Collector only has odd classes
const collectorClass = collectorInternals[i].maxClass % 2 === 0 ? collectorInternals[i].maxClass - 1 : collectorInternals[i].maxClass; const collectorClass = collectorInternals[i].maxClass % 2 === 0 ? collectorInternals[i].maxClass - 1 : collectorInternals[i].maxClass
ship.use(collectorInternals[i], ModuleUtils.findInternal('cc', collectorClass, 'D')); ship.use(collectorInternals[i], ModuleUtils.findInternal('cc', collectorClass, 'D'))
usedSlots.push(collectorInternals[i]); usedSlots.push(collectorInternals[i])
collectorLimpetsRequired -= collectorInternals[i].m.maximum; collectorLimpetsRequired -= collectorInternals[i].m.maximum
} }
} }
} }
// Power distributor to power the mining lasers indefinitely // Power distributor to power the mining lasers indefinitely
const wepRateRequired = ship.hardpoints.filter(h => h.m != null) const wepRateRequired = ship.hardpoints.filter(h => h.m != null)
.reduce(function(a, b) { .reduce(function (a, b) {
return a + b.m.getEps(); return a + b.m.getEps()
}, 0); }, 0)
standardOpts.pd = ship.getAvailableModules().matchingPowerDist({ weprate: wepRateRequired }).id; standardOpts.pd = ship.getAvailableModules().matchingPowerDist({weprate: wepRateRequired}).id
// Fill the empty internals with cargo racks // Fill the empty internals with cargo racks
for (let i = ship.internal.length; i--;) { for (let i = ship.internal.length; i--;) {
let slot = ship.internal[i]; let slot = ship.internal[i]
if (usedSlots.indexOf(slot) == -1 && canMount(ship, slot, 'cr')) { if (usedSlots.indexOf(slot) == -1 && canMount(ship, slot, 'cr')) {
ship.use(slot, ModuleUtils.findInternal('cr', slot.maxClass, 'E')); ship.use(slot, ModuleUtils.findInternal('cr', slot.maxClass, 'E'))
} }
} }
ship.useLightestStandard(standardOpts); ship.useLightestStandard(standardOpts)
} }
/** /**
* Racer Role * Racer Role
* @param {Ship} ship Ship instance * @param {Ship} ship Ship instance
*/ */
export function racer(ship) { export function racer (ship) {
let standardOpts = {}, let standardOpts = {},
usedSlots = [], usedSlots = [],
sgSlot, sgSlot,
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass); sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass)
// Cargo hatch can be disabled // Cargo hatch can be disabled
ship.setSlotEnabled(ship.cargoHatch, false); ship.setSlotEnabled(ship.cargoHatch, false)
// Shield generator // Shield generator
const shieldOrder = [1, 2, 3, 4, 5, 6, 7, 8]; const shieldOrder = [1, 2, 3, 4, 5, 6, 7, 8]
const shieldInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const shieldInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.sg) .filter(a => (!a.eligible) || a.eligible.sg)
.filter(a => a.maxClass >= sg.class) .filter(a => a.maxClass >= sg.class)
.sort((a, b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass)); .sort((a, b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass))
for (let i = 0; i < shieldInternals.length; i++) { for (let i = 0; i < shieldInternals.length; i++) {
if (canMount(ship, shieldInternals[i], 'sg')) { if (canMount(ship, shieldInternals[i], 'sg')) {
ship.use(shieldInternals[i], sg); ship.use(shieldInternals[i], sg)
usedSlots.push(shieldInternals[i]); usedSlots.push(shieldInternals[i])
sgSlot = shieldInternals[i]; sgSlot = shieldInternals[i]
break; break
} }
} }
// Empty the hardpoints // Empty the hardpoints
for (let s of ship.hardpoints) { for (let s of ship.hardpoints) {
ship.use(s, null); ship.use(s, null)
} }
// Empty the internals // Empty the internals
for (let i = ship.internal.length; i--;) { for (let i = ship.internal.length; i--;) {
let slot = ship.internal[i]; let slot = ship.internal[i]
if (usedSlots.indexOf(slot) == -1) { if (usedSlots.indexOf(slot) == -1) {
ship.use(slot, null); ship.use(slot, null)
} }
} }
// Best thrusters // Best thrusters
if (ship.standard[1].maxClass === 3) { if (ship.standard[1].maxClass === 3) {
standardOpts.th = 'tz'; standardOpts.th = 'tz'
} else if (ship.standard[1].maxClass === 2) { } else if (ship.standard[1].maxClass === 2) {
standardOpts.th = 'u0'; standardOpts.th = 'u0'
} else { } else {
standardOpts.th = ship.standard[1].maxClass + 'A'; standardOpts.th = ship.standard[1].maxClass + 'A'
} }
// Best power distributor for more boosting // Best power distributor for more boosting
standardOpts.pd = ship.standard[4].maxClass + 'A'; standardOpts.pd = ship.standard[4].maxClass + 'A'
// Smallest possible FSD drive // Smallest possible FSD drive
standardOpts.fsd = '2D'; standardOpts.fsd = '2D'
// Minimal fuel tank // Minimal fuel tank
standardOpts.ft = '1C'; standardOpts.ft = '1C'
// Disable nearly everything // Disable nearly everything
standardOpts.fsdDisabled = true; standardOpts.fsdDisabled = true
standardOpts.sDisabled = true; standardOpts.sDisabled = true
standardOpts.pdDisabled = true; standardOpts.pdDisabled = true
standardOpts.lsDisabled = true; standardOpts.lsDisabled = true
ship.useLightestStandard(standardOpts); ship.useLightestStandard(standardOpts)
// Apply engineering to each module // Apply engineering to each module
// ship.standard[1].m.blueprint = getBlueprint('Engine_Dirty', ship.standard[0]); // ship.standard[1].m.blueprint = getBlueprint('Engine_Dirty', ship.standard[0]);

View File

@@ -13,7 +13,6 @@ const LS_KEY_STATE = 'state';
const LS_KEY_SIZE_RATIO = 'sizeRatio'; const LS_KEY_SIZE_RATIO = 'sizeRatio';
const LS_KEY_TOOLTIPS = 'tooltips'; const LS_KEY_TOOLTIPS = 'tooltips';
const LS_KEY_MODULE_RESISTANCES = 'moduleResistances'; const LS_KEY_MODULE_RESISTANCES = 'moduleResistances';
const LS_KEY_ROLLS = 'matsPerGrade';
let LS; let LS;
@@ -85,7 +84,6 @@ export class Persist extends EventEmitter {
} }
let moduleResistances = _get(LS_KEY_MODULE_RESISTANCES); let moduleResistances = _get(LS_KEY_MODULE_RESISTANCES);
let matsPerGrade = _get(LS_KEY_ROLLS);
let tips = _get(LS_KEY_TOOLTIPS); let tips = _get(LS_KEY_TOOLTIPS);
let insurance = _getString(LS_KEY_INSURANCE); let insurance = _getString(LS_KEY_INSURANCE);
let shipDiscount = _get(LS_KEY_SHIP_DISCOUNT); let shipDiscount = _get(LS_KEY_SHIP_DISCOUNT);
@@ -104,13 +102,6 @@ export class Persist extends EventEmitter {
this.outfittingTab = _getString(LS_KEY_OUTFITTING_TAB); this.outfittingTab = _getString(LS_KEY_OUTFITTING_TAB);
this.state = _get(LS_KEY_STATE); this.state = _get(LS_KEY_STATE);
this.sizeRatio = _get(LS_KEY_SIZE_RATIO) || 1; this.sizeRatio = _get(LS_KEY_SIZE_RATIO) || 1;
this.matsPerGrade = matsPerGrade || {
1: 2,
2: 2,
3: 4,
4: 4,
5: 10
};
this.tooltipsEnabled = tips === null ? true : tips; this.tooltipsEnabled = tips === null ? true : tips;
this.moduleResistancesEnabled = moduleResistances === null ? true : moduleResistances; this.moduleResistancesEnabled = moduleResistances === null ? true : moduleResistances;
@@ -161,10 +152,6 @@ export class Persist extends EventEmitter {
this.moduleResistancesEnabled = !!newValue && newValue.toLowerCase() == 'true'; this.moduleResistancesEnabled = !!newValue && newValue.toLowerCase() == 'true';
this.emit('moduleresistances', this.moduleResistancesEnabled); this.emit('moduleresistances', this.moduleResistancesEnabled);
break; break;
case LS_KEY_ROLLS:
this.matsPerGrade = JSON.parse(newValue);
this.emit('matsPerGrade', this.matsPerGrade);
break;
} }
} catch (e) { } catch (e) {
// On JSON.Parse Error - don't sync or do anything // On JSON.Parse Error - don't sync or do anything
@@ -470,23 +457,6 @@ export class Persist extends EventEmitter {
return this.moduleDiscount; return this.moduleDiscount;
} }
/**
* Get the saved ship discount
* @param {Object} matsPerGrade # of rolls per grade
*/
setRolls(matsPerGrade) {
this.matsPerGrade = matsPerGrade;
_put(LS_KEY_ROLLS, this.matsPerGrade);
this.emit('matsPerGrade');
}
/**
* Get the saved Mats per grade
* @return {Object} # of rolls per grade
*/
getRolls() {
return this.matsPerGrade;
}
/** /**
* Persist selected cost tab * Persist selected cost tab
* @param {number} tabName Cost tab name * @param {number} tabName Cost tab name

View File

@@ -7,7 +7,7 @@ import { Modifications } from 'coriolis-data/dist';
* @param {Object} blueprint The blueprint at the required grade * @param {Object} blueprint The blueprint at the required grade
* @param {string} grp The group of the module * @param {string} grp The group of the module
* @param {Object} m The module to compare with * @param {Object} m The module to compare with
* @param {string} specialName The name of the special * @param specialName
* @returns {Object} The react components * @returns {Object} The react components
*/ */
export function specialToolTip(translate, blueprint, grp, m, specialName) { export function specialToolTip(translate, blueprint, grp, m, specialName) {
@@ -18,35 +18,36 @@ export function specialToolTip(translate, blueprint, grp, m, specialName) {
if (m) { if (m) {
// We also add in any benefits from specials that aren't covered above // We also add in any benefits from specials that aren't covered above
if (m.blueprint) { if (m.blueprint) {
for (const feature in Modifications.modifierActions[specialName]) { for (const feature in Modifications.modifierActions[specialName]) {
// if (!blueprint.features[feature] && !m.mods.feature) { // if (!blueprint.features[feature] && !m.mods.feature) {
const featureDef = Modifications.modifications[feature]; const featureDef = Modifications.modifications[feature];
if (featureDef && !featureDef.hidden) { if (featureDef && !featureDef.hidden) {
let symbol = ''; let symbol = '';
if (feature === 'jitter') { if (feature === 'jitter') {
symbol = '°'; symbol = '°';
} else if (featureDef.type === 'percentage') { } else if (featureDef.type === 'percentage') {
symbol = '%'; symbol = '%';
} }
let current = m.getModValue(feature) - m.getModValue(feature, true); let current = m.getModValue(feature) - m.getModValue(feature, true);
if (featureDef.type === 'percentage') { if (featureDef.type === 'percentage') {
current = Math.round(current / 10) / 10; current = Math.round(current / 10) / 10;
} else if (featureDef.type === 'numeric') { } else if (featureDef.type === 'numeric') {
current /= 100; current /= 100;
} }
const currentIsBeneficial = isValueBeneficial(feature, current); const currentIsBeneficial = isValueBeneficial(feature, current);
effects.push( effects.push(
<tr key={feature + '_specialTT'}> <tr key={feature + '_specialTT'}>
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td> <td style={{textAlign: 'left'}}>{translate(feature, grp)}</td>
<td>&nbsp;</td> <td>&nbsp;</td>
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'} <td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'}
style={{ textAlign: 'right' }}>{current}{symbol}</td> style={{textAlign: 'right'}}>{current}{symbol}</td>
<td>&nbsp;</td> <td>&nbsp;</td>
</tr> </tr>
); );
} }
} }
} }
} }
@@ -288,7 +289,7 @@ export function isValueBeneficial(feature, value) {
*/ */
export function getBlueprint(name, module) { export function getBlueprint(name, module) {
// Start with a copy of the blueprint // Start with a copy of the blueprint
const findMod = val => Object.keys(Modifications.blueprints).find(elem => elem.toString().toLowerCase().search(val.toString().toLowerCase().replace(/(OutfittingFieldType_|persecond)/igm, '')) >= 0); const findMod = val => Object.keys(Modifications.blueprints).find(elem => elem.toString().toLowerCase().search(val.toString().toLowerCase().replace(/(OutfittingFieldType_|persecond)/igm, '')) >= 0)
const found = Modifications.blueprints[findMod(name)]; const found = Modifications.blueprints[findMod(name)];
if (!found || !found.fdname) { if (!found || !found.fdname) {
return {}; return {};
@@ -381,33 +382,34 @@ export function getPercent(m) {
let result = null; let result = null;
const features = m.blueprint.grades[m.blueprint.grade].features; const features = m.blueprint.grades[m.blueprint.grade].features;
for (const featureName in features) { for (const featureName in features) {
if (features[featureName][0] === features[featureName][1]) {
continue;
}
let value = _getValue(m, featureName); if (features[featureName][0] === features[featureName][1]) {
let mult; continue;
}
let value = _getValue(m, featureName);
let mult;
if (Modifications.modifications[featureName].higherbetter) { if (Modifications.modifications[featureName].higherbetter) {
// Higher is better, but is this making it better or worse? // Higher is better, but is this making it better or worse?
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) { if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
mult = Math.round((value - features[featureName][1]) / (features[featureName][0] - features[featureName][1]) * 100); mult = Math.round((value - features[featureName][1]) / (features[featureName][0] - features[featureName][1]) * 100);
} else { } else {
mult = Math.round((value - features[featureName][0]) / (features[featureName][1] - features[featureName][0]) * 100); mult = Math.round((value - features[featureName][0]) / (features[featureName][1] - features[featureName][0]) * 100);
} }
} else { } else {
// Higher is worse, but is this making it better or worse? // Higher is worse, but is this making it better or worse?
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) { if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
mult = Math.round((value - features[featureName][0]) / (features[featureName][1] - features[featureName][0]) * 100); mult = Math.round((value - features[featureName][0]) / (features[featureName][1] - features[featureName][0]) * 100);
} else { } else {
mult = Math.round((value - features[featureName][1]) / (features[featureName][0] - features[featureName][1]) * 100); mult = Math.round((value - features[featureName][1]) / (features[featureName][0] - features[featureName][1]) * 100);
} }
} }
if (result && result != mult) { if (result && result != mult) {
return null; return null;
} else if (result != mult) { } else if (result != mult) {
result = mult; result = mult;
} }
} }
return result; return result;
@@ -417,7 +419,6 @@ export function getPercent(m) {
* Query a feature value * Query a feature value
* @param {Object} m The module for which to perform the query * @param {Object} m The module for which to perform the query
* @param {string} featureName The feature being queried * @param {string} featureName The feature being queried
* @returns {number} The value of the modification as a %
*/ */
function _getValue(m, featureName) { function _getValue(m, featureName) {
if (Modifications.modifications[featureName].type == 'percentage') { if (Modifications.modifications[featureName].type == 'percentage') {

View File

@@ -318,7 +318,7 @@ function _addModifications(module, modifiers, blueprint, grade, specialModificat
if (!modifiers) return; if (!modifiers) return;
let special; let special;
if (specialModifications) { if (specialModifications) {
special = Modifications.specials[Object.keys(specialModifications)[0]]; special = Modifications.specials[Object.keys(specialModifications)[0]]
} }
for (const i in modifiers) { for (const i in modifiers) {
// Some special modifications // Some special modifications
@@ -345,7 +345,7 @@ function _addModifications(module, modifiers, blueprint, grade, specialModificat
let value; let value;
if (i === 'OutfittingFieldType_DefenceModifierShieldMultiplier') { if (i === 'OutfittingFieldType_DefenceModifierShieldMultiplier') {
value = modifiers[i].value - 1; value = modifiers[i].value - 1;
} else if (i === 'OutfittingFieldType_DefenceModifierHealthMultiplier' && blueprint.startsWith('Armour_')) { } else if (i === 'OutfittingFieldType_DefenceModifierHealthMultiplier' && blueprint.startsWith('Armour_')) {
value = (modifiers[i].value - module.hullboost) / module.hullboost; value = (modifiers[i].value - module.hullboost) / module.hullboost;
} else if (i === 'OutfittingFieldType_DefenceModifierHealthMultiplier') { } else if (i === 'OutfittingFieldType_DefenceModifierHealthMultiplier') {
value = modifiers[i].value / module.hullboost; value = modifiers[i].value / module.hullboost;

View File

@@ -1,26 +1,26 @@
import Ship from '../shipyard/Ship'; import Ship from '../shipyard/Ship'
import { HARDPOINT_NUM_TO_CLASS, shipModelFromJson } from './CompanionApiUtils'; import { HARDPOINT_NUM_TO_CLASS, shipModelFromJson } from './CompanionApiUtils'
import { Ships } from 'coriolis-data/dist'; import { Ships } from 'coriolis-data/dist'
import Module from '../shipyard/Module'; import Module from '../shipyard/Module'
import { Modules } from 'coriolis-data/dist'; import { Modules } from 'coriolis-data/dist'
import { Modifications } from 'coriolis-data/dist'; import { Modifications } from 'coriolis-data/dist'
import { getBlueprint } from './BlueprintFunctions'; import { getBlueprint } from './BlueprintFunctions'
/** /**
* Obtain a module given its FD Name * Obtain a module given its FD Name
* @param {string} fdname the FD Name of the module * @param {string} fdname the FD Name of the module
* @return {Module} the module * @return {Module} the module
*/ */
function _moduleFromFdName(fdname) { function _moduleFromFdName (fdname) {
if (!fdname) return null; if (!fdname) return null
fdname = fdname.toLowerCase(); fdname = fdname.toLowerCase()
// Check standard modules // Check standard modules
for (const grp in Modules.standard) { for (const grp in Modules.standard) {
if (Modules.standard.hasOwnProperty(grp)) { if (Modules.standard.hasOwnProperty(grp)) {
for (const i in Modules.standard[grp]) { for (const i in Modules.standard[grp]) {
if (Modules.standard[grp][i].symbol && Modules.standard[grp][i].symbol.toLowerCase() === fdname) { if (Modules.standard[grp][i].symbol && Modules.standard[grp][i].symbol.toLowerCase() === fdname) {
// Found it // Found it
return new Module({ template: Modules.standard[grp][i] }); return new Module({template: Modules.standard[grp][i]})
} }
} }
} }
@@ -32,7 +32,7 @@ function _moduleFromFdName(fdname) {
for (const i in Modules.hardpoints[grp]) { for (const i in Modules.hardpoints[grp]) {
if (Modules.hardpoints[grp][i].symbol && Modules.hardpoints[grp][i].symbol.toLowerCase() === fdname) { if (Modules.hardpoints[grp][i].symbol && Modules.hardpoints[grp][i].symbol.toLowerCase() === fdname) {
// Found it // Found it
return new Module({ template: Modules.hardpoints[grp][i] }); return new Module({template: Modules.hardpoints[grp][i]})
} }
} }
} }
@@ -44,14 +44,14 @@ function _moduleFromFdName(fdname) {
for (const i in Modules.internal[grp]) { for (const i in Modules.internal[grp]) {
if (Modules.internal[grp][i].symbol && Modules.internal[grp][i].symbol.toLowerCase() === fdname) { if (Modules.internal[grp][i].symbol && Modules.internal[grp][i].symbol.toLowerCase() === fdname) {
// Found it // Found it
return new Module({ template: Modules.internal[grp][i] }); return new Module({template: Modules.internal[grp][i]})
} }
} }
} }
} }
// Not found // Not found
return null; return null
} }
/** /**
@@ -59,16 +59,16 @@ function _moduleFromFdName(fdname) {
* @param {object} json the Loadout event JSON * @param {object} json the Loadout event JSON
* @return {Ship} the built ship * @return {Ship} the built ship
*/ */
export function shipFromLoadoutJSON(json) { export function shipFromLoadoutJSON (json) {
// Start off building a basic ship // Start off building a basic ship
const shipModel = shipModelFromJson(json); const shipModel = shipModelFromJson(json)
if (!shipModel) { if (!shipModel) {
throw 'No such ship found: "' + json.Ship + '"'; throw 'No such ship found: "' + json.Ship + '"'
} }
const shipTemplate = Ships[shipModel]; const shipTemplate = Ships[shipModel]
let ship = new Ship(shipModel, shipTemplate.properties, shipTemplate.slots); let ship = new Ship(shipModel, shipTemplate.properties, shipTemplate.slots)
ship.buildWith(null); ship.buildWith(null)
// Initial Ship building, don't do engineering yet. // Initial Ship building, don't do engineering yet.
let opts = []; let opts = [];
@@ -76,135 +76,135 @@ export function shipFromLoadoutJSON(json) {
switch (module.Slot.toLowerCase()) { switch (module.Slot.toLowerCase()) {
// Cargo Hatch. // Cargo Hatch.
case 'cargohatch': case 'cargohatch':
ship.cargoHatch.enabled = module.On; ship.cargoHatch.enabled = module.On
ship.cargoHatch.priority = module.Priority; ship.cargoHatch.priority = module.Priority
break; break
// Add the bulkheads // Add the bulkheads
case 'armour': case 'armour':
if (module.Item.toLowerCase().endsWith('_armour_grade1')) { if (module.Item.toLowerCase().endsWith('_armour_grade1')) {
ship.useBulkhead(0, true); ship.useBulkhead(0, true)
} else if (module.Item.toLowerCase().endsWith('_armour_grade2')) { } else if (module.Item.toLowerCase().endsWith('_armour_grade2')) {
ship.useBulkhead(1, true); ship.useBulkhead(1, true)
} else if (module.Item.toLowerCase().endsWith('_armour_grade3')) { } else if (module.Item.toLowerCase().endsWith('_armour_grade3')) {
ship.useBulkhead(2, true); ship.useBulkhead(2, true)
} else if (module.Item.toLowerCase().endsWith('_armour_mirrored')) { } else if (module.Item.toLowerCase().endsWith('_armour_mirrored')) {
ship.useBulkhead(3, true); ship.useBulkhead(3, true)
} else if (module.Item.toLowerCase().endsWith('_armour_reactive')) { } else if (module.Item.toLowerCase().endsWith('_armour_reactive')) {
ship.useBulkhead(4, true); ship.useBulkhead(4, true)
} else { } else {
throw 'Unknown bulkheads "' + module.Item + '"'; throw 'Unknown bulkheads "' + module.Item + '"'
} }
ship.bulkheads.enabled = true; ship.bulkheads.enabled = true
if (module.Engineering) _addModifications(ship.bulkheads.m, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect); if (module.Engineering) _addModifications(ship.bulkheads.m, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect)
break; break
case 'powerplant': case 'powerplant':
const powerplant = _moduleFromFdName(module.Item); const powerplant = _moduleFromFdName(module.Item)
ship.use(ship.standard[0], powerplant, true); ship.use(ship.standard[0], powerplant, true)
ship.standard[0].enabled = module.On; ship.standard[0].enabled = module.On
ship.standard[0].priority = module.Priority; ship.standard[0].priority = module.Priority
if (module.Engineering) _addModifications(powerplant, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect); if (module.Engineering) _addModifications(powerplant, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect)
break; break
case 'mainengines': case 'mainengines':
const thrusters = _moduleFromFdName(module.Item); const thrusters = _moduleFromFdName(module.Item)
ship.use(ship.standard[1], thrusters, true); ship.use(ship.standard[1], thrusters, true)
ship.standard[1].enabled = module.On; ship.standard[1].enabled = module.On
ship.standard[1].priority = module.Priority; ship.standard[1].priority = module.Priority
if (module.Engineering) _addModifications(thrusters, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect); if (module.Engineering) _addModifications(thrusters, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect)
break; break
case 'frameshiftdrive': case 'frameshiftdrive':
const frameshiftdrive = _moduleFromFdName(module.Item); const frameshiftdrive = _moduleFromFdName(module.Item)
ship.use(ship.standard[2], frameshiftdrive, true); ship.use(ship.standard[2], frameshiftdrive, true)
ship.standard[2].enabled = module.On; ship.standard[2].enabled = module.On
ship.standard[2].priority = module.Priority; ship.standard[2].priority = module.Priority
if (module.Engineering) _addModifications(frameshiftdrive, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect); if (module.Engineering) _addModifications(frameshiftdrive, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect)
break; break
case 'lifesupport': case 'lifesupport':
const lifesupport = _moduleFromFdName(module.Item); const lifesupport = _moduleFromFdName(module.Item)
ship.use(ship.standard[3], lifesupport, true); ship.use(ship.standard[3], lifesupport, true)
ship.standard[3].enabled = module.On === true; ship.standard[3].enabled = module.On === true
ship.standard[3].priority = module.Priority; ship.standard[3].priority = module.Priority
if (module.Engineering) _addModifications(lifesupport, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect); if (module.Engineering) _addModifications(lifesupport, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect)
break; break
case 'powerdistributor': case 'powerdistributor':
const powerdistributor = _moduleFromFdName(module.Item); const powerdistributor = _moduleFromFdName(module.Item)
ship.use(ship.standard[4], powerdistributor, true); ship.use(ship.standard[4], powerdistributor, true)
ship.standard[4].enabled = module.On; ship.standard[4].enabled = module.On
ship.standard[4].priority = module.Priority; ship.standard[4].priority = module.Priority
if (module.Engineering) _addModifications(powerdistributor, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect); if (module.Engineering) _addModifications(powerdistributor, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect)
break; break
case 'radar': case 'radar':
const sensors = _moduleFromFdName(module.Item); const sensors = _moduleFromFdName(module.Item)
ship.use(ship.standard[5], sensors, true); ship.use(ship.standard[5], sensors, true)
ship.standard[5].enabled = module.On; ship.standard[5].enabled = module.On
ship.standard[5].priority = module.Priority; ship.standard[5].priority = module.Priority
if (module.Engineering) _addModifications(sensors, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect); if (module.Engineering) _addModifications(sensors, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect)
break; break
case 'fueltank': case 'fueltank':
const fueltank = _moduleFromFdName(module.Item); const fueltank = _moduleFromFdName(module.Item)
ship.use(ship.standard[6], fueltank, true); ship.use(ship.standard[6], fueltank, true)
ship.standard[6].enabled = true; ship.standard[6].enabled = true
ship.standard[6].priority = 0; ship.standard[6].priority = 0
break; break
default: default:
} }
for (const module of json.Modules) { for (const module of json.Modules) {
if (module.Slot.toLowerCase().search(/hardpoint/) !== -1) { if (module.Slot.toLowerCase().search(/hardpoint/) !== -1) {
// Add hardpoints // Add hardpoints
let hardpoint; let hardpoint;
let hardpointClassNum = -1; let hardpointClassNum = -1
let hardpointSlotNum = -1; let hardpointSlotNum = -1
let hardpointArrayNum = 0; let hardpointArrayNum = 0
for (let i in shipTemplate.slots.hardpoints) { for (let i in shipTemplate.slots.hardpoints) {
if (shipTemplate.slots.hardpoints[i] === hardpointClassNum) { if (shipTemplate.slots.hardpoints[i] === hardpointClassNum) {
// Another slot of the same class // Another slot of the same class
hardpointSlotNum++; hardpointSlotNum++
} else { } else {
// The first slot of a new class // The first slot of a new class
hardpointClassNum = shipTemplate.slots.hardpoints[i]; hardpointClassNum = shipTemplate.slots.hardpoints[i]
hardpointSlotNum = 1; hardpointSlotNum = 1
} }
// Now that we know what we're looking for, find it // Now that we know what we're looking for, find it
const hardpointName = HARDPOINT_NUM_TO_CLASS[hardpointClassNum] + 'Hardpoint' + hardpointSlotNum; const hardpointName = HARDPOINT_NUM_TO_CLASS[hardpointClassNum] + 'Hardpoint' + hardpointSlotNum
const hardpointSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === hardpointName.toLowerCase()); const hardpointSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === hardpointName.toLowerCase())
if (!hardpointSlot) { if (!hardpointSlot) {
// This can happen with old imports that don't contain new hardpoints // This can happen with old imports that don't contain new hardpoints
} else if (!hardpointSlot) { } else if (!hardpointSlot) {
// No module // No module
} else { } else {
hardpoint = _moduleFromFdName(hardpointSlot.Item); hardpoint = _moduleFromFdName(hardpointSlot.Item)
ship.use(ship.hardpoints[hardpointArrayNum], hardpoint, true); ship.use(ship.hardpoints[hardpointArrayNum], hardpoint, true)
ship.hardpoints[hardpointArrayNum].enabled = hardpointSlot.On; ship.hardpoints[hardpointArrayNum].enabled = hardpointSlot.On
ship.hardpoints[hardpointArrayNum].priority = hardpointSlot.Priority; ship.hardpoints[hardpointArrayNum].priority = hardpointSlot.Priority
opts.push({ coriolisMod: hardpoint, json: hardpointSlot }); opts.push({coriolisMod: hardpoint, json: hardpointSlot});
} }
hardpointArrayNum++; hardpointArrayNum++
} }
} }
if (module.Slot.toLowerCase().search(/slot\d/) !== -1) { if (module.Slot.toLowerCase().search(/slot\d/) !== -1) {
let internalSlotNum = 1; let internalSlotNum = 1
let militarySlotNum = 1; let militarySlotNum = 1
for (let i in shipTemplate.slots.internal) { for (let i in shipTemplate.slots.internal) {
const isMilitary = isNaN(shipTemplate.slots.internal[i]) ? shipTemplate.slots.internal[i].name = 'military' : false; const isMilitary = isNaN(shipTemplate.slots.internal[i]) ? shipTemplate.slots.internal[i].name = 'military' : false
// The internal slot might be a standard or a military slot. Military slots have a different naming system // The internal slot might be a standard or a military slot. Military slots have a different naming system
let internalSlot = null; let internalSlot = null
if (isMilitary) { if (isMilitary) {
const internalName = 'Military0' + militarySlotNum; const internalName = 'Military0' + militarySlotNum
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase()); internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase())
militarySlotNum++; militarySlotNum++
} else { } else {
// Slot numbers are not contiguous so handle skips. // Slot numbers are not contiguous so handle skips.
while (internalSlot === null && internalSlotNum < 99) { while (internalSlot === null && internalSlotNum < 99) {
// Slot sizes have no relationship to the actual size, either, so check all possibilities // Slot sizes have no relationship to the actual size, either, so check all possibilities
for (let slotsize = 0; slotsize < 9; slotsize++) { for (let slotsize = 0; slotsize < 9; slotsize++) {
const internalName = 'Slot' + (internalSlotNum <= 9 ? '0' : '') + internalSlotNum + '_Size' + slotsize; const internalName = 'Slot' + (internalSlotNum <= 9 ? '0' : '') + internalSlotNum + '_Size' + slotsize
if (json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase())) { if (json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase())) {
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase()); internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase());
break; break
} }
} }
internalSlotNum++; internalSlotNum++
} }
} }
@@ -213,12 +213,12 @@ export function shipFromLoadoutJSON(json) {
} else if (!internalSlot) { } else if (!internalSlot) {
// No module // No module
} else { } else {
const internalJson = internalSlot; const internalJson = internalSlot
const internal = _moduleFromFdName(internalJson.Item); const internal = _moduleFromFdName(internalJson.Item)
ship.use(ship.internal[i], internal, true); ship.use(ship.internal[i], internal, true)
ship.internal[i].enabled = internalJson.On === true; ship.internal[i].enabled = internalJson.On === true
ship.internal[i].priority = internalJson.Priority; ship.internal[i].priority = internalJson.Priority
opts.push({ coriolisMod: internal, json: internalSlot }); opts.push({coriolisMod: internal, json: internalSlot});
} }
} }
} }
@@ -226,16 +226,17 @@ export function shipFromLoadoutJSON(json) {
} }
for (const i of opts) { for (const i of opts) {
if (i.json.Engineering) _addModifications(i.coriolisMod, i.json.Engineering.Modifiers, i.json.Engineering.BlueprintName, i.json.Engineering.Level, i.json.Engineering.ExperimentalEffect); if (i.json.Engineering) _addModifications(i.coriolisMod, i.json.Engineering.Modifiers, i.json.Engineering.BlueprintName, i.json.Engineering.Level, i.json.Engineering.ExperimentalEffect)
} }
// We don't have any information on it so guess it's priority 5 and disabled // We don't have any information on it so guess it's priority 5 and disabled
if (!ship.cargoHatch) { if (!ship.cargoHatch) {
ship.cargoHatch.enabled = false; ship.cargoHatch.enabled = false
ship.cargoHatch.priority = 4; ship.cargoHatch.priority = 4
} }
console.log(ship)
// Now update the ship's codes before returning it // Now update the ship's codes before returning it
return ship.updatePowerPrioritesString().updatePowerEnabledString().updateModificationsString(); return ship.updatePowerPrioritesString().updatePowerEnabledString().updateModificationsString()
} }
/** /**
@@ -246,18 +247,18 @@ export function shipFromLoadoutJSON(json) {
* @param {Object} grade the grade of the modification * @param {Object} grade the grade of the modification
* @param {Object} specialModifications special modification * @param {Object} specialModifications special modification
*/ */
function _addModifications(module, modifiers, blueprint, grade, specialModifications) { function _addModifications (module, modifiers, blueprint, grade, specialModifications) {
if (!modifiers) return; if (!modifiers) return
let special; let special
if (specialModifications) { if (specialModifications) {
special = Modifications.specials[specialModifications]; special = Modifications.specials[specialModifications]
} }
for (const i in modifiers) { for (const i in modifiers) {
// Some special modifications // Some special modifications
// Look up the modifiers to find what we need to do // Look up the modifiers to find what we need to do
const findMod = val => Object.keys(Modifications.modifierActions).find(elem => elem.toString().toLowerCase().replace(/(outfittingfieldtype_|persecond)/igm, '') === val.toString().toLowerCase().replace(/(outfittingfieldtype_|persecond)/igm, '')); const findMod = val => Object.keys(Modifications.modifierActions).find(elem => elem.toString().toLowerCase().replace(/(outfittingfieldtype_|persecond)/igm, '') === val.toString().toLowerCase().replace(/(outfittingfieldtype_|persecond)/igm, ''))
const modifierActions = Modifications.modifierActions[findMod(modifiers[i].Label)]; const modifierActions = Modifications.modifierActions[findMod(modifiers[i].Label)]
// TODO: Figure out how to scale this value. //TODO: Figure out how to scale this value.
if (!!modifiers[i].LessIsGood) { if (!!modifiers[i].LessIsGood) {
} }
@@ -266,26 +267,26 @@ function _addModifications(module, modifiers, blueprint, grade, specialModificat
value = modifiers[i].Value * 100; value = modifiers[i].Value * 100;
} }
if (modifiers[i].Label.search('Resistance') >= 0) { if (modifiers[i].Label.search('Resistance') >= 0) {
value = (modifiers[i].Value * 100) - (modifiers[i].OriginalValue * 100); value = (modifiers[i].Value * 100) - (modifiers[i].OriginalValue * 100)
} }
// Carry out the required changes // Carry out the required changes
for (const action in modifierActions) { for (const action in modifierActions) {
if (isNaN(modifierActions[action])) { if (isNaN(modifierActions[action])) {
module.setModValue(action, modifierActions[action]); module.setModValue(action, modifierActions[action])
} else { } else {
module.setModValue(action, value); module.setModValue(action, value)
} }
} }
} }
// Add the blueprint definition, grade and special // Add the blueprint definition, grade and special
if (blueprint) { if (blueprint) {
module.blueprint = getBlueprint(blueprint, module); module.blueprint = getBlueprint(blueprint, module)
if (grade) { if (grade) {
module.blueprint.grade = Number(grade); module.blueprint.grade = Number(grade)
} }
if (special) { if (special) {
module.blueprint.special = special; module.blueprint.special = special
} }
} }
} }

View File

@@ -8,7 +8,7 @@ import request from 'superagent';
* @param {function} error Failure/Error callback * @param {function} error Failure/Error callback
*/ */
export default function shorternUrl(url, success, error) { export default function shorternUrl(url, success, error) {
shortenUrlOrbis(url, success, error); shortenUrlEddp(url, success, error);
} }
const SHORTEN_API_GOOGLE = 'https://www.googleapis.com/urlshortener/v1/url?key='; const SHORTEN_API_GOOGLE = 'https://www.googleapis.com/urlshortener/v1/url?key=';
@@ -64,32 +64,3 @@ function shortenUrlEddp(url, success, error) {
error('Not Online'); error('Not Online');
} }
} }
const SHORTEN_API_ORBIS = 'https://s.orbis.zone/a';
/**
* Shorten a URL using Orbis's URL shortener API
* @param {string} url The URL to shorten
* @param {function} success Success callback
* @param {function} error Failure/Error callback
*/
function shortenUrlOrbis(url, success, error) {
if (window.navigator.onLine) {
try {
request.post(SHORTEN_API_ORBIS)
.field('lsturl', url)
.field('format', 'json')
.end(function(err, response) {
if (err) {
error('Bad Request');
} else {
success(response.body.short);
}
});
} catch (e) {
console.log(e)
error(e.message ? e.message : e);
}
} else {
error('Not Online');
}
}

View File

@@ -38,7 +38,7 @@
<% } %> <% } %>
<!-- Piwik --> <!-- Piwik -->
<!-- <script type="text/javascript"> <script type="text/javascript">
var _paq = _paq || []; var _paq = _paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */ /* tracker methods like "setCustomDimension" should be called before "trackPageView" */
_paq.push(["setCookieDomain", "*.coriolis.edcd.io"]); _paq.push(["setCookieDomain", "*.coriolis.edcd.io"]);
@@ -51,7 +51,7 @@
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s); g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
})(); })();
</script>--> </script>
<!-- End Piwik Code --> <!-- End Piwik Code -->
<!-- Bugsnag --> <!-- Bugsnag -->