mirror of
https://github.com/EDCD/coriolis.git
synced 2025-12-08 14:33:22 +00:00
Make outfitting page working
This commit is contained in:
@@ -123,6 +123,7 @@
|
||||
"sideEffects": false,
|
||||
"dependencies": {
|
||||
"@babel/polyfill": "^7.0.0",
|
||||
"auto-bind": "^2.1.1",
|
||||
"browserify-zlib-next": "^1.0.1",
|
||||
"classnames": "^2.2.6",
|
||||
"coriolis-data": "../coriolis-data",
|
||||
|
||||
@@ -24,7 +24,6 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
||||
onSelect: PropTypes.func.isRequired,
|
||||
diffDetails: PropTypes.func,
|
||||
m: PropTypes.object,
|
||||
ship: PropTypes.object.isRequired,
|
||||
warning: PropTypes.func,
|
||||
slotDiv: PropTypes.object
|
||||
};
|
||||
@@ -49,7 +48,7 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
||||
*/
|
||||
_initState(props, context) {
|
||||
const { translate } = context.language;
|
||||
const { m, warning, onSelect, ship } = props;
|
||||
const { m } = props;
|
||||
const list = [], fuzzy = [];
|
||||
let currentGroup;
|
||||
|
||||
@@ -63,13 +62,7 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
||||
list.push(
|
||||
<div key={'div-' + category} className="select-group cap">{catName}</div>,
|
||||
this._buildGroup(
|
||||
ship,
|
||||
m,
|
||||
warning,
|
||||
(m, event) => {
|
||||
this._hideDiff(event);
|
||||
onSelect(m);
|
||||
},
|
||||
category,
|
||||
infos,
|
||||
),
|
||||
@@ -91,15 +84,14 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
||||
|
||||
/**
|
||||
* Generate React Components for Module Group
|
||||
* @param {Ship} ship Ship the selection is for
|
||||
* @param {Object} mountedModule Mounted Module
|
||||
* @param {Function} warningFunc Warning function
|
||||
* @param {function} onSelect Select/Mount callback
|
||||
* @param {String} category Category key
|
||||
* @param {Array} modules Available modules
|
||||
* @return {React.Component} Available Module Group contents
|
||||
*/
|
||||
_buildGroup(ship, mountedModule, warningFunc, onSelect, category, modules) {
|
||||
_buildGroup(mountedModule, category, modules) {
|
||||
const { warning } = this.props;
|
||||
const ship = mountedModule.getShip();
|
||||
const classMapping = groupBy(modules, (info) => info.meta.class);
|
||||
|
||||
const itemsPerClass = Math.max(
|
||||
@@ -133,7 +125,10 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
||||
let eventHandlers = {};
|
||||
if (!disabled) {
|
||||
const showDiff = this._showDiff.bind(this, mountedModule, info);
|
||||
const select = onSelect.bind(null, info);
|
||||
const select = (event) => {
|
||||
this._hideDiff(event);
|
||||
this.props.onSelect(Item);
|
||||
};
|
||||
|
||||
eventHandlers = {
|
||||
onMouseEnter: this._over.bind(this, showDiff),
|
||||
@@ -149,7 +144,7 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
||||
<li key={Item} data-id={Item}
|
||||
ref={Item === mountedModule.getItem() ? (ref) => { this.activeSlotRef = ref; } : undefined}
|
||||
className={cn('c', {
|
||||
warning: !disabled && warningFunc && warningFunc(info),
|
||||
warning: !disabled && warning && warning(info),
|
||||
active: mountedModule.getItem() === Item,
|
||||
disabled,
|
||||
hardpoint: mountSymbol,
|
||||
@@ -187,10 +182,11 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
||||
_showDiff(mountedModule, hoveringModule, rect) {
|
||||
if (this.props.diffDetails) {
|
||||
this.touchTimeout = null;
|
||||
this.context.tooltip(
|
||||
this.props.diffDetails(hoveringModule, mountedModule),
|
||||
rect,
|
||||
);
|
||||
// TODO:
|
||||
// this.context.tooltip(
|
||||
// this.props.diffDetails(hoveringModule, mountedModule),
|
||||
// rect,
|
||||
// );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,40 +3,27 @@ import SlotSection from './SlotSection';
|
||||
import Slot from './Slot';
|
||||
import { MountFixed, MountGimballed, MountTurret } from '../components/SvgIcons';
|
||||
import { stopCtxPropagation } from '../utils/UtilityFunctions';
|
||||
import autoBind from 'auto-bind';
|
||||
|
||||
/**
|
||||
* Hardpoint slot section
|
||||
*/
|
||||
export default class HardpointSlotSection extends SlotSection {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param {Object} props React Component properties
|
||||
* @param {Object} context React Component context
|
||||
*/
|
||||
constructor(props, context) {
|
||||
super(props, context, 'hardpoints', 'hardpoints');
|
||||
this._empty = this._empty.bind(this);
|
||||
this.selectedRefId = null;
|
||||
this.firstRefId = 'emptyall';
|
||||
this.lastRefId = 'nl-F';
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle focus when component updates
|
||||
* @param {Object} prevProps React Component properties
|
||||
*/
|
||||
componentDidUpdate(prevProps) {
|
||||
this._handleSectionFocus(prevProps,this.firstRefId, this.lastRefId);
|
||||
constructor(props) {
|
||||
super(props, 'hardpoints');
|
||||
autoBind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty all slots
|
||||
*/
|
||||
_empty() {
|
||||
this.selectedRefId = 'emptyall';
|
||||
this.props.ship.emptyWeapons();
|
||||
this.props.onChange();
|
||||
// TODO:
|
||||
// this.props.ship.emptyWeapons();
|
||||
this._close();
|
||||
}
|
||||
|
||||
@@ -47,9 +34,8 @@ export default class HardpointSlotSection extends SlotSection {
|
||||
* @param {SyntheticEvent} event Event
|
||||
*/
|
||||
_fill(group, mount, event) {
|
||||
this.selectedRefId = group + '-' + mount;
|
||||
this.props.ship.useWeapon(group, mount, null, event.getModifierState('Alt'));
|
||||
this.props.onChange();
|
||||
// TODO:
|
||||
// this.props.ship.useWeapon(group, mount, null, event.getModifierState('Alt'));
|
||||
this._close();
|
||||
}
|
||||
|
||||
@@ -73,16 +59,12 @@ export default class HardpointSlotSection extends SlotSection {
|
||||
slots.push(<Slot
|
||||
key={h.object.Slot}
|
||||
maxClass={h.getSize()}
|
||||
onOpen={this._openMenu.bind(this, h)}
|
||||
onSelect={this._selectModule.bind(this, h)}
|
||||
onChange={this.props.onChange}
|
||||
selected={currentMenu == h}
|
||||
currentMenu={currentMenu}
|
||||
drag={this._drag.bind(this, h)}
|
||||
dragOver={this._dragOverSlot.bind(this, h)}
|
||||
drop={this._drop}
|
||||
dropClass={this._dropClass(h, originSlot, targetSlot)}
|
||||
ship={ship}
|
||||
slot={h}
|
||||
m={h}
|
||||
enabled={h.enabled ? true : false}
|
||||
/>);
|
||||
}
|
||||
@@ -95,66 +77,67 @@ export default class HardpointSlotSection extends SlotSection {
|
||||
* @param {Function} translate Translate function
|
||||
* @return {React.Component} Section menu
|
||||
*/
|
||||
_getSectionMenu(translate) {
|
||||
_getSectionMenu() {
|
||||
const { translate } = this.context.language;
|
||||
let _fill = this._fill;
|
||||
|
||||
return <div className='select hardpoint' onClick={(e) => e.stopPropagation()} onContextMenu={stopCtxPropagation}>
|
||||
<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' tabIndex="0" onClick={this._empty} ref={smRef => this.sectionRefArr['emptyall'] = smRef}>{translate('empty all')}</li>
|
||||
<li className='optional-hide' style={{ textAlign: 'center', marginTop: '1em' }}>{translate('PHRASE_ALT_ALL')}</li>
|
||||
</ul>
|
||||
<div className='select-group cap'>{translate('pl')}</div>
|
||||
<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' 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' 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" tabIndex="0" onClick={_fill.bind(this, 'pl', 'F')}><MountFixed className='lg'/></li>
|
||||
<li className="c" tabIndex="0" onClick={_fill.bind(this, 'pl', 'G')}><MountGimballed className='lg'/></li>
|
||||
<li className="c" tabIndex="0" onClick={_fill.bind(this, 'pl', 'T')}><MountTurret className='lg'/></li>
|
||||
</ul>
|
||||
<div className='select-group cap'>{translate('ul')}</div>
|
||||
<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' 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' 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" tabIndex="0" onClick={_fill.bind(this, 'ul', 'F')}><MountFixed className='lg'/></li>
|
||||
<li className="c" tabIndex="0" onClick={_fill.bind(this, 'ul', 'G')}><MountGimballed className='lg'/></li>
|
||||
<li className="c" tabIndex="0" onClick={_fill.bind(this, 'ul', 'T')}><MountTurret className='lg'/></li>
|
||||
</ul>
|
||||
<div className='select-group cap'>{translate('bl')}</div>
|
||||
<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' 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' 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" tabIndex="0" onClick={_fill.bind(this, 'bl', 'F')}><MountFixed className='lg'/></li>
|
||||
<li className="c" tabIndex="0" onClick={_fill.bind(this, 'bl', 'G')}><MountGimballed className='lg'/></li>
|
||||
<li className="c" tabIndex="0" onClick={_fill.bind(this, 'bl', 'T')}><MountTurret className='lg'/></li>
|
||||
</ul>
|
||||
<div className='select-group cap'>{translate('mc')}</div>
|
||||
<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' 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' 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" tabIndex="0" onClick={_fill.bind(this, 'mc', 'F')}><MountFixed className='lg'/></li>
|
||||
<li className="c" tabIndex="0" onClick={_fill.bind(this, 'mc', 'G')}><MountGimballed className='lg'/></li>
|
||||
<li className="c" tabIndex="0" onClick={_fill.bind(this, 'mc', 'T')}><MountTurret className='lg'/></li>
|
||||
</ul>
|
||||
<div className='select-group cap'>{translate('c')}</div>
|
||||
<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' 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' 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" tabIndex="0" onClick={_fill.bind(this, 'c', 'F')}><MountFixed className='lg'/></li>
|
||||
<li className="c" tabIndex="0" onClick={_fill.bind(this, 'c', 'G')}><MountGimballed className='lg'/></li>
|
||||
<li className="c" tabIndex="0" onClick={_fill.bind(this, 'c', 'T')}><MountTurret className='lg'/></li>
|
||||
</ul>
|
||||
<div className='select-group cap'>{translate('fc')}</div>
|
||||
<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' 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' 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" tabIndex="0" onClick={_fill.bind(this, 'fc', 'F')}><MountFixed className='lg'/></li>
|
||||
<li className="c" tabIndex="0" onClick={_fill.bind(this, 'fc', 'G')}><MountGimballed className='lg'/></li>
|
||||
<li className="c" tabIndex="0" onClick={_fill.bind(this, 'fc', 'T')}><MountTurret className='lg'/></li>
|
||||
</ul>
|
||||
<div className='select-group cap'>{translate('pa')}</div>
|
||||
<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' tabIndex="0" onClick={_fill.bind(this, 'pa', 'F')}>{translate('pa')}</li>
|
||||
</ul>
|
||||
<div className='select-group cap'>{translate('rg')}</div>
|
||||
<ul>
|
||||
<li className='lc' tabIndex='0' onClick={_fill.bind(this, 'rg', 'F')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['rg-F'] = smRef}>{translate('rg')}</li>
|
||||
<li className='lc' tabIndex="0" onClick={_fill.bind(this, 'rg', 'F')}>{translate('rg')}</li>
|
||||
</ul>
|
||||
<div className='select-group cap'>{translate('nl')}</div>
|
||||
<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' tabIndex="0" onClick={_fill.bind(this, 'nl', 'F')}>{translate('nl')}</li>
|
||||
</ul>
|
||||
<div className='select-group cap'>{translate('rfl')}</div>
|
||||
<ul>
|
||||
<li className='c' tabIndex='0' onClick={_fill.bind(this, 'rfl', 'F')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['rfl-F'] = smRef}><MountFixed className='lg'/></li>
|
||||
<li className='c' tabIndex='0' onClick={_fill.bind(this, 'rfl', 'T')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['rfl-T'] = smRef}><MountTurret className='lg'/></li>
|
||||
<li className="c" tabIndex="0" onClick={_fill.bind(this, 'rfl', 'F')}><MountFixed className='lg'/></li>
|
||||
<li className="c" tabIndex="0" onClick={_fill.bind(this, 'rfl', 'T')}><MountTurret className='lg'/></li>
|
||||
</ul>
|
||||
</div>;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import Slot from './Slot';
|
||||
import * as ModuleUtils from '../shipyard/ModuleUtils';
|
||||
import { stopCtxPropagation } from '../utils/UtilityFunctions';
|
||||
import { canMount } from '../utils/SlotFunctions';
|
||||
import autoBind from 'auto-bind';
|
||||
|
||||
/**
|
||||
* Internal slot section
|
||||
@@ -12,40 +13,18 @@ export default class InternalSlotSection extends SlotSection {
|
||||
/**
|
||||
* Constructor
|
||||
* @param {Object} props React Component properties
|
||||
* @param {Object} context React Component context
|
||||
*/
|
||||
constructor(props, context) {
|
||||
super(props, context, 'internal', 'optional internal');
|
||||
this._empty = this._empty.bind(this);
|
||||
this._fillWithCargo = this._fillWithCargo.bind(this);
|
||||
this._fillWithCells = this._fillWithCells.bind(this);
|
||||
this._fillWithArmor = this._fillWithArmor.bind(this);
|
||||
this._fillWithModuleReinforcementPackages = this._fillWithModuleReinforcementPackages.bind(this);
|
||||
this._fillWithFuelTanks = this._fillWithFuelTanks.bind(this);
|
||||
this._fillWithLuxuryCabins = this._fillWithLuxuryCabins.bind(this);
|
||||
this._fillWithFirstClassCabins = this._fillWithFirstClassCabins.bind(this);
|
||||
this._fillWithBusinessClassCabins = this._fillWithBusinessClassCabins.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);
|
||||
constructor(props) {
|
||||
super(props, 'optional internal');
|
||||
autoBind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty all slots
|
||||
*/
|
||||
_empty() {
|
||||
this.selectedRefId = 'emptyall';
|
||||
this.props.ship.emptyInternal();
|
||||
this.props.onChange();
|
||||
// TODO:
|
||||
// this.props.ship.emptyInternal();
|
||||
this._close();
|
||||
}
|
||||
|
||||
@@ -54,7 +33,6 @@ export default class InternalSlotSection extends SlotSection {
|
||||
* @param {SyntheticEvent} event Event
|
||||
*/
|
||||
_fillWithCargo(event) {
|
||||
this.selectedRefId = 'cargo';
|
||||
let clobber = event.getModifierState('Alt');
|
||||
let ship = this.props.ship;
|
||||
ship.internal.forEach((slot) => {
|
||||
@@ -62,7 +40,6 @@ export default class InternalSlotSection extends SlotSection {
|
||||
ship.use(slot, ModuleUtils.findInternal('cr', slot.maxClass, 'E'));
|
||||
}
|
||||
});
|
||||
this.props.onChange();
|
||||
this._close();
|
||||
}
|
||||
|
||||
@@ -71,7 +48,6 @@ export default class InternalSlotSection extends SlotSection {
|
||||
* @param {SyntheticEvent} event Event
|
||||
*/
|
||||
_fillWithFuelTanks(event) {
|
||||
this.selectedRefId = 'ft';
|
||||
let clobber = event.getModifierState('Alt');
|
||||
let ship = this.props.ship;
|
||||
ship.internal.forEach((slot) => {
|
||||
@@ -79,7 +55,6 @@ export default class InternalSlotSection extends SlotSection {
|
||||
ship.use(slot, ModuleUtils.findInternal('ft', slot.maxClass, 'C'));
|
||||
}
|
||||
});
|
||||
this.props.onChange();
|
||||
this._close();
|
||||
}
|
||||
|
||||
@@ -88,7 +63,6 @@ export default class InternalSlotSection extends SlotSection {
|
||||
* @param {SyntheticEvent} event Event
|
||||
*/
|
||||
_fillWithLuxuryCabins(event) {
|
||||
this.selectedRefId = 'pcq';
|
||||
let clobber = event.getModifierState('Alt');
|
||||
let ship = this.props.ship;
|
||||
ship.internal.forEach((slot) => {
|
||||
@@ -96,7 +70,6 @@ export default class InternalSlotSection extends SlotSection {
|
||||
ship.use(slot, ModuleUtils.findInternal('pcq', Math.min(slot.maxClass, 6), 'B')); // Passenger cabins top out at 6
|
||||
}
|
||||
});
|
||||
this.props.onChange();
|
||||
this._close();
|
||||
}
|
||||
|
||||
@@ -105,7 +78,6 @@ export default class InternalSlotSection extends SlotSection {
|
||||
* @param {SyntheticEvent} event Event
|
||||
*/
|
||||
_fillWithFirstClassCabins(event) {
|
||||
this.selectedRefId = 'pcm';
|
||||
let clobber = event.getModifierState('Alt');
|
||||
let ship = this.props.ship;
|
||||
ship.internal.forEach((slot) => {
|
||||
@@ -113,7 +85,6 @@ export default class InternalSlotSection extends SlotSection {
|
||||
ship.use(slot, ModuleUtils.findInternal('pcm', Math.min(slot.maxClass, 6), 'C')); // Passenger cabins top out at 6
|
||||
}
|
||||
});
|
||||
this.props.onChange();
|
||||
this._close();
|
||||
}
|
||||
|
||||
@@ -122,7 +93,6 @@ export default class InternalSlotSection extends SlotSection {
|
||||
* @param {SyntheticEvent} event Event
|
||||
*/
|
||||
_fillWithBusinessClassCabins(event) {
|
||||
this.selectedRefId = 'pci';
|
||||
let clobber = event.getModifierState('Alt');
|
||||
let ship = this.props.ship;
|
||||
ship.internal.forEach((slot) => {
|
||||
@@ -130,7 +100,6 @@ export default class InternalSlotSection extends SlotSection {
|
||||
ship.use(slot, ModuleUtils.findInternal('pci', Math.min(slot.maxClass, 6), 'D')); // Passenger cabins top out at 6
|
||||
}
|
||||
});
|
||||
this.props.onChange();
|
||||
this._close();
|
||||
}
|
||||
|
||||
@@ -139,7 +108,6 @@ export default class InternalSlotSection extends SlotSection {
|
||||
* @param {SyntheticEvent} event Event
|
||||
*/
|
||||
_fillWithEconomyClassCabins(event) {
|
||||
this.selectedRefId = 'pce';
|
||||
let clobber = event.getModifierState('Alt');
|
||||
let ship = this.props.ship;
|
||||
ship.internal.forEach((slot) => {
|
||||
@@ -147,7 +115,6 @@ export default class InternalSlotSection extends SlotSection {
|
||||
ship.use(slot, ModuleUtils.findInternal('pce', Math.min(slot.maxClass, 6), 'E')); // Passenger cabins top out at 6
|
||||
}
|
||||
});
|
||||
this.props.onChange();
|
||||
this._close();
|
||||
}
|
||||
|
||||
@@ -156,7 +123,6 @@ export default class InternalSlotSection extends SlotSection {
|
||||
* @param {SyntheticEvent} event Event
|
||||
*/
|
||||
_fillWithCells(event) {
|
||||
this.selectedRefId = 'scb';
|
||||
let clobber = event.getModifierState('Alt');
|
||||
let ship = this.props.ship;
|
||||
let chargeCap = 0; // Capacity of single activation
|
||||
@@ -167,7 +133,6 @@ export default class InternalSlotSection extends SlotSection {
|
||||
chargeCap += slot.m.recharge;
|
||||
}
|
||||
});
|
||||
this.props.onChange();
|
||||
this._close();
|
||||
}
|
||||
|
||||
@@ -176,7 +141,6 @@ export default class InternalSlotSection extends SlotSection {
|
||||
* @param {SyntheticEvent} event Event
|
||||
*/
|
||||
_fillWithArmor(event) {
|
||||
this.selectedRefId = 'hr';
|
||||
let clobber = event.getModifierState('Alt');
|
||||
let ship = this.props.ship;
|
||||
ship.internal.forEach((slot) => {
|
||||
@@ -184,7 +148,6 @@ export default class InternalSlotSection extends SlotSection {
|
||||
ship.use(slot, ModuleUtils.findInternal('hr', Math.min(slot.maxClass, 5), 'D')); // Hull reinforcements top out at 5D
|
||||
}
|
||||
});
|
||||
this.props.onChange();
|
||||
this._close();
|
||||
}
|
||||
|
||||
@@ -193,7 +156,6 @@ export default class InternalSlotSection extends SlotSection {
|
||||
* @param {SyntheticEvent} event Event
|
||||
*/
|
||||
_fillWithModuleReinforcementPackages(event) {
|
||||
this.selectedRefId = 'mrp';
|
||||
let clobber = event.getModifierState('Alt');
|
||||
let ship = this.props.ship;
|
||||
ship.internal.forEach((slot) => {
|
||||
@@ -201,7 +163,6 @@ export default class InternalSlotSection extends SlotSection {
|
||||
ship.use(slot, ModuleUtils.findInternal('mrp', Math.min(slot.maxClass, 5), 'D')); // Module reinforcements top out at 5D
|
||||
}
|
||||
});
|
||||
this.props.onChange();
|
||||
this._close();
|
||||
}
|
||||
|
||||
@@ -220,24 +181,16 @@ export default class InternalSlotSection extends SlotSection {
|
||||
let slots = [];
|
||||
let { currentMenu, ship } = this.props;
|
||||
let { originSlot, targetSlot } = this.state;
|
||||
let { fuelCapacity } = ship;
|
||||
|
||||
for (const slot of ship.getInternals(undefined, true)) {
|
||||
for (const m of ship.getInternals(undefined, true)) {
|
||||
slots.push(<Slot
|
||||
key={slot.object.Slot}
|
||||
maxClass={slot.getSize()}
|
||||
onOpen={this._openMenu.bind(this, slot)}
|
||||
onChange={this.props.onChange}
|
||||
onSelect={this._selectModule.bind(this, slot)}
|
||||
selected={currentMenu == slot}
|
||||
slot={slot}
|
||||
drag={this._drag.bind(this, slot)}
|
||||
dragOver={this._dragOverSlot.bind(this, slot)}
|
||||
key={m.object.Slot}
|
||||
currentMenu={currentMenu}
|
||||
m={m}
|
||||
drag={this._drag.bind(this, m)}
|
||||
dragOver={this._dragOverSlot.bind(this, m)}
|
||||
drop={this._drop}
|
||||
dropClass={this._dropClass(slot, originSlot, targetSlot)}
|
||||
fuel={fuelCapacity}
|
||||
ship={ship}
|
||||
enabled={slot.isEnabled()}
|
||||
dropClass={this._dropClass(m, originSlot, targetSlot)}
|
||||
/>);
|
||||
}
|
||||
|
||||
@@ -250,19 +203,21 @@ export default class InternalSlotSection extends SlotSection {
|
||||
* @param {Function} ship The ship
|
||||
* @return {React.Component} Section menu
|
||||
*/
|
||||
_getSectionMenu(translate, ship) {
|
||||
_getSectionMenu() {
|
||||
const { ship } = this.props;
|
||||
const { translate } = this.context.language;
|
||||
return <div className='select' onClick={e => e.stopPropagation()} onContextMenu={stopCtxPropagation}>
|
||||
<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' tabIndex='0' onClick={this._fillWithCargo} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['cargo'] = smRef}>{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' tabIndex='0' onClick={this._fillWithArmor} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['hr'] = smRef}>{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' tabIndex='0' onClick={this._fillWithFuelTanks} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['ft'] = smRef}>{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' tabIndex='0' onClick={this._fillWithBusinessClassCabins} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['pci'] = smRef}>{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>
|
||||
{ ship.luxuryCabins ? <li className='lc' tabIndex='0' onClick={this._fillWithLuxuryCabins} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['pcq'] = smRef}>{translate('pcq')}</li> : ''}
|
||||
<li className='lc' tabIndex='0' onClick={this._empty}>{translate('empty all')}</li>
|
||||
<li className='lc' tabIndex='0' onClick={this._fillWithCargo}>{translate('cargo')}</li>
|
||||
<li className='lc' tabIndex='0' onClick={this._fillWithCells}>{translate('scb')}</li>
|
||||
<li className='lc' tabIndex='0' onClick={this._fillWithArmor}>{translate('hr')}</li>
|
||||
<li className='lc' tabIndex='0' onClick={this._fillWithModuleReinforcementPackages}>{translate('mrp')}</li>
|
||||
<li className='lc' tabIndex='0' onClick={this._fillWithFuelTanks}>{translate('ft')}</li>
|
||||
<li className='lc' tabIndex='0' onClick={this._fillWithEconomyClassCabins}>{translate('pce')}</li>
|
||||
<li className='lc' tabIndex='0' onClick={this._fillWithBusinessClassCabins}>{translate('pci')}</li>
|
||||
<li className='lc' tabIndex='0' onClick={this._fillWithFirstClassCabins} onKeyDown={ship.luxuryCabins ? '' : this._keyDown}>{translate('pcm')}</li>
|
||||
{ ship.luxuryCabins ? <li className='lc' tabIndex='0' onClick={this._fillWithLuxuryCabins}>{translate('pcq')}</li> : ''}
|
||||
<li className='optional-hide' style={{ textAlign: 'center', marginTop: '1em' }}>{translate('PHRASE_ALT_ALL')}</li>
|
||||
</ul>
|
||||
</div>;
|
||||
|
||||
@@ -12,33 +12,28 @@ export default class Modification extends TranslatedComponent {
|
||||
static propTypes = {
|
||||
m: PropTypes.instanceOf(Module).isRequired,
|
||||
property: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
highlight: PropTypes.bool,
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param {Object} props React Component properties
|
||||
* @param {Object} context React Component context
|
||||
*/
|
||||
constructor(props, context) {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const { m, property } = props;
|
||||
const originalValue = m.get(property);
|
||||
this.state = { originalValue, value: String(originalValue) };
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify listeners that a new value has been entered and commited.
|
||||
*/
|
||||
_updateFinished() {
|
||||
const { m, property } = this.props;
|
||||
const { value, originalValue } = this.state;
|
||||
const numValue = Number(value);
|
||||
if (!isNaN(numValue) && originalValue !== numValue) {
|
||||
const { m, property, value } = this.props;
|
||||
const { inputValue } = this.state;
|
||||
const numValue = Number(inputValue);
|
||||
if (!isNaN(numValue) && value !== numValue) {
|
||||
m.set(property, numValue);
|
||||
this.props.onChange();
|
||||
this.setState({ originalValue: numValue });
|
||||
this.setState({ inputValue: undefined });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,13 +43,13 @@ export default class Modification extends TranslatedComponent {
|
||||
*/
|
||||
render() {
|
||||
const { translate, formats } = this.context.language;
|
||||
const { m, property, highlight } = this.props;
|
||||
const { originalValue, value } = this.state;
|
||||
const { m, property, highlight, value } = this.props;
|
||||
const { inputValue } = this.state;
|
||||
|
||||
// Some features only apply to specific modules; these features will be
|
||||
// undefined on items that do not belong to the same class. Filter these
|
||||
// features here
|
||||
if (originalValue === undefined) {
|
||||
if (value === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -69,7 +64,7 @@ export default class Modification extends TranslatedComponent {
|
||||
<tr>
|
||||
<td className="input-container">
|
||||
<span>
|
||||
<NumberEditor value={value} stepModifier={1}
|
||||
<NumberEditor value={inputValue || value} stepModifier={1}
|
||||
decimals={2} step={0.01} style={{ textAlign: 'right' }}
|
||||
className={cn(
|
||||
'cb',
|
||||
@@ -81,9 +76,9 @@ export default class Modification extends TranslatedComponent {
|
||||
event.stopPropagation();
|
||||
}
|
||||
}}
|
||||
onValueChange={(value) => {
|
||||
if (value.length <= 15) {
|
||||
this.setState({ value });
|
||||
onValueChange={(inputValue) => {
|
||||
if (inputValue.length <= 15) {
|
||||
this.setState({ inputValue });
|
||||
}
|
||||
}} />
|
||||
{/* TODO: support unit */}
|
||||
|
||||
@@ -18,10 +18,7 @@ import { getModuleInfo } from 'ed-forge/lib/data/items';
|
||||
export default class ModificationsMenu extends TranslatedComponent {
|
||||
static propTypes = {
|
||||
className: PropTypes.string,
|
||||
ship: PropTypes.object.isRequired,
|
||||
m: PropTypes.object.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
modButton:PropTypes.object
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -47,13 +44,11 @@ export default class ModificationsMenu extends TranslatedComponent {
|
||||
|
||||
/**
|
||||
* Render the blueprints
|
||||
* @param {Object} props React component properties
|
||||
* @param {Object} context React component context
|
||||
* @return {Object} list: Array of React Components
|
||||
*/
|
||||
_renderBlueprints(props, context) {
|
||||
const { m } = props;
|
||||
const { language, tooltip, termtip } = context;
|
||||
_renderBlueprints() {
|
||||
const { m } = this.props;
|
||||
const { language, tooltip, termtip } = this.context;
|
||||
const { translate } = language;
|
||||
|
||||
const blueprints = [];
|
||||
@@ -71,13 +66,13 @@ export default class ModificationsMenu extends TranslatedComponent {
|
||||
style={{ width: '2em' }}
|
||||
// onMouseOver={termtip.bind(null, tooltipContent)}
|
||||
// onMouseOut={tooltip.bind(null, null)}
|
||||
onClick={this._change(() => {
|
||||
onClick={() => {
|
||||
m.setBlueprint(blueprint, grade);
|
||||
this.setState({
|
||||
blueprintMenuOpened: false,
|
||||
specialMenuOpened: true,
|
||||
});
|
||||
})}
|
||||
}}
|
||||
ref={active ? (ref) => { this.selectedModRef = ref; } : undefined}
|
||||
>{grade}</li>
|
||||
);
|
||||
@@ -102,9 +97,9 @@ export default class ModificationsMenu extends TranslatedComponent {
|
||||
* @param {Object} context React component context
|
||||
* @return {Object} list: Array of React Components
|
||||
*/
|
||||
_renderSpecials(props, context) {
|
||||
const { m } = props;
|
||||
const { language, tooltip, termtip } = context;
|
||||
_renderSpecials() {
|
||||
const { m } = this.props;
|
||||
const { language, tooltip, termtip } = this.context;
|
||||
const translate = language.translate;
|
||||
|
||||
const applied = m.getExperimental();
|
||||
@@ -150,8 +145,7 @@ export default class ModificationsMenu extends TranslatedComponent {
|
||||
_mkModification(property, highlight) {
|
||||
const { m } = this.props;
|
||||
return <Modification key={property} highlight={highlight} m={m}
|
||||
property={property} onChange={this._change()}
|
||||
/>;
|
||||
property={property} value={m.get(property)} />;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,22 +176,6 @@ export default class ModificationsMenu extends TranslatedComponent {
|
||||
this.setState({ blueprintMenuOpened: !this.state.blueprintMenuOpened });
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a callback that performs an action in form of a callback given as
|
||||
* arguments and notifiers listeners.
|
||||
* @param {function} cb Action to perform
|
||||
* @returns {function} Change callback
|
||||
*/
|
||||
_change(cb) {
|
||||
return (...args) => {
|
||||
this.context.tooltip(null);
|
||||
if (cb) {
|
||||
cb(...args);
|
||||
}
|
||||
this.props.onChange();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the specials menu
|
||||
*/
|
||||
@@ -211,11 +189,11 @@ export default class ModificationsMenu extends TranslatedComponent {
|
||||
* @returns {function} Callback
|
||||
*/
|
||||
_specialSelected(special) {
|
||||
return this._change(() => {
|
||||
return () => {
|
||||
const { m } = this.props;
|
||||
m.setExperimental(special);
|
||||
this.setState({ specialMenuOpened: false });
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -232,14 +210,6 @@ export default class ModificationsMenu extends TranslatedComponent {
|
||||
return;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* set focus to the modification menu icon after mod menu is unmounted.
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
if (this.props.modButton) {
|
||||
this.props.modButton.focus();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the list
|
||||
@@ -259,10 +229,10 @@ export default class ModificationsMenu extends TranslatedComponent {
|
||||
let renderComponents = [];
|
||||
switch (true) {
|
||||
case !appliedBlueprint || blueprintMenuOpened:
|
||||
renderComponents = this._renderBlueprints(this.props, this.context);
|
||||
renderComponents = this._renderBlueprints();
|
||||
break;
|
||||
case specialMenuOpened:
|
||||
renderComponents = this._renderSpecials(this.props, this.context);
|
||||
renderComponents = this._renderSpecials();
|
||||
break;
|
||||
default:
|
||||
// Since the first case didn't apply, there is a blueprint applied so
|
||||
@@ -301,12 +271,12 @@ export default class ModificationsMenu extends TranslatedComponent {
|
||||
<div
|
||||
className="section-menu button-inline-menu warning"
|
||||
style={{ cursor: 'pointer' }}
|
||||
onClick={this._change(() => {
|
||||
onClick={() => {
|
||||
m.resetEngineering();
|
||||
this.selectedModRef = null;
|
||||
this.selectedSpecialRef = null;
|
||||
this.setState({ blueprintProgress: undefined });
|
||||
})}
|
||||
}}
|
||||
onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_RESET')}
|
||||
onMouseOut={tooltip.bind(null, null)}
|
||||
>{translate('reset')}</div>,
|
||||
@@ -324,10 +294,10 @@ export default class ModificationsMenu extends TranslatedComponent {
|
||||
'section-menu button-inline-menu',
|
||||
{ active: blueprintProgress === 0 },
|
||||
)} style={{ cursor: 'pointer' }}
|
||||
onClick={this._change(() => {
|
||||
onClick={() => {
|
||||
m.setBlueprintProgress(0);
|
||||
this.setState({ blueprintProgress: 0 });
|
||||
})}
|
||||
}}
|
||||
onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_WORST')}
|
||||
onMouseOut={tooltip.bind(null, null)}
|
||||
>{translate('0%')}</td>
|
||||
@@ -336,10 +306,10 @@ export default class ModificationsMenu extends TranslatedComponent {
|
||||
'section-menu button-inline-menu',
|
||||
{ active: blueprintProgress === 0.5 },
|
||||
)} style={{ cursor: 'pointer' }}
|
||||
onClick={this._change(() => {
|
||||
onClick={() => {
|
||||
m.setBlueprintProgress(0.5);
|
||||
this.setState({ blueprintProgress: 0.5 });
|
||||
})}
|
||||
}}
|
||||
onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_FIFTY')}
|
||||
onMouseOut={tooltip.bind(null, null)}
|
||||
>{translate('50%')}</td>
|
||||
@@ -349,10 +319,10 @@ export default class ModificationsMenu extends TranslatedComponent {
|
||||
{ active: blueprintProgress === 1 },
|
||||
)}
|
||||
style={{ cursor: 'pointer' }}
|
||||
onClick={this._change(() => {
|
||||
onClick={() => {
|
||||
m.setBlueprintProgress(1);
|
||||
this.setState({ blueprintProgress: 1 });
|
||||
})}
|
||||
}}
|
||||
onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_BEST')}
|
||||
onMouseOut={tooltip.bind(null, null)}
|
||||
>{translate('100%')}</td>
|
||||
@@ -362,11 +332,11 @@ export default class ModificationsMenu extends TranslatedComponent {
|
||||
{ active: blueprintProgress % 0.5 !== 0 },
|
||||
)}
|
||||
style={{ cursor: 'pointer' }}
|
||||
onClick={this._change(() => {
|
||||
onClick={() => {
|
||||
const blueprintProgress = Math.random();
|
||||
m.setBlueprintProgress(blueprintProgress);
|
||||
this.setState({ blueprintProgress });
|
||||
})}
|
||||
}}
|
||||
onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_RANDOM')}
|
||||
onMouseOut={tooltip.bind(null, null)}
|
||||
>{translate('random')}</td>
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import autoBind from 'auto-bind';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import TranslatedComponent from './TranslatedComponent';
|
||||
import cn from 'classnames';
|
||||
import { Warning } from './SvgIcons';
|
||||
import * as Calc from '../shipyard/Calculations';
|
||||
|
||||
import { ShipProps } from 'ed-forge';
|
||||
const {
|
||||
SPEED, JUMP_RANGE, TOTAL_RANGE, SHIELD_METRICS, ARMOUR_METRICS, MODULE_ARMOUR,
|
||||
MODULE_PROTECTION
|
||||
MAX_SPEED, BOOST_SPEED, DAMAGE_METRICS, JUMP_METRICS, SHIELD_METRICS,
|
||||
ARMOUR_METRICS, CARGO_CAPACITY, FUEL_CAPACITY, UNLADEN_MASS, MAXIMUM_MASS,
|
||||
MODULE_PROTECTION_METRICS
|
||||
} = ShipProps;
|
||||
import { OBJECT_EVENT } from 'ed-forge/lib/Ship';
|
||||
|
||||
/**
|
||||
* Ship Summary Table / Stats
|
||||
*/
|
||||
export default class ShipSummaryTable extends TranslatedComponent {
|
||||
|
||||
static propTypes = {
|
||||
ship: PropTypes.object.isRequired,
|
||||
marker: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -27,12 +27,24 @@ export default class ShipSummaryTable extends TranslatedComponent {
|
||||
*/
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.didContextChange = this.didContextChange.bind(this);
|
||||
autoBind(this);
|
||||
this.state = {
|
||||
shieldColour: 'blue'
|
||||
};
|
||||
}
|
||||
|
||||
_onChange() {
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.props.ship.on(OBJECT_EVENT, this._onChange);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.ship.removeListener(OBJECT_EVENT, this._onChange);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the table
|
||||
* @return {React.Component} Summary table
|
||||
@@ -45,31 +57,39 @@ export default class ShipSummaryTable extends TranslatedComponent {
|
||||
let formats = language.formats;
|
||||
let { time, int, round, f1, f2 } = formats;
|
||||
let hide = tooltip.bind(null, null);
|
||||
const shieldGenerator = ship.getShieldGenerator();
|
||||
const sgClassNames = cn({ warning: shieldGenerator && !ship.shield, muted: !shieldGenerator });
|
||||
const sgTooltip = shieldGenerator ? 'TT_SUMMARY_SHIELDS' : 'TT_SUMMARY_SHIELDS_NONFUNCTIONAL';
|
||||
const timeToDrain = Calc.timeToDrainWep(ship, 4);
|
||||
const canThrust = ship.canThrust(cargo, ship.fuelCapacity);
|
||||
|
||||
const speed = ship.get(MAX_SPEED);
|
||||
const shipBoost = ship.get(BOOST_SPEED);
|
||||
const canThrust = 0 < speed;
|
||||
const canBoost = canThrust && !isNaN(shipBoost);
|
||||
const speedTooltip = canThrust ? 'TT_SUMMARY_SPEED' : 'TT_SUMMARY_SPEED_NONFUNCTIONAL';
|
||||
const canBoost = ship.canBoost(cargo, ship.fuelCapacity);
|
||||
const boostTooltip = canBoost ? 'TT_SUMMARY_BOOST' : canThrust ? 'TT_SUMMARY_BOOST_NONFUNCTIONAL' : 'TT_SUMMARY_SPEED_NONFUNCTIONAL';
|
||||
const canJump = ship.getSlotStatus(ship.standard[2]) == 3;
|
||||
const sgMetrics = Calc.shieldMetrics(ship, pips.sys);
|
||||
const shipBoost = canBoost ? Calc.calcBoost(ship) : 'No Boost';
|
||||
const restingHeat = Math.sqrt(((ship.standard[0].m.pgen * ship.standard[0].m.eff) / ship.heatCapacity) / 0.2);
|
||||
const armourMetrics = Calc.armourMetrics(ship);
|
||||
let shieldColour = 'blue';
|
||||
if (shieldGenerator && shieldGenerator.m.grp === 'psg') {
|
||||
shieldColour = 'green';
|
||||
} else if (shieldGenerator && shieldGenerator.m.grp === 'bsg') {
|
||||
shieldColour = 'purple';
|
||||
|
||||
const sgMetrics = ship.get(SHIELD_METRICS);
|
||||
const armourMetrics = ship.get(ARMOUR_METRICS);
|
||||
const damageMetrics = ship.get(DAMAGE_METRICS);
|
||||
const moduleProtectionMetrics = ship.get(MODULE_PROTECTION_METRICS);
|
||||
const timeToDrain = damageMetrics.timeToDrain[8];
|
||||
|
||||
const shieldGenerator = ship.getShieldGenerator();
|
||||
const sgClassNames = cn({
|
||||
warning: shieldGenerator && !shieldGenerator.isEnabled(),
|
||||
muted: !shieldGenerator,
|
||||
});
|
||||
const sgTooltip = shieldGenerator ? 'TT_SUMMARY_SHIELDS' : 'TT_SUMMARY_SHIELDS_NONFUNCTIONAL';
|
||||
let shieldColour;
|
||||
switch (shieldGenerator.readMeta('type')) {
|
||||
case 'biweaveshieldgen': shieldColour = 'purple'; break;
|
||||
case 'prismaticshieldgen': shieldColour = 'green'; break;
|
||||
default: shieldColour = 'blue';
|
||||
}
|
||||
this.state = {
|
||||
shieldColour
|
||||
};
|
||||
|
||||
let speed = ship.get(SPEED);
|
||||
let jumpRange = ship.get(JUMP_RANGE);
|
||||
const jumpRangeMetrics = ship.getMetrics(JUMP_METRICS);
|
||||
// TODO:
|
||||
const canJump = true;
|
||||
|
||||
return <div id='summary'>
|
||||
<div style={{display: "table", width: "100%"}}>
|
||||
@@ -79,7 +99,7 @@ export default class ShipSummaryTable extends TranslatedComponent {
|
||||
<tr className='main'>
|
||||
<th rowSpan={2} className={ cn({ 'bg-warning-disabled': speed == 0 }) }>{translate('speed')}</th>
|
||||
<th rowSpan={2} className={ cn({ 'bg-warning-disabled': !canBoost }) }>{translate('boost')}</th>
|
||||
<th colSpan={5} className={ cn({ 'bg-warning-disabled': jumpRange == 0 }) }>{translate('jump range')}</th>
|
||||
<th colSpan={5} className={ cn({ 'bg-warning-disabled': jumpRangeMetrics.jumpRange == 0 }) }>{translate('jump range')}</th>
|
||||
<th rowSpan={2}>{translate('shield')}</th>
|
||||
<th rowSpan={2}>{translate('integrity')}</th>
|
||||
<th rowSpan={2}>{translate('DPS')}</th>
|
||||
@@ -97,11 +117,11 @@ export default class ShipSummaryTable extends TranslatedComponent {
|
||||
<th rowSpan={2}>{translate('resting heat (Beta)')}</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th className={ cn({ 'lft': true, 'bg-warning-disabled': !canJump }) }>{translate('max')}</th>
|
||||
<th className={ cn({ 'bg-warning-disabled': !canJump }) }>{translate('unladen')}</th>
|
||||
<th className={ cn({ 'bg-warning-disabled': !canJump }) }>{translate('laden')}</th>
|
||||
<th className={ cn({ 'bg-warning-disabled': !canJump }) }>{translate('total unladen')}</th>
|
||||
<th className={ cn({ 'bg-warning-disabled': !canJump }) }>{translate('total laden')}</th>
|
||||
<th className="lft">{translate('max')}</th>
|
||||
<th>{translate('unladen')}</th>
|
||||
<th>{translate('laden')}</th>
|
||||
<th>{translate('total unladen')}</th>
|
||||
<th>{translate('total laden')}</th>
|
||||
<th className='lft'>{translate('hull')}</th>
|
||||
<th>{translate('unladen')}</th>
|
||||
<th>{translate('laden')}</th>
|
||||
@@ -109,30 +129,88 @@ export default class ShipSummaryTable extends TranslatedComponent {
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td onMouseEnter={termtip.bind(null, speedTooltip, { cap: 0 })} onMouseLeave={hide}>{ canThrust ? <span>{int(ship.calcSpeed(4, ship.fuelCapacity, 0, false))}{u['m/s']}</span> : <span className='warning'>0 <Warning/></span> }</td>
|
||||
<td onMouseEnter={termtip.bind(null, boostTooltip, { cap: 0 })} onMouseLeave={hide}>{ canBoost ? <span>{int(ship.calcSpeed(4, ship.fuelCapacity, 0, true))}{u['m/s']}</span> : <span className='warning'>0 <Warning/></span> }</td>
|
||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_MAX_SINGLE_JUMP', { cap: 0 })} onMouseLeave={hide}>{ canJump ? <span>{ f2(Calc.jumpRange(ship.unladenMass + ship.standard[2].m.getMaxFuelPerJump(), ship.standard[2].m, ship.standard[2].m.getMaxFuelPerJump(), ship))}{u.LY}</span> : <span className='warning'>0 <Warning/></span> }</td>
|
||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_UNLADEN_SINGLE_JUMP', { cap: 0 })} onMouseLeave={hide}>{ canJump ? <span>{f2(Calc.jumpRange(ship.unladenMass + ship.fuelCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}</span> : <span className='warning'>0 <Warning/></span> }</td>
|
||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_LADEN_SINGLE_JUMP', { cap: 0 })} onMouseLeave={hide}>{ canJump ? <span>{f2(Calc.jumpRange(ship.unladenMass + ship.fuelCapacity + ship.cargoCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}</span> : <span className='warning'>0 <Warning/></span> }</td>
|
||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_UNLADEN_TOTAL_JUMP', { cap: 0 })} onMouseLeave={hide}>{ canJump ? <span>{f2(Calc.totalJumpRange(ship.unladenMass + ship.fuelCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}</span> : <span className='warning'>0 <Warning/></span> }</td>
|
||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_LADEN_TOTAL_JUMP', { cap: 0 })} onMouseLeave={hide}>{ canJump ? <span>{f2(Calc.totalJumpRange(ship.unladenMass + ship.fuelCapacity + ship.cargoCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}</span> : <span className='warning'>0 <Warning/></span> }</td>
|
||||
<td className={sgClassNames} onMouseEnter={termtip.bind(null, sgTooltip, { cap: 0 })} onMouseLeave={hide}>{int(ship.shield)}{u.MJ}</td>
|
||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_INTEGRITY', { cap: 0 })} onMouseLeave={hide}>{int(ship.armour)}</td>
|
||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_DPS', { cap: 0 })} onMouseLeave={hide}>{f1(ship.totalDps)}</td>
|
||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_EPS', { cap: 0 })} onMouseLeave={hide}>{f1(ship.totalEps)}</td>
|
||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_TTD', { cap: 0 })} onMouseLeave={hide}>{timeToDrain === Infinity ? '∞' : time(timeToDrain)}</td>
|
||||
<td onMouseEnter={termtip.bind(null, speedTooltip, { cap: 0 })}
|
||||
onMouseLeave={hide}
|
||||
>{canThrust
|
||||
? <span>{int(speed)}{u['m/s']}</span>
|
||||
: <span className='warning'>0<Warning/></span>
|
||||
}</td>
|
||||
<td onMouseEnter={termtip.bind(null, boostTooltip, { cap: 0 })}
|
||||
onMouseLeave={hide}
|
||||
>{canBoost
|
||||
? <span>{int(shipBoost)}{u['m/s']}</span>
|
||||
: <span className='warning'>0<Warning/></span>
|
||||
}</td>
|
||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_MAX_SINGLE_JUMP', { cap: 0 })}
|
||||
onMouseLeave={hide}
|
||||
>{canJump
|
||||
// TODO:
|
||||
? <span>{NaN}{u.LY}</span>
|
||||
: <span className='warning'>0<Warning/></span>
|
||||
}</td>
|
||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_UNLADEN_SINGLE_JUMP', { cap: 0 })}
|
||||
onMouseLeave={hide}
|
||||
>{canJump
|
||||
// TODO:
|
||||
? <span>{NaN}{u.LY}</span>
|
||||
: <span className='warning'>0<Warning/></span>
|
||||
}</td>
|
||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_LADEN_SINGLE_JUMP', { cap: 0 })}
|
||||
onMouseLeave={hide}
|
||||
>{canJump
|
||||
? <span>{f2(jumpRangeMetrics.jumpRange)}{u.LY}</span>
|
||||
: <span className='warning'>0<Warning/></span>
|
||||
}</td>
|
||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_UNLADEN_TOTAL_JUMP', { cap: 0 })}
|
||||
onMouseLeave={hide}
|
||||
>{canJump
|
||||
// TODO:
|
||||
? <span>{NaN}{u.LY}</span>
|
||||
: <span className='warning'>0 <Warning/></span>
|
||||
}</td>
|
||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_LADEN_TOTAL_JUMP', { cap: 0 })}
|
||||
onMouseLeave={hide}
|
||||
>{canJump
|
||||
? <span>{f2(jumpRangeMetrics.totalRange)}{u.LY}</span>
|
||||
: <span className='warning'>0<Warning/></span>
|
||||
}</td>
|
||||
<td className={sgClassNames}
|
||||
onMouseEnter={termtip.bind(null, sgTooltip, { cap: 0 })}
|
||||
onMouseLeave={hide}
|
||||
>{int(sgMetrics.shieldStrength)}{u.MJ}</td>
|
||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_INTEGRITY', { cap: 0 })}
|
||||
onMouseLeave={hide}
|
||||
>{int(armourMetrics.armour)}</td>
|
||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_DPS', { cap: 0 })}
|
||||
onMouseLeave={hide}
|
||||
>{f1(damageMetrics.dps)}</td>
|
||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_EPS', { cap: 0 })}
|
||||
onMouseLeave={hide}
|
||||
>{f1(damageMetrics.eps)}</td>
|
||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_TTD', { cap: 0 })}
|
||||
onMouseLeave={hide}
|
||||
>{timeToDrain === Infinity ? '∞' : time(timeToDrain)}</td>
|
||||
{/* <td>{f1(ship.totalHps)}</td> */}
|
||||
<td>{round(ship.cargoCapacity)}{u.T}</td>
|
||||
<td>{ship.passengerCapacity}</td>
|
||||
<td>{round(ship.fuelCapacity)}{u.T}</td>
|
||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_HULL_MASS', { cap: 0 })} onMouseLeave={hide}>{ship.hullMass}{u.T}</td>
|
||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_UNLADEN_MASS', { cap: 0 })} onMouseLeave={hide}>{int(ship.unladenMass)}{u.T}</td>
|
||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_LADEN_MASS', { cap: 0 })} onMouseLeave={hide}>{int(ship.ladenMass)}{u.T}</td>
|
||||
<td>{int(ship.hardness)}</td>
|
||||
<td>{ship.crew}</td>
|
||||
<td>{ship.masslock}</td>
|
||||
<td>{shipBoost !== 'No Boost' ? formats.time(shipBoost) : 'No Boost'}</td>
|
||||
<td>{formats.pct(restingHeat)}</td>
|
||||
<td>{round(ship.get(CARGO_CAPACITY))}{u.T}</td>
|
||||
{/* TODO: PAX */}
|
||||
<td>{NaN}</td>
|
||||
<td>{round(ship.get(FUEL_CAPACITY))}{u.T}</td>
|
||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_HULL_MASS', { cap: 0 })}
|
||||
onMouseLeave={hide}
|
||||
>{ship.getBaseProperty('hullmass')}{u.T}</td>
|
||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_UNLADEN_MASS', { cap: 0 })}
|
||||
onMouseLeave={hide}
|
||||
>{int(ship.get(UNLADEN_MASS))}{u.T}</td>
|
||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_LADEN_MASS', { cap: 0 })}
|
||||
onMouseLeave={hide}
|
||||
>{int(ship.get(MAXIMUM_MASS))}{u.T}</td>
|
||||
<td>{int(ship.getBaseProperty('hardness'))}</td>
|
||||
<td>{ship.readMeta('crew')}</td>
|
||||
<td>{ship.getBaseProperty('masslock')}</td>
|
||||
{/* TODO: boost intervall */}
|
||||
<td>{NaN}</td>
|
||||
{/* TODO: resting heat */}
|
||||
<td>{NaN}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -161,19 +239,19 @@ export default class ShipSummaryTable extends TranslatedComponent {
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{translate(shieldGenerator && shieldGenerator.m.grp || 'No Shield')}</td>
|
||||
<td>{formats.pct1(ship.shieldExplRes)}</td>
|
||||
<td>{formats.pct1(ship.shieldKinRes)}</td>
|
||||
<td>{formats.pct1(ship.shieldThermRes)}</td>
|
||||
<td>{translate(shieldGenerator.readMeta('type') || 'No Shield')}</td>
|
||||
<td>{formats.pct1(1 - sgMetrics.explosive.damageMultiplier)}</td>
|
||||
<td>{formats.pct1(1 - sgMetrics.kinetic.damageMultiplier)}</td>
|
||||
<td>{formats.pct1(1 - sgMetrics.thermal.damageMultiplier)}</td>
|
||||
<td></td>
|
||||
|
||||
<td>{int(ship && sgMetrics.summary > 0 ? sgMetrics.summary : 0)}{u.MJ}</td>
|
||||
<td>{int(ship && sgMetrics.summary > 0 ? sgMetrics.summary / sgMetrics.explosive.base : 0)}{u.MJ}</td>
|
||||
<td>{int(ship && sgMetrics.summary ? sgMetrics.summary / sgMetrics.kinetic.base : 0)}{u.MJ}</td>
|
||||
<td>{int(ship && sgMetrics.summary ? sgMetrics.summary / sgMetrics.thermal.base : 0)}{u.MJ}</td>
|
||||
<td>{int(sgMetrics.shieldStrength || 0)}{u.MJ}</td>
|
||||
<td>{int(sgMetrics.shieldStrength / sgMetrics.explosive.damageMultiplier || 0)}{u.MJ}</td>
|
||||
<td>{int(sgMetrics.shieldStrength / sgMetrics.kinetic.damageMultiplier || 0)}{u.MJ}</td>
|
||||
<td>{int(sgMetrics.shieldStrength / sgMetrics.thermal.damageMultiplier || 0)}{u.MJ}</td>
|
||||
<td></td>
|
||||
<td>{sgMetrics && sgMetrics.recover === Math.Inf ? translate('Never') : formats.time(sgMetrics.recover)}</td>
|
||||
<td>{sgMetrics && sgMetrics.recharge === Math.Inf ? translate('Never') : formats.time(sgMetrics.recharge)}</td>
|
||||
<td>{formats.time(sgMetrics.recover) || translate('Never')}</td>
|
||||
<td>{formats.time(sgMetrics.recharge) || translate('Never')}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<thead>
|
||||
@@ -200,19 +278,18 @@ export default class ShipSummaryTable extends TranslatedComponent {
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{translate(ship && ship.bulkheads && ship.bulkheads.m && ship.bulkheads.m.name || 'No Armour')}</td>
|
||||
<td>{formats.pct1(ship.hullExplRes)}</td>
|
||||
<td>{formats.pct1(ship.hullKinRes)}</td>
|
||||
<td>{formats.pct1(ship.hullThermRes)}</td>
|
||||
<td>{formats.pct1(ship.hullCausRes)}</td>
|
||||
<td>{int(armourMetrics.total)}</td>
|
||||
<td>{int(armourMetrics.total / armourMetrics.explosive.total)}</td>
|
||||
<td>{int(armourMetrics.total/ armourMetrics.kinetic.total)}</td>
|
||||
<td>{int(armourMetrics.total / armourMetrics.thermal.total)}</td>
|
||||
<td>{int(armourMetrics.total/ armourMetrics.caustic.total)}</td>
|
||||
<td>{int(armourMetrics.modulearmour)}</td>
|
||||
<td>{int(armourMetrics.moduleprotection * 100) + '%'}</td>
|
||||
|
||||
<td>{translate(ship.getAlloys().readMeta('type') || 'No Armour')}</td>
|
||||
<td>{formats.pct1(1 - armourMetrics.explosive.damageMultiplier)}</td>
|
||||
<td>{formats.pct1(1 - armourMetrics.kinetic.damageMultiplier)}</td>
|
||||
<td>{formats.pct1(1 - armourMetrics.thermal.damageMultiplier)}</td>
|
||||
<td>{formats.pct1(1 - armourMetrics.caustic.damageMultiplier)}</td>
|
||||
<td>{int(armourMetrics.armour)}</td>
|
||||
<td>{int(armourMetrics.armour / armourMetrics.explosive.damageMultiplier)}</td>
|
||||
<td>{int(armourMetrics.armour / armourMetrics.kinetic.damageMultiplier)}</td>
|
||||
<td>{int(armourMetrics.armour / armourMetrics.thermal.damageMultiplier)}</td>
|
||||
<td>{int(armourMetrics.armour / armourMetrics.caustic.damageMultiplier)}</td>
|
||||
<td>{int(moduleProtectionMetrics.moduleArmour)}</td>
|
||||
<td>{formats.pct1(1 - moduleProtectionMetrics.moduleProtection)}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from 'react';
|
||||
import Persist from '../stores/Persist';
|
||||
import PropTypes from 'prop-types';
|
||||
import TranslatedComponent from './TranslatedComponent';
|
||||
import cn from 'classnames';
|
||||
@@ -9,8 +8,9 @@ import ModificationsMenu from './ModificationsMenu';
|
||||
import { diffDetails } from '../utils/SlotFunctions';
|
||||
import { stopCtxPropagation, wrapCtxMenu } from '../utils/UtilityFunctions';
|
||||
import { blueprintTooltip } from '../utils/BlueprintFunctions';
|
||||
import { Ship, Module } from 'ed-forge';
|
||||
import { Module } from 'ed-forge';
|
||||
import { REG_MILITARY_SLOT, REG_HARDPOINT_SLOT } from 'ed-forge/lib/data/slots';
|
||||
import autoBind from 'auto-bind';
|
||||
|
||||
const HARDPOINT_SLOT_LABELS = {
|
||||
1: 'S',
|
||||
@@ -24,11 +24,8 @@ const HARDPOINT_SLOT_LABELS = {
|
||||
*/
|
||||
export default class Slot extends TranslatedComponent {
|
||||
static propTypes = {
|
||||
onSelect: PropTypes.func.isRequired,
|
||||
onOpen: PropTypes.func.isRequired,
|
||||
selected: PropTypes.bool,
|
||||
slot: PropTypes.instanceOf(Module),
|
||||
ship: PropTypes.instanceOf(Ship),
|
||||
currentMenu: PropTypes.any,
|
||||
m: PropTypes.instanceOf(Module),
|
||||
warning: PropTypes.func,
|
||||
drag: PropTypes.func,
|
||||
drop: PropTypes.func,
|
||||
@@ -41,31 +38,53 @@ export default class Slot extends TranslatedComponent {
|
||||
*/
|
||||
constructor(props) {
|
||||
super(props);
|
||||
autoBind(this);
|
||||
this.state = { menuIndex: 0 };
|
||||
}
|
||||
|
||||
this._modificationsSelected = false;
|
||||
|
||||
this._contextMenu = wrapCtxMenu(this._contextMenu.bind(this));
|
||||
this._getMaxClassLabel = this._getMaxClassLabel.bind(this);
|
||||
/**
|
||||
* Opens a menu while setting state.
|
||||
* @param {Object} newMenuIndex New menu index
|
||||
* @param {Event} event Event object
|
||||
*/
|
||||
_openMenu(newMenuIndex, event) {
|
||||
const slotName = this.props.m.getSlot();
|
||||
if (
|
||||
this.props.currentMenu === slotName &&
|
||||
newMenuIndex === this.state.menuIndex
|
||||
) {
|
||||
this.context.closeMenu();
|
||||
} {
|
||||
this.setState({ menuIndex: newMenuIndex });
|
||||
this.context.openMenu(slotName);
|
||||
}
|
||||
// If we don't stop event propagation, the underlying divs also might
|
||||
// get clicked which would open up other menus
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the slot contents
|
||||
* @param {Object} m Mounted Module
|
||||
* @param {Function} translate Translate function
|
||||
* @param {Object} formats Localized Formats map
|
||||
* @param {Object} u Localized Units Map
|
||||
* @return {React.Component} Slot contents
|
||||
*/
|
||||
_getSlotDetails(m, translate, formats, u) {
|
||||
if (m) {
|
||||
let classRating = String(m.getSize()) + m.getRating();
|
||||
let { drag, drop, ship } = this.props;
|
||||
let { termtip, tooltip } = this.context;
|
||||
let showModuleResistances = Persist.showModuleResistances();
|
||||
_getSlotDetails() {
|
||||
const { m } = this.props;
|
||||
let { termtip, tooltip, language } = this.context;
|
||||
const { translate, units, formats } = language;
|
||||
|
||||
if (m.isEmpty()) {
|
||||
return <div className="empty">
|
||||
{translate(
|
||||
m.getSlot().match(REG_MILITARY_SLOT) ? 'emptyrestricted' : 'empty'
|
||||
)}
|
||||
</div>;
|
||||
} else {
|
||||
let classRating = String(m.getClass()) + m.getRating();
|
||||
let { drag, drop } = this.props;
|
||||
|
||||
// Modifications tooltip shows blueprint and grade, if available
|
||||
// let modTT = translate('modified');
|
||||
// const blueprint = m.getBlueprint();
|
||||
let modTT = translate('modified');
|
||||
const blueprint = m.getBlueprint();
|
||||
// const experimental = m.getExperimental();
|
||||
// const grade = m.getGrade();
|
||||
// if (blueprint) {
|
||||
@@ -82,12 +101,10 @@ export default class Slot extends TranslatedComponent {
|
||||
// }
|
||||
|
||||
let mass = m.get('mass') || m.get('cargo') || m.get('fuel') || 0;
|
||||
const enabled = m.isEnabled();
|
||||
|
||||
const className = cn('details', enabled ? '' : 'disabled');
|
||||
const disabled = !m.isEnabled();
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
className={cn('details', { disabled })}
|
||||
draggable="true"
|
||||
onDragStart={drag}
|
||||
onDragEnd={drop}
|
||||
@@ -95,65 +112,26 @@ export default class Slot extends TranslatedComponent {
|
||||
<div className={'cb'}>
|
||||
<div className={'l'}>
|
||||
{classRating} {translate(m.readMeta('type'))}
|
||||
{m.mods && Object.keys(m.mods).length > 0 ? (
|
||||
{blueprint && (
|
||||
<span
|
||||
onMouseOver={termtip.bind(null, modTT)}
|
||||
onMouseOut={tooltip.bind(null, null)}
|
||||
>
|
||||
<Modified />
|
||||
</span>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</div>
|
||||
<div className={'r'}>
|
||||
{formats.round(mass)}
|
||||
{u.T}
|
||||
{units.T}
|
||||
</div>
|
||||
</div>
|
||||
<div className={'cb'}>
|
||||
{/* { m.getOptMass() ? <div className={'l'}>{translate('optmass', 'sg')}: {formats.int(m.getOptMass())}{u.T}</div> : null }
|
||||
{ m.getMaxMass() ? <div className={'l'}>{translate('maxmass', 'sg')}: {formats.int(m.getMaxMass())}{u.T}</div> : null }
|
||||
{ m.bins ? <div className={'l'}>{m.bins} <u>{translate('bins')}</u></div> : null }
|
||||
{ m.bays ? <div className={'l'}>{translate('bays')}: {m.bays}</div> : null }
|
||||
{ m.rebuildsperbay ? <div className={'l'}>{translate('rebuildsperbay')}: {m.rebuildsperbay}</div> : null }
|
||||
{ m.rate ? <div className={'l'}>{translate('rate')}: {m.rate}{u.kgs} {translate('refuel time')}: {formats.time(this.props.fuel * 1000 / m.rate)}</div> : null }
|
||||
{ m.getAmmo() && m.grp !== 'scb' ? <div className={'l'}>{translate('ammunition')}: {formats.gen(m.getAmmo())}</div> : null }
|
||||
{ m.getSpinup() ? <div className={'l'}>{translate('spinup')}: {formats.f1(m.getSpinup())}{u.s}</div> : null }
|
||||
{ m.getDuration() ? <div className={'l'}>{translate('duration')}: {formats.f1(m.getDuration())}{u.s}</div> : null }
|
||||
{ m.grp === 'scb' ? <div className={'l'}>{translate('cells')}: {formats.int(m.getAmmo() + 1)}</div> : null }
|
||||
{ m.grp === 'gsrp' ? <div className={'l'}>{translate('shield addition')}: {formats.f1(m.getShieldAddition())}{u.MJ}</div> : null }
|
||||
{ m.grp === 'gfsb' ? <div className={'l'}>{translate('jump addition')}: {formats.f1(m.getJumpBoost())}{u.LY}</div> : null }
|
||||
{ m.grp === 'gs' ? <div className={'l'}>{translate('shield addition')}: {formats.f1(m.getShieldAddition())}{u.MJ}</div> : null }
|
||||
{ m.getShieldReinforcement() ? <div className={'l'}>{translate('shieldreinforcement')}: {formats.f1(m.getDuration() * m.getShieldReinforcement())}{u.MJ}</div> : null }
|
||||
{ m.getShieldReinforcement() ? <div className={'l'}>{translate('total')}: {formats.int((m.getAmmo() + 1) * (m.getDuration() * m.getShieldReinforcement()))}{u.MJ}</div> : null }
|
||||
{ m.repair ? <div className={'l'}>{translate('repair')}: {m.repair}</div> : null }
|
||||
{ m.getFacingLimit() ? <div className={'l'}>{translate('facinglimit')} {formats.f1(m.getFacingLimit())}°</div> : null }
|
||||
{ m.getRange() ? <div className={'l'}>{translate('range')} {formats.f2(m.getRange())}{u.km}</div> : null }
|
||||
{ m.getRangeT() ? <div className={'l'}>{translate('ranget')} {formats.f1(m.getRangeT())}{u.s}</div> : null }
|
||||
{ m.getTime() ? <div className={'l'}>{translate('time')}: {formats.time(m.getTime())}</div> : null }
|
||||
{ m.getHackTime() ? <div className={'l'}>{translate('hacktime')}: {formats.time(m.getHackTime())}</div> : null }
|
||||
{ m.maximum ? <div className={'l'}>{translate('max')}: {(m.maximum)}</div> : null }
|
||||
{ m.rangeLS ? <div className={'l'}>{translate('range')}: {m.rangeLS}{u.Ls}</div> : null }
|
||||
{ m.rangeLS === null ? <div className={'l'}>∞{u.Ls}</div> : null }
|
||||
{ m.rangeRating ? <div className={'l'}>{translate('range')}: {m.rangeRating}</div> : null }
|
||||
{ m.passengers ? <div className={'l'}>{translate('passengers')}: {m.passengers}</div> : null }
|
||||
{ m.getRegenerationRate() ? <div className='l'>{translate('regen')}: {formats.round1(m.getRegenerationRate())}{u.ps}</div> : null }
|
||||
{ m.getBrokenRegenerationRate() ? <div className='l'>{translate('brokenregen')}: {formats.round1(m.getBrokenRegenerationRate())}{u.ps}</div> : null }
|
||||
{ showModuleResistances && m.getExplosiveResistance() ? <div className='l'>{translate('explres')}: {formats.pct(m.getExplosiveResistance())}</div> : null }
|
||||
{ showModuleResistances && m.getKineticResistance() ? <div className='l'>{translate('kinres')}: {formats.pct(m.getKineticResistance())}</div> : null }
|
||||
{ showModuleResistances && m.getThermalResistance() ? <div className='l'>{translate('thermres')}: {formats.pct(m.getThermalResistance())}</div> : null }
|
||||
{ showModuleResistances && m.getCausticResistance() ? <div className='l'>{translate('causres')}: {formats.pct(m.getCausticResistance())}</div> : null }
|
||||
{ m.getHullReinforcement() ? <div className='l'>{translate('armour')}: {formats.int(m.getHullReinforcement() + ship.baseArmour * m.getModValue('hullboost') / 10000)}</div> : null }
|
||||
{ m.getProtection() ? <div className='l'>{translate('protection')}: {formats.rPct(m.getProtection())}</div> : null }
|
||||
{ m.getIntegrity() ? <div className='l'>{translate('integrity')}: {formats.int(m.getIntegrity())}</div> : null } */}
|
||||
{(m.getApplicableBlueprints() || []).length > 0 ? (
|
||||
<div className="r"
|
||||
ref={(modButton) => (this.modButton = modButton)}
|
||||
>
|
||||
<button onClick={this._toggleModifications.bind(this)}
|
||||
<div className="r">
|
||||
<button onClick={this._openMenu.bind(this, 1)}
|
||||
onContextMenu={stopCtxPropagation}
|
||||
onMouseOver={termtip.bind(null, 'modifications')}
|
||||
onMouseOver={termtip.bind(null, translate('modifications'))}
|
||||
onMouseOut={tooltip.bind(null, null)}
|
||||
>
|
||||
<ListModifications />
|
||||
@@ -163,35 +141,24 @@ export default class Slot extends TranslatedComponent {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return <div className={'empty'}>{translate('empty')}</div>;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the CSS class name for the slot. Can/should be overriden
|
||||
* as necessary.
|
||||
* @return {string} CSS Class name
|
||||
*/
|
||||
_getClassNames() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the label for the slot size/class
|
||||
* Should be overriden if necessary
|
||||
* @return {string} label
|
||||
*/
|
||||
_getMaxClassLabel() {
|
||||
const { slot } = this.props;
|
||||
let size = slot.getSize();
|
||||
const { m } = this.props;
|
||||
let size = m.getSize();
|
||||
switch (true) {
|
||||
case slot.getSlot() === 'armour':
|
||||
case m.getSlot() === 'armour':
|
||||
return '';
|
||||
case size === 0:
|
||||
// This can also happen for armour but that case was handled above
|
||||
return 'U';
|
||||
case Boolean(slot.getSlot().match(REG_HARDPOINT_SLOT)):
|
||||
case Boolean(m.getSlot().match(REG_HARDPOINT_SLOT)):
|
||||
return HARDPOINT_SLOT_LABELS[size];
|
||||
default:
|
||||
return size;
|
||||
@@ -205,7 +172,13 @@ export default class Slot extends TranslatedComponent {
|
||||
_contextMenu(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
this.props.onSelect(null,null);
|
||||
const { m } = this.props;
|
||||
m.reset();
|
||||
if (this.props.currentMenu === m.getSlot()) {
|
||||
this.context.closeMenu();
|
||||
} else {
|
||||
this.forceUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -215,65 +188,38 @@ export default class Slot extends TranslatedComponent {
|
||||
render() {
|
||||
let language = this.context.language;
|
||||
let translate = language.translate;
|
||||
let { ship, slot, dropClass, dragOver, onOpen, onChange, selected, onSelect, warning } = this.props;
|
||||
let slotDetails, modificationsMarker, menu;
|
||||
|
||||
if (!selected) {
|
||||
// If not selected then sure that modifications flag is unset
|
||||
this._modificationsSelected = false;
|
||||
}
|
||||
|
||||
if (!slot.isEmpty()) {
|
||||
slotDetails = this._getSlotDetails(slot, translate, language.formats, language.units); // Must be implemented by sub classes
|
||||
} else {
|
||||
slotDetails = <div className={'empty'}>
|
||||
{translate(
|
||||
slot.getSlot().match(REG_MILITARY_SLOT) ? 'emptyrestricted' : 'empty'
|
||||
)}
|
||||
</div>;
|
||||
}
|
||||
|
||||
if (selected) {
|
||||
if (this._modificationsSelected) {
|
||||
menu = <ModificationsMenu
|
||||
className={this._getClassNames()}
|
||||
onChange={onChange}
|
||||
ship={ship}
|
||||
m={slot}
|
||||
modButton = {this.modButton}
|
||||
/>;
|
||||
} else {
|
||||
menu = <AvailableModulesMenu
|
||||
className={this._getClassNames()}
|
||||
m={slot}
|
||||
ship={ship}
|
||||
onSelect={onSelect}
|
||||
warning={warning}
|
||||
diffDetails={diffDetails.bind(ship, this.context.language)}
|
||||
/>;
|
||||
}
|
||||
}
|
||||
let { currentMenu, m, dropClass, dragOver, warning } = this.props;
|
||||
const { menuIndex } = this.state;
|
||||
|
||||
// TODO: implement touch dragging
|
||||
|
||||
const selected = currentMenu === m.getSlot();
|
||||
return (
|
||||
<div className={cn('slot', dropClass, { selected })} onClick={onOpen}
|
||||
<div
|
||||
className={cn('slot', dropClass, { selected })}
|
||||
onContextMenu={this._contextMenu}
|
||||
onDragOver={dragOver} tabIndex="0"
|
||||
onClick={this._openMenu.bind(this, 0)}
|
||||
>
|
||||
<div className='details-container'>
|
||||
<div className='sz'>{this._getMaxClassLabel(translate)}</div>
|
||||
{slotDetails}
|
||||
</div>
|
||||
{menu}
|
||||
<div className={cn(
|
||||
'details-container',
|
||||
{ warning: warning && warning(m) },
|
||||
)}>
|
||||
<div className="sz">{this._getMaxClassLabel(translate)}</div>
|
||||
{this._getSlotDetails()}
|
||||
</div>
|
||||
{selected && menuIndex === 0 &&
|
||||
<AvailableModulesMenu
|
||||
m={m}
|
||||
onSelect={(item) => {
|
||||
m.setItem(item);
|
||||
this.context.closeMenu();
|
||||
}}
|
||||
warning={warning}
|
||||
// diffDetails={diffDetails.bind(ship, this.context.language)}
|
||||
/>}
|
||||
{selected && menuIndex === 1 &&
|
||||
<ModificationsMenu m={m} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the modifications flag when selecting the modifications icon
|
||||
*/
|
||||
_toggleModifications() {
|
||||
this._modificationsSelected = !this._modificationsSelected;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { canMount } from '../utils/SlotFunctions';
|
||||
import { Equalizer } from '../components/SvgIcons';
|
||||
import cn from 'classnames';
|
||||
import { Ship } from 'ed-forge';
|
||||
import autoBind from 'auto-bind';
|
||||
const browser = require('detect-browser');
|
||||
|
||||
/**
|
||||
@@ -14,36 +15,20 @@ const browser = require('detect-browser');
|
||||
export default class SlotSection extends TranslatedComponent {
|
||||
static propTypes = {
|
||||
ship: PropTypes.instanceOf(Ship),
|
||||
onChange: PropTypes.func.isRequired,
|
||||
// code: PropTypes.string.isRequired,
|
||||
togglePwr: PropTypes.func,
|
||||
sectionMenuRefs: PropTypes.object
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param {Object} props React Component properties
|
||||
* @param {Object} context React Component context
|
||||
* @param {string} sectionId Section DOM Id
|
||||
* @param {string} sectionName Section name
|
||||
*/
|
||||
constructor(props, context, sectionId, sectionName) {
|
||||
constructor(props, sectionName) {
|
||||
super(props);
|
||||
this.sectionId = sectionId;
|
||||
this.sectionName = sectionName;
|
||||
this.ssHeadRef = null;
|
||||
autoBind(this);
|
||||
|
||||
this.sectionName = sectionName;
|
||||
|
||||
this.sectionRefArr = this.props.sectionMenuRefs[this.sectionId] = [];
|
||||
this.sectionRefArr['selectedRef'] = null;
|
||||
this._getSlots = this._getSlots.bind(this);
|
||||
this._selectModule = this._selectModule.bind(this);
|
||||
this._getSectionMenu = this._getSectionMenu.bind(this);
|
||||
this._contextMenu = this._contextMenu.bind(this);
|
||||
this._drop = this._drop.bind(this);
|
||||
this._dragOverNone = this._dragOverNone.bind(this);
|
||||
this._close = this._close.bind(this);
|
||||
this._keyDown = this._keyDown.bind(this);
|
||||
this._handleSectionFocus = this._handleSectionFocus.bind(this);
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
@@ -53,83 +38,6 @@ export default class SlotSection extends TranslatedComponent {
|
||||
// _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
|
||||
* @param {string} menu Menu name
|
||||
* @param {SyntheticEvent} event Event
|
||||
*/
|
||||
_openMenu(menu, event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (this.props.currentMenu === menu) {
|
||||
menu = null;
|
||||
}
|
||||
this.context.openMenu(menu);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mount/Use the specified module in the slot
|
||||
* @param {Object} slot Slot
|
||||
* @param {Object} m Selected module
|
||||
*/
|
||||
_selectModule(slot, m) {
|
||||
slot.setItem(m);
|
||||
this.props.onChange();
|
||||
this._close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Slot Drag Handler
|
||||
* @param {object} originSlot Origin slot model
|
||||
@@ -206,7 +114,6 @@ export default class SlotSection extends TranslatedComponent {
|
||||
// Copy power info
|
||||
targetSlot.enabled = originSlot.enabled;
|
||||
targetSlot.priority = originSlot.priority;
|
||||
this.props.onChange();
|
||||
}
|
||||
} else {
|
||||
// Store power info
|
||||
@@ -235,7 +142,6 @@ export default class SlotSection extends TranslatedComponent {
|
||||
targetSlot.enabled = targetEnabled;
|
||||
targetSlot.priority = targetPriority;
|
||||
}
|
||||
this.props.onChange();
|
||||
this.props.ship
|
||||
.updatePowerGenerated()
|
||||
.updatePowerUsed()
|
||||
@@ -281,6 +187,17 @@ export default class SlotSection extends TranslatedComponent {
|
||||
return 'ineligible'; // Cannot be dropped / invalid drop slot
|
||||
}
|
||||
|
||||
_open(newMenu, event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const { currentMenu } = this.props;
|
||||
if (currentMenu === newMenu) {
|
||||
this.context.closeMenu();
|
||||
} else {
|
||||
this.context.openMenu(newMenu);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close current menu
|
||||
*/
|
||||
@@ -297,14 +214,13 @@ export default class SlotSection extends TranslatedComponent {
|
||||
render() {
|
||||
let translate = this.context.language.translate;
|
||||
let sectionMenuOpened = this.props.currentMenu === this.sectionName;
|
||||
let open = this._openMenu.bind(this, this.sectionName);
|
||||
let ctx = wrapCtxMenu(this._contextMenu);
|
||||
|
||||
return (
|
||||
<div id={this.sectionId} className={'group'} onDragLeave={this._dragOverNone}>
|
||||
<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>
|
||||
{sectionMenuOpened ? this._getSectionMenu(translate, this.props.ship) : null }
|
||||
<div className="group" onDragLeave={this._dragOverNone}>
|
||||
<div className={cn('section-menu', { selected: sectionMenuOpened })}
|
||||
onContextMenu={wrapCtxMenu(this._contextMenu)} onClick={this._open.bind(this, this.sectionName)}>
|
||||
<h1 tabIndex="0">{translate(this.sectionName)}<Equalizer/></h1>
|
||||
{sectionMenuOpened && this._getSectionMenu()}
|
||||
</div>
|
||||
{this._getSlots()}
|
||||
</div>
|
||||
|
||||
@@ -4,8 +4,10 @@ import SlotSection from './SlotSection';
|
||||
import Slot from './Slot';
|
||||
import Module from '../shipyard/Module';
|
||||
import * as ShipRoles from '../shipyard/ShipRoles';
|
||||
import { stopCtxPropagation } from '../utils/UtilityFunctions';
|
||||
import autoBind from 'auto-bind';
|
||||
import { stopCtxPropagation, moduleGet } from '../utils/UtilityFunctions';
|
||||
import { ShipProps } from 'ed-forge';
|
||||
const { CONSUMED_RETR, LADEN_MASS } = ShipProps;
|
||||
|
||||
/**
|
||||
* Standard Slot section
|
||||
@@ -16,29 +18,16 @@ export default class StandardSlotSection extends SlotSection {
|
||||
* @param {Object} props React Component properties
|
||||
* @param {Object} context React Component context
|
||||
*/
|
||||
constructor(props, context) {
|
||||
super(props, context, 'standard', 'core internal');
|
||||
this._optimizeStandard = this._optimizeStandard.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);
|
||||
constructor(props) {
|
||||
super(props, 'core internal');
|
||||
autoBind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the lightest/optimal available standard modules
|
||||
*/
|
||||
_optimizeStandard() {
|
||||
this.selectedRefId = 'maxjump';
|
||||
this.props.ship.useLightestStandard();
|
||||
this.props.onChange();
|
||||
this._close();
|
||||
}
|
||||
|
||||
@@ -48,10 +37,7 @@ export default class StandardSlotSection extends SlotSection {
|
||||
* @param {integer} bulkheadIndex Bulkhead to use see Constants.BulkheadNames
|
||||
*/
|
||||
_multiPurpose(shielded, bulkheadIndex) {
|
||||
this.selectedRefId = 'multipurpose';
|
||||
if (bulkheadIndex === 2) this.selectedRefId = 'combat';
|
||||
ShipRoles.multiPurpose(this.props.ship, shielded, bulkheadIndex);
|
||||
this.props.onChange();
|
||||
this._close();
|
||||
}
|
||||
|
||||
@@ -60,9 +46,7 @@ export default class StandardSlotSection extends SlotSection {
|
||||
* @param {Boolean} shielded True if shield generator should be included
|
||||
*/
|
||||
_optimizeCargo(shielded) {
|
||||
this.selectedRefId = 'trader';
|
||||
ShipRoles.trader(this.props.ship, shielded);
|
||||
this.props.onChange();
|
||||
this._close();
|
||||
}
|
||||
|
||||
@@ -71,9 +55,7 @@ export default class StandardSlotSection extends SlotSection {
|
||||
* @param {Boolean} shielded True if shield generator should be included
|
||||
*/
|
||||
_optimizeMiner(shielded) {
|
||||
this.selectedRefId = 'miner';
|
||||
ShipRoles.miner(this.props.ship, shielded);
|
||||
this.props.onChange();
|
||||
this._close();
|
||||
}
|
||||
|
||||
@@ -82,10 +64,7 @@ export default class StandardSlotSection extends SlotSection {
|
||||
* @param {Boolean} planetary True if Planetary Vehicle Hangar (PVH) should be included
|
||||
*/
|
||||
_optimizeExplorer(planetary) {
|
||||
this.selectedRefId = 'explorer';
|
||||
if (planetary) this.selectedRefId = 'planetary';
|
||||
ShipRoles.explorer(this.props.ship, planetary);
|
||||
this.props.onChange();
|
||||
this._close();
|
||||
}
|
||||
|
||||
@@ -93,20 +72,7 @@ export default class StandardSlotSection extends SlotSection {
|
||||
* Racer role
|
||||
*/
|
||||
_optimizeRacer() {
|
||||
this.selectedRefId = 'racer';
|
||||
ShipRoles.racer(this.props.ship);
|
||||
this.props.onChange();
|
||||
this._close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the specified bulkhead
|
||||
* @param {Object} bulkhead Bulkhead module details
|
||||
*/
|
||||
_selectBulkhead(bulkhead) {
|
||||
this.props.ship.useBulkhead(bulkhead.index);
|
||||
this.context.tooltip();
|
||||
this.props.onChange();
|
||||
this._close();
|
||||
}
|
||||
|
||||
@@ -117,122 +83,48 @@ export default class StandardSlotSection extends SlotSection {
|
||||
this._optimizeStandard();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new slot for a given module.
|
||||
* @param {Module} m Module to create the slot for
|
||||
* @param {function} warning Warning callback
|
||||
* @return {React.Component} Slot component
|
||||
*/
|
||||
_mkSlot(m, warning) {
|
||||
const { currentMenu } = this.props;
|
||||
return <Slot key={m.getSlot()} m={m} warning={warning}
|
||||
currentMenu={currentMenu}
|
||||
/>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the slot React Components
|
||||
* @return {Array} Array of Slots
|
||||
*/
|
||||
_getSlots() {
|
||||
let { ship, currentMenu } = this.props;
|
||||
let slots = new Array(8);
|
||||
let open = this._openMenu;
|
||||
let select = this._selectModule;
|
||||
// let st = ship.standard;
|
||||
// let avail = ship.getAvailableModules().standard;
|
||||
// let bh = ship.bulkheads;
|
||||
|
||||
let armour = ship.getAlloys();
|
||||
slots[0] = <Slot
|
||||
key='bh'
|
||||
slot={armour}
|
||||
modules={armour.getApplicableItems()}
|
||||
onOpen={open.bind(this, armour)}
|
||||
onSelect={this._selectBulkhead}
|
||||
selected={currentMenu == armour}
|
||||
onChange={this.props.onChange}
|
||||
ship={ship}
|
||||
/>;
|
||||
|
||||
const powerPlant = ship.getPowerPlant();
|
||||
slots[1] = <Slot
|
||||
key='pp'
|
||||
slot={powerPlant}
|
||||
modules={powerPlant.getApplicableItems()}
|
||||
onOpen={open.bind(this, powerPlant)}
|
||||
onSelect={select.bind(this, powerPlant)}
|
||||
selected={currentMenu == powerPlant}
|
||||
onChange={this.props.onChange}
|
||||
ship={ship}
|
||||
warning={m => ship.get(ShipProps.CONSUMED_RETR) < m.get('powercapacity')}
|
||||
/>;
|
||||
|
||||
const thrusters = ship.getThrusters();
|
||||
slots[2] = <Slot
|
||||
key='th'
|
||||
slot={thrusters}
|
||||
modules={thrusters.getApplicableItems()}
|
||||
onOpen={open.bind(this, thrusters)}
|
||||
onSelect={select.bind(this, thrusters)}
|
||||
selected={currentMenu == thrusters}
|
||||
onChange={this.props.onChange}
|
||||
ship={ship}
|
||||
warning={m => m.get('enginemaximalmass') < ship.get(ShipProps.LADEN_MASS)}
|
||||
/>;
|
||||
|
||||
|
||||
const { ship } = this.props;
|
||||
const fsd = ship.getFSD();
|
||||
slots[3] = <Slot
|
||||
key='fsd'
|
||||
slot={fsd}
|
||||
modules={fsd.getApplicableItems()}
|
||||
onOpen={open.bind(this, fsd)}
|
||||
onSelect={select.bind(this, fsd)}
|
||||
onChange={this.props.onChange}
|
||||
ship={ship}
|
||||
selected={currentMenu == fsd}
|
||||
/>;
|
||||
|
||||
const lifeSupport = ship.getLifeSupport();
|
||||
slots[4] = <Slot
|
||||
key='ls'
|
||||
slot={lifeSupport}
|
||||
modules={lifeSupport.getApplicableItems()}
|
||||
onOpen={open.bind(this, lifeSupport)}
|
||||
onSelect={select.bind(this, lifeSupport)}
|
||||
onChange={this.props.onChange}
|
||||
ship={ship}
|
||||
selected={currentMenu == lifeSupport}
|
||||
/>;
|
||||
|
||||
const powerDistributor = ship.getPowerDistributor();
|
||||
slots[5] = <Slot
|
||||
key='pd'
|
||||
slot={powerDistributor}
|
||||
modules={powerDistributor.getApplicableItems()}
|
||||
onOpen={open.bind(this, powerDistributor)}
|
||||
onSelect={select.bind(this, powerDistributor)}
|
||||
selected={currentMenu == powerDistributor}
|
||||
onChange={this.props.onChange}
|
||||
ship={ship}
|
||||
warning={m => m instanceof Module ? m.getEnginesCapacity() <= ship.boostEnergy : m.engcap <= ship.boostEnergy}
|
||||
/>;
|
||||
|
||||
const sensors = ship.getSensors();
|
||||
slots[6] = <Slot
|
||||
key='ss'
|
||||
slot={sensors}
|
||||
modules={sensors.getApplicableItems()}
|
||||
onOpen={open.bind(this, sensors)}
|
||||
onSelect={select.bind(this, sensors)}
|
||||
selected={currentMenu == sensors}
|
||||
onChange={this.props.onChange}
|
||||
ship={ship}
|
||||
/>;
|
||||
|
||||
const fuelTank = ship.getCoreFuelTank();
|
||||
slots[7] = <Slot
|
||||
key='ft'
|
||||
slot={fuelTank}
|
||||
modules={fuelTank.getApplicableItems()}
|
||||
onOpen={open.bind(this, fuelTank)}
|
||||
onSelect={select.bind(this, fuelTank)}
|
||||
selected={currentMenu == fuelTank}
|
||||
onChange={this.props.onChange}
|
||||
ship={ship}
|
||||
// Show warning when fuel tank is smaller than FSD Max Fuel
|
||||
warning= {m => m.get('fuel') < fsd.get('maxfuel')}
|
||||
/>;
|
||||
|
||||
return slots;
|
||||
return [
|
||||
this._mkSlot(ship.getAlloys()),
|
||||
this._mkSlot(
|
||||
ship.getPowerPlant(),
|
||||
(m) => moduleGet(m, 'powercapacity') < ship.get(CONSUMED_RETR),
|
||||
),
|
||||
this._mkSlot(
|
||||
ship.getThrusters(),
|
||||
(m) => moduleGet(m, 'enginemaximalmass') < ship.get(LADEN_MASS),
|
||||
),
|
||||
this._mkSlot(fsd),
|
||||
this._mkSlot(
|
||||
ship.getPowerDistributor(),
|
||||
(m) => moduleGet(m, 'enginescapacity') <= ship.getBaseProperty('boostenergy'),
|
||||
),
|
||||
this._mkSlot(ship.getLifeSupport()),
|
||||
this._mkSlot(ship.getSensors()),
|
||||
this._mkSlot(
|
||||
ship.getCoreFuelTank(),
|
||||
(m) => moduleGet(m, 'fuel') < fsd.get('maxfuel')
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -240,21 +132,21 @@ export default class StandardSlotSection extends SlotSection {
|
||||
* @param {Function} translate Translate function
|
||||
* @return {React.Component} Section menu
|
||||
*/
|
||||
_getSectionMenu(translate) {
|
||||
let planetaryDisabled = this.props.ship.internal.length < 4;
|
||||
_getSectionMenu() {
|
||||
const { translate } = this.context.language;
|
||||
return <div className='select' onClick={(e) => e.stopPropagation()} onContextMenu={stopCtxPropagation}>
|
||||
<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' tabIndex="0" onClick={this._optimizeStandard}>{translate('Maximize Jump Range')}</li>
|
||||
</ul>
|
||||
<div className='select-group cap'>{translate('roles')}</div>
|
||||
<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' tabIndex="0" onClick={this._multiPurpose.bind(this, true, 2)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['combat'] = smRef}>{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' tabIndex="0" onClick={this._optimizeExplorer.bind(this, false)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['explorer'] = smRef}>{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='lc' tabIndex="0" onClick={this._optimizeMiner.bind(this, true)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['miner'] = smRef}>{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' tabIndex="0" onClick={this._multiPurpose.bind(this, false, 0)}>{translate('Multi-purpose')}</li>
|
||||
<li className='lc' tabIndex="0" onClick={this._multiPurpose.bind(this, true, 2)}>{translate('Combat')}</li>
|
||||
<li className='lc' tabIndex="0" onClick={this._optimizeCargo.bind(this, true)}>{translate('Trader')}</li>
|
||||
<li className='lc' tabIndex="0" onClick={this._optimizeExplorer.bind(this, false)}>{translate('Explorer')}</li>
|
||||
<li className='lc' tabIndex="0" onClick={this._optimizeExplorer.bind(this, true)}>{translate('Planetary Explorer')}</li>
|
||||
<li className='lc' tabIndex="0" onClick={this._optimizeMiner.bind(this, true)}>{translate('Miner')}</li>
|
||||
<li className='lc' tabIndex="0" onClick={this._optimizeRacer.bind(this)}>{translate('Racer')}</li>
|
||||
</ul>
|
||||
</div>;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import SlotSection from './SlotSection';
|
||||
import Slot from './Slot';
|
||||
import { stopCtxPropagation } from '../utils/UtilityFunctions';
|
||||
import autoBind from 'auto-bind';
|
||||
|
||||
/**
|
||||
* Utility Slot Section
|
||||
@@ -10,28 +11,16 @@ export default class UtilitySlotSection extends SlotSection {
|
||||
/**
|
||||
* Constructor
|
||||
* @param {Object} props React Component properties
|
||||
* @param {Object} context React Component context
|
||||
*/
|
||||
constructor(props, context) {
|
||||
super(props, context, 'utility', 'utility mounts');
|
||||
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);
|
||||
constructor(props) {
|
||||
super(props, 'utility mounts');
|
||||
autoBind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty all utility slots and close the menu
|
||||
*/
|
||||
_empty() {
|
||||
this.selectedRefId = this.firstRefId;
|
||||
this.props.ship.emptyUtility();
|
||||
this.props.onChange();
|
||||
this._close();
|
||||
@@ -45,9 +34,6 @@ export default class UtilitySlotSection extends SlotSection {
|
||||
* @param {Synthetic} event 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.onChange();
|
||||
this._close();
|
||||
@@ -73,16 +59,13 @@ export default class UtilitySlotSection extends SlotSection {
|
||||
slots.push(<Slot
|
||||
key={h.object.Slot}
|
||||
maxClass={h.getSize()}
|
||||
onOpen={this._openMenu.bind(this,h)}
|
||||
onSelect={this._selectModule.bind(this, h)}
|
||||
onChange={this.props.onChange}
|
||||
selected={currentMenu == h}
|
||||
currentMenu={currentMenu}
|
||||
drag={this._drag.bind(this, h)}
|
||||
dragOver={this._dragOverSlot.bind(this, h)}
|
||||
drop={this._drop}
|
||||
dropClass={this._dropClass(h, originSlot, targetSlot)}
|
||||
ship={ship}
|
||||
slot={h}
|
||||
m={h}
|
||||
enabled={h.enabled ? true : false}
|
||||
/>);
|
||||
}
|
||||
@@ -95,33 +78,34 @@ export default class UtilitySlotSection extends SlotSection {
|
||||
* @param {Function} translate Translate function
|
||||
* @return {React.Component} Section menu
|
||||
*/
|
||||
_getSectionMenu(translate) {
|
||||
_getSectionMenu() {
|
||||
const { translate } = this.context.language;
|
||||
let _use = this._use;
|
||||
|
||||
return <div className='select' onClick={(e) => e.stopPropagation()} onContextMenu={stopCtxPropagation}>
|
||||
<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' tabIndex='0' onClick={this._empty}>{translate('empty all')}</li>
|
||||
<li className='optional-hide' style={{ textAlign: 'center', marginTop: '1em' }}>{translate('PHRASE_ALT_ALL')}</li>
|
||||
</ul>
|
||||
<div className='select-group cap'>{translate('sb')}</div>
|
||||
<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' tabIndex='0' onClick={_use.bind(this, 'sb', 'B', null)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['sb-B'] = smRef}>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' tabIndex='0' onClick={_use.bind(this, 'sb', 'D', null)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['sb-D'] = smRef}>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' tabIndex='0' onClick={_use.bind(this, 'sb', 'A', null)}>A</li>
|
||||
<li className='c' tabIndex='0' onClick={_use.bind(this, 'sb', 'B', null)}>B</li>
|
||||
<li className='c' tabIndex='0' onClick={_use.bind(this, 'sb', 'C', null)}>C</li>
|
||||
<li className='c' tabIndex='0' onClick={_use.bind(this, 'sb', 'D', null)}>D</li>
|
||||
<li className='c' tabIndex='0' onClick={_use.bind(this, 'sb', 'E', null)}>E</li>
|
||||
</ul>
|
||||
<div className='select-group cap'>{translate('hs')}</div>
|
||||
<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' tabIndex='0' onClick={_use.bind(this, 'hs', null, 'Heat Sink Launcher')}>{translate('Heat Sink Launcher')}</li>
|
||||
</ul>
|
||||
<div className='select-group cap'>{translate('ch')}</div>
|
||||
<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' tabIndex='0' onClick={_use.bind(this, 'ch', null, 'Chaff Launcher')}>{translate('Chaff Launcher')}</li>
|
||||
</ul>
|
||||
<div className='select-group cap'>{translate('po')}</div>
|
||||
<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' tabIndex='0' onClick={_use.bind(this, 'po', null, 'Point Defence')}>{translate('Point Defence')}</li>
|
||||
</ul>
|
||||
</div>;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import Router from '../Router';
|
||||
import Persist from '../stores/Persist';
|
||||
import * as Utils from '../utils/UtilityFunctions';
|
||||
import { Factory, Ship } from 'ed-forge';
|
||||
import { STATE_EVENT, OBJECT_EVENT } from 'ed-forge/lib/Ship';
|
||||
import * as _ from 'lodash';
|
||||
import { toDetailedBuild } from '../shipyard/Serializer';
|
||||
import { outfitURL } from '../utils/UrlGenerators';
|
||||
@@ -38,16 +39,7 @@ import ModalExport from '../components/ModalExport';
|
||||
import ModalPermalink from '../components/ModalPermalink';
|
||||
import ModalShoppingList from '../components/ModalShoppingList';
|
||||
import ModalOrbis from '../components/ModalOrbis';
|
||||
|
||||
/**
|
||||
* Document Title Generator
|
||||
* @param {String} shipName Ship Name
|
||||
* @param {String} buildName Build Name
|
||||
* @return {String} Document title
|
||||
*/
|
||||
function getTitle(shipName, buildName) {
|
||||
return buildName ? buildName : shipName;
|
||||
}
|
||||
import autoBind from 'auto-bind';
|
||||
|
||||
/**
|
||||
* The Outfitting Page
|
||||
@@ -60,13 +52,8 @@ export default class OutfittingPage extends Page {
|
||||
*/
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
// window.Perf = Perf;
|
||||
autoBind(this);
|
||||
this.state = this._initState(props, context);
|
||||
this._keyDown = this._keyDown.bind(this);
|
||||
this._exportBuild = this._exportBuild.bind(this);
|
||||
this._opponentUpdated = this._opponentUpdated.bind(this);
|
||||
this._engagementRangeUpdated = this._engagementRangeUpdated.bind(this);
|
||||
this._sectionMenuRefs = {};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,24 +68,32 @@ export default class OutfittingPage extends Page {
|
||||
let buildName = params.bn;
|
||||
let savedCode = Persist.getBuild(shipId, buildName);
|
||||
let code = params.code || savedCode;
|
||||
let ship = code ? new Ship(code) : Factory.newShip(shipId); // Create a new Ship instance
|
||||
code = ship.compress();
|
||||
|
||||
this._getTitle = getTitle.bind(this, ship.getShipType());
|
||||
// Create a new Ship instance
|
||||
const ship = code ? new Ship(code) : Factory.newShip(shipId);
|
||||
ship.on(STATE_EVENT, this._shipUpdated);
|
||||
ship.on(OBJECT_EVENT, this._shipUpdated);
|
||||
|
||||
return {
|
||||
error: null,
|
||||
title: this._getTitle(buildName),
|
||||
costTab: Persist.getCostTab() || 'costs',
|
||||
buildName,
|
||||
newBuildName: buildName,
|
||||
shipId,
|
||||
ship,
|
||||
code,
|
||||
code: ship.compress(),
|
||||
savedCode,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this pages title for the browser.
|
||||
* @returns {string} Page title
|
||||
*/
|
||||
_getTitle() {
|
||||
const { buildName } = this.state;
|
||||
const { translate } = this.context.language;
|
||||
return buildName || translate(this.ship.getShipType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle build name change and update state
|
||||
* @param {SyntheticEvent} event React Event
|
||||
@@ -108,10 +103,12 @@ export default class OutfittingPage extends Page {
|
||||
newBuildName: event.target.value
|
||||
};
|
||||
|
||||
if (Persist.hasBuild(this.state.shipId, stateChanges.newBuildName)) {
|
||||
const { ship } = this.state;
|
||||
const shipId = ship.getShipType();
|
||||
if (Persist.hasBuild(shipId, stateChanges.newBuildName)) {
|
||||
stateChanges.savedCode = Persist.getBuild(
|
||||
this.state.shipId,
|
||||
stateChanges.newBuildName
|
||||
shipId,
|
||||
stateChanges.newBuildName,
|
||||
);
|
||||
} else {
|
||||
stateChanges.savedCode = null;
|
||||
@@ -124,9 +121,9 @@ export default class OutfittingPage extends Page {
|
||||
* Update the control part of the route
|
||||
*/
|
||||
_updateRoute() {
|
||||
const { ship, shipId, buildName } = this.state;
|
||||
const { ship } = this.state;
|
||||
const code = ship.compress();
|
||||
this._updateRoute(shipId, buildName, code);
|
||||
this._setRoute();
|
||||
this.setState({ code });
|
||||
}
|
||||
|
||||
@@ -193,13 +190,14 @@ export default class OutfittingPage extends Page {
|
||||
* Save the current build
|
||||
*/
|
||||
_saveBuild() {
|
||||
const { ship, buildName, newBuildName, shipId } = this.state;
|
||||
const { ship, buildName, newBuildName } = this.state;
|
||||
const shipId = ship.getShipType();
|
||||
|
||||
// If this is a stock ship the code won't be set, so ensure that we have it
|
||||
const code = this.state.code || ship.compress();
|
||||
|
||||
Persist.saveBuild(shipId, newBuildName, code);
|
||||
this._updateRoute(shipId, newBuildName, code);
|
||||
this._setRoute();
|
||||
|
||||
let opponent, opponentBuild, opponentSys, opponentEng, opponentWep;
|
||||
if (
|
||||
@@ -232,7 +230,6 @@ export default class OutfittingPage extends Page {
|
||||
opponentSys,
|
||||
opponentEng,
|
||||
opponentWep,
|
||||
title: this._getTitle(newBuildName)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -240,11 +237,12 @@ export default class OutfittingPage extends Page {
|
||||
* Rename the current build
|
||||
*/
|
||||
_renameBuild() {
|
||||
const { code, buildName, newBuildName, shipId, ship } = this.state;
|
||||
const { code, buildName, newBuildName, ship } = this.state;
|
||||
const shipId = ship.getShipType();
|
||||
if (buildName != newBuildName && newBuildName.length) {
|
||||
Persist.deleteBuild(shipId, buildName);
|
||||
Persist.saveBuild(shipId, newBuildName, code);
|
||||
this._updateRoute(shipId, newBuildName, code);
|
||||
this._setRoute();
|
||||
this.setState({
|
||||
buildName: newBuildName,
|
||||
code,
|
||||
@@ -265,20 +263,19 @@ export default class OutfittingPage extends Page {
|
||||
* Reset build to Stock/Factory defaults
|
||||
*/
|
||||
_resetBuild() {
|
||||
const { ship, shipId, buildName } = this.state;
|
||||
let { ship } = this.state;
|
||||
// Rebuild ship
|
||||
ship.buildWith(Ships[shipId].defaults);
|
||||
// Reset controls
|
||||
const code = ship.compress();
|
||||
ship = Factory.newShip(ship.getShipType());
|
||||
// Update state, and refresh the ship
|
||||
this._updateRoute(shipId, buildName, code);
|
||||
this.setState({ ship, code: undefined }, () => this._setRoute());
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the build
|
||||
*/
|
||||
_deleteBuild() {
|
||||
const { shipId, buildName } = this.state;
|
||||
const { ship, buildName } = this.state;
|
||||
const shipId = ship.getShipType();
|
||||
Persist.deleteBuild(shipId, buildName);
|
||||
|
||||
let opponentBuild;
|
||||
@@ -291,7 +288,7 @@ export default class OutfittingPage extends Page {
|
||||
} else {
|
||||
opponentBuild = this.state.opponentBuild;
|
||||
}
|
||||
Router.go(outfitURL(this.state.shipId));
|
||||
Router.go(outfitURL(shipId));
|
||||
|
||||
this.setState({ opponentBuild });
|
||||
}
|
||||
@@ -315,24 +312,24 @@ export default class OutfittingPage extends Page {
|
||||
* Called when the code for the ship has been updated, to synchronise the rest of the data
|
||||
*/
|
||||
_codeUpdated() {
|
||||
const { code, shipId, buildName } = this.state;
|
||||
const { ship, code, buildName } = this.state;
|
||||
const shipId = ship.getShipType();
|
||||
|
||||
this.setState({
|
||||
ship: new Ship(code),
|
||||
}, () => this._updateRoute(shipId, buildName, code));
|
||||
this.setState(
|
||||
{ ship: new Ship(code), },
|
||||
() => this._setRoute(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the ship has been updated, to set the code and then update accordingly
|
||||
*/
|
||||
_shipUpdated() {
|
||||
let { ship, shipId, buildName } = this.state;
|
||||
let { ship } = this.state;
|
||||
const code = ship.compress();
|
||||
// Only update the state if this really has been updated
|
||||
if (this.state.code != code) {
|
||||
this.setState({ code }, () =>
|
||||
this._updateRoute(shipId, buildName, code)
|
||||
);
|
||||
this.setState({ code }, () => this._setRoute());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,8 +339,9 @@ export default class OutfittingPage extends Page {
|
||||
* @param {string} buildName Current build name
|
||||
* @param {string} code Serialized ship 'code'
|
||||
*/
|
||||
_updateRoute(shipId, buildName, code) {
|
||||
Router.replace(outfitURL(shipId, code, buildName));
|
||||
_setRoute() {
|
||||
const { ship, code, buildName } = this.state;
|
||||
Router.replace(outfitURL(ship.getShipType(), code, buildName));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -463,31 +461,10 @@ export default class OutfittingPage extends Page {
|
||||
} = state,
|
||||
hide = tooltip.bind(null, null),
|
||||
menu = this.props.currentMenu,
|
||||
shipUpdated = this._shipUpdated,
|
||||
canSave = (newBuildName || buildName) && code !== savedCode,
|
||||
canRename = buildName && newBuildName && buildName != newBuildName,
|
||||
canReload = savedCode && canSave;
|
||||
|
||||
// Code can be blank for a default loadout. Prefix it with the ship name to ensure that changes in default ships is picked up
|
||||
code = ship.name + (code || '');
|
||||
|
||||
// Markers are used to propagate state changes without requiring a deep comparison of the ship, as that takes a long time
|
||||
// const _sStr = ship.getStandardString();
|
||||
// const _iStr = ship.getInternalString();
|
||||
// const _hStr = ship.getHardpointsString();
|
||||
// const _pStr = `${ship.getPowerEnabledString()}${ship.getPowerPrioritiesString()}`;
|
||||
// const _mStr = ship.getModificationsString();
|
||||
|
||||
// const standardSlotMarker = `${ship.name}${_sStr}${_pStr}${_mStr}${
|
||||
// ship.ladenMass
|
||||
// }${cargo}${fuel}`;
|
||||
// const internalSlotMarker = `${ship.name}${_iStr}${_pStr}${_mStr}`;
|
||||
// const hardpointsSlotMarker = `${ship.name}${_hStr}${_pStr}${_mStr}`;
|
||||
// const boostMarker = `${ship.canBoost(cargo, fuel)}`;
|
||||
// const shipSummaryMarker = `${
|
||||
// ship.name
|
||||
// }${_sStr}${_iStr}${_hStr}${_pStr}${_mStr}${ship.ladenMass}${cargo}${fuel}`;
|
||||
|
||||
// const requirements = Ships[ship.id].requirements;
|
||||
// let requirementElements = [];
|
||||
// /**
|
||||
@@ -654,46 +631,11 @@ export default class OutfittingPage extends Page {
|
||||
</div>
|
||||
|
||||
{/* Main tables */}
|
||||
{/* <ShipSummaryTable
|
||||
ship={ship}
|
||||
marker={shipSummaryMarker}
|
||||
/> */}
|
||||
<StandardSlotSection
|
||||
ship={ship}
|
||||
// code={standardSlotMarker}
|
||||
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}
|
||||
sectionMenuRefs={this._sectionMenuRefs}
|
||||
/>
|
||||
<HardpointSlotSection
|
||||
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}
|
||||
sectionMenuRefs={this._sectionMenuRefs}
|
||||
/>
|
||||
<ShipSummaryTable ship={ship} />
|
||||
<StandardSlotSection ship={ship} currentMenu={menu} />
|
||||
<InternalSlotSection ship={ship} currentMenu={menu} />
|
||||
<HardpointSlotSection ship={ship} currentMenu={menu} />
|
||||
<UtilitySlotSection ship={ship} currentMenu={menu} />
|
||||
|
||||
{/* Control of ship and opponent */}
|
||||
{/* <div className="group quarter">
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Module } from 'ed-forge';
|
||||
|
||||
/**
|
||||
* Wraps the callback/context menu handler such that the default
|
||||
@@ -83,3 +84,18 @@ export function isEmpty(obj) {
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetches a property from either a Module or a moduleInfo object
|
||||
* @param {Object} m Either a Module or a moduleInfo object
|
||||
* @param {string} property Property name
|
||||
* @returns {number} Property value
|
||||
*/
|
||||
export function moduleGet(m, property) {
|
||||
if (m instanceof Module) {
|
||||
return m.get(property);
|
||||
} else {
|
||||
// Assume its a moduleInfo object
|
||||
return m.props[property];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user