mirror of
https://github.com/EDCD/coriolis.git
synced 2025-12-08 14:33:22 +00:00
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## About
|
## About
|
||||||
|
|
||||||
The Coriolis project was inspired by [E:D Shipyard](http://www.edshipyard.com/) and, of course, [Elite Dangerous](http://www.elitedangerous.com). The ultimate goal of Coriolis is to provide rich features to support in-game play and planning while engaging the E:D community to support its development.
|
The Coriolis project was inspired by E:D Shipyard and, of course, [Elite Dangerous](http://www.elitedangerous.com). The ultimate goal of Coriolis is to provide rich features to support in-game play and planning while engaging the E:D community to support its development.
|
||||||
|
|
||||||
Coriolis was created using assets and imagery from Elite: Dangerous, with the permission of Frontier Developments plc, for non-commercial purposes. It is not endorsed by nor reflects the views or opinions of Frontier Developments and no employee of Frontier Developments was involved in the making of it.
|
Coriolis was created using assets and imagery from Elite: Dangerous, with the permission of Frontier Developments plc, for non-commercial purposes. It is not endorsed by nor reflects the views or opinions of Frontier Developments and no employee of Frontier Developments was involved in the making of it.
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ export default class Coriolis extends React.Component {
|
|||||||
this.state = {
|
this.state = {
|
||||||
noTouch: !('ontouchstart' in window || navigator.msMaxTouchPoints || navigator.maxTouchPoints),
|
noTouch: !('ontouchstart' in window || navigator.msMaxTouchPoints || navigator.maxTouchPoints),
|
||||||
page: null,
|
page: null,
|
||||||
announcements: [],
|
// Announcements must have an expiry date in format "YYYY-MM-DDTHH:MM:SSZ"
|
||||||
|
announcements: [{expiry: "2024-11-30T00:00:00Z", text: "Mandalay added"}, {expiry: "2024-12-06T00:00:00Z", text: "Concord Cannon added"}, {expiry: "2024-12-08T00:00:00Z", text: "Boost Interval Feature added"}],
|
||||||
language: getLanguage(Persist.getLangCode()),
|
language: getLanguage(Persist.getLangCode()),
|
||||||
route: {},
|
route: {},
|
||||||
sizeRatio: Persist.getSizeRatio()
|
sizeRatio: Persist.getSizeRatio()
|
||||||
|
|||||||
@@ -39,13 +39,18 @@ const GRPCAT = {
|
|||||||
'ml': 'lasers',
|
'ml': 'lasers',
|
||||||
'c': 'projectiles',
|
'c': 'projectiles',
|
||||||
'mc': 'projectiles',
|
'mc': 'projectiles',
|
||||||
|
'advmc': 'projectiles',
|
||||||
'axmc': 'experimental',
|
'axmc': 'experimental',
|
||||||
|
'axmce': 'experimental',
|
||||||
|
'ntp': 'experimental',
|
||||||
'fc': 'projectiles',
|
'fc': 'projectiles',
|
||||||
'rfl': 'experimental',
|
'rfl': 'experimental',
|
||||||
'pa': 'projectiles',
|
'pa': 'projectiles',
|
||||||
'rg': 'projectiles',
|
'rg': 'projectiles',
|
||||||
'mr': 'ordnance',
|
'mr': 'ordnance',
|
||||||
|
'amr': 'ordnance',
|
||||||
'axmr': 'experimental',
|
'axmr': 'experimental',
|
||||||
|
'axmre': 'experimental',
|
||||||
'rcpl': 'experimental',
|
'rcpl': 'experimental',
|
||||||
'dtl': 'experimental',
|
'dtl': 'experimental',
|
||||||
'tbsc': 'experimental',
|
'tbsc': 'experimental',
|
||||||
@@ -104,8 +109,8 @@ const CATEGORIES = {
|
|||||||
|
|
||||||
// Hardpoints
|
// Hardpoints
|
||||||
'lasers': ['pl', 'ul', 'bl'],
|
'lasers': ['pl', 'ul', 'bl'],
|
||||||
'projectiles': ['mc', 'c', 'fc', 'pa', 'rg'],
|
'projectiles': ['mc', 'advmc', 'c', 'fc', 'pa', 'rg'],
|
||||||
'ordnance': ['mr', 'tp', 'nl'],
|
'ordnance': ['mr', 'amr', 'tp', 'nl'],
|
||||||
// Utilities
|
// Utilities
|
||||||
'sb': ['sb'],
|
'sb': ['sb'],
|
||||||
'hs': ['hs'],
|
'hs': ['hs'],
|
||||||
@@ -113,7 +118,7 @@ const CATEGORIES = {
|
|||||||
'defence': ['ch', 'po', 'ec'],
|
'defence': ['ch', 'po', 'ec'],
|
||||||
'scanners': ['sc', 'ss', 'cs', 'kw', 'ws'], // Overloaded with internal scanners
|
'scanners': ['sc', 'ss', 'cs', 'kw', 'ws'], // Overloaded with internal scanners
|
||||||
// Experimental
|
// Experimental
|
||||||
'experimental': ['axmc', 'axmr', 'rfl', 'tbrfl', 'tbsc', 'tbem', 'xs', 'sfn', 'rcpl', 'dtl', 'rsl', 'mahr',],
|
'experimental': ['axmc', 'axmce', 'axmr', 'axmre', 'ntp','rfl', 'tbrfl', 'tbsc', 'tbem', 'xs', 'sfn', 'rcpl', 'dtl', 'rsl', 'mahr',],
|
||||||
'weapon stabilizers': ['ews'],
|
'weapon stabilizers': ['ews'],
|
||||||
// Guardian
|
// Guardian
|
||||||
'guardian': ['gpp', 'gpd', 'gpc', 'ggc', 'gsrp', 'gfsb', 'ghrp', 'gmrp', 'gsc'],
|
'guardian': ['gpp', 'gpd', 'gpc', 'ggc', 'gsrp', 'gfsb', 'ghrp', 'gmrp', 'gsc'],
|
||||||
@@ -213,16 +218,30 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
if (categories.length === 1) {
|
if (categories.length === 1) {
|
||||||
// Show category header instead of group header
|
// Show category header instead of group header
|
||||||
if (m && grp == m.grp) {
|
if (m && grp == m.grp) {
|
||||||
list.push(<div ref={(elem) => this.groupElem = elem} key={category}
|
// If this is a missing module/weapon, skip it
|
||||||
|
if (m.grp == "mh" || m.grp == "mm"){
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
list.push(<div ref={(elem) => this.groupElem = elem} key={category}
|
||||||
className={'select-category upp'}>{translate(category)}</div>);
|
className={'select-category upp'}>{translate(category)}</div>);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
list.push(<div key={category} className={'select-category upp'}>{translate(category)}</div>);
|
if (category == "mh" || category == "mm"){
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
list.push(<div key={category} className={'select-category upp'}>{translate(category)}</div>);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Show category header as well as group header
|
// Show category header as well as group header
|
||||||
if (!categoryHeader) {
|
if (!categoryHeader) {
|
||||||
list.push(<div key={category} className={'select-category upp'}>{translate(category)}</div>);
|
if (category == "mh" || category == "mm"){
|
||||||
categoryHeader = true;
|
continue;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
list.push(<div key={category} className={'select-category upp'}>{translate(category)}</div>);
|
||||||
|
categoryHeader = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (m && grp == m.grp) {
|
if (m && grp == m.grp) {
|
||||||
list.push(<div ref={(elem) => this.groupElem = elem} key={grp}
|
list.push(<div ref={(elem) => this.groupElem = elem} key={grp}
|
||||||
@@ -241,7 +260,11 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
} else if (i.mount === 'T') {
|
} else if (i.mount === 'T') {
|
||||||
mount = 'Turreted';
|
mount = 'Turreted';
|
||||||
}
|
}
|
||||||
const fuzz = { grp, m: i, name: `${i.class}${i.rating}${mount ? ' ' + mount : ''} ${translate(grp)}` };
|
let special = '';
|
||||||
|
if (typeof(i.special) !== 'undefined') {
|
||||||
|
special = `(${translate(i.special)})`;
|
||||||
|
}
|
||||||
|
const fuzz = { grp, m: i, name: `${i.class}${i.rating}${mount ? ' ' + mount : ''} ${translate(grp)} ${translate(special)}` };
|
||||||
fuzzy.push(fuzz);
|
fuzzy.push(fuzz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -298,6 +321,11 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
let itemsOnThisRow = 0;
|
let itemsOnThisRow = 0;
|
||||||
for (let i = 0; i < sortedModules.length; i++) {
|
for (let i = 0; i < sortedModules.length; i++) {
|
||||||
let m = sortedModules[i];
|
let m = sortedModules[i];
|
||||||
|
// If m.grp is mh or mm, or m.symbol contains 'Missing' skip it
|
||||||
|
if (m.grp == 'mh' || m.grp == 'mm' || (typeof(m.symbol) !== 'undefined' && m.symbol.includes("Missing"))) {
|
||||||
|
// If this is a missing module, skip it
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let mount = null;
|
let mount = null;
|
||||||
let disabled = false;
|
let disabled = false;
|
||||||
prevName = m.name;
|
prevName = m.name;
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ export default class HardpointSlot extends Slot {
|
|||||||
{showModuleResistances && m.getThermalResistance() ? <div
|
{showModuleResistances && m.getThermalResistance() ? <div
|
||||||
className='l'>{translate('thermres')}: {formats.pct(m.getThermalResistance())}</div> : null}
|
className='l'>{translate('thermres')}: {formats.pct(m.getThermalResistance())}</div> : null}
|
||||||
{m.getIntegrity() ? <div className='l'>{translate('integrity')}: {formats.int(m.getIntegrity())}</div> : null}
|
{m.getIntegrity() ? <div className='l'>{translate('integrity')}: {formats.int(m.getIntegrity())}</div> : null}
|
||||||
|
{m.getInfo() ? <div className='l'>{translate(m.getInfo())}</div> : null}
|
||||||
{m && validMods.length > 0 ? <div className='r' tabIndex="0" ref={modButton => this.modButton = modButton}>
|
{m && validMods.length > 0 ? <div className='r' tabIndex="0" ref={modButton => this.modButton = modButton}>
|
||||||
<button tabIndex="-1" onClick={this._toggleModifications.bind(this)} onContextMenu={stopCtxPropagation}
|
<button tabIndex="-1" onClick={this._toggleModifications.bind(this)} onContextMenu={stopCtxPropagation}
|
||||||
onMouseOver={termtip.bind(null, 'modifications')} onMouseOut={tooltip.bind(null, null)}>
|
onMouseOver={termtip.bind(null, 'modifications')} onMouseOut={tooltip.bind(null, null)}>
|
||||||
|
|||||||
@@ -388,9 +388,11 @@ export default class Header extends TranslatedComponent {
|
|||||||
if (this.props.announcements) {
|
if (this.props.announcements) {
|
||||||
announcements = [];
|
announcements = [];
|
||||||
for (let announce of this.props.announcements) {
|
for (let announce of this.props.announcements) {
|
||||||
if (announce.expiry < Date.now()) {
|
// Announcement has expired, skip it
|
||||||
|
if (Date.now() > Date.parse(announce.expiry)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// Add announcements which have not expired to the menu
|
||||||
announcements.push(<Announcement text={announce.text} />);
|
announcements.push(<Announcement text={announce.text} />);
|
||||||
announcements.push(<hr/>);
|
announcements.push(<hr/>);
|
||||||
}
|
}
|
||||||
@@ -398,7 +400,6 @@ export default class Header extends TranslatedComponent {
|
|||||||
return (
|
return (
|
||||||
<div className='menu-list' onClick={ (e) => e.stopPropagation() } style={{ whiteSpace: 'nowrap' }}>
|
<div className='menu-list' onClick={ (e) => e.stopPropagation() } style={{ whiteSpace: 'nowrap' }}>
|
||||||
{announcements}
|
{announcements}
|
||||||
<hr />
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ export default class InternalSlot extends Slot {
|
|||||||
{ m.getHullReinforcement() ? <div className='l'>{translate('armour')}: {formats.int(m.getHullReinforcement() + ship.baseArmour * m.getModValue('hullboost') / 10000)}</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.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.getIntegrity() ? <div className='l'>{translate('integrity')}: {formats.int(m.getIntegrity())}</div> : null }
|
||||||
|
{ m.getInfo() ? <div className='l'>{translate(m.getInfo())}</div> : null }
|
||||||
{ m && validMods.length > 0 ? <div className='r' tabIndex="0" ref={ modButton => this.modButton = modButton }><button tabIndex="-1" onClick={this._toggleModifications.bind(this)} onContextMenu={stopCtxPropagation} onMouseOver={termtip.bind(null, 'modifications')} onMouseOut={tooltip.bind(null, null)}><ListModifications /></button></div> : null }
|
{ m && validMods.length > 0 ? <div className='r' tabIndex="0" ref={ modButton => this.modButton = modButton }><button tabIndex="-1" onClick={this._toggleModifications.bind(this)} onContextMenu={stopCtxPropagation} onMouseOver={termtip.bind(null, 'modifications')} onMouseOut={tooltip.bind(null, null)}><ListModifications /></button></div> : null }
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
|
|||||||
@@ -1,281 +1,281 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import ContainerDimensions from 'react-container-dimensions';
|
import ContainerDimensions from 'react-container-dimensions';
|
||||||
import * as d3 from 'd3';
|
import * as d3 from 'd3';
|
||||||
import TranslatedComponent from './TranslatedComponent';
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
|
|
||||||
const MARGIN = { top: 15, right: 20, bottom: 35, left: 60 };
|
const MARGIN = { top: 15, right: 20, bottom: 35, left: 60 };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Line Chart
|
* Line Chart
|
||||||
*/
|
*/
|
||||||
export default class LineChart extends TranslatedComponent {
|
export default class LineChart extends TranslatedComponent {
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
code: '',
|
code: '',
|
||||||
xMin: 0,
|
xMin: 0,
|
||||||
yMin: 0,
|
yMin: 0,
|
||||||
points: 20,
|
points: 20,
|
||||||
colors: ['#ff8c0d'],
|
colors: ['#ff8c0d'],
|
||||||
aspect: 0.5
|
aspect: 0.5
|
||||||
};
|
};
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
func: PropTypes.func.isRequired,
|
func: PropTypes.func.isRequired,
|
||||||
xLabel: PropTypes.string.isRequired,
|
xLabel: PropTypes.string.isRequired,
|
||||||
xMin: PropTypes.number,
|
xMin: PropTypes.number,
|
||||||
xMax: PropTypes.number.isRequired,
|
xMax: PropTypes.number.isRequired,
|
||||||
xUnit: PropTypes.string.isRequired,
|
xUnit: PropTypes.string.isRequired,
|
||||||
xMark: PropTypes.number,
|
xMark: PropTypes.number,
|
||||||
yLabel: PropTypes.string.isRequired,
|
yLabel: PropTypes.string.isRequired,
|
||||||
yMin: PropTypes.number,
|
yMin: PropTypes.number,
|
||||||
yMax: PropTypes.number.isRequired,
|
yMax: PropTypes.number.isRequired,
|
||||||
yUnit: PropTypes.string,
|
yUnit: PropTypes.string,
|
||||||
series: PropTypes.array,
|
series: PropTypes.array,
|
||||||
colors: PropTypes.array,
|
colors: PropTypes.array,
|
||||||
points: PropTypes.number,
|
points: PropTypes.number,
|
||||||
aspect: PropTypes.number,
|
aspect: PropTypes.number,
|
||||||
code: PropTypes.string,
|
code: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
* @param {Object} context React Component context
|
* @param {Object} context React Component context
|
||||||
*/
|
*/
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this._updateDimensions = this._updateDimensions.bind(this);
|
this._updateDimensions = this._updateDimensions.bind(this);
|
||||||
this._updateSeries = this._updateSeries.bind(this);
|
this._updateSeries = this._updateSeries.bind(this);
|
||||||
this._tooltip = this._tooltip.bind(this);
|
this._tooltip = this._tooltip.bind(this);
|
||||||
this._showTip = this._showTip.bind(this);
|
this._showTip = this._showTip.bind(this);
|
||||||
this._hideTip = this._hideTip.bind(this);
|
this._hideTip = this._hideTip.bind(this);
|
||||||
this._moveTip = this._moveTip.bind(this);
|
this._moveTip = this._moveTip.bind(this);
|
||||||
|
|
||||||
const series = props.series;
|
const series = props.series;
|
||||||
|
|
||||||
let xScale = d3.scaleLinear();
|
let xScale = d3.scaleLinear();
|
||||||
let yScale = d3.scaleLinear();
|
let yScale = d3.scaleLinear();
|
||||||
let xAxisScale = d3.scaleLinear();
|
let xAxisScale = d3.scaleLinear();
|
||||||
|
|
||||||
this.xAxis = d3.axisBottom(xAxisScale).tickSizeOuter(0);
|
this.xAxis = d3.axisBottom(xAxisScale).tickSizeOuter(0);
|
||||||
this.yAxis = d3.axisLeft(yScale).ticks(6).tickSizeOuter(0);
|
this.yAxis = d3.axisLeft(yScale).ticks(6).tickSizeOuter(0);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
xScale,
|
xScale,
|
||||||
xAxisScale,
|
xAxisScale,
|
||||||
yScale,
|
yScale,
|
||||||
tipHeight: 2 + (1.2 * (series ? series.length : 0.8)),
|
tipHeight: 2 + (1.2 * (series ? series.length : 0.8)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update tooltip content
|
* Update tooltip content
|
||||||
* @param {number} xPos x coordinate
|
* @param {number} xPos x coordinate
|
||||||
* @param {number} width current container width
|
* @param {number} width current container width
|
||||||
*/
|
*/
|
||||||
_tooltip(xPos, width) {
|
_tooltip(xPos, width) {
|
||||||
let { xLabel, yLabel, xUnit, yUnit, func, series } = this.props;
|
let { xLabel, yLabel, xUnit, yUnit, func, series } = this.props;
|
||||||
let { xScale, yScale } = this.state;
|
let { xScale, yScale } = this.state;
|
||||||
let { formats, translate } = this.context.language;
|
let { formats, translate } = this.context.language;
|
||||||
let x0 = xScale.invert(xPos),
|
let x0 = xScale.invert(xPos),
|
||||||
y0 = func(x0),
|
y0 = func(x0),
|
||||||
tips = this.tipContainer,
|
tips = this.tipContainer,
|
||||||
yTotal = 0,
|
yTotal = 0,
|
||||||
flip = (xPos / width > 0.50),
|
flip = (xPos / width > 0.50),
|
||||||
tipWidth = 0,
|
tipWidth = 0,
|
||||||
tipHeightPx = tips.selectAll('rect').node().getBoundingClientRect().height;
|
tipHeightPx = tips.selectAll('rect').node().getBoundingClientRect().height;
|
||||||
|
|
||||||
|
|
||||||
xPos = xScale(x0); // Clamp xPos
|
xPos = xScale(x0); // Clamp xPos
|
||||||
|
|
||||||
tips.selectAll('text.text-tip.y').text(function(d, i) {
|
tips.selectAll('text.text-tip.y').text(function(d, i) {
|
||||||
let yVal = series ? y0[series[i]] : y0;
|
let yVal = series ? y0[series[i]] : y0;
|
||||||
yTotal += yVal;
|
yTotal += yVal;
|
||||||
return (series ? translate(series[i]) : '') + ' ' + formats.f2(yVal);
|
return (series ? translate(series[i]) : '') + ' ' + formats.f2(yVal);
|
||||||
}).append('tspan').attr('class', 'metric').text(yUnit ? ' ' + yUnit : '');
|
}).append('tspan').attr('class', 'metric').text(yUnit ? ' ' + yUnit : '');
|
||||||
|
|
||||||
tips.selectAll('text').each(function() {
|
tips.selectAll('text').each(function() {
|
||||||
if (this.getBBox().width > tipWidth) {
|
if (this.getBBox().width > tipWidth) {
|
||||||
tipWidth = Math.ceil(this.getBBox().width);
|
tipWidth = Math.ceil(this.getBBox().width);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let tipY = Math.floor(yScale(yTotal / (series ? series.length : 1)) - (tipHeightPx / 2));
|
let tipY = Math.floor(yScale(yTotal / (series ? series.length : 1)) - (tipHeightPx / 2));
|
||||||
|
|
||||||
tipWidth += 8;
|
tipWidth += 8;
|
||||||
tips.attr('transform', 'translate(' + xPos + ',' + tipY + ')');
|
tips.attr('transform', 'translate(' + xPos + ',' + tipY + ')');
|
||||||
tips.selectAll('text.text-tip').attr('x', flip ? -12 : 12).style('text-anchor', flip ? 'end' : 'start');
|
tips.selectAll('text.text-tip').attr('x', flip ? -12 : 12).style('text-anchor', flip ? 'end' : 'start');
|
||||||
tips.selectAll('text.text-tip.x').text(formats.f2(x0)).append('tspan').attr('class', 'metric').text(' ' + xUnit);
|
tips.selectAll('text.text-tip.x').text(formats.f2(x0)).append('tspan').attr('class', 'metric').text(' ' + xUnit);
|
||||||
tips.selectAll('rect').attr('width', tipWidth + 4).attr('x', flip ? -tipWidth - 12 : 8).attr('y', 0).style('text-anchor', flip ? 'end' : 'start');
|
tips.selectAll('rect').attr('width', tipWidth + 4).attr('x', flip ? -tipWidth - 12 : 8).attr('y', 0).style('text-anchor', flip ? 'end' : 'start');
|
||||||
this.markersContainer.selectAll('circle').attr('cx', xPos).attr('cy', (d, i) => yScale(series ? y0[series[i]] : y0));
|
this.markersContainer.selectAll('circle').attr('cx', xPos).attr('cy', (d, i) => yScale(series ? y0[series[i]] : y0));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update dimensions based on properties and scale
|
* Update dimensions based on properties and scale
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
* @param {number} scale size ratio / scale
|
* @param {number} scale size ratio / scale
|
||||||
* @param {number} width current width of the container
|
* @param {number} width current width of the container
|
||||||
* @returns {Object} calculated dimensions
|
* @returns {Object} calculated dimensions
|
||||||
*/
|
*/
|
||||||
_updateDimensions(props, scale, width) {
|
_updateDimensions(props, scale, width) {
|
||||||
const { xMax, xMin, yMin, yMax } = props;
|
const { xMax, xMin, yMin, yMax } = props;
|
||||||
const innerWidth = width - MARGIN.left - MARGIN.right;
|
const innerWidth = width - MARGIN.left - MARGIN.right;
|
||||||
const outerHeight = Math.round(width * props.aspect);
|
const outerHeight = Math.round(width * props.aspect);
|
||||||
const innerHeight = outerHeight - MARGIN.top - MARGIN.bottom;
|
const innerHeight = outerHeight - MARGIN.top - MARGIN.bottom;
|
||||||
|
|
||||||
this.state.xScale.range([0, innerWidth]).domain([xMin, xMax || 1]).clamp(true);
|
this.state.xScale.range([0, innerWidth]).domain([xMin, xMax || 1]).clamp(true);
|
||||||
this.state.xAxisScale.range([0, innerWidth]).domain([xMin, xMax]).clamp(true);
|
this.state.xAxisScale.range([0, innerWidth]).domain([xMin, xMax]).clamp(true);
|
||||||
this.state.yScale.range([innerHeight, 0]).domain([yMin, yMax + (yMax - yMin) * 0.1]); // 10% higher than maximum value for tooltip visibility
|
this.state.yScale.range([innerHeight, 0]).domain([yMin, yMax + (yMax - yMin) * 0.1]); // 10% higher than maximum value for tooltip visibility
|
||||||
return { innerWidth, outerHeight, innerHeight };
|
return { innerWidth, outerHeight, innerHeight };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show tooltip
|
* Show tooltip
|
||||||
* @param {SyntheticEvent} e Event
|
* @param {SyntheticEvent} e Event
|
||||||
*/
|
*/
|
||||||
_showTip(e) {
|
_showTip(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.tipContainer.style('display', null);
|
this.tipContainer.style('display', null);
|
||||||
this.markersContainer.style('display', null);
|
this.markersContainer.style('display', null);
|
||||||
this._moveTip(e);
|
this._moveTip(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move and update tooltip
|
* Move and update tooltip
|
||||||
* @param {SyntheticEvent} e Event
|
* @param {SyntheticEvent} e Event
|
||||||
* @param {number} width current container width
|
* @param {number} width current container width
|
||||||
*/
|
*/
|
||||||
_moveTip(e, width) {
|
_moveTip(e, width) {
|
||||||
let clientX = e.touches ? e.touches[0].clientX : e.clientX;
|
let clientX = e.touches ? e.touches[0].clientX : e.clientX;
|
||||||
this._tooltip(Math.round(clientX - e.currentTarget.getBoundingClientRect().left), width);
|
this._tooltip(Math.round(clientX - e.currentTarget.getBoundingClientRect().left), width);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hide tooltip
|
* Hide tooltip
|
||||||
* @param {SyntheticEvent} e Event
|
* @param {SyntheticEvent} e Event
|
||||||
*/
|
*/
|
||||||
_hideTip(e) {
|
_hideTip(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.tipContainer.style('display', 'none');
|
this.tipContainer.style('display', 'none');
|
||||||
this.markersContainer.style('display', 'none');
|
this.markersContainer.style('display', 'none');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update series generated from props
|
* Update series generated from props
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
* @param {Object} state React Component state
|
* @param {Object} state React Component state
|
||||||
*/
|
*/
|
||||||
_updateSeries(props, state) {
|
_updateSeries(props, state) {
|
||||||
let { func, xMin, xMax, series, points } = props;
|
let { func, xMin, xMax, series, points } = props;
|
||||||
let delta = (xMax - xMin) / points;
|
let delta = (xMax - xMin) / points;
|
||||||
let seriesData = new Array(points);
|
let seriesData = new Array(points);
|
||||||
|
|
||||||
if (delta) {
|
if (delta) {
|
||||||
seriesData = new Array(points);
|
seriesData = new Array(points);
|
||||||
for (let i = 0, x = xMin; i < points; i++) {
|
for (let i = 0, x = xMin; i < points; i++) {
|
||||||
seriesData[i] = [x, func(x)];
|
seriesData[i] = [x, func(x)];
|
||||||
x += delta;
|
x += delta;
|
||||||
}
|
}
|
||||||
seriesData[points - 1] = [xMax, func(xMax)];
|
seriesData[points - 1] = [xMax, func(xMax)];
|
||||||
} else {
|
} else {
|
||||||
let yVal = func(xMin);
|
let yVal = func(xMin);
|
||||||
seriesData = [[0, yVal], [1, yVal]];
|
seriesData = [[0, yVal], [1, yVal]];
|
||||||
}
|
}
|
||||||
|
|
||||||
const markerElems = [];
|
const markerElems = [];
|
||||||
const detailElems = [<text key='lbl' className='text-tip x' y='1.25em'/>];
|
const detailElems = [<text key='lbl' className='text-tip x' y='1.25em'/>];
|
||||||
const seriesLines = [];
|
const seriesLines = [];
|
||||||
for (let i = 0, l = series ? series.length : 1; i < l; i++) {
|
for (let i = 0, l = series ? series.length : 1; i < l; i++) {
|
||||||
const yAccessor = series ? function(d) { return state.yScale(d[1][this]); }.bind(series[i]) : (d) => state.yScale(d[1]);
|
const yAccessor = series ? function(d) { return state.yScale(d[1][this]); }.bind(series[i]) : (d) => state.yScale(d[1]);
|
||||||
seriesLines.push(d3.line().x((d, i) => this.state.xScale(d[0])).y(yAccessor));
|
seriesLines.push(d3.line().x((d, i) => this.state.xScale(d[0])).y(yAccessor));
|
||||||
detailElems.push(<text key={i} className='text-tip y' strokeWidth={0} fill={props.colors[i]} y={1.25 * (i + 2) + 'em'}/>);
|
detailElems.push(<text key={i} className='text-tip y' strokeWidth={0} fill={props.colors[i]} y={1.25 * (i + 2) + 'em'}/>);
|
||||||
markerElems.push(<circle key={i} className='marker' r='4' />);
|
markerElems.push(<circle key={i} className='marker' r='4' />);
|
||||||
}
|
}
|
||||||
|
|
||||||
const tipHeight = 2 + (1.2 * (seriesLines ? seriesLines.length : 0.8));
|
const tipHeight = 2 + (1.2 * (seriesLines ? seriesLines.length : 0.8));
|
||||||
|
|
||||||
this.setState({ markerElems, detailElems, seriesLines, seriesData, tipHeight });
|
this.setState({ markerElems, detailElems, seriesLines, seriesData, tipHeight });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update dimensions and series data based on props and context.
|
* Update dimensions and series data based on props and context.
|
||||||
*/
|
*/
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
this._updateSeries(this.props, this.state);
|
this._updateSeries(this.props, this.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update state based on property and context changes
|
* Update state based on property and context changes
|
||||||
* @param {Object} nextProps Incoming/Next properties
|
* @param {Object} nextProps Incoming/Next properties
|
||||||
* @param {Object} nextContext Incoming/Next conext
|
* @param {Object} nextContext Incoming/Next conext
|
||||||
*/
|
*/
|
||||||
componentWillReceiveProps(nextProps, nextContext) {
|
componentWillReceiveProps(nextProps, nextContext) {
|
||||||
const props = this.props;
|
const props = this.props;
|
||||||
|
|
||||||
if (props.code != nextProps.code) {
|
if (props.code != nextProps.code) {
|
||||||
this._updateSeries(nextProps, this.state);
|
this._updateSeries(nextProps, this.state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the chart
|
* Render the chart
|
||||||
* @return {React.Component} Chart SVG
|
* @return {React.Component} Chart SVG
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<ContainerDimensions>
|
<ContainerDimensions>
|
||||||
{ ({ width, height }) => {
|
{ ({ width, height }) => {
|
||||||
const { innerWidth, outerHeight, innerHeight } = this._updateDimensions(this.props, this.context.sizeRatio, width, height);
|
const { innerWidth, outerHeight, innerHeight } = this._updateDimensions(this.props, this.context.sizeRatio, width, height);
|
||||||
const { xMin, xMax, xLabel, yLabel, xUnit, yUnit, xMark, colors } = this.props;
|
const { xMin, xMax, xLabel, yLabel, xUnit, yUnit, xMark, colors } = this.props;
|
||||||
const { tipHeight, detailElems, markerElems, seriesData, seriesLines } = this.state;
|
const { tipHeight, detailElems, markerElems, seriesData, seriesLines } = this.state;
|
||||||
const lines = seriesLines.map((line, i) => <path key={i} className='line' fill='none' stroke={colors[i]} strokeWidth='1' d={line(seriesData)} />).reverse();
|
const lines = seriesLines.map((line, i) => <path key={i} className='line' fill='none' stroke={colors[i]} strokeWidth='1' d={line(seriesData)} />).reverse();
|
||||||
|
|
||||||
const markX = xMark ? innerWidth * (xMark - xMin) / (xMax - xMin) : 0;
|
const markX = xMark ? innerWidth * (xMark - xMin) / (xMax - xMin) : 0;
|
||||||
const xmark = xMark ? <path key={'mark'} className='line' fill='none' strokeDasharray='5,5' stroke={'#ff8c0d'} strokeWidth='1' d={'M ' + markX + ' ' + innerHeight + ' L ' + markX + ' 0'} /> : '';
|
const xmark = xMark ? <path key={'mark'} className='line' fill='none' strokeDasharray='5,5' stroke={'#ff8c0d'} strokeWidth='1' d={'M ' + markX + ' ' + innerHeight + ' L ' + markX + ' 0'} /> : '';
|
||||||
return (
|
return (
|
||||||
<div width={width} height={height}>
|
<div width={width} height={height}>
|
||||||
<svg style={{ width: '100%', height: outerHeight }}>
|
<svg style={{ width: '100%', height: outerHeight }}>
|
||||||
<g transform={`translate(${MARGIN.left},${MARGIN.top})`}>
|
<g transform={`translate(${MARGIN.left},${MARGIN.top})`}>
|
||||||
<g>{xmark}</g>
|
<g>{xmark}</g>
|
||||||
<g>{lines}</g>
|
<g>{lines}</g>
|
||||||
<g className='x axis' ref={(elem) => d3.select(elem).call(this.xAxis)} transform={`translate(0,${innerHeight})`}>
|
<g className='x axis' ref={(elem) => d3.select(elem).call(this.xAxis)} transform={`translate(0,${innerHeight})`}>
|
||||||
<text className='cap' y='30' dy='.1em' x={innerWidth / 2} style={{ textAnchor: 'middle' }}>
|
<text className='cap' y='30' dy='.1em' x={innerWidth / 2} style={{ textAnchor: 'middle' }}>
|
||||||
<tspan>{xLabel}</tspan>
|
<tspan>{xLabel}</tspan>
|
||||||
<tspan className='metric'> ({xUnit})</tspan>
|
<tspan className='metric'> ({xUnit})</tspan>
|
||||||
</text>
|
</text>
|
||||||
</g>
|
</g>
|
||||||
<g className='y axis' ref={(elem) => d3.select(elem).call(this.yAxis)}>
|
<g className='y axis' ref={(elem) => d3.select(elem).call(this.yAxis)}>
|
||||||
<text className='cap' transform='rotate(-90)' y='-50' dy='.1em' x={innerHeight / -2} style={{ textAnchor: 'middle' }}>
|
<text className='cap' transform='rotate(-90)' y='-50' dy='.1em' x={innerHeight / -2} style={{ textAnchor: 'middle' }}>
|
||||||
<tspan>{yLabel}</tspan>
|
<tspan>{yLabel}</tspan>
|
||||||
{ yUnit && <tspan className='metric'> ({yUnit})</tspan> }
|
{ yUnit && <tspan className='metric'> ({yUnit})</tspan> }
|
||||||
</text>
|
</text>
|
||||||
</g>
|
</g>
|
||||||
<g ref={(g) => this.tipContainer = d3.select(g)} style={{ display: 'none' }}>
|
<g ref={(g) => this.tipContainer = d3.select(g)} style={{ display: 'none' }}>
|
||||||
<rect className='tooltip' height={tipHeight + 'em'}></rect>
|
<rect className='tooltip' height={tipHeight + 'em'}></rect>
|
||||||
{detailElems}
|
{detailElems}
|
||||||
</g>
|
</g>
|
||||||
<g ref={(g) => this.markersContainer = d3.select(g)} style={{ display: 'none' }}>
|
<g ref={(g) => this.markersContainer = d3.select(g)} style={{ display: 'none' }}>
|
||||||
{markerElems}
|
{markerElems}
|
||||||
</g>
|
</g>
|
||||||
<rect
|
<rect
|
||||||
fillOpacity='0'
|
fillOpacity='0'
|
||||||
height={innerHeight}
|
height={innerHeight}
|
||||||
width={innerWidth + 1}
|
width={innerWidth + 1}
|
||||||
onMouseEnter={this._showTip}
|
onMouseEnter={this._showTip}
|
||||||
onTouchStart={this._showTip}
|
onTouchStart={this._showTip}
|
||||||
onMouseLeave={this._hideTip}
|
onMouseLeave={this._hideTip}
|
||||||
onTouchEnd={this._hideTip}
|
onTouchEnd={this._hideTip}
|
||||||
onMouseMove={e => this._moveTip(e, width)}
|
onMouseMove={e => this._moveTip(e, width)}
|
||||||
onTouchMove={e => this._moveTip(e, width)}
|
onTouchMove={e => this._moveTip(e, width)}
|
||||||
/>
|
/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</ContainerDimensions>
|
</ContainerDimensions>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,18 @@ export default class ModalPermalink extends TranslatedComponent {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy the shortened URL to the clipboard
|
||||||
|
* @param {Event} e Click event
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
copyShortLink() {
|
||||||
|
let copyText = document.getElementById("shortenedUrl");
|
||||||
|
// Copy the text inside the shortendUrl input to the clipboard
|
||||||
|
copyText.select();
|
||||||
|
document.execCommand("copy");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the modal
|
* Render the modal
|
||||||
* @return {React.Component} Modal Content
|
* @return {React.Component} Modal Content
|
||||||
@@ -42,15 +54,17 @@ export default class ModalPermalink extends TranslatedComponent {
|
|||||||
let translate = this.context.language.translate;
|
let translate = this.context.language.translate;
|
||||||
|
|
||||||
return <div className='modal' onClick={ (e) => e.stopPropagation() }>
|
return <div className='modal' onClick={ (e) => e.stopPropagation() }>
|
||||||
<h2>{translate('permalink')}</h2>
|
<h3>{translate('permalink')}</h3>
|
||||||
<br/>
|
<br/>
|
||||||
<h3>{translate('URL')}</h3>
|
<h3>{translate('URL')}</h3>
|
||||||
<input value={this.props.url} size={40} readOnly onFocus={ (e) => e.target.select() }/>
|
<input value={this.props.url} size={40} readOnly onFocus={ (e) => e.target.select() }/>
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
<h3 >{translate('shortened')}</h3>
|
<h3 >{translate('shortened')}</h3>
|
||||||
<input value={this.state.shortenedUrl} readOnly size={25} onFocus={ (e) => e.target.select() }/>
|
<input id={'shortenedUrl'} value={this.state.shortenedUrl} readOnly size={25} onFocus={ (e) => e.target.select() }/><button className={'cb dismiss cap'} onClick={this.copyShortLink}>{translate('copy to clipboard')}</button>
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
<p>s.orbis.zone is the new URL shortener domain, old eddp.co urls are considered end of life and could go down at any moment. Sorry for any inconvenience.</p>
|
<hr />
|
||||||
|
<p>s.orbis.zone is the URL shortener domain. These links should persist indefinitely going forward. If for some reason there is a problem with the link shortening process, please report it in the EDCD Discord Server.</p>
|
||||||
|
<hr />
|
||||||
<button className={'r dismiss cap'} onClick={this.context.hideModal}>{translate('close')}</button>
|
<button className={'r dismiss cap'} onClick={this.context.hideModal}>{translate('close')}</button>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ const base64url = require('base64url');
|
|||||||
export default class ModalShoppingList extends TranslatedComponent {
|
export default class ModalShoppingList extends TranslatedComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
ship: PropTypes.object.isRequired
|
ship: PropTypes.object.isRequired,
|
||||||
|
buildName: PropTypes.string
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -90,8 +91,10 @@ export default class ModalShoppingList extends TranslatedComponent {
|
|||||||
request
|
request
|
||||||
.get('http://localhost:44405/commanders')
|
.get('http://localhost:44405/commanders')
|
||||||
.end((err, res) => {
|
.end((err, res) => {
|
||||||
|
this.display = 'block';
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
|
this.display = 'none';
|
||||||
return this.setState({ failed: true });
|
return this.setState({ failed: true });
|
||||||
}
|
}
|
||||||
const cmdrs = JSON.parse(res.text);
|
const cmdrs = JSON.parse(res.text);
|
||||||
@@ -147,6 +150,34 @@ export default class ModalShoppingList extends TranslatedComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fix issues with the item name for bulkheads when sending to EDOMH
|
||||||
|
* @param {*} ship Ship object
|
||||||
|
* @param {*} item Item name
|
||||||
|
* @returns updated item name
|
||||||
|
*/
|
||||||
|
fixArmourItemNameForEDOMH(ship, item) {
|
||||||
|
// The module blueprint fdname contains "Armour_" it's a bulkhead and we need to pre-populate the item field with the correct name from the ship object
|
||||||
|
switch (ship.bulkheads.m.name){
|
||||||
|
case "Lightweight Alloy":
|
||||||
|
item = ship.id + "_Armour_Grade1";
|
||||||
|
break;
|
||||||
|
case "Reinforced Alloy":
|
||||||
|
item = ship.id + "_Armour_Grade2";
|
||||||
|
break;
|
||||||
|
case "Military Grade Composite":
|
||||||
|
item = ship.id + "_Armour_Grade3";
|
||||||
|
break;
|
||||||
|
case "Mirrored Surface Composite":
|
||||||
|
item = ship.id + "_Armour_Mirrored";
|
||||||
|
break;
|
||||||
|
case "Reactive Surface Composite":
|
||||||
|
item = ship.id + "_Armour_Reactive";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send all blueprints to EDOMH. This is a modified copy of registerBPs because this.state.blueprints was empty when I tried to modify sendToEDEng and I couldn't figure out why
|
* Send all blueprints to EDOMH. This is a modified copy of registerBPs because this.state.blueprints was empty when I tried to modify sendToEDEng and I couldn't figure out why
|
||||||
* @param {Event} event React event
|
* @param {Event} event React event
|
||||||
@@ -154,6 +185,7 @@ export default class ModalShoppingList extends TranslatedComponent {
|
|||||||
sendToEDOMH(event) {
|
sendToEDOMH(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const ship = this.props.ship;
|
const ship = this.props.ship;
|
||||||
|
const buildName = this.props.buildName;
|
||||||
let blueprints = [];
|
let blueprints = [];
|
||||||
|
|
||||||
//create the json
|
//create the json
|
||||||
@@ -166,20 +198,38 @@ export default class ModalShoppingList extends TranslatedComponent {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (module.m.blueprint.special) {
|
if (module.m.blueprint.special) {
|
||||||
|
let item = "";
|
||||||
|
// If the module blueprint fdname contains "Armour_" it's a bulkhead and we need to pre-populate the item field with the correct name from the ship object
|
||||||
|
if (module.m.blueprint.fdname.includes("Armour_")) {
|
||||||
|
item = this.fixArmourItemNameForEDOMH(ship, item)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item = module.m.symbol;
|
||||||
|
}
|
||||||
|
|
||||||
blueprints.push({
|
blueprints.push({
|
||||||
"item": module.m.symbol,
|
"item": item,
|
||||||
"blueprint": module.m.blueprint.special.edname
|
"blueprint": module.m.blueprint.special.edname
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
for (const g in module.m.blueprint.grades) {
|
for (let g in module.m.blueprint.grades) {
|
||||||
if (!module.m.blueprint.grades.hasOwnProperty(g)) {
|
if (!module.m.blueprint.grades.hasOwnProperty(g)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (g < module.m.blueprint.grade) {
|
// We only want the grade that the module is currently at, not every grade up to that point
|
||||||
|
if (Number(g) !== module.m.blueprint.grade) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
let item = "";
|
||||||
|
// If the module blueprint fdname contains "Armour_" it's a bulkhead and we need to pre-populate the item field with the correct name from the ship object
|
||||||
|
if (module.m.blueprint.fdname.includes("Armour_")) {
|
||||||
|
item = this.fixArmourItemNameForEDOMH(ship, item)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item = module.m.symbol;
|
||||||
|
}
|
||||||
blueprints.push({
|
blueprints.push({
|
||||||
"item": module.m.symbol,
|
"item": item,
|
||||||
"blueprint": module.m.blueprint.fdname,
|
"blueprint": module.m.blueprint.fdname,
|
||||||
"grade": module.m.blueprint.grade,
|
"grade": module.m.blueprint.grade,
|
||||||
"highestGradePercentage":1.0
|
"highestGradePercentage":1.0
|
||||||
@@ -188,16 +238,18 @@ export default class ModalShoppingList extends TranslatedComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let shipName = buildName + " - " + ship.name;
|
||||||
|
|
||||||
//create JSON to encode
|
//create JSON to encode
|
||||||
let baseJson = {
|
let baseJson = {
|
||||||
"version":1,
|
"version":1,
|
||||||
"name":ship.name, // TO-DO: Import build name and put that here correctly
|
"name": shipName, // TO-DO: Import build name and put that here correctly
|
||||||
"items": blueprints
|
"items": blueprints
|
||||||
}
|
}
|
||||||
|
|
||||||
let JSONString = JSON.stringify(baseJson)
|
let JSONString = JSON.stringify(baseJson)
|
||||||
let deflated = zlib.deflateSync(JSONString)
|
let deflated = zlib.deflateSync(JSONString)
|
||||||
|
|
||||||
//actually encode
|
//actually encode
|
||||||
let link = base64url.encode(deflated)
|
let link = base64url.encode(deflated)
|
||||||
link = "edomh://coriolis/?" + link;
|
link = "edomh://coriolis/?" + link;
|
||||||
@@ -219,14 +271,15 @@ export default class ModalShoppingList extends TranslatedComponent {
|
|||||||
if (!module.m.blueprint.grade || !module.m.blueprint.grades) {
|
if (!module.m.blueprint.grade || !module.m.blueprint.grades) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (const g in module.m.blueprint.grades) {
|
for (let g in module.m.blueprint.grades) {
|
||||||
if (!module.m.blueprint.grades.hasOwnProperty(g)) {
|
if (!module.m.blueprint.grades.hasOwnProperty(g)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (g > module.m.blueprint.grade) {
|
// Ignore grades higher than the grade selected
|
||||||
|
if (Number(g) > module.m.blueprint.grade) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (const i in module.m.blueprint.grades[g].components) {
|
for (let i in module.m.blueprint.grades[g].components) {
|
||||||
if (!module.m.blueprint.grades[g].components.hasOwnProperty(i)) {
|
if (!module.m.blueprint.grades[g].components.hasOwnProperty(i)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -236,16 +289,16 @@ export default class ModalShoppingList extends TranslatedComponent {
|
|||||||
mats[i] = module.m.blueprint.grades[g].components[i] * this.state.matsPerGrade[g];
|
mats[i] = module.m.blueprint.grades[g].components[i] * this.state.matsPerGrade[g];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (module.m.blueprint.special) {
|
}
|
||||||
for (const j in module.m.blueprint.special.components) {
|
if (module.m.blueprint.special) {
|
||||||
if (!module.m.blueprint.special.components.hasOwnProperty(j)) {
|
for (const j in module.m.blueprint.special.components) {
|
||||||
continue;
|
if (!module.m.blueprint.special.components.hasOwnProperty(j)) {
|
||||||
}
|
continue;
|
||||||
if (mats[j]) {
|
}
|
||||||
mats[j] += module.m.blueprint.special.components[j];
|
if (mats[j]) {
|
||||||
} else {
|
mats[j] += module.m.blueprint.special.components[j];
|
||||||
mats[j] = module.m.blueprint.special.components[j];
|
} else {
|
||||||
}
|
mats[j] = module.m.blueprint.special.components[j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -302,34 +355,46 @@ export default class ModalShoppingList extends TranslatedComponent {
|
|||||||
this.sendToEDEng = this.sendToEDEng.bind(this);
|
this.sendToEDEng = this.sendToEDEng.bind(this);
|
||||||
this.sendToEDOMH = this.sendToEDOMH.bind(this);
|
this.sendToEDOMH = this.sendToEDOMH.bind(this);
|
||||||
return <div className='modal' onClick={ (e) => e.stopPropagation() }>
|
return <div className='modal' onClick={ (e) => e.stopPropagation() }>
|
||||||
<h2>{translate('PHRASE_SHOPPING_MATS')}</h2>
|
<h3>{translate('PHRASE_SHOPPING_MATS')}</h3>
|
||||||
<label>{translate('Grade 1 rolls ')}</label>
|
|
||||||
<input id={1} type={'number'} min={0} defaultValue={this.state.matsPerGrade[1]} onChange={this.changeHandler} />
|
|
||||||
<br/>
|
|
||||||
<label>{translate('Grade 2 rolls ')}</label>
|
|
||||||
<input id={2} type={'number'} min={0} defaultValue={this.state.matsPerGrade[2]} onChange={this.changeHandler} />
|
|
||||||
<br/>
|
|
||||||
<label>{translate('Grade 3 rolls ')}</label>
|
|
||||||
<input id={3} type={'number'} min={0} value={this.state.matsPerGrade[3]} onChange={this.changeHandler} />
|
|
||||||
<br/>
|
|
||||||
<label>{translate('Grade 4 rolls ')}</label>
|
|
||||||
<input id={4} type={'number'} min={0} value={this.state.matsPerGrade[4]} onChange={this.changeHandler} />
|
|
||||||
<br/>
|
|
||||||
<label>{translate('Grade 5 rolls ')}</label>
|
|
||||||
<input id={5} type={'number'} min={0} value={this.state.matsPerGrade[5]} onChange={this.changeHandler} />
|
|
||||||
<div>
|
<div>
|
||||||
<textarea className='cb json' readOnly value={this.state.matsList} />
|
<p>{translate('PHRASE_DIFFERENT_ROLLS')}</p>
|
||||||
|
<label>{translate('G1')}</label>
|
||||||
|
<input className={'groll'} id={1} type={'number'} min={0} defaultValue={this.state.matsPerGrade[1]} onChange={this.changeHandler} />
|
||||||
|
| <label>{translate('G2')}</label>
|
||||||
|
<input className={'groll'} id={2} type={'number'} min={0} defaultValue={this.state.matsPerGrade[2]} onChange={this.changeHandler} />
|
||||||
|
| <label>{translate('G3')}</label>
|
||||||
|
<input className={'groll'} id={3} type={'number'} min={0} value={this.state.matsPerGrade[3]} onChange={this.changeHandler} />
|
||||||
|
| <label>{translate('G4')}</label>
|
||||||
|
<input className={'groll'} id={4} type={'number'} min={0} value={this.state.matsPerGrade[4]} onChange={this.changeHandler} />
|
||||||
|
| <label>{translate('G5')}</label>
|
||||||
|
<input className={'groll'} id={5} type={'number'} min={0} value={this.state.matsPerGrade[5]} onChange={this.changeHandler} />
|
||||||
</div>
|
</div>
|
||||||
<label hidden={!compatible} className={'l cap'}>{translate('CMDR Name')}</label>
|
|
||||||
<br/>
|
<div>
|
||||||
<select hidden={!compatible} className={'cmdr-select l cap'} onChange={this.cmdrChangeHandler} defaultValue={this.state.cmdrName}>
|
<p>{translate('PHRASE_ALL_MODULES_ALL_ROLLS')}</p>
|
||||||
{this.state.cmdrs.map(e => <option key={e}>{e}</option>)}
|
<textarea className='cb json' readOnly value={this.state.matsList} />
|
||||||
</select>
|
<p>{translate('PHRASE_FOR_FINER_CONTROL')}</p>
|
||||||
<br/>
|
</div>
|
||||||
<p hidden={!this.state.failed} id={'failed'} className={'l'}>{translate('PHRASE_FAIL_EDENGINEER')}</p>
|
|
||||||
<p hidden={compatible} id={'browserbad'} className={'l'}>{translate('PHRASE_FIREFOX_EDENGINEER')}</p>
|
<div id='edengineer' display={this.display} hidden={!!this.state.failed && !compatible}>
|
||||||
<button className={'l cb dismiss cap'} disabled={!!this.state.failed || !compatible} onClick={this.sendToEDEng}>{translate('Send to EDEngineer')}</button>
|
<hr />
|
||||||
<button style={{marginTop: 5}} className={'l cb dismiss cap'} disabled={!!this.state.failed} onClick={this.sendToEDOMH}>{translate('Send to EDOMH')}</button>
|
<h3>ED Engineer</h3>
|
||||||
|
<h4 hidden={compatible} id={'browserbad'} className={'l'}>{translate('PHRASE_FIREFOX_EDENGINEER')}</h4>
|
||||||
|
<h4 hidden={!this.state.failed} id={'failed'} className={'l'}>{translate('PHRASE_FAILED_TO_FIND_EDENGINEER')}</h4>
|
||||||
|
<label for='cmdr-select' hidden={!!this.state.failed || !compatible} className={'l cap'}>{translate('CMDR Name:')}</label>
|
||||||
|
<select id='cmdr-select' hidden={!!this.state.failed || !compatible} className={'cmdr-select l cap'} onChange={this.cmdrChangeHandler} defaultValue={this.state.cmdrName}>
|
||||||
|
{this.state.cmdrs.map(e => <option key={e}>{e}</option>)}
|
||||||
|
</select>
|
||||||
|
<br/>
|
||||||
|
<button className={'l cb dismiss cap'} disabled={!!this.state.failed || !compatible} onClick={this.sendToEDEng}>{translate('Send to EDEngineer')}</button>
|
||||||
|
</div>
|
||||||
|
<div id='edomh'>
|
||||||
|
<hr />
|
||||||
|
<h3>ED Odyssey Materials Helper</h3>
|
||||||
|
<p>{translate('PHRASE_ENSURE_EDOMH')}</p>
|
||||||
|
<button className={'l cb dismiss cap'} onClick={this.sendToEDOMH}>{translate('Send to EDOMH')}</button>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
<button className={'r dismiss cap'} onClick={this.context.hideModal}>{translate('close')}</button>
|
<button className={'r dismiss cap'} onClick={this.context.hideModal}>{translate('close')}</button>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ export default class ModificationsMenu extends TranslatedComponent {
|
|||||||
this.modValDidChange = false; // used to determine if component update was caused by change in modification value.
|
this.modValDidChange = false; // used to determine if component update was caused by change in modification value.
|
||||||
this._handleModChange = this._handleModChange.bind(this);
|
this._handleModChange = this._handleModChange.bind(this);
|
||||||
|
|
||||||
|
// console.log(props.m.blueprint)
|
||||||
this.state = {
|
this.state = {
|
||||||
blueprintMenuOpened: !(props.m.blueprint && props.m.blueprint.name),
|
blueprintMenuOpened: !(props.m.blueprint && props.m.blueprint.name),
|
||||||
specialMenuOpened: false
|
specialMenuOpened: false
|
||||||
@@ -421,15 +422,31 @@ export default class ModificationsMenu extends TranslatedComponent {
|
|||||||
let haveBlueprint = false;
|
let haveBlueprint = false;
|
||||||
let blueprintTt;
|
let blueprintTt;
|
||||||
let blueprintCv;
|
let blueprintCv;
|
||||||
|
let bprintSearchName;
|
||||||
|
|
||||||
|
// If the fdname is Weapon_Overcharged, we need to check if it's an MC
|
||||||
|
if (m.blueprint && m.blueprint.fdname) {
|
||||||
|
// Set the bprintSearchName value to the fdname of the blueprint for this module
|
||||||
|
bprintSearchName = m.blueprint.fdname;
|
||||||
|
if (m.blueprint.fdname === 'Weapon_Overcharged') {
|
||||||
|
// If the module is a MultiCannon, we need to fix the blueprint search name, else it will find the Laser Weapon_Overcharged Blueprint and not the MC Weapon_Overcharged Blueprint
|
||||||
|
if (m.symbol.match(/MultiCannon/i)) {
|
||||||
|
// console.log(Modifications.modules[m.grp].blueprints['MC_Overcharged']);
|
||||||
|
// console.log(m.blueprint.fdname);
|
||||||
|
bprintSearchName = 'MC_Overcharged';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// TODO: Fix this to actually find the correct blueprint.
|
// TODO: Fix this to actually find the correct blueprint.
|
||||||
if (!m.blueprint || !m.blueprint.name || !m.blueprint.fdname || !Modifications.modules[m.grp].blueprints || !Modifications.modules[m.grp].blueprints[m.blueprint.fdname]) {
|
if (!m.blueprint || !m.blueprint.name || !m.blueprint.fdname || !Modifications.modules[m.grp].blueprints || !Modifications.modules[m.grp].blueprints[bprintSearchName]) {
|
||||||
this.props.ship.clearModuleBlueprint(m);
|
this.props.ship.clearModuleBlueprint(m);
|
||||||
this.props.ship.clearModuleSpecial(m);
|
this.props.ship.clearModuleSpecial(m);
|
||||||
}
|
}
|
||||||
if (m.blueprint && m.blueprint.name && Modifications.modules[m.grp].blueprints[m.blueprint.fdname].grades[m.blueprint.grade]) {
|
if (m.blueprint && m.blueprint.name && Modifications.modules[m.grp].blueprints[bprintSearchName].grades[m.blueprint.grade]) {
|
||||||
blueprintLabel = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade;
|
blueprintLabel = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade;
|
||||||
haveBlueprint = true;
|
haveBlueprint = true;
|
||||||
blueprintTt = blueprintTooltip(translate, m.blueprint.grades[m.blueprint.grade], Modifications.modules[m.grp].blueprints[m.blueprint.fdname].grades[m.blueprint.grade].engineers, m.grp);
|
// console.log(haveBlueprint);
|
||||||
|
blueprintTt = blueprintTooltip(translate, m.blueprint.grades[m.blueprint.grade], Modifications.modules[m.grp].blueprints[bprintSearchName].grades[m.blueprint.grade].engineers, m.grp);
|
||||||
blueprintCv = getPercent(m);
|
blueprintCv = getPercent(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,92 +1,92 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import ContainerDimensions from 'react-container-dimensions';
|
import ContainerDimensions from 'react-container-dimensions';
|
||||||
import * as d3 from 'd3';
|
import * as d3 from 'd3';
|
||||||
|
|
||||||
const CORIOLIS_COLOURS = ['#FF8C0D', '#1FB0FF', '#71A052', '#D5D54D'];
|
const CORIOLIS_COLOURS = ['#FF8C0D', '#1FB0FF', '#71A052', '#D5D54D'];
|
||||||
const LABEL_COLOUR = '#000000';
|
const LABEL_COLOUR = '#000000';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A pie chart
|
* A pie chart
|
||||||
*/
|
*/
|
||||||
export default class PieChart extends Component {
|
export default class PieChart extends Component {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
data : PropTypes.array.isRequired
|
data : PropTypes.array.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
* @param {Object} context React Component context
|
* @param {Object} context React Component context
|
||||||
*/
|
*/
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.pie = d3.pie().value((d) => d.value);
|
this.pie = d3.pie().value((d) => d.value);
|
||||||
this.colors = CORIOLIS_COLOURS;
|
this.colors = CORIOLIS_COLOURS;
|
||||||
this.arc = d3.arc();
|
this.arc = d3.arc();
|
||||||
this.arc.innerRadius(0);
|
this.arc.innerRadius(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a slice of the pie chart
|
* Generate a slice of the pie chart
|
||||||
* @param {Object} d the data for this slice
|
* @param {Object} d the data for this slice
|
||||||
* @param {number} i the index of this slice
|
* @param {number} i the index of this slice
|
||||||
* @param {number} width the current width of the parent container
|
* @param {number} width the current width of the parent container
|
||||||
* @returns {Object} the SVG for the slice
|
* @returns {Object} the SVG for the slice
|
||||||
*/
|
*/
|
||||||
sliceGenerator(d, i, width) {
|
sliceGenerator(d, i, width) {
|
||||||
if (!d || d.value == 0) {
|
if (!d || d.value == 0) {
|
||||||
// Ignore 0 values
|
// Ignore 0 values
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data } = this.props;
|
const { data } = this.props;
|
||||||
|
|
||||||
// Push the labels further out from the centre of the slice
|
// Push the labels further out from the centre of the slice
|
||||||
let [labelX, labelY] = this.arc.centroid(d);
|
let [labelX, labelY] = this.arc.centroid(d);
|
||||||
const labelTranslate = `translate(${labelX * 1.5}, ${labelY * 1.5})`;
|
const labelTranslate = `translate(${labelX * 1.5}, ${labelY * 1.5})`;
|
||||||
|
|
||||||
// Put the keys in a line with equal spacing
|
// Put the keys in a line with equal spacing
|
||||||
const nonZeroItems = data.filter(d => d.value != 0).length;
|
const nonZeroItems = data.filter(d => d.value != 0).length;
|
||||||
const thisItemIndex = data.slice(0, i + 1).filter(d => d.value != 0).length - 1;
|
const thisItemIndex = data.slice(0, i + 1).filter(d => d.value != 0).length - 1;
|
||||||
const keyX = -width / 2 + (width / nonZeroItems) * (thisItemIndex + 0.5);
|
const keyX = -width / 2 + (width / nonZeroItems) * (thisItemIndex + 0.5);
|
||||||
const keyTranslate = `translate(${keyX}, ${width * 0.45})`;
|
const keyTranslate = `translate(${keyX}, ${width * 0.45})`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g key={`group-${i}`}>
|
<g key={`group-${i}`}>
|
||||||
<path key={`arc-${i}`} d={this.arc(d)} style={{ fill: this.colors[i] }} />
|
<path key={`arc-${i}`} d={this.arc(d)} style={{ fill: this.colors[i] }} />
|
||||||
<text key={`label-${i}`} transform={labelTranslate} style={{ strokeWidth: '0px', fill: LABEL_COLOUR }} textAnchor='middle'>{d.value}</text>
|
<text key={`label-${i}`} transform={labelTranslate} style={{ strokeWidth: '0px', fill: LABEL_COLOUR }} textAnchor='middle'>{d.value}</text>
|
||||||
<text key={`key-${i}`} transform={keyTranslate} style={{ strokeWidth:'0px', fill: this.colors[i] }} textAnchor='middle'>{d.data.label}</text>
|
<text key={`key-${i}`} transform={keyTranslate} style={{ strokeWidth:'0px', fill: this.colors[i] }} textAnchor='middle'>{d.data.label}</text>
|
||||||
</g>
|
</g>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the component
|
* Render the component
|
||||||
* @returns {object} Markup
|
* @returns {object} Markup
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<ContainerDimensions>
|
<ContainerDimensions>
|
||||||
{ ({ width }) => {
|
{ ({ width }) => {
|
||||||
const pie = this.pie(this.props.data),
|
const pie = this.pie(this.props.data),
|
||||||
translate = `translate(${width / 2}, ${width * 0.4})`;
|
translate = `translate(${width / 2}, ${width * 0.4})`;
|
||||||
|
|
||||||
this.arc.outerRadius(width * 0.4);
|
this.arc.outerRadius(width * 0.4);
|
||||||
return (
|
return (
|
||||||
<div width={width} height={width}>
|
<div width={width} height={width}>
|
||||||
<svg style={{ stroke: 'None' }} width={width} height={width * 0.9}>
|
<svg style={{ stroke: 'None' }} width={width} height={width * 0.9}>
|
||||||
<g transform={translate}>
|
<g transform={translate}>
|
||||||
{pie.map((d, i) => this.sliceGenerator(d, i, width))}
|
{pie.map((d, i) => this.sliceGenerator(d, i, width))}
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</ContainerDimensions>
|
</ContainerDimensions>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,15 +125,32 @@ export default class PowerManagement extends TranslatedComponent {
|
|||||||
retractedElem = <td className='ptr disabled upp' colSpan='2' onClick={toggleEnabled}>{translate('disabled')}</td>;
|
retractedElem = <td className='ptr disabled upp' colSpan='2' onClick={toggleEnabled}>{translate('disabled')}</td>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this is a Guardian Shield Reinforcement Package or Guardian Hull Reinforcement Package, or Guardian Module Reinforcement Package, it cannot change priority
|
||||||
|
console.log(slot);
|
||||||
|
let priorityField;
|
||||||
|
if (m.symbol) {
|
||||||
|
if (m.symbol.match(/GuardianShield/i) || m.symbol.match(/GuardianHull/i) || m.symbol.match(/GuardianModule/i)) {
|
||||||
|
priorityField = <td>1</td>;
|
||||||
|
} else {
|
||||||
|
priorityField = <td>
|
||||||
|
<span className='flip ptr btn' onClick={this._priority.bind(this, slot, -1)}>►</span>
|
||||||
|
{' ' + (slot.priority + 1) + ' '}
|
||||||
|
<span className='ptr btn' onClick={this._priority.bind(this, slot, 1)}>►</span>
|
||||||
|
</td>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
priorityField = <td>
|
||||||
|
<span className='flip ptr btn' onClick={this._priority.bind(this, slot, -1)}>►</span>
|
||||||
|
{' ' + (slot.priority + 1) + ' '}
|
||||||
|
<span className='ptr btn' onClick={this._priority.bind(this, slot, 1)}>►</span>
|
||||||
|
</td>;
|
||||||
|
}
|
||||||
powerRows.push(<tr key={i} className={cn('highlight', { disabled: !slot.enabled })}>
|
powerRows.push(<tr key={i} className={cn('highlight', { disabled: !slot.enabled })}>
|
||||||
<td className='ptr' style={{ width: '1em' }} onClick={toggleEnabled}>{m.class + m.rating}</td>
|
<td className='ptr' style={{ width: '1em' }} onClick={toggleEnabled}>{m.class + m.rating}</td>
|
||||||
<td className='ptr le shorten cap' onClick={toggleEnabled}>{slotName(translate, slot)}</td>
|
<td className='ptr le shorten cap' onClick={toggleEnabled}>{slotName(translate, slot)}</td>
|
||||||
<td className='ptr' onClick={toggleEnabled}><u>{translate(slot.type)}</u></td>
|
<td className='ptr' onClick={toggleEnabled}><u>{translate(slot.type)}</u></td>
|
||||||
<td>
|
{priorityField}
|
||||||
<span className='flip ptr btn' onClick={this._priority.bind(this, slot, -1)}>►</span>
|
|
||||||
{' ' + (slot.priority + 1) + ' '}
|
|
||||||
<span className='ptr btn' onClick={this._priority.bind(this, slot, 1)}>►</span>
|
|
||||||
</td>
|
|
||||||
<td className='ri ptr' style={{ width: '3.25em' }} onClick={toggleEnabled}>{pwr(m.getPowerUsage())}</td>
|
<td className='ri ptr' style={{ width: '3.25em' }} onClick={toggleEnabled}>{pwr(m.getPowerUsage())}</td>
|
||||||
<td className='ri ptr' style={{ width: '3em' }} onClick={toggleEnabled}><u>{pct(m.getPowerUsage() / ship.powerAvailable)}</u></td>
|
<td className='ri ptr' style={{ width: '3em' }} onClick={toggleEnabled}><u>{pct(m.getPowerUsage() / ship.powerAvailable)}</u></td>
|
||||||
{retractedElem}
|
{retractedElem}
|
||||||
|
|||||||
@@ -52,7 +52,8 @@ export default class ShipSummaryTable extends TranslatedComponent {
|
|||||||
const boostTooltip = canBoost ? 'TT_SUMMARY_BOOST' : canThrust ? 'TT_SUMMARY_BOOST_NONFUNCTIONAL' : 'TT_SUMMARY_SPEED_NONFUNCTIONAL';
|
const boostTooltip = canBoost ? 'TT_SUMMARY_BOOST' : canThrust ? 'TT_SUMMARY_BOOST_NONFUNCTIONAL' : 'TT_SUMMARY_SPEED_NONFUNCTIONAL';
|
||||||
const canJump = ship.getSlotStatus(ship.standard[2]) == 3;
|
const canJump = ship.getSlotStatus(ship.standard[2]) == 3;
|
||||||
const sgMetrics = Calc.shieldMetrics(ship, pips.sys);
|
const sgMetrics = Calc.shieldMetrics(ship, pips.sys);
|
||||||
const shipBoost = canBoost ? Calc.calcBoost(ship) : 'No Boost';
|
const distBoost = canBoost ? Calc.calcBoost(ship) : 'No Boost';
|
||||||
|
//const shipBoost = ship.boostInterval(ship)
|
||||||
const restingHeat = Math.sqrt(((ship.standard[0].m.pgen * ship.standard[0].m.eff) / ship.heatCapacity) / 0.2);
|
const restingHeat = Math.sqrt(((ship.standard[0].m.pgen * ship.standard[0].m.eff) / ship.heatCapacity) / 0.2);
|
||||||
const armourMetrics = Calc.armourMetrics(ship);
|
const armourMetrics = Calc.armourMetrics(ship);
|
||||||
let shieldColour = 'blue';
|
let shieldColour = 'blue';
|
||||||
@@ -72,6 +73,7 @@ export default class ShipSummaryTable extends TranslatedComponent {
|
|||||||
<tr className='main'>
|
<tr className='main'>
|
||||||
<th rowSpan={2} className={ cn({ 'bg-warning-disabled': !canThrust }) }>{translate('speed')}</th>
|
<th rowSpan={2} className={ cn({ 'bg-warning-disabled': !canThrust }) }>{translate('speed')}</th>
|
||||||
<th rowSpan={2} className={ cn({ 'bg-warning-disabled': !canBoost }) }>{translate('boost')}</th>
|
<th rowSpan={2} className={ cn({ 'bg-warning-disabled': !canBoost }) }>{translate('boost')}</th>
|
||||||
|
<th onMouseEnter={termtip.bind(null, 'TT_SUMMARY_BOOST_INTERVALS', { cap: 0 })}colSpan={2} className={ cn({ 'bg-warning-disabled': !canBoost }) }>{translate('boost int')}</th>
|
||||||
<th colSpan={5} className={ cn({ 'bg-warning-disabled': !canJump }) }>{translate('jump range')}</th>
|
<th colSpan={5} className={ cn({ 'bg-warning-disabled': !canJump }) }>{translate('jump range')}</th>
|
||||||
<th rowSpan={2}>{translate('shield')}</th>
|
<th rowSpan={2}>{translate('shield')}</th>
|
||||||
<th rowSpan={2}>{translate('integrity')}</th>
|
<th rowSpan={2}>{translate('integrity')}</th>
|
||||||
@@ -86,10 +88,11 @@ export default class ShipSummaryTable extends TranslatedComponent {
|
|||||||
<th onMouseEnter={termtip.bind(null, 'hull hardness', { cap: 0 })} onMouseLeave={hide} rowSpan={2}>{translate('hrd')}</th>
|
<th onMouseEnter={termtip.bind(null, 'hull hardness', { cap: 0 })} onMouseLeave={hide} rowSpan={2}>{translate('hrd')}</th>
|
||||||
<th rowSpan={2}>{translate('crew')}</th>
|
<th rowSpan={2}>{translate('crew')}</th>
|
||||||
<th onMouseEnter={termtip.bind(null, 'mass lock factor', { cap: 0 })} onMouseLeave={hide} rowSpan={2}>{translate('MLF')}</th>
|
<th onMouseEnter={termtip.bind(null, 'mass lock factor', { cap: 0 })} onMouseLeave={hide} rowSpan={2}>{translate('MLF')}</th>
|
||||||
<th onMouseEnter={termtip.bind(null, 'TT_SUMMARY_BOOST_INTERVAL', { cap: 0 })} onMouseLeave={hide} rowSpan={2}>{translate('boost interval')}</th>
|
|
||||||
<th rowSpan={2}>{translate('resting heat (Beta)')}</th>
|
<th rowSpan={2}>{translate('resting heat (Beta)')}</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th onMouseEnter={termtip.bind(null, 'TT_SUMMARY_BOOST_INTERVAL', { cap: 0 })} onMouseLeave={hide}>{translate('distro')}</th>
|
||||||
|
<th onMouseEnter={termtip.bind(null, 'TT_SUMMARY_SHIP_BOOST_INTERVAL', { cap: 0 })} onMouseLeave={hide}>{translate('ship')}</th>
|
||||||
<th className={ cn({ 'lft': true, 'bg-warning-disabled': !canJump }) }>{translate('max')}</th>
|
<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('unladen')}</th>
|
||||||
<th className={ cn({ 'bg-warning-disabled': !canJump }) }>{translate('laden')}</th>
|
<th className={ cn({ 'bg-warning-disabled': !canJump }) }>{translate('laden')}</th>
|
||||||
@@ -104,6 +107,8 @@ export default class ShipSummaryTable extends TranslatedComponent {
|
|||||||
<tr>
|
<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, 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, 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>{distBoost !== 'No Boost' ? formats.time(distBoost) : 'No Boost'}</td>
|
||||||
|
<td>{ship.boostInt && ship.boostInt !== 'undefined' ? formats.time(ship.boostInt) : 0 }</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_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_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_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>
|
||||||
@@ -124,7 +129,6 @@ export default class ShipSummaryTable extends TranslatedComponent {
|
|||||||
<td>{int(ship.hardness)}</td>
|
<td>{int(ship.hardness)}</td>
|
||||||
<td>{ship.crew}</td>
|
<td>{ship.crew}</td>
|
||||||
<td>{ship.masslock}</td>
|
<td>{ship.masslock}</td>
|
||||||
<td>{shipBoost !== 'No Boost' ? formats.time(shipBoost) : 'No Boost'}</td>
|
|
||||||
<td>{formats.pct(restingHeat)}</td>
|
<td>{formats.pct(restingHeat)}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -1,386 +1,386 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
const MARGIN_LR = 8; // Left/ Right margin
|
const MARGIN_LR = 8; // Left/ Right margin
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Horizontal Slider
|
* Horizontal Slider
|
||||||
*/
|
*/
|
||||||
export default class Slider extends React.Component {
|
export default class Slider extends React.Component {
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
axis: false,
|
axis: false,
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 1,
|
max: 1,
|
||||||
scale: 1 // SVG render scale
|
scale: 1 // SVG render scale
|
||||||
};
|
};
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
axis: PropTypes.bool,
|
axis: PropTypes.bool,
|
||||||
axisUnit: PropTypes.string,// units (T, M, etc.)
|
axisUnit: PropTypes.string,// units (T, M, etc.)
|
||||||
max: PropTypes.number,
|
max: PropTypes.number,
|
||||||
min: PropTypes.number,
|
min: PropTypes.number,
|
||||||
onChange: PropTypes.func.isRequired,// function which determins percent value
|
onChange: PropTypes.func.isRequired,// function which determins percent value
|
||||||
onResize: PropTypes.func,
|
onResize: PropTypes.func,
|
||||||
percent: PropTypes.number.isRequired,// value of slider
|
percent: PropTypes.number.isRequired,// value of slider
|
||||||
scale: PropTypes.number
|
scale: PropTypes.number
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
*/
|
*/
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this._down = this._down.bind(this);
|
this._down = this._down.bind(this);
|
||||||
this._move = this._move.bind(this);
|
this._move = this._move.bind(this);
|
||||||
this._up = this._up.bind(this);
|
this._up = this._up.bind(this);
|
||||||
this._keyup = this._keyup.bind(this);
|
this._keyup = this._keyup.bind(this);
|
||||||
this._keydown = this._keydown.bind(this);
|
this._keydown = this._keydown.bind(this);
|
||||||
this._touchstart = this._touchstart.bind(this);
|
this._touchstart = this._touchstart.bind(this);
|
||||||
this._touchend = this._touchend.bind(this);
|
this._touchend = this._touchend.bind(this);
|
||||||
|
|
||||||
this._updatePercent = this._updatePercent.bind(this);
|
this._updatePercent = this._updatePercent.bind(this);
|
||||||
this._updateDimensions = this._updateDimensions.bind(this);
|
this._updateDimensions = this._updateDimensions.bind(this);
|
||||||
|
|
||||||
this.state = { width: 0 };
|
this.state = { width: 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On Mouse/Touch down handler
|
* On Mouse/Touch down handler
|
||||||
* @param {SyntheticEvent} event Event
|
* @param {SyntheticEvent} event Event
|
||||||
*/
|
*/
|
||||||
_down(event) {
|
_down(event) {
|
||||||
let rect = event.currentTarget.getBoundingClientRect();
|
let rect = event.currentTarget.getBoundingClientRect();
|
||||||
this.left = rect.left;
|
this.left = rect.left;
|
||||||
this.width = rect.width;
|
this.width = rect.width;
|
||||||
this._move(event);
|
this._move(event);
|
||||||
this.touchStartTimer = setTimeout(() => this.sliderInputBox._setDisplay('block'), 1500);
|
this.touchStartTimer = setTimeout(() => this.sliderInputBox._setDisplay('block'), 1500);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the slider percentage on move
|
* Update the slider percentage on move
|
||||||
* @param {SyntheticEvent} event Event
|
* @param {SyntheticEvent} event Event
|
||||||
*/
|
*/
|
||||||
_move(event) {
|
_move(event) {
|
||||||
if(this.width !== null && this.left != null) {
|
if(this.width !== null && this.left != null) {
|
||||||
let clientX = event.touches ? event.touches[0].clientX : event.clientX;
|
let clientX = event.touches ? event.touches[0].clientX : event.clientX;
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this._updatePercent(clientX - this.left, this.width);
|
this._updatePercent(clientX - this.left, this.width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On Mouse/Touch up handler
|
* On Mouse/Touch up handler
|
||||||
* @param {Event} event DOM Event
|
* @param {Event} event DOM Event
|
||||||
*/
|
*/
|
||||||
_up(event) {
|
_up(event) {
|
||||||
this.sliderInputBox.sliderVal.focus();
|
this.sliderInputBox.sliderVal.focus();
|
||||||
clearTimeout(this.touchStartTimer);
|
clearTimeout(this.touchStartTimer);
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.left = null;
|
this.left = null;
|
||||||
this.width = null;
|
this.width = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Key up handler for keyboard.
|
* Key up handler for keyboard.
|
||||||
* display the number field then set focus to it
|
* display the number field then set focus to it
|
||||||
* when "Enter" key is pressed
|
* when "Enter" key is pressed
|
||||||
* @param {Event} event Keyboard event
|
* @param {Event} event Keyboard event
|
||||||
*/
|
*/
|
||||||
_keyup(event) {
|
_keyup(event) {
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case 'Enter':
|
case 'Enter':
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.sliderInputBox._setDisplay('block');
|
this.sliderInputBox._setDisplay('block');
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Key down handler
|
* Key down handler
|
||||||
* increment slider position by +/- 1 when right/left arrow key is pressed or held
|
* increment slider position by +/- 1 when right/left arrow key is pressed or held
|
||||||
* @param {Event} event Keyboard even
|
* @param {Event} event Keyboard even
|
||||||
*/
|
*/
|
||||||
_keydown(event) {
|
_keydown(event) {
|
||||||
let newVal = this.props.percent * this.props.max;
|
let newVal = this.props.percent * this.props.max;
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case 'ArrowRight':
|
case 'ArrowRight':
|
||||||
newVal += 1;
|
newVal += 1;
|
||||||
if (newVal <= this.props.max) this.props.onChange(newVal / this.props.max);
|
if (newVal <= this.props.max) this.props.onChange(newVal / this.props.max);
|
||||||
return;
|
return;
|
||||||
case 'ArrowLeft':
|
case 'ArrowLeft':
|
||||||
newVal -= 1;
|
newVal -= 1;
|
||||||
if (newVal >= 0) this.props.onChange(newVal / this.props.max);
|
if (newVal >= 0) this.props.onChange(newVal / this.props.max);
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Touch start handler
|
* Touch start handler
|
||||||
* @param {Event} event DOM Event
|
* @param {Event} event DOM Event
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
_touchstart(event) {
|
_touchstart(event) {
|
||||||
this.touchStartTimer = setTimeout(() => this.sliderInputBox._setDisplay('block'), 1500);
|
this.touchStartTimer = setTimeout(() => this.sliderInputBox._setDisplay('block'), 1500);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Touch end handler
|
* Touch end handler
|
||||||
* @param {Event} event DOM Event
|
* @param {Event} event DOM Event
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
_touchend(event) {
|
_touchend(event) {
|
||||||
this.sliderInputBox.sliderVal.focus();
|
this.sliderInputBox.sliderVal.focus();
|
||||||
clearTimeout(this.touchStartTimer);
|
clearTimeout(this.touchStartTimer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if the user is still dragging
|
* Determine if the user is still dragging
|
||||||
* @param {SyntheticEvent} event Event
|
* @param {SyntheticEvent} event Event
|
||||||
*/
|
*/
|
||||||
_enter(event) {
|
_enter(event) {
|
||||||
if(event.buttons !== 1) {
|
if(event.buttons !== 1) {
|
||||||
this.left = null;
|
this.left = null;
|
||||||
this.width = null;
|
this.width = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the slider percentage
|
* Update the slider percentage
|
||||||
* @param {number} pos Slider drag position
|
* @param {number} pos Slider drag position
|
||||||
* @param {number} width Slider width
|
* @param {number} width Slider width
|
||||||
* @param {Event} event DOM Event
|
* @param {Event} event DOM Event
|
||||||
*/
|
*/
|
||||||
_updatePercent(pos, width) {
|
_updatePercent(pos, width) {
|
||||||
this.props.onChange(Math.min(Math.max(pos / width, 0), 1));
|
this.props.onChange(Math.min(Math.max(pos / width, 0), 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update dimenions from rendered DOM
|
* Update dimenions from rendered DOM
|
||||||
*/
|
*/
|
||||||
_updateDimensions() {
|
_updateDimensions() {
|
||||||
this.setState({
|
this.setState({
|
||||||
outerWidth: this.node.getBoundingClientRect().width
|
outerWidth: this.node.getBoundingClientRect().width
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add listeners when about to mount
|
* Add listeners when about to mount
|
||||||
*/
|
*/
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
if (this.props.onResize) {
|
if (this.props.onResize) {
|
||||||
this.resizeListener = this.props.onResize(this._updateDimensions);
|
this.resizeListener = this.props.onResize(this._updateDimensions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trigger DOM updates on mount
|
* Trigger DOM updates on mount
|
||||||
*/
|
*/
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this._updateDimensions();
|
this._updateDimensions();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove listeners on unmount
|
* Remove listeners on unmount
|
||||||
*/
|
*/
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
if (this.resizeListener) {
|
if (this.resizeListener) {
|
||||||
this.resizeListener.remove();
|
this.resizeListener.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the slider
|
* Render the slider
|
||||||
* @return {React.Component} The slider
|
* @return {React.Component} The slider
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
let outerWidth = this.state.outerWidth;
|
let outerWidth = this.state.outerWidth;
|
||||||
let { axis, axisUnit, min, max, scale } = this.props;
|
let { axis, axisUnit, min, max, scale } = this.props;
|
||||||
let style = {
|
let style = {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: axis ? '2.5em' : '1.5em',
|
height: axis ? '2.5em' : '1.5em',
|
||||||
boxSizing: 'border-box'
|
boxSizing: 'border-box'
|
||||||
};
|
};
|
||||||
if (!outerWidth) {
|
if (!outerWidth) {
|
||||||
return <svg style={style} ref={node => this.node = node} />;
|
return <svg style={style} ref={node => this.node = node} />;
|
||||||
}
|
}
|
||||||
let margin = MARGIN_LR * scale;
|
let margin = MARGIN_LR * scale;
|
||||||
let width = outerWidth - (margin * 2);
|
let width = outerWidth - (margin * 2);
|
||||||
let pctPos = width * this.props.percent;
|
let pctPos = width * this.props.percent;
|
||||||
return <div><svg
|
return <div><svg
|
||||||
onMouseUp={this._up} onMouseEnter={this._enter.bind(this)} onMouseMove={this._move} onKeyUp={this._keyup} onKeyDown={this._keydown} style={style} ref={node => this.node = node} tabIndex="0">
|
onMouseUp={this._up} onMouseEnter={this._enter.bind(this)} onMouseMove={this._move} onKeyUp={this._keyup} onKeyDown={this._keydown} style={style} ref={node => this.node = node} tabIndex="0">
|
||||||
<rect className='primary' style={{ opacity: 0.3 }} x={margin} y='0.25em' rx='0.3em' ry='0.3em' width={width} height='0.7em' />
|
<rect className='primary' style={{ opacity: 0.3 }} x={margin} y='0.25em' rx='0.3em' ry='0.3em' width={width} height='0.7em' />
|
||||||
<rect className='primary-disabled' x={margin} y='0.45em' rx='0.15em' ry='0.15em' width={pctPos} height='0.3em' />
|
<rect className='primary-disabled' x={margin} y='0.45em' rx='0.15em' ry='0.15em' width={pctPos} height='0.3em' />
|
||||||
<circle className='primary' r={margin} cy='0.6em' cx={pctPos + margin} />
|
<circle className='primary' r={margin} cy='0.6em' cx={pctPos + margin} />
|
||||||
<rect x={margin} width={width} height='100%' fillOpacity='0' style={{ cursor: 'col-resize' }} onMouseDown={this._down} onTouchMove={this._move} onTouchStart={this._down} onTouchEnd={this._touchend} />
|
<rect x={margin} width={width} height='100%' fillOpacity='0' style={{ cursor: 'col-resize' }} onMouseDown={this._down} onTouchMove={this._move} onTouchStart={this._down} onTouchEnd={this._touchend} />
|
||||||
{axis && <g style={{ fontSize: '.7em' }}>
|
{axis && <g style={{ fontSize: '.7em' }}>
|
||||||
<text className='primary-disabled' y='3em' x={margin} style={{ textAnchor: 'middle' }}>{min + axisUnit}</text>
|
<text className='primary-disabled' y='3em' x={margin} style={{ textAnchor: 'middle' }}>{min + axisUnit}</text>
|
||||||
<text className='primary-disabled' y='3em' x='50%' style={{ textAnchor: 'middle' }}>{(min + max / 2) + axisUnit}</text>
|
<text className='primary-disabled' y='3em' x='50%' style={{ textAnchor: 'middle' }}>{(min + max / 2) + axisUnit}</text>
|
||||||
<text className='primary-disabled' y='3em' x='100%' style={{ textAnchor: 'end' }}>{max + axisUnit}</text>
|
<text className='primary-disabled' y='3em' x='100%' style={{ textAnchor: 'end' }}>{max + axisUnit}</text>
|
||||||
</g>}
|
</g>}
|
||||||
</svg>
|
</svg>
|
||||||
<TextInputBox ref={(tb) => this.sliderInputBox = tb}
|
<TextInputBox ref={(tb) => this.sliderInputBox = tb}
|
||||||
onChange={this.props.onChange}
|
onChange={this.props.onChange}
|
||||||
percent={this.props.percent}
|
percent={this.props.percent}
|
||||||
axisUnit={this.props.axisUnit}
|
axisUnit={this.props.axisUnit}
|
||||||
scale={this.props.scale}
|
scale={this.props.scale}
|
||||||
max={this.props.max}
|
max={this.props.max}
|
||||||
/>
|
/>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* New component to add keyboard support for sliders - works on all devices (desktop, iOS, Android)
|
* New component to add keyboard support for sliders - works on all devices (desktop, iOS, Android)
|
||||||
**/
|
**/
|
||||||
class TextInputBox extends React.Component {
|
class TextInputBox extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
axisUnit: PropTypes.string,// units (T, M, etc.)
|
axisUnit: PropTypes.string,// units (T, M, etc.)
|
||||||
max: PropTypes.number,
|
max: PropTypes.number,
|
||||||
onChange: PropTypes.func.isRequired,// function which determins percent value
|
onChange: PropTypes.func.isRequired,// function which determins percent value
|
||||||
percent: PropTypes.number.isRequired,// value of slider
|
percent: PropTypes.number.isRequired,// value of slider
|
||||||
scale: PropTypes.number
|
scale: PropTypes.number
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Determine if the user is still dragging
|
* Determine if the user is still dragging
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
*/
|
*/
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this._handleFocus = this._handleFocus.bind(this);
|
this._handleFocus = this._handleFocus.bind(this);
|
||||||
this._handleBlur = this._handleBlur.bind(this);
|
this._handleBlur = this._handleBlur.bind(this);
|
||||||
this._handleChange = this._handleChange.bind(this);
|
this._handleChange = this._handleChange.bind(this);
|
||||||
this._keyup = this._keyup.bind(this);
|
this._keyup = this._keyup.bind(this);
|
||||||
this.state = this._getInitialState();
|
this.state = this._getInitialState();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Update input value if slider changes will change props/state
|
* Update input value if slider changes will change props/state
|
||||||
* @param {Object} nextProps React Component properites
|
* @param {Object} nextProps React Component properites
|
||||||
* @param {Object} nextState React Component state values
|
* @param {Object} nextState React Component state values
|
||||||
*/
|
*/
|
||||||
componentWillReceiveProps(nextProps, nextState) {
|
componentWillReceiveProps(nextProps, nextState) {
|
||||||
let nextValue = nextProps.percent * nextProps.max;
|
let nextValue = nextProps.percent * nextProps.max;
|
||||||
// See https://stackoverflow.com/questions/32414308/updating-state-on-props-change-in-react-form
|
// See https://stackoverflow.com/questions/32414308/updating-state-on-props-change-in-react-form
|
||||||
if (nextValue !== this.state.inputValue && nextValue <= nextProps.max) {
|
if (nextValue !== this.state.inputValue && nextValue <= nextProps.max) {
|
||||||
this.setState({ inputValue: nextValue });
|
this.setState({ inputValue: nextValue });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Update slider textbox visibility/values if changes are made to slider
|
* Update slider textbox visibility/values if changes are made to slider
|
||||||
* @param {Object} prevProps React Component properites
|
* @param {Object} prevProps React Component properites
|
||||||
* @param {Object} prevState React Component state values
|
* @param {Object} prevState React Component state values
|
||||||
*/
|
*/
|
||||||
componentDidUpdate(prevProps, prevState) {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
if (prevState.divStyle.display == 'none' && this.state.divStyle.display == 'block') {
|
if (prevState.divStyle.display == 'none' && this.state.divStyle.display == 'block') {
|
||||||
this.enterTimer = setTimeout(() => this.sliderVal.focus(), 10);
|
this.enterTimer = setTimeout(() => this.sliderVal.focus(), 10);
|
||||||
}
|
}
|
||||||
if (prevProps.max !== this.props.max && this.state.inputValue > this.props.max) {
|
if (prevProps.max !== this.props.max && this.state.inputValue > this.props.max) {
|
||||||
// they chose a different module
|
// they chose a different module
|
||||||
this.setState({ inputValue: this.props.max });
|
this.setState({ inputValue: this.props.max });
|
||||||
}
|
}
|
||||||
if (this.state.inputValue != prevState.inputValue && prevProps.max == this.props.max) {
|
if (this.state.inputValue != prevState.inputValue && prevProps.max == this.props.max) {
|
||||||
this.props.onChange(this.state.inputValue / this.props.max);
|
this.props.onChange(this.state.inputValue / this.props.max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Set initial state for the textbox.
|
* Set initial state for the textbox.
|
||||||
* We may want to rethink this to
|
* We may want to rethink this to
|
||||||
* try and make it a stateless component
|
* try and make it a stateless component
|
||||||
* @returns {object} React state object with initial values set
|
* @returns {object} React state object with initial values set
|
||||||
*/
|
*/
|
||||||
_getInitialState() {
|
_getInitialState() {
|
||||||
return {
|
return {
|
||||||
divStyle: { display:'none' },
|
divStyle: { display:'none' },
|
||||||
inputStyle: { width:'4em' },
|
inputStyle: { width:'4em' },
|
||||||
labelStyle: { marginLeft: '.1em' },
|
labelStyle: { marginLeft: '.1em' },
|
||||||
maxLength:5,
|
maxLength:5,
|
||||||
size:5,
|
size:5,
|
||||||
min:0,
|
min:0,
|
||||||
tabIndex:-1,
|
tabIndex:-1,
|
||||||
type:'number',
|
type:'number',
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
inputValue: this.props.percent * this.props.max
|
inputValue: this.props.percent * this.props.max
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {string} val block or none
|
* @param {string} val block or none
|
||||||
*/
|
*/
|
||||||
_setDisplay(val) {
|
_setDisplay(val) {
|
||||||
this.setState({
|
this.setState({
|
||||||
divStyle: { display:val }
|
divStyle: { display:val }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Update the input value
|
* Update the input value
|
||||||
* when textbox gets focus
|
* when textbox gets focus
|
||||||
*/
|
*/
|
||||||
_handleFocus() {
|
_handleFocus() {
|
||||||
this.setState({
|
this.setState({
|
||||||
inputValue:this._getValue()
|
inputValue:this._getValue()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Update inputValue when textbox loses focus
|
* Update inputValue when textbox loses focus
|
||||||
*/
|
*/
|
||||||
_handleBlur() {
|
_handleBlur() {
|
||||||
this._setDisplay('none');
|
this._setDisplay('none');
|
||||||
if (this.state.inputValue !== '') {
|
if (this.state.inputValue !== '') {
|
||||||
this.props.onChange(this.state.inputValue / this.props.max);
|
this.props.onChange(this.state.inputValue / this.props.max);
|
||||||
} else {
|
} else {
|
||||||
this.setState({
|
this.setState({
|
||||||
inputValue: this.props.percent * this.props.max
|
inputValue: this.props.percent * this.props.max
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Get the value in the text box
|
* Get the value in the text box
|
||||||
* @returns {number} inputValue Value of the input box
|
* @returns {number} inputValue Value of the input box
|
||||||
*/
|
*/
|
||||||
_getValue() {
|
_getValue() {
|
||||||
return this.state.inputValue;
|
return this.state.inputValue;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Update and set limits on input box
|
* Update and set limits on input box
|
||||||
* values depending on what user
|
* values depending on what user
|
||||||
* has selected
|
* has selected
|
||||||
*
|
*
|
||||||
* @param {SyntheticEvent} event ReactJs onChange event
|
* @param {SyntheticEvent} event ReactJs onChange event
|
||||||
*/
|
*/
|
||||||
_handleChange(event) {
|
_handleChange(event) {
|
||||||
if (event.target.value < 0) {
|
if (event.target.value < 0) {
|
||||||
this.setState({ inputValue: 0 });
|
this.setState({ inputValue: 0 });
|
||||||
} else if (event.target.value <= this.props.max) {
|
} else if (event.target.value <= this.props.max) {
|
||||||
this.setState({ inputValue: event.target.value });
|
this.setState({ inputValue: event.target.value });
|
||||||
} else {
|
} else {
|
||||||
this.setState({ inputValue: this.props.max });
|
this.setState({ inputValue: this.props.max });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Key up handler for input field.
|
* Key up handler for input field.
|
||||||
* If user hits Enter key, blur/close the input field
|
* If user hits Enter key, blur/close the input field
|
||||||
* @param {Event} event Keyboard event
|
* @param {Event} event Keyboard event
|
||||||
*/
|
*/
|
||||||
_keyup(event) {
|
_keyup(event) {
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case 'Enter':
|
case 'Enter':
|
||||||
this.sliderVal.blur();
|
this.sliderVal.blur();
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Get the value in the text box
|
* Get the value in the text box
|
||||||
* @return {React.Component} Text Input component for Slider
|
* @return {React.Component} Text Input component for Slider
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
let { axisUnit, onChange, percent, scale } = this.props;
|
let { axisUnit, onChange, percent, scale } = this.props;
|
||||||
return <div style={this.state.divStyle}><input style={this.state.inputStyle} value={this._getValue()} min={this.state.min} max={this.props.max} onChange={this._handleChange} onKeyUp={this._keyup} tabIndex={this.state.tabIndex} maxLength={this.state.maxLength} size={this.state.size} onBlur={() => {this._handleBlur();}} onFocus={() => {this._handleFocus();}} type={this.state.type} ref={(ip) => this.sliderVal = ip}/><text className="primary upp" style={this.state.labelStyle}>{this.props.axisUnit}</text></div>;
|
return <div style={this.state.divStyle}><input style={this.state.inputStyle} value={this._getValue()} min={this.state.min} max={this.props.max} onChange={this._handleChange} onKeyUp={this._keyup} tabIndex={this.state.tabIndex} maxLength={this.state.maxLength} size={this.state.size} onBlur={() => {this._handleBlur();}} onFocus={() => {this._handleFocus();}} type={this.state.type} ref={(ip) => this.sliderVal = ip}/><text className="primary upp" style={this.state.labelStyle}>{this.props.axisUnit}</text></div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ export default class Slot extends TranslatedComponent {
|
|||||||
let translate = language.translate;
|
let translate = language.translate;
|
||||||
let { ship, m, enabled, dropClass, dragOver, onOpen, onChange, selected, eligible, onSelect, warning, availableModules } = this.props;
|
let { ship, m, enabled, dropClass, dragOver, onOpen, onChange, selected, eligible, onSelect, warning, availableModules } = this.props;
|
||||||
let slotDetails, modificationsMarker, menu;
|
let slotDetails, modificationsMarker, menu;
|
||||||
|
let missing = false;
|
||||||
|
|
||||||
if (!selected) {
|
if (!selected) {
|
||||||
// If not selected then sure that modifications flag is unset
|
// If not selected then sure that modifications flag is unset
|
||||||
@@ -108,6 +109,11 @@ export default class Slot extends TranslatedComponent {
|
|||||||
if (m) {
|
if (m) {
|
||||||
slotDetails = this._getSlotDetails(m, enabled, translate, language.formats, language.units); // Must be implemented by sub classes
|
slotDetails = this._getSlotDetails(m, enabled, translate, language.formats, language.units); // Must be implemented by sub classes
|
||||||
modificationsMarker = JSON.stringify(m);
|
modificationsMarker = JSON.stringify(m);
|
||||||
|
if(typeof m.grp !== 'undefined' || m.grp !== null) {
|
||||||
|
if(m.grp == "mh" || m.grp == "mm") {
|
||||||
|
missing = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
slotDetails = <div className={'empty'}>{translate(eligible ? 'emptyrestricted' : 'empty')}</div>;
|
slotDetails = <div className={'empty'}>{translate(eligible ? 'emptyrestricted' : 'empty')}</div>;
|
||||||
modificationsMarker = '';
|
modificationsMarker = '';
|
||||||
@@ -138,13 +144,16 @@ export default class Slot extends TranslatedComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement touch dragging
|
// TODO: implement touch dragging
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn('slot', dropClass, { selected })} onClick={onOpen} onKeyDown={this._keyDown} onContextMenu={this._contextMenu} onDragOver={dragOver} tabIndex="0" ref={slotDiv => this.slotDiv = slotDiv}>
|
<div className={cn('slot', dropClass, { selected })} onClick={onOpen} onKeyDown={this._keyDown} onContextMenu={this._contextMenu} onDragOver={dragOver} tabIndex="0" ref={slotDiv => this.slotDiv = slotDiv}>
|
||||||
<div className='details-container'>
|
{
|
||||||
|
// If missing module/hardpoint, set the div container to warning status.
|
||||||
|
}
|
||||||
|
<div className={ missing === true ? 'details-container warning' : 'details-container'}>
|
||||||
<div className='sz'>{this._getMaxClassLabel(translate)}</div>
|
<div className='sz'>{this._getMaxClassLabel(translate)}</div>
|
||||||
{slotDetails}
|
{slotDetails}
|
||||||
</div>
|
</div>
|
||||||
{menu}
|
{menu}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -93,6 +93,11 @@ export default class StandardSlot extends TranslatedComponent {
|
|||||||
this._modificationsSelected = false;
|
this._modificationsSelected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this is a missing module, therefore has the 'info' field, set the warning value on the module to be true when loaded.
|
||||||
|
if (m.info) {
|
||||||
|
warning = () => true;
|
||||||
|
}
|
||||||
|
|
||||||
const modificationsMarker = JSON.stringify(m);
|
const modificationsMarker = JSON.stringify(m);
|
||||||
|
|
||||||
if (selected) {
|
if (selected) {
|
||||||
@@ -124,14 +129,14 @@ export default class StandardSlot extends TranslatedComponent {
|
|||||||
<div className={cn('details-container', { warning: warning && warning(slot.m), disabled: m.grp !== 'bh' && !slot.enabled })}>
|
<div className={cn('details-container', { warning: warning && warning(slot.m), disabled: m.grp !== 'bh' && !slot.enabled })}>
|
||||||
<div className={'sz'}>{m.grp == 'bh' ? m.name.charAt(0) : slot.maxClass}</div>
|
<div className={'sz'}>{m.grp == 'bh' ? m.name.charAt(0) : slot.maxClass}</div>
|
||||||
<div>
|
<div>
|
||||||
<div className={'l'}>{classRating} {translate(m.name || m.grp)}{m.mods && Object.keys(m.mods).length > 0 ? <span className='r' onMouseOver={termtip.bind(null, modTT)} onMouseOut={tooltip.bind(null, null)}><Modified /></span> : null }</div>
|
<div className={'l'}>{classRating} {m.getInfo() ? translate(m.ukName) : translate(m.name || m.grp)}{m.mods && Object.keys(m.mods).length > 0 ? <span className='r' onMouseOver={termtip.bind(null, modTT)} onMouseOut={tooltip.bind(null, null)}><Modified /></span> : null }</div>
|
||||||
<div className={'r'}>{formats.round(mass)}{units.T}</div>
|
<div className={'r'}>{formats.round(mass)}{units.T}</div>
|
||||||
<div/>
|
<div/>
|
||||||
<div className={'cb'}>
|
<div className={'cb'}>
|
||||||
{ m.getMinMass() ? <div className='l'>{translate('minimum mass')}: {formats.int(m.getMinMass())}{units.T}</div> : null }
|
{ m.getMinMass() ? <div className='l'>{translate('minmass')}: {formats.int(m.getMinMass())}{units.T}</div> : null }
|
||||||
{ m.getOptMass() ? <div className='l'>{translate('optimal mass')}: {formats.int(m.getOptMass())}{units.T}</div> : null }
|
{ m.getOptMass() ? <div className='l'>{translate('optmass')}: {formats.int(m.getOptMass())}{units.T}</div> : null }
|
||||||
{ m.getMaxMass() ? <div className='l'>{translate('max mass')}: {formats.int(m.getMaxMass())}{units.T}</div> : null }
|
{ m.getMaxMass() ? <div className='l'>{translate('maxmass')}: {formats.int(m.getMaxMass())}{units.T}</div> : null }
|
||||||
{ m.getOptMul() ? <div className='l'>{translate('optimal multiplier')}: {formats.rPct(m.getOptMul())}</div> : null }
|
{ m.getOptMul() ? <div className='l'>{translate('optmul')}: {formats.rPct(m.getOptMul())}</div> : null }
|
||||||
{ m.getRange() ? <div className='l'>{translate('range', m.grp)}: {formats.f2(m.getRange())}{units.km}</div> : null }
|
{ m.getRange() ? <div className='l'>{translate('range', m.grp)}: {formats.f2(m.getRange())}{units.km}</div> : null }
|
||||||
{ m.time ? <div className='l'>{translate('time')}: {formats.time(m.time)}</div> : null }
|
{ m.time ? <div className='l'>{translate('time')}: {formats.time(m.time)}</div> : null }
|
||||||
{ m.getThermalEfficiency() ? <div className='l'>{translate('efficiency')}: {formats.f2(m.getThermalEfficiency())}</div> : null }
|
{ m.getThermalEfficiency() ? <div className='l'>{translate('efficiency')}: {formats.f2(m.getThermalEfficiency())}</div> : null }
|
||||||
@@ -144,7 +149,8 @@ export default class StandardSlot extends TranslatedComponent {
|
|||||||
{ showModuleResistances && m.getKineticResistance() ? <div className='l'>{translate('kinres')}: {formats.pct(m.getKineticResistance())}</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.getThermalResistance() ? <div className='l'>{translate('thermres')}: {formats.pct(m.getThermalResistance())}</div> : null }
|
||||||
{ m.getIntegrity() ? <div className='l'>{translate('integrity')}: {formats.int(m.getIntegrity())}</div> : null }
|
{ m.getIntegrity() ? <div className='l'>{translate('integrity')}: {formats.int(m.getIntegrity())}</div> : null }
|
||||||
{ validMods.length > 0 ? <div className='r' tabIndex="0" ref={ modButton => this.modButton = modButton }><button tabIndex="-1" onClick={this._toggleModifications.bind(this)} onContextMenu={stopCtxPropagation} onMouseOver={termtip.bind(null, 'modifications')} onMouseOut={tooltip.bind(null, null)}><ListModifications /></button></div> : null }
|
{ m.getInfo() ? <div className='l'>{translate(m.getInfo())}</div> : null }
|
||||||
|
{ m.getInfo() ? <div className='r'></div> : validMods.length > 0 ? <div className='r' tabIndex="0" ref={ modButton => this.modButton = modButton }><button tabIndex="-1" onClick={this._toggleModifications.bind(this)} onContextMenu={stopCtxPropagation} onMouseOver={termtip.bind(null, 'modifications')} onMouseOut={tooltip.bind(null, null)}><ListModifications /></button></div> : null }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ export default class StandardSlotSection extends SlotSection {
|
|||||||
selected={currentMenu == st[4]}
|
selected={currentMenu == st[4]}
|
||||||
onChange={this.props.onChange}
|
onChange={this.props.onChange}
|
||||||
ship={ship}
|
ship={ship}
|
||||||
warning={m => m instanceof Module ? m.getEnginesCapacity() <= ship.boostEnergy : m.engcap <= ship.boostEnergy}
|
warning={m => m instanceof Module ? m.getEnginesCapacity() < ship.boostEnergy : m.engcap < ship.boostEnergy}
|
||||||
/>;
|
/>;
|
||||||
|
|
||||||
slots[6] = <StandardSlot
|
slots[6] = <StandardSlot
|
||||||
|
|||||||
@@ -1,80 +1,80 @@
|
|||||||
import TranslatedComponent from './TranslatedComponent';
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import ContainerDimensions from 'react-container-dimensions';
|
import ContainerDimensions from 'react-container-dimensions';
|
||||||
import { BarChart, Bar, XAxis, YAxis, LabelList } from 'recharts';
|
import { BarChart, Bar, XAxis, YAxis, LabelList } from 'recharts';
|
||||||
|
|
||||||
const CORIOLIS_COLOURS = ['#FF8C0D', '#1FB0FF', '#71A052', '#D5D54D'];
|
const CORIOLIS_COLOURS = ['#FF8C0D', '#1FB0FF', '#71A052', '#D5D54D'];
|
||||||
const LABEL_COLOUR = '#000000';
|
const LABEL_COLOUR = '#000000';
|
||||||
const AXIS_COLOUR = '#C06400';
|
const AXIS_COLOUR = '#C06400';
|
||||||
|
|
||||||
const ASPECT = 1;
|
const ASPECT = 1;
|
||||||
|
|
||||||
const merge = function(one, two) {
|
const merge = function(one, two) {
|
||||||
return Object.assign({}, one, two);
|
return Object.assign({}, one, two);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A vertical bar chart
|
* A vertical bar chart
|
||||||
*/
|
*/
|
||||||
export default class VerticalBarChart extends TranslatedComponent {
|
export default class VerticalBarChart extends TranslatedComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
data : PropTypes.array.isRequired,
|
data : PropTypes.array.isRequired,
|
||||||
yMax : PropTypes.number
|
yMax : PropTypes.number
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
* @param {Object} context React Component context
|
* @param {Object} context React Component context
|
||||||
*/
|
*/
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this._termtip = this._termtip.bind(this);
|
this._termtip = this._termtip.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the bar chart
|
* Render the bar chart
|
||||||
* @returns {Object} the markup
|
* @returns {Object} the markup
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
const { tooltip, termtip } = this.context;
|
const { tooltip, termtip } = this.context;
|
||||||
|
|
||||||
// Calculate maximum for Y
|
// Calculate maximum for Y
|
||||||
let dataMax = Math.max(...this.props.data.map(d => d.value));
|
let dataMax = Math.max(...this.props.data.map(d => d.value));
|
||||||
if (dataMax == -Infinity) dataMax = 0;
|
if (dataMax == -Infinity) dataMax = 0;
|
||||||
let yMax = this.props.yMax ? Math.round(this.props.yMax) : 0;
|
let yMax = this.props.yMax ? Math.round(this.props.yMax) : 0;
|
||||||
const localMax = Math.max(dataMax, yMax);
|
const localMax = Math.max(dataMax, yMax);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ContainerDimensions>
|
<ContainerDimensions>
|
||||||
{ ({ width }) => (
|
{ ({ width }) => (
|
||||||
<div width='100%'>
|
<div width='100%'>
|
||||||
<BarChart width={width} height={width * ASPECT} data={this.props.data} margin={{ top: 5, right: 5, left: 5, bottom: 5 }}>
|
<BarChart width={width} height={width * ASPECT} data={this.props.data} margin={{ top: 5, right: 5, left: 5, bottom: 5 }}>
|
||||||
<XAxis interval={0} fontSize='0.8em' stroke={AXIS_COLOUR} dataKey='label' />
|
<XAxis interval={0} fontSize='0.8em' stroke={AXIS_COLOUR} dataKey='label' />
|
||||||
<YAxis interval={'preserveStart'} tickCount={11} fontSize='0.8em' stroke={AXIS_COLOUR} type='number' domain={[0, localMax]}/>
|
<YAxis interval={'preserveStart'} tickCount={11} fontSize='0.8em' stroke={AXIS_COLOUR} type='number' domain={[0, localMax]}/>
|
||||||
<Bar dataKey='value' fill={CORIOLIS_COLOURS[0]} isAnimationActive={false} onMouseOver={this._termtip} onMouseOut={tooltip.bind(null, null)}>
|
<Bar dataKey='value' fill={CORIOLIS_COLOURS[0]} isAnimationActive={false} onMouseOver={this._termtip} onMouseOut={tooltip.bind(null, null)}>
|
||||||
<LabelList dataKey='value' position='insideTop'/>
|
<LabelList dataKey='value' position='insideTop'/>
|
||||||
</Bar>
|
</Bar>
|
||||||
</BarChart>
|
</BarChart>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</ContainerDimensions>
|
</ContainerDimensions>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a term tip
|
* Generate a term tip
|
||||||
* @param {Object} d the data
|
* @param {Object} d the data
|
||||||
* @param {number} i the index
|
* @param {number} i the index
|
||||||
* @param {Object} e the event
|
* @param {Object} e the event
|
||||||
* @returns {Object} termtip markup
|
* @returns {Object} termtip markup
|
||||||
*/
|
*/
|
||||||
_termtip(d, i, e) {
|
_termtip(d, i, e) {
|
||||||
if (this.props.data[i].tooltip) {
|
if (this.props.data[i].tooltip) {
|
||||||
return this.context.termtip(this.props.data[i].tooltip, e);
|
return this.context.termtip(this.props.data[i].tooltip, e);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
export const formats = {
|
export const formats = {
|
||||||
decimal: ',',
|
decimal: ',',
|
||||||
thousands: '.',
|
thousands: '.',
|
||||||
grouping: [3],
|
grouping: [3],
|
||||||
currency: ['', ' €'],
|
currency: ['', ' €'],
|
||||||
dateTime: '%A, der %e. %B %Y, %X',
|
dateTime: '%A, der %e. %B %Y, %X',
|
||||||
date: '%d.%m.%Y',
|
date: '%d.%m.%Y',
|
||||||
time: '%H:%M:%S',
|
time: '%H:%M:%S',
|
||||||
periods: ['AM', 'PM'], // unused
|
periods: ['AM', 'PM'], // unused
|
||||||
days: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
|
days: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
|
||||||
shortDays: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'],
|
shortDays: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'],
|
||||||
months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
|
months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
|
||||||
shortMonths: ['Jan', 'Feb', 'Mrz', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez']
|
shortMonths: ['Jan', 'Feb', 'Mrz', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez']
|
||||||
};
|
};
|
||||||
|
|
||||||
export { default as terms } from './de.json';
|
export { default as terms } from './de.json';
|
||||||
|
|||||||
@@ -26,6 +26,9 @@
|
|||||||
"PHRASE_NO_SPECIAL": "No experimental effect",
|
"PHRASE_NO_SPECIAL": "No experimental effect",
|
||||||
"PHRASE_SHOPPING_LIST": "Stations that sell this build",
|
"PHRASE_SHOPPING_LIST": "Stations that sell this build",
|
||||||
"PHRASE_SHOPPING_MATS": "Materials needed for this build",
|
"PHRASE_SHOPPING_MATS": "Materials needed for this build",
|
||||||
|
"PHRASE_DIFFERENT_ROLLS": "Material requirements will differ, based on the number of rolls per grade, per module.",
|
||||||
|
"PHRASE_FOR_FINER_CONTROL": "For finer control over rolls per grade/module, a more accurate list of required mats and help in finding those mats, please consider using the export options below to ED Odyssey Materials Helper, or ED Engineer, or use the Crafting Lists feature on inara.cz.",
|
||||||
|
"PHRASE_ALL_MODULES_ALL_ROLLS": "The list below, assumes standard to G5 Engineered (approx 80% - 90%) with the rolls above, for ALL engineered modules in the build. You can adjust the number of rolls above for each grade, however it will still apply to all engineered modules in the build.",
|
||||||
"PHRASE_REFIT_SHOPPING_LIST": "Stations that sell required modules",
|
"PHRASE_REFIT_SHOPPING_LIST": "Stations that sell required modules",
|
||||||
"PHRASE_TOTAL_EFFECTIVE_SHIELD": "Total amount of damage that can be taken from each damage type, if using all shield cells",
|
"PHRASE_TOTAL_EFFECTIVE_SHIELD": "Total amount of damage that can be taken from each damage type, if using all shield cells",
|
||||||
"PHRASE_TIME_TO_LOSE_SHIELDS": "Shields will hold for",
|
"PHRASE_TIME_TO_LOSE_SHIELDS": "Shields will hold for",
|
||||||
@@ -63,7 +66,9 @@
|
|||||||
"TT_SUMMARY_SPEED": "With full fuel tank and 4 pips to ENG",
|
"TT_SUMMARY_SPEED": "With full fuel tank and 4 pips to ENG",
|
||||||
"TT_SUMMARY_SPEED_NONFUNCTIONAL": "Thrusters powered off or over maximum mass with full fuel and cargo loads",
|
"TT_SUMMARY_SPEED_NONFUNCTIONAL": "Thrusters powered off or over maximum mass with full fuel and cargo loads",
|
||||||
"TT_SUMMARY_BOOST": "With full fuel tank and 4 pips to ENG",
|
"TT_SUMMARY_BOOST": "With full fuel tank and 4 pips to ENG",
|
||||||
"TT_SUMMARY_BOOST_INTERVAL": "Time between each boost with 4 pips to ENG",
|
"TT_SUMMARY_SHIP_BOOST_INTERVAL": "Time each boost lasts on this ship",
|
||||||
|
"TT_SUMMARY_BOOST_INTERVAL": "Time between boosts with 4 pips to ENG",
|
||||||
|
"TT_SUMMARY_BOOST_INTERVALS": "If DISTRO is less than or equal to SHIP, the ship can boost continuously",
|
||||||
"TT_SUMMARY_BOOST_NONFUNCTIONAL": "Power distributor not able to supply enough power to boost",
|
"TT_SUMMARY_BOOST_NONFUNCTIONAL": "Power distributor not able to supply enough power to boost",
|
||||||
"TT_SUMMARY_SHIELDS": "Raw shield strength, including boosters",
|
"TT_SUMMARY_SHIELDS": "Raw shield strength, including boosters",
|
||||||
"TT_SUMMARY_SHIELDS_SCB": "Raw shield strength, including boosters and SCBs",
|
"TT_SUMMARY_SHIELDS_SCB": "Raw shield strength, including boosters and SCBs",
|
||||||
@@ -81,8 +86,10 @@
|
|||||||
"TT_SUMMARY_UNLADEN_TOTAL_JUMP": "Farthest possible range with no cargo, a full fuel tank, and jumping as far as possible each time",
|
"TT_SUMMARY_UNLADEN_TOTAL_JUMP": "Farthest possible range with no cargo, a full fuel tank, and jumping as far as possible each time",
|
||||||
"TT_SUMMARY_LADEN_TOTAL_JUMP": "Farthest possible range with full cargo, a full fuel tank, and jumping as far as possible each time",
|
"TT_SUMMARY_LADEN_TOTAL_JUMP": "Farthest possible range with full cargo, a full fuel tank, and jumping as far as possible each time",
|
||||||
"HELP_MODIFICATIONS_MENU": "Click on a number to enter a new value, or drag along the bar for small changes",
|
"HELP_MODIFICATIONS_MENU": "Click on a number to enter a new value, or drag along the bar for small changes",
|
||||||
"PHRASE_FAIL_EDENGINEER": "Failed to send to EDEngineer (Launch EDEngineer and make sure the API is started then refresh the page.)",
|
"PHRASE_ENSURE_EDOMH": "Ensure ED Odyssey Material Helper is installed and registered to handle edomh:// urls, else this button will do nothing!",
|
||||||
"PHRASE_FIREFOX_EDENGINEER": "Sending to EDEngineer is not compatible with Firefox's security settings. Please try again with Chrome.",
|
"PHRASE_FIREFOX_EDENGINEER": "Sending to EDEngineer is not compatible with Firefox's security settings. Please try again with Chrome.",
|
||||||
|
"PHRASE_FAILED_TO_FIND_EDENGINEER": "Failed to find ED Engineer API. Please ensure it is running and try again.",
|
||||||
|
"MISSING_MODULES": "Missing Modules",
|
||||||
"am": "Auto Field-Maintenance Unit",
|
"am": "Auto Field-Maintenance Unit",
|
||||||
"bh": "Bulkheads",
|
"bh": "Bulkheads",
|
||||||
"bl": "Beam Laser",
|
"bl": "Beam Laser",
|
||||||
@@ -109,11 +116,17 @@
|
|||||||
"kw": "Kill Warrant Scanner",
|
"kw": "Kill Warrant Scanner",
|
||||||
"ls": "Life Support",
|
"ls": "Life Support",
|
||||||
"mc": "Multi-cannon",
|
"mc": "Multi-cannon",
|
||||||
|
"mh": "Missing Weapon/Utility",
|
||||||
|
"mm": "Missing Module",
|
||||||
|
"advmc": "Multi-cannon (Advanced)",
|
||||||
"axmc": "AX Multi-cannon",
|
"axmc": "AX Multi-cannon",
|
||||||
|
"axmce": "AX Multi-cannon (Enhanced)",
|
||||||
"ml": "Mining Laser",
|
"ml": "Mining Laser",
|
||||||
"mlc": "Multi Limpet Controller",
|
"mlc": "Multi Limpet Controller",
|
||||||
"mr": "Missile Rack",
|
"mr": "Missile Rack",
|
||||||
|
"amr": "Missile Rack (Advanced)",
|
||||||
"axmr": "AX Missile Rack",
|
"axmr": "AX Missile Rack",
|
||||||
|
"axmre": "AX Missile Rack (Enhanced)",
|
||||||
"ews": "Experimental Weapon Stabilizer",
|
"ews": "Experimental Weapon Stabilizer",
|
||||||
"mrp": "Module Reinforcement Package",
|
"mrp": "Module Reinforcement Package",
|
||||||
"nl": "Mine Launcher",
|
"nl": "Mine Launcher",
|
||||||
@@ -159,6 +172,7 @@
|
|||||||
"sua": "Supercruise Assist",
|
"sua": "Supercruise Assist",
|
||||||
"t": "thrusters",
|
"t": "thrusters",
|
||||||
"tp": "Torpedo Pylon",
|
"tp": "Torpedo Pylon",
|
||||||
|
"ntp": "Nanite Torpedo Pylon",
|
||||||
"ul": "Burst Laser",
|
"ul": "Burst Laser",
|
||||||
"Send To EDEngineer": "Send To EDEngineer",
|
"Send To EDEngineer": "Send To EDEngineer",
|
||||||
"Send To EDOMH": "Send To EDOMH",
|
"Send To EDOMH": "Send To EDOMH",
|
||||||
@@ -212,6 +226,7 @@
|
|||||||
"boost interval": "Boost interval",
|
"boost interval": "Boost interval",
|
||||||
"total": "Total",
|
"total": "Total",
|
||||||
"ammo": "Ammunition maximum",
|
"ammo": "Ammunition maximum",
|
||||||
|
"info": "Info",
|
||||||
"boot": "Boot time",
|
"boot": "Boot time",
|
||||||
"hacktime": "Hack time",
|
"hacktime": "Hack time",
|
||||||
"brokenregen": "Broken regeneration rate",
|
"brokenregen": "Broken regeneration rate",
|
||||||
@@ -261,8 +276,10 @@
|
|||||||
"thermres": "Thermal resistance",
|
"thermres": "Thermal resistance",
|
||||||
"wepcap": "Weapons capacity",
|
"wepcap": "Weapons capacity",
|
||||||
"weprate": "Weapons recharge rate",
|
"weprate": "Weapons recharge rate",
|
||||||
|
"minmass": "Minimum mass",
|
||||||
"minmass_sg": "Minimum hull mass",
|
"minmass_sg": "Minimum hull mass",
|
||||||
"optmass_sg": "Optimal hull mass",
|
"optmass_sg": "Optimal hull mass",
|
||||||
|
"maxmass": "Maximum mass",
|
||||||
"maxmass_sg": "Maximum hull mass",
|
"maxmass_sg": "Maximum hull mass",
|
||||||
"minmul_sg": "Minimum strength",
|
"minmul_sg": "Minimum strength",
|
||||||
"optmul_sg": "Optimal strength",
|
"optmul_sg": "Optimal strength",
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
export const formats = {
|
export const formats = {
|
||||||
decimal: '.',
|
decimal: '.',
|
||||||
thousands: ',',
|
thousands: ',',
|
||||||
grouping: [3],
|
grouping: [3],
|
||||||
currency: ['₩', ''],
|
currency: ['₩', ''],
|
||||||
dateTime: '%a %b %e %X %Y',
|
dateTime: '%a %b %e %X %Y',
|
||||||
date: '%Y/%m/%d',
|
date: '%Y/%m/%d',
|
||||||
time: '%H:%M:%S',
|
time: '%H:%M:%S',
|
||||||
periods: ['오전', '오후'],
|
periods: ['오전', '오후'],
|
||||||
days: ['일요일', '월요일', '화요일', '수요일', '목요일', '금요일', '토요일'],
|
days: ['일요일', '월요일', '화요일', '수요일', '목요일', '금요일', '토요일'],
|
||||||
shortDays: ['일', '월', '화', '수', '목', '금', '토'],
|
shortDays: ['일', '월', '화', '수', '목', '금', '토'],
|
||||||
months: ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'],
|
months: ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'],
|
||||||
shortMonths: ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월']
|
shortMonths: ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월']
|
||||||
};
|
};
|
||||||
|
|
||||||
export { default as terms } from './ko.json';
|
export { default as terms } from './ko.json';
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -45,6 +45,9 @@ export default class ErrorDetails extends React.Component {
|
|||||||
return <div className='error'>
|
return <div className='error'>
|
||||||
<h1>Jameson, we have a problem..</h1>
|
<h1>Jameson, we have a problem..</h1>
|
||||||
<h1><small>{error.message}</small></h1>
|
<h1><small>{error.message}</small></h1>
|
||||||
|
Import Error handling has been improved, but still isn't perfect. <br/>MOST Import failures are a result of missing modules in Coriolis, <br />OR incorrect import strings generated by third party apps. If you're seeing this page, we may have failed to handle the errors in your import correctly. Please see the data output below, specifically the 'scriptUrl:' section if it's there and then if you feel confident enough, please check the github issues page linked below and see if there is a similar issue already logged. If not, please create a new issue with the data below. If you're not confident, please ask for help on the Coriolis Channel of the EDCD Discord server.
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
{importerror ? <div>If you are attempting to import a ship from EDDI or EDMC and are seeing a 'Z_BUF_ERROR' it means that the URL has not been provided correctly. This is a common problem when using Microsoft Internet Explorer or Microsoft Edge, and you should use another browser instead.</div> : null }
|
{importerror ? <div>If you are attempting to import a ship from EDDI or EDMC and are seeing a 'Z_BUF_ERROR' it means that the URL has not been provided correctly. This is a common problem when using Microsoft Internet Explorer or Microsoft Edge, and you should use another browser instead.</div> : null }
|
||||||
<br/>
|
<br/>
|
||||||
|
|||||||
@@ -700,7 +700,9 @@ export default class OutfittingPage extends Page {
|
|||||||
* Generates the shopping list
|
* Generates the shopping list
|
||||||
*/
|
*/
|
||||||
_genShoppingList() {
|
_genShoppingList() {
|
||||||
this.context.showModal(<ModalShoppingList ship={this.state.ship} />);
|
this.context.showModal(<ModalShoppingList
|
||||||
|
ship={this.state.ship}
|
||||||
|
buildName={this.state.buildName} />);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ export const ModuleGroupToName = {
|
|||||||
pd: 'Power Distributor',
|
pd: 'Power Distributor',
|
||||||
s: 'Sensors',
|
s: 'Sensors',
|
||||||
ft: 'Fuel Tank',
|
ft: 'Fuel Tank',
|
||||||
pas: 'Planetary Approach Suite',
|
|
||||||
|
|
||||||
// Internal
|
// Internal
|
||||||
fs: 'Fuel Scoop',
|
fs: 'Fuel Scoop',
|
||||||
@@ -60,6 +59,7 @@ export const ModuleGroupToName = {
|
|||||||
sua: 'Supercruise Assist',
|
sua: 'Supercruise Assist',
|
||||||
mlc: "Multi Limpet Controller",
|
mlc: "Multi Limpet Controller",
|
||||||
rpl: "Repair Limpet Controller",
|
rpl: "Repair Limpet Controller",
|
||||||
|
pas: 'Planetary Approach Suite',
|
||||||
|
|
||||||
// Hard Points
|
// Hard Points
|
||||||
bl: 'Beam Laser',
|
bl: 'Beam Laser',
|
||||||
@@ -77,11 +77,15 @@ export const ModuleGroupToName = {
|
|||||||
nl: 'Mine Launcher',
|
nl: 'Mine Launcher',
|
||||||
ml: 'Mining Laser',
|
ml: 'Mining Laser',
|
||||||
mr: 'Missile Rack',
|
mr: 'Missile Rack',
|
||||||
|
amr: 'Missile Rack (Advanced)',
|
||||||
axmr: 'AX Missile Rack',
|
axmr: 'AX Missile Rack',
|
||||||
|
axmre: 'AX Missile Rack (Enhanced)',
|
||||||
pa: 'Plasma Accelerator',
|
pa: 'Plasma Accelerator',
|
||||||
po: 'Point Defence',
|
po: 'Point Defence',
|
||||||
mc: 'Multi-cannon',
|
mc: 'Multi-cannon',
|
||||||
|
advmc: 'Multi-cannon (Advanced)',
|
||||||
axmc: 'AX Multi-cannon',
|
axmc: 'AX Multi-cannon',
|
||||||
|
axmce: 'AX Multi-cannon (Enhanced)',
|
||||||
pl: 'Pulse Laser',
|
pl: 'Pulse Laser',
|
||||||
rg: 'Rail Gun',
|
rg: 'Rail Gun',
|
||||||
sb: 'Shield Booster',
|
sb: 'Shield Booster',
|
||||||
|
|||||||
@@ -439,6 +439,15 @@ export default class Module {
|
|||||||
return this.get('integrity', modified);
|
return this.get('integrity', modified);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the info of this module
|
||||||
|
* @param {Boolean} [modified=false] Whether to take modifications into account
|
||||||
|
* @return {String} the info of this module
|
||||||
|
*/
|
||||||
|
getInfo(modified = false) {
|
||||||
|
return (modified && this.getModValue('info')) || this.info;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the mass of this module
|
* Get the mass of this module
|
||||||
* @param {Boolean} [modified=true] Whether to take modifications into account
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ export default class Ship {
|
|||||||
*/
|
*/
|
||||||
canBoost(cargo, fuel) {
|
canBoost(cargo, fuel) {
|
||||||
return this.canThrust(cargo, fuel) && // Thrusters operational
|
return this.canThrust(cargo, fuel) && // Thrusters operational
|
||||||
this.standard[4].m.getEnginesCapacity() > this.boostEnergy; // PD capacitor is sufficient for boost
|
this.standard[4].m.getEnginesCapacity() >= this.boostEnergy; // PD capacitor is sufficient for boost
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -108,9 +108,9 @@ export class Persist extends EventEmitter {
|
|||||||
this.matsPerGrade = matsPerGrade || {
|
this.matsPerGrade = matsPerGrade || {
|
||||||
1: 2,
|
1: 2,
|
||||||
2: 2,
|
2: 2,
|
||||||
3: 4,
|
3: 3,
|
||||||
4: 4,
|
4: 4,
|
||||||
5: 10
|
5: 5
|
||||||
};
|
};
|
||||||
this.cmdrName = cmdrName || { selected: '', cmdrs: [] };
|
this.cmdrName = cmdrName || { selected: '', cmdrs: [] };
|
||||||
this.tooltipsEnabled = tips === null ? true : tips;
|
this.tooltipsEnabled = tips === null ? true : tips;
|
||||||
|
|||||||
@@ -1,435 +1,447 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Modifications } from 'coriolis-data/dist';
|
import { Modifications } from 'coriolis-data/dist';
|
||||||
import { STATS_FORMATTING } from '../shipyard/StatsFormatting';
|
import { STATS_FORMATTING } from '../shipyard/StatsFormatting';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a tooltip with details of a blueprint's specials
|
* Generate a tooltip with details of a blueprint's specials
|
||||||
* @param {Object} translate The translate object
|
* @param {Object} translate The translate object
|
||||||
* @param {Object} blueprint The blueprint at the required grade
|
* @param {Object} blueprint The blueprint at the required grade
|
||||||
* @param {string} grp The group of the module
|
* @param {string} grp The group of the module
|
||||||
* @param {Object} m The module to compare with
|
* @param {Object} m The module to compare with
|
||||||
* @param {string} specialName The name of the special
|
* @param {string} specialName The name of the special
|
||||||
* @returns {Object} The react components
|
* @returns {Object} The react components
|
||||||
*/
|
*/
|
||||||
export function specialToolTip(translate, blueprint, grp, m, specialName) {
|
export function specialToolTip(translate, blueprint, grp, m, specialName) {
|
||||||
const effects = [];
|
const effects = [];
|
||||||
if (!blueprint || !blueprint.features) {
|
if (!blueprint || !blueprint.features) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
if (m) {
|
if (m) {
|
||||||
// We also add in any benefits from specials that aren't covered above
|
// We also add in any benefits from specials that aren't covered above
|
||||||
if (m.blueprint) {
|
if (m.blueprint) {
|
||||||
for (const feature in Modifications.modifierActions[specialName]) {
|
for (const feature in Modifications.modifierActions[specialName]) {
|
||||||
// if (!blueprint.features[feature] && !m.mods.feature) {
|
// if (!blueprint.features[feature] && !m.mods.feature) {
|
||||||
const featureDef = Modifications.modifications[feature];
|
const featureDef = Modifications.modifications[feature];
|
||||||
if (featureDef && !featureDef.hidden) {
|
if (featureDef && !featureDef.hidden) {
|
||||||
let symbol = '';
|
let symbol = '';
|
||||||
if (feature === 'jitter') {
|
if (feature === 'jitter') {
|
||||||
symbol = '°';
|
symbol = '°';
|
||||||
} else if (featureDef.type === 'percentage') {
|
} else if (featureDef.type === 'percentage') {
|
||||||
symbol = '%';
|
symbol = '%';
|
||||||
}
|
}
|
||||||
let current = m.getModValue(feature) - m.getModValue(feature, true);
|
let current = m.getModValue(feature) - m.getModValue(feature, true);
|
||||||
if (featureDef.type === 'percentage') {
|
if (featureDef.type === 'percentage') {
|
||||||
current = Math.round(current / 10) / 10;
|
current = Math.round(current / 10) / 10;
|
||||||
} else if (featureDef.type === 'numeric') {
|
} else if (featureDef.type === 'numeric') {
|
||||||
current /= 100;
|
current /= 100;
|
||||||
}
|
}
|
||||||
const currentIsBeneficial = isValueBeneficial(feature, current);
|
const currentIsBeneficial = isValueBeneficial(feature, current);
|
||||||
|
|
||||||
effects.push(
|
effects.push(
|
||||||
<tr key={feature + '_specialTT'}>
|
<tr key={feature + '_specialTT'}>
|
||||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'}
|
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'}
|
||||||
style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<table width='100%'>
|
<table width='100%'>
|
||||||
<tbody>
|
<tbody>
|
||||||
{effects}
|
{effects}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a tooltip with details of a blueprint's effects
|
* Generate a tooltip with details of a blueprint's effects
|
||||||
* @param {Object} translate The translate object
|
* @param {Object} translate The translate object
|
||||||
* @param {Object} blueprint The blueprint at the required grade
|
* @param {Object} blueprint The blueprint at the required grade
|
||||||
* @param {Array} engineers The engineers supplying this blueprint
|
* @param {Array} engineers The engineers supplying this blueprint
|
||||||
* @param {string} grp The group of the module
|
* @param {string} grp The group of the module
|
||||||
* @param {Object} m The module to compare with
|
* @param {Object} m The module to compare with
|
||||||
* @returns {Object} The react components
|
* @returns {Object} The react components
|
||||||
*/
|
*/
|
||||||
export function blueprintTooltip(translate, blueprint, engineers, grp, m) {
|
export function blueprintTooltip(translate, blueprint, engineers, grp, m) {
|
||||||
const effects = [];
|
const effects = [];
|
||||||
if (!blueprint || !blueprint.features) {
|
if (!blueprint || !blueprint.features) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
for (const feature in blueprint.features) {
|
for (const feature in blueprint.features) {
|
||||||
const featureIsBeneficial = isBeneficial(feature, blueprint.features[feature]);
|
const featureIsBeneficial = isBeneficial(feature, blueprint.features[feature]);
|
||||||
const featureDef = Modifications.modifications[feature];
|
const featureDef = Modifications.modifications[feature];
|
||||||
if (!featureDef.hidden) {
|
if (!featureDef.hidden) {
|
||||||
let symbol = '';
|
let symbol = '';
|
||||||
if (feature === 'jitter') {
|
if (feature === 'jitter') {
|
||||||
symbol = '°';
|
symbol = '°';
|
||||||
} else if (featureDef.type === 'percentage') {
|
} else if (featureDef.type === 'percentage') {
|
||||||
symbol = '%';
|
symbol = '%';
|
||||||
}
|
}
|
||||||
let lowerBound = blueprint.features[feature][0];
|
let lowerBound = blueprint.features[feature][0];
|
||||||
let upperBound = blueprint.features[feature][1];
|
let upperBound = blueprint.features[feature][1];
|
||||||
if (featureDef.type === 'percentage') {
|
if (featureDef.type === 'percentage') {
|
||||||
lowerBound = Math.round(lowerBound * 1000) / 10;
|
lowerBound = Math.round(lowerBound * 1000) / 10;
|
||||||
upperBound = Math.round(upperBound * 1000) / 10;
|
upperBound = Math.round(upperBound * 1000) / 10;
|
||||||
}
|
}
|
||||||
const lowerIsBeneficial = isValueBeneficial(feature, lowerBound);
|
const lowerIsBeneficial = isValueBeneficial(feature, lowerBound);
|
||||||
const upperIsBeneficial = isValueBeneficial(feature, upperBound);
|
const upperIsBeneficial = isValueBeneficial(feature, upperBound);
|
||||||
if (m) {
|
if (m) {
|
||||||
// We have a module - add in the current value
|
// We have a module - add in the current value
|
||||||
let current = m.getModValue(feature);
|
let current = m.getModValue(feature);
|
||||||
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
|
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
|
||||||
current = Math.round(current / 10) / 10;
|
current = Math.round(current / 10) / 10;
|
||||||
} else if (featureDef.type === 'numeric') {
|
} else if (featureDef.type === 'numeric') {
|
||||||
current /= 100;
|
current /= 100;
|
||||||
}
|
}
|
||||||
const currentIsBeneficial = isValueBeneficial(feature, current);
|
const currentIsBeneficial = isValueBeneficial(feature, current);
|
||||||
effects.push(
|
effects.push(
|
||||||
<tr key={feature}>
|
<tr key={feature}>
|
||||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
||||||
<td className={lowerBound === 0 ? '' : lowerIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{lowerBound}{symbol}</td>
|
<td className={lowerBound === 0 ? '' : lowerIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{lowerBound}{symbol}</td>
|
||||||
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
||||||
<td className={upperBound === 0 ? '' : upperIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{upperBound}{symbol}</td>
|
<td className={upperBound === 0 ? '' : upperIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{upperBound}{symbol}</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// We do not have a module, no value
|
// We do not have a module, no value
|
||||||
effects.push(
|
effects.push(
|
||||||
<tr key={feature}>
|
<tr key={feature}>
|
||||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
||||||
<td className={lowerBound === 0 ? '' : lowerIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{lowerBound}{symbol}</td>
|
<td className={lowerBound === 0 ? '' : lowerIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{lowerBound}{symbol}</td>
|
||||||
<td className={upperBound === 0 ? '' : upperIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{upperBound}{symbol}</td>
|
<td className={upperBound === 0 ? '' : upperIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{upperBound}{symbol}</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m) {
|
if (m) {
|
||||||
// Because we have a module add in any benefits that aren't part of the primary blueprint
|
// Because we have a module add in any benefits that aren't part of the primary blueprint
|
||||||
for (const feature in m.mods) {
|
for (const feature in m.mods) {
|
||||||
if (!blueprint.features[feature]) {
|
if (!blueprint.features[feature]) {
|
||||||
const featureDef = Modifications.modifications[feature];
|
const featureDef = Modifications.modifications[feature];
|
||||||
if (featureDef && !featureDef.hidden) {
|
if (featureDef && !featureDef.hidden) {
|
||||||
let symbol = '';
|
let symbol = '';
|
||||||
if (feature === 'jitter') {
|
if (feature === 'jitter') {
|
||||||
symbol = '°';
|
symbol = '°';
|
||||||
} else if (featureDef.type === 'percentage') {
|
} else if (featureDef.type === 'percentage') {
|
||||||
symbol = '%';
|
symbol = '%';
|
||||||
}
|
}
|
||||||
let current = m.getModValue(feature);
|
let current = m.getModValue(feature);
|
||||||
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
|
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
|
||||||
current = Math.round(current / 10) / 10;
|
current = Math.round(current / 10) / 10;
|
||||||
} else if (featureDef.type === 'numeric') {
|
} else if (featureDef.type === 'numeric') {
|
||||||
current /= 100;
|
current /= 100;
|
||||||
}
|
}
|
||||||
const currentIsBeneficial = isValueBeneficial(feature, current);
|
const currentIsBeneficial = isValueBeneficial(feature, current);
|
||||||
effects.push(
|
effects.push(
|
||||||
<tr key={feature}>
|
<tr key={feature}>
|
||||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We also add in any benefits from specials that aren't covered above
|
// We also add in any benefits from specials that aren't covered above
|
||||||
if (m.blueprint && m.blueprint.special) {
|
if (m.blueprint && m.blueprint.special) {
|
||||||
for (const feature in Modifications.modifierActions[m.blueprint.special.edname]) {
|
for (const feature in Modifications.modifierActions[m.blueprint.special.edname]) {
|
||||||
if (!blueprint.features[feature] && !m.mods.feature) {
|
if (!blueprint.features[feature] && !m.mods.feature) {
|
||||||
const featureDef = Modifications.modifications[feature];
|
const featureDef = Modifications.modifications[feature];
|
||||||
if (featureDef && !featureDef.hidden) {
|
if (featureDef && !featureDef.hidden) {
|
||||||
let symbol = '';
|
let symbol = '';
|
||||||
if (feature === 'jitter') {
|
if (feature === 'jitter') {
|
||||||
symbol = '°';
|
symbol = '°';
|
||||||
} else if (featureDef.type === 'percentage') {
|
} else if (featureDef.type === 'percentage') {
|
||||||
symbol = '%';
|
symbol = '%';
|
||||||
}
|
}
|
||||||
let current = m.getModValue(feature);
|
let current = m.getModValue(feature);
|
||||||
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
|
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
|
||||||
current = Math.round(current / 10) / 10;
|
current = Math.round(current / 10) / 10;
|
||||||
} else if (featureDef.type === 'numeric') {
|
} else if (featureDef.type === 'numeric') {
|
||||||
current /= 100;
|
current /= 100;
|
||||||
}
|
}
|
||||||
const currentIsBeneficial = isValueBeneficial(feature, current);
|
const currentIsBeneficial = isValueBeneficial(feature, current);
|
||||||
effects.push(
|
effects.push(
|
||||||
<tr key={feature}>
|
<tr key={feature}>
|
||||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let components;
|
let components;
|
||||||
if (!m) {
|
if (!m) {
|
||||||
components = [];
|
components = [];
|
||||||
for (const component in blueprint.components) {
|
for (const component in blueprint.components) {
|
||||||
components.push(
|
components.push(
|
||||||
<tr key={component}>
|
<tr key={component}>
|
||||||
<td style={{ textAlign: 'left' }}>{translate(component)}</td>
|
<td style={{ textAlign: 'left' }}>{translate(component)}</td>
|
||||||
<td style={{ textAlign: 'right' }}>{blueprint.components[component]}</td>
|
<td style={{ textAlign: 'right' }}>{blueprint.components[component]}</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let engineersList;
|
let engineersList;
|
||||||
if (engineers) {
|
if (engineers) {
|
||||||
engineersList = [];
|
engineersList = [];
|
||||||
for (const engineer of engineers) {
|
for (const engineer of engineers) {
|
||||||
engineersList.push(
|
engineersList.push(
|
||||||
<tr key={engineer}>
|
<tr key={engineer}>
|
||||||
<td style={{ textAlign: 'left' }}>{engineer}</td>
|
<td style={{ textAlign: 'left' }}>{engineer}</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<table width='100%'>
|
<table width='100%'>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{translate('feature')}</td>
|
<td>{translate('feature')}</td>
|
||||||
<td>{translate('worst')}</td>
|
<td>{translate('worst')}</td>
|
||||||
{m ? <td>{translate('current')}</td> : null }
|
{m ? <td>{translate('current')}</td> : null }
|
||||||
<td>{translate('best')}</td>
|
<td>{translate('best')}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{effects}
|
{effects}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{ components ? <table width='100%'>
|
{ components ? <table width='100%'>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{translate('component')}</td>
|
<td>{translate('component')}</td>
|
||||||
<td>{translate('amount')}</td>
|
<td>{translate('amount')}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{components}
|
{components}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table> : null }
|
</table> : null }
|
||||||
{ engineersList ? <table width='100%'>
|
{ engineersList ? <table width='100%'>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{translate('engineers')}</td>
|
<td>{translate('engineers')}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{engineersList}
|
{engineersList}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table> : null }
|
</table> : null }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this blueprint feature beneficial?
|
* Is this blueprint feature beneficial?
|
||||||
* @param {string} feature The name of the feature
|
* @param {string} feature The name of the feature
|
||||||
* @param {array} values The value of the feature
|
* @param {array} values The value of the feature
|
||||||
* @returns {boolean} True if this feature is beneficial
|
* @returns {boolean} True if this feature is beneficial
|
||||||
*/
|
*/
|
||||||
export function isBeneficial(feature, values) {
|
export function isBeneficial(feature, values) {
|
||||||
const fact = (values[0] < 0 || (values[0] === 0 && values[1] < 0));
|
const fact = (values[0] < 0 || (values[0] === 0 && values[1] < 0));
|
||||||
if (Modifications.modifications[feature].higherbetter) {
|
if (Modifications.modifications[feature].higherbetter) {
|
||||||
return !fact;
|
return !fact;
|
||||||
} else {
|
} else {
|
||||||
return fact;
|
return fact;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this feature value beneficial?
|
* Is this feature value beneficial?
|
||||||
* @param {string} feature The name of the feature
|
* @param {string} feature The name of the feature
|
||||||
* @param {number} value The value of the feature
|
* @param {number} value The value of the feature
|
||||||
* @returns {boolean} True if this value is beneficial
|
* @returns {boolean} True if this value is beneficial
|
||||||
*/
|
*/
|
||||||
export function isValueBeneficial(feature, value) {
|
export function isValueBeneficial(feature, value) {
|
||||||
if (Modifications.modifications[feature].higherbetter) {
|
if (Modifications.modifications[feature].higherbetter) {
|
||||||
return value > 0;
|
return value > 0;
|
||||||
} else {
|
} else {
|
||||||
return value < 0;
|
return value < 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is the change as shown beneficial?
|
* Is the change as shown beneficial?
|
||||||
* @param {string} feature The name of the feature
|
* @param {string} feature The name of the feature
|
||||||
* @param {number} value The value of the feature as percentage change
|
* @param {number} value The value of the feature as percentage change
|
||||||
* @returns True if the value is beneficial
|
* @returns True if the value is beneficial
|
||||||
*/
|
*/
|
||||||
export function isChangeValueBeneficial(feature, value) {
|
export function isChangeValueBeneficial(feature, value) {
|
||||||
let changeHigherBetter = STATS_FORMATTING[feature].higherbetter;
|
let changeHigherBetter = STATS_FORMATTING[feature].higherbetter;
|
||||||
if (changeHigherBetter === undefined) {
|
if (changeHigherBetter === undefined) {
|
||||||
return isValueBeneficial(feature, value);
|
return isValueBeneficial(feature, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changeHigherBetter) {
|
if (changeHigherBetter) {
|
||||||
return value > 0;
|
return value > 0;
|
||||||
} else {
|
} else {
|
||||||
return value < 0;
|
return value < 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a blueprint with a given name and an optional module
|
* Get a blueprint with a given name and an optional module
|
||||||
* @param {string} name The name of the blueprint
|
* @param {string} name The name of the blueprint
|
||||||
* @param {Object} module The module for which to obtain this blueprint
|
* @param {Object} module The module for which to obtain this blueprint
|
||||||
* @returns {Object} The matching blueprint
|
* @returns {Object} The matching blueprint
|
||||||
*/
|
*/
|
||||||
export function getBlueprint(name, module) {
|
export function getBlueprint(name, module) {
|
||||||
// Start with a copy of the blueprint
|
// Special case for multi-cannons. Conflicting 'Weapon_Overcharged' Blueprints exist due to FD's naming conventions. If this blueprint is for a multi-cannon, we need to use the correct blueprint.
|
||||||
const findMod = val => Object.keys(Modifications.blueprints).find(elem => elem.toString().toLowerCase().search(val.toString().toLowerCase().replace(/(OutfittingFieldType_|persecond)/igm, '')) >= 0);
|
if (name === 'weapon_overcharged') {
|
||||||
const found = Modifications.blueprints[findMod(name)];
|
if (module.symbol.match(/MultiCannon/i)) {
|
||||||
if (!found || !found.fdname) {
|
name = 'mc_overcharged';
|
||||||
return {};
|
}
|
||||||
}
|
}
|
||||||
const blueprint = JSON.parse(JSON.stringify(found));
|
else if (name === 'Weapon_Overcharged') {
|
||||||
return blueprint;
|
if (module.symbol.match(/MultiCannon/i)) {
|
||||||
}
|
name = 'MC_Overcharged';
|
||||||
|
}
|
||||||
/**
|
}
|
||||||
* Provide 'percent' primary modifications
|
// Start with a copy of the blueprint
|
||||||
* @param {Object} ship The ship for which to perform the modifications
|
const findMod = val => Object.keys(Modifications.blueprints).find(elem => elem.toString().toLowerCase().search(val.toString().toLowerCase().replace(/(OutfittingFieldType_|persecond)/igm, '')) >= 0);
|
||||||
* @param {Object} m The module for which to perform the modifications
|
const found = Modifications.blueprints[findMod(name)];
|
||||||
* @param {Number} percent The percent to set values to of full.
|
if (!found || !found.fdname) {
|
||||||
*/
|
console.error('Blueprint not found:', name);
|
||||||
export function setPercent(ship, m, percent) {
|
return {};
|
||||||
ship.clearModifications(m);
|
}
|
||||||
// Pick given value as multiplier
|
const blueprint = JSON.parse(JSON.stringify(found));
|
||||||
const mult = percent / 100;
|
return blueprint;
|
||||||
setQualityCB(m.blueprint, mult, (featureName, value) => ship.setModification(m, featureName, value));
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
/**
|
* Provide 'percent' primary modifications
|
||||||
* Sets the blueprint quality and fires a callback for each property affected.
|
* @param {Object} ship The ship for which to perform the modifications
|
||||||
* @param {Object} blueprint The ship for which to perform the modifications
|
* @param {Object} m The module for which to perform the modifications
|
||||||
* @param {Number} quality The quality to apply - float number 0 to 1.
|
* @param {Number} percent The percent to set values to of full.
|
||||||
* @param {Function} cb The Callback to run for each property. Function (featureName, value)
|
*/
|
||||||
*/
|
export function setPercent(ship, m, percent) {
|
||||||
export function setQualityCB(blueprint, quality, cb) {
|
ship.clearModifications(m);
|
||||||
// Pick given value as multiplier
|
// Pick given value as multiplier
|
||||||
const features = blueprint.grades[blueprint.grade].features;
|
const mult = percent / 100;
|
||||||
for (const featureName in features) {
|
setQualityCB(m.blueprint, mult, (featureName, value) => ship.setModification(m, featureName, value));
|
||||||
let value;
|
}
|
||||||
if (Modifications.modifications[featureName].higherbetter) {
|
|
||||||
// Higher is better, but is this making it better or worse?
|
/**
|
||||||
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
* Sets the blueprint quality and fires a callback for each property affected.
|
||||||
value = features[featureName][1] + ((features[featureName][0] - features[featureName][1]) * quality);
|
* @param {Object} blueprint The ship for which to perform the modifications
|
||||||
} else {
|
* @param {Number} quality The quality to apply - float number 0 to 1.
|
||||||
value = features[featureName][0] + ((features[featureName][1] - features[featureName][0]) * quality);
|
* @param {Function} cb The Callback to run for each property. Function (featureName, value)
|
||||||
}
|
*/
|
||||||
} else {
|
export function setQualityCB(blueprint, quality, cb) {
|
||||||
// Higher is worse, but is this making it better or worse?
|
// Pick given value as multiplier
|
||||||
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
const features = blueprint.grades[blueprint.grade].features;
|
||||||
value = features[featureName][0] + ((features[featureName][1] - features[featureName][0]) * quality);
|
for (const featureName in features) {
|
||||||
} else {
|
let value;
|
||||||
value = features[featureName][1] + ((features[featureName][0] - features[featureName][1]) * quality);
|
if (Modifications.modifications[featureName].higherbetter) {
|
||||||
}
|
// Higher is better, but is this making it better or worse?
|
||||||
}
|
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
||||||
|
value = features[featureName][1] + ((features[featureName][0] - features[featureName][1]) * quality);
|
||||||
if (Modifications.modifications[featureName].type == 'percentage') {
|
} else {
|
||||||
value = value * 10000;
|
value = features[featureName][0] + ((features[featureName][1] - features[featureName][0]) * quality);
|
||||||
} else if (Modifications.modifications[featureName].type == 'numeric') {
|
}
|
||||||
value = value * 100;
|
} else {
|
||||||
}
|
// Higher is worse, but is this making it better or worse?
|
||||||
|
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
||||||
cb(featureName, value);
|
value = features[featureName][0] + ((features[featureName][1] - features[featureName][0]) * quality);
|
||||||
}
|
} else {
|
||||||
}
|
value = features[featureName][1] + ((features[featureName][0] - features[featureName][1]) * quality);
|
||||||
|
}
|
||||||
/**
|
}
|
||||||
* Provide 'random' primary modifications
|
|
||||||
* @param {Object} ship The ship for which to perform the modifications
|
if (Modifications.modifications[featureName].type == 'percentage') {
|
||||||
* @param {Object} m The module for which to perform the modifications
|
value = value * 10000;
|
||||||
*/
|
} else if (Modifications.modifications[featureName].type == 'numeric') {
|
||||||
export function setRandom(ship, m) {
|
value = value * 100;
|
||||||
// Pick a single value for our randomness
|
}
|
||||||
setPercent(ship, m, Math.random() * 100);
|
|
||||||
}
|
cb(featureName, value);
|
||||||
|
}
|
||||||
/**
|
}
|
||||||
* Provide 'percent' primary query
|
|
||||||
* @param {Object} m The module for which to perform the query
|
/**
|
||||||
* @returns {Number} percent The percentage indicator of current applied values.
|
* Provide 'random' primary modifications
|
||||||
*/
|
* @param {Object} ship The ship for which to perform the modifications
|
||||||
export function getPercent(m) {
|
* @param {Object} m The module for which to perform the modifications
|
||||||
let result = null;
|
*/
|
||||||
const features = m.blueprint.grades[m.blueprint.grade].features;
|
export function setRandom(ship, m) {
|
||||||
for (const featureName in features) {
|
// Pick a single value for our randomness
|
||||||
if (features[featureName][0] === features[featureName][1]) {
|
setPercent(ship, m, Math.random() * 100);
|
||||||
continue;
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
let value = _getValue(m, featureName);
|
* Provide 'percent' primary query
|
||||||
let mult;
|
* @param {Object} m The module for which to perform the query
|
||||||
if (Modifications.modifications[featureName].higherbetter) {
|
* @returns {Number} percent The percentage indicator of current applied values.
|
||||||
// Higher is better, but is this making it better or worse?
|
*/
|
||||||
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
export function getPercent(m) {
|
||||||
mult = Math.round((value - features[featureName][1]) / (features[featureName][0] - features[featureName][1]) * 100);
|
let result = null;
|
||||||
} else {
|
const features = m.blueprint.grades[m.blueprint.grade].features;
|
||||||
mult = Math.round((value - features[featureName][0]) / (features[featureName][1] - features[featureName][0]) * 100);
|
for (const featureName in features) {
|
||||||
}
|
if (features[featureName][0] === features[featureName][1]) {
|
||||||
} else {
|
continue;
|
||||||
// Higher is worse, but is this making it better or worse?
|
}
|
||||||
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
|
||||||
mult = Math.round((value - features[featureName][0]) / (features[featureName][1] - features[featureName][0]) * 100);
|
let value = _getValue(m, featureName);
|
||||||
} else {
|
let mult;
|
||||||
mult = Math.round((value - features[featureName][1]) / (features[featureName][0] - features[featureName][1]) * 100);
|
if (Modifications.modifications[featureName].higherbetter) {
|
||||||
}
|
// Higher is better, but is this making it better or worse?
|
||||||
}
|
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
||||||
|
mult = Math.round((value - features[featureName][1]) / (features[featureName][0] - features[featureName][1]) * 100);
|
||||||
if (result && result != mult) {
|
} else {
|
||||||
return null;
|
mult = Math.round((value - features[featureName][0]) / (features[featureName][1] - features[featureName][0]) * 100);
|
||||||
} else if (result != mult) {
|
}
|
||||||
result = mult;
|
} else {
|
||||||
}
|
// Higher is worse, but is this making it better or worse?
|
||||||
}
|
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
||||||
|
mult = Math.round((value - features[featureName][0]) / (features[featureName][1] - features[featureName][0]) * 100);
|
||||||
return result;
|
} else {
|
||||||
}
|
mult = Math.round((value - features[featureName][1]) / (features[featureName][0] - features[featureName][1]) * 100);
|
||||||
|
}
|
||||||
/**
|
}
|
||||||
* Query a feature value
|
|
||||||
* @param {Object} m The module for which to perform the query
|
if (result && result != mult) {
|
||||||
* @param {string} featureName The feature being queried
|
return null;
|
||||||
* @returns {number} The value of the modification as a %
|
} else if (result != mult) {
|
||||||
*/
|
result = mult;
|
||||||
function _getValue(m, featureName) {
|
}
|
||||||
if (Modifications.modifications[featureName].type == 'percentage') {
|
}
|
||||||
return m.getModValue(featureName, true) / 10000;
|
|
||||||
} else if (Modifications.modifications[featureName].type == 'numeric') {
|
return result;
|
||||||
return m.getModValue(featureName, true) / 100;
|
}
|
||||||
} else {
|
|
||||||
return m.getModValue(featureName, true);
|
/**
|
||||||
}
|
* Query a feature value
|
||||||
}
|
* @param {Object} m The module for which to perform the query
|
||||||
|
* @param {string} featureName The feature being queried
|
||||||
|
* @returns {number} The value of the modification as a %
|
||||||
|
*/
|
||||||
|
function _getValue(m, featureName) {
|
||||||
|
if (Modifications.modifications[featureName].type == 'percentage') {
|
||||||
|
return m.getModValue(featureName, true) / 10000;
|
||||||
|
} else if (Modifications.modifications[featureName].type == 'numeric') {
|
||||||
|
return m.getModValue(featureName, true) / 100;
|
||||||
|
} else {
|
||||||
|
return m.getModValue(featureName, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ export const SHIP_FD_NAME_TO_CORIOLIS_NAME = {
|
|||||||
'Independant_Trader': 'keelback',
|
'Independant_Trader': 'keelback',
|
||||||
'Krait_MkII': 'krait_mkii',
|
'Krait_MkII': 'krait_mkii',
|
||||||
'Mamba': 'mamba',
|
'Mamba': 'mamba',
|
||||||
|
'Mandalay': 'mandalay',
|
||||||
'Krait_Light': 'krait_phantom',
|
'Krait_Light': 'krait_phantom',
|
||||||
'Orca': 'orca',
|
'Orca': 'orca',
|
||||||
'Python': 'python',
|
'Python': 'python',
|
||||||
@@ -38,6 +39,7 @@ export const SHIP_FD_NAME_TO_CORIOLIS_NAME = {
|
|||||||
'SideWinder': 'sidewinder',
|
'SideWinder': 'sidewinder',
|
||||||
'Type6': 'type_6_transporter',
|
'Type6': 'type_6_transporter',
|
||||||
'Type7': 'type_7_transport',
|
'Type7': 'type_7_transport',
|
||||||
|
'Type8': 'type_8_transport',
|
||||||
'Type9': 'type_9_heavy',
|
'Type9': 'type_9_heavy',
|
||||||
'Type9_Military': 'type_10_defender',
|
'Type9_Military': 'type_10_defender',
|
||||||
'TypeX': 'alliance_chieftain',
|
'TypeX': 'alliance_chieftain',
|
||||||
|
|||||||
@@ -6,6 +6,22 @@ import { Modules } from 'coriolis-data/dist';
|
|||||||
import { Modifications } from 'coriolis-data/dist';
|
import { Modifications } from 'coriolis-data/dist';
|
||||||
import { getBlueprint, setQualityCB } from './BlueprintFunctions';
|
import { getBlueprint, setQualityCB } from './BlueprintFunctions';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an imported module is valid
|
||||||
|
* @param {Object} module the module to check
|
||||||
|
* @param {Object} moduleType the type of module to check
|
||||||
|
* @return {boolean} true if the module is valid
|
||||||
|
*/
|
||||||
|
function _isValidImportedModule(module, moduleType) {
|
||||||
|
// First of all, has the _moduleFromFdName function returned 'null'?
|
||||||
|
if (!module){
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain a module given its FD Name
|
* Obtain a module given its FD Name
|
||||||
* @param {string} fdname the FD Name of the module
|
* @param {string} fdname the FD Name of the module
|
||||||
@@ -98,49 +114,90 @@ export function shipFromLoadoutJSON(json) {
|
|||||||
if (module.Engineering) _addModifications(ship.bulkheads.m, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
if (module.Engineering) _addModifications(ship.bulkheads.m, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
||||||
break;
|
break;
|
||||||
case 'powerplant':
|
case 'powerplant':
|
||||||
const powerplant = _moduleFromFdName(module.Item);
|
let powerplant = _moduleFromFdName(module.Item);
|
||||||
|
// Check the powerplant returned is valid
|
||||||
|
if (!_isValidImportedModule(powerplant, 'powerplant'))
|
||||||
|
{
|
||||||
|
powerplant = _moduleFromFdName('Int_Missing_Powerplant');
|
||||||
|
module.Engineering = null;
|
||||||
|
}
|
||||||
ship.use(ship.standard[0], powerplant, true);
|
ship.use(ship.standard[0], powerplant, true);
|
||||||
ship.standard[0].enabled = module.On;
|
ship.standard[0].enabled = module.On;
|
||||||
ship.standard[0].priority = module.Priority;
|
ship.standard[0].priority = module.Priority;
|
||||||
if (module.Engineering) _addModifications(powerplant, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
if (module.Engineering) _addModifications(powerplant, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
||||||
break;
|
break;
|
||||||
case 'mainengines':
|
case 'mainengines':
|
||||||
const thrusters = _moduleFromFdName(module.Item);
|
let thrusters = _moduleFromFdName(module.Item);
|
||||||
|
// Check the thrusters returned is valid
|
||||||
|
if (!_isValidImportedModule(thrusters, 'thrusters'))
|
||||||
|
{
|
||||||
|
thrusters = _moduleFromFdName('Int_Missing_Engine');
|
||||||
|
module.Engineering = null;
|
||||||
|
}
|
||||||
ship.use(ship.standard[1], thrusters, true);
|
ship.use(ship.standard[1], thrusters, true);
|
||||||
ship.standard[1].enabled = module.On;
|
ship.standard[1].enabled = module.On;
|
||||||
ship.standard[1].priority = module.Priority;
|
ship.standard[1].priority = module.Priority;
|
||||||
if (module.Engineering) _addModifications(thrusters, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
if (module.Engineering) _addModifications(thrusters, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
||||||
break;
|
break;
|
||||||
case 'frameshiftdrive':
|
case 'frameshiftdrive':
|
||||||
const frameshiftdrive = _moduleFromFdName(module.Item);
|
let frameshiftdrive = _moduleFromFdName(module.Item);
|
||||||
|
// Check the frameshiftdrive returned is valid
|
||||||
|
if (!_isValidImportedModule(frameshiftdrive, 'frameshiftdrive'))
|
||||||
|
{
|
||||||
|
frameshiftdrive = _moduleFromFdName('Int_Missing_Hyperdrive');
|
||||||
|
module.Engineering = null;
|
||||||
|
}
|
||||||
ship.use(ship.standard[2], frameshiftdrive, true);
|
ship.use(ship.standard[2], frameshiftdrive, true);
|
||||||
ship.standard[2].enabled = module.On;
|
ship.standard[2].enabled = module.On;
|
||||||
ship.standard[2].priority = module.Priority;
|
ship.standard[2].priority = module.Priority;
|
||||||
if (module.Engineering) _addModifications(frameshiftdrive, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
if (module.Engineering) _addModifications(frameshiftdrive, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
||||||
break;
|
break;
|
||||||
case 'lifesupport':
|
case 'lifesupport':
|
||||||
const lifesupport = _moduleFromFdName(module.Item);
|
let lifesupport = _moduleFromFdName(module.Item);
|
||||||
|
// Check the lifesupport returned is valid
|
||||||
|
if (!_isValidImportedModule(lifesupport, 'lifesupport'))
|
||||||
|
{
|
||||||
|
lifesupport = _moduleFromFdName('Int_Missing_LifeSupport');
|
||||||
|
module.Engineering = null;
|
||||||
|
}
|
||||||
ship.use(ship.standard[3], lifesupport, true);
|
ship.use(ship.standard[3], lifesupport, true);
|
||||||
ship.standard[3].enabled = module.On === true;
|
ship.standard[3].enabled = module.On === true;
|
||||||
ship.standard[3].priority = module.Priority;
|
ship.standard[3].priority = module.Priority;
|
||||||
if (module.Engineering) _addModifications(lifesupport, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
if (module.Engineering) _addModifications(lifesupport, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
||||||
break;
|
break;
|
||||||
case 'powerdistributor':
|
case 'powerdistributor':
|
||||||
const powerdistributor = _moduleFromFdName(module.Item);
|
let powerdistributor = _moduleFromFdName(module.Item);
|
||||||
|
// Check the powerdistributor returned is valid
|
||||||
|
if (!_isValidImportedModule(powerdistributor, 'powerdistributor'))
|
||||||
|
{
|
||||||
|
powerdistributor = _moduleFromFdName('Int_Missing_PowerDistributor');
|
||||||
|
module.Engineering = null;
|
||||||
|
}
|
||||||
ship.use(ship.standard[4], powerdistributor, true);
|
ship.use(ship.standard[4], powerdistributor, true);
|
||||||
ship.standard[4].enabled = module.On;
|
ship.standard[4].enabled = module.On;
|
||||||
ship.standard[4].priority = module.Priority;
|
ship.standard[4].priority = module.Priority;
|
||||||
if (module.Engineering) _addModifications(powerdistributor, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
if (module.Engineering) _addModifications(powerdistributor, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
||||||
break;
|
break;
|
||||||
case 'radar':
|
case 'radar':
|
||||||
const sensors = _moduleFromFdName(module.Item);
|
let sensors = _moduleFromFdName(module.Item);
|
||||||
|
// Check the sensors returned is valid
|
||||||
|
if (!_isValidImportedModule(sensors, 'sensors'))
|
||||||
|
{
|
||||||
|
sensors = _moduleFromFdName('Int_Missing_Sensors');
|
||||||
|
module.Engineering = null;
|
||||||
|
}
|
||||||
ship.use(ship.standard[5], sensors, true);
|
ship.use(ship.standard[5], sensors, true);
|
||||||
ship.standard[5].enabled = module.On;
|
ship.standard[5].enabled = module.On;
|
||||||
ship.standard[5].priority = module.Priority;
|
ship.standard[5].priority = module.Priority;
|
||||||
if (module.Engineering) _addModifications(sensors, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
if (module.Engineering) _addModifications(sensors, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
||||||
break;
|
break;
|
||||||
case 'fueltank':
|
case 'fueltank':
|
||||||
const fueltank = _moduleFromFdName(module.Item);
|
let fueltank = _moduleFromFdName(module.Item);
|
||||||
|
// Check the fueltank returned is valid
|
||||||
|
if (!_isValidImportedModule(fueltank, 'fueltank'))
|
||||||
|
{
|
||||||
|
fueltank = _moduleFromFdName('Int_Missing_FuelTank');
|
||||||
|
}
|
||||||
ship.use(ship.standard[6], fueltank, true);
|
ship.use(ship.standard[6], fueltank, true);
|
||||||
ship.standard[6].enabled = true;
|
ship.standard[6].enabled = true;
|
||||||
ship.standard[6].priority = 0;
|
ship.standard[6].priority = 0;
|
||||||
@@ -170,10 +227,27 @@ export function shipFromLoadoutJSON(json) {
|
|||||||
// This can happen with old imports that don't contain new hardpoints
|
// This can happen with old imports that don't contain new hardpoints
|
||||||
} else {
|
} else {
|
||||||
hardpoint = _moduleFromFdName(hardpointSlot.Item);
|
hardpoint = _moduleFromFdName(hardpointSlot.Item);
|
||||||
ship.use(ship.hardpoints[hardpointArrayNum], hardpoint, true);
|
// Check the hardpoint module returned is valid
|
||||||
ship.hardpoints[hardpointArrayNum].enabled = hardpointSlot.On;
|
if (!_isValidImportedModule(hardpoint, 'hardpoint')){
|
||||||
ship.hardpoints[hardpointArrayNum].priority = hardpointSlot.Priority;
|
// Check if it's a Utility or Hardpoint
|
||||||
modsToAdd.push({ coriolisMod: hardpoint, json: hardpointSlot });
|
if (hardpointSlot.Slot.toLowerCase().search(/tiny/))
|
||||||
|
{
|
||||||
|
// Use the missing_hardpoint module 'Missing Hardpoint' which will inform the user that the module is missing
|
||||||
|
hardpoint = _moduleFromFdName('Hpt_Missing_Hardpoint');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Use the missing_hardpoint module 'Missing Utility' which will inform the user that the module is missing
|
||||||
|
hardpoint = _moduleFromFdName('Hpt_Missing_Utility');
|
||||||
|
}
|
||||||
|
ship.use(ship.hardpoints[hardpointArrayNum], hardpoint, true);
|
||||||
|
ship.hardpoints[hardpointArrayNum].enabled = hardpointSlot.On;
|
||||||
|
ship.hardpoints[hardpointArrayNum].priority = hardpointSlot.Priority;
|
||||||
|
} else {
|
||||||
|
ship.use(ship.hardpoints[hardpointArrayNum], hardpoint, true);
|
||||||
|
ship.hardpoints[hardpointArrayNum].enabled = hardpointSlot.On;
|
||||||
|
ship.hardpoints[hardpointArrayNum].priority = hardpointSlot.Priority;
|
||||||
|
modsToAdd.push({ coriolisMod: hardpoint, json: hardpointSlot });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
hardpointArrayNum++;
|
hardpointArrayNum++;
|
||||||
}
|
}
|
||||||
@@ -187,13 +261,17 @@ export function shipFromLoadoutJSON(json) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const isMilitary = isNaN(shipTemplate.slots.internal[i]) ? shipTemplate.slots.internal[i].name == 'Military' : false;
|
const isMilitary = isNaN(shipTemplate.slots.internal[i]) ? shipTemplate.slots.internal[i].name == 'Military' : false;
|
||||||
|
const isPlanetary = isNaN(shipTemplate.slots.internal[i]) ? shipTemplate.slots.internal[i].name == 'PlanetaryApproachSuite' : false;
|
||||||
|
|
||||||
// The internal slot might be a standard or a military slot. Military slots have a different naming system
|
// The internal slot might be a standard or a military slot, or a planetary slot. Military and Planetary slots have a different naming system
|
||||||
let internalSlot = null;
|
let internalSlot = null;
|
||||||
if (isMilitary) {
|
if (isMilitary) {
|
||||||
const internalName = 'Military0' + militarySlotNum;
|
const internalName = 'Military0' + militarySlotNum;
|
||||||
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase());
|
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase());
|
||||||
militarySlotNum++;
|
militarySlotNum++;
|
||||||
|
} else if (isPlanetary) {
|
||||||
|
const internalName = 'PlanetaryApproachSuite';
|
||||||
|
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase());
|
||||||
} else {
|
} else {
|
||||||
// Slot numbers are not contiguous so handle skips.
|
// Slot numbers are not contiguous so handle skips.
|
||||||
for (; internalSlot === null && internalSlotNum < 99; internalSlotNum++) {
|
for (; internalSlot === null && internalSlotNum < 99; internalSlotNum++) {
|
||||||
@@ -212,11 +290,22 @@ export function shipFromLoadoutJSON(json) {
|
|||||||
// This can happen with old imports that don't contain new slots
|
// This can happen with old imports that don't contain new slots
|
||||||
} else {
|
} else {
|
||||||
const internalJson = internalSlot;
|
const internalJson = internalSlot;
|
||||||
const internal = _moduleFromFdName(internalJson.Item);
|
let internal = _moduleFromFdName(internalJson.Item);
|
||||||
ship.use(ship.internal[i], internal, true);
|
// Check the internal module returned is valid
|
||||||
ship.internal[i].enabled = internalJson.On === true;
|
if (!_isValidImportedModule(internal, 'internal'))
|
||||||
ship.internal[i].priority = internalJson.Priority;
|
{
|
||||||
modsToAdd.push({ coriolisMod: internal, json: internalSlot });
|
internal = _moduleFromFdName('Int_Missing_Module');
|
||||||
|
ship.use(ship.internal[i], internal, true);
|
||||||
|
ship.internal[i].enabled = internalJson.On === true;
|
||||||
|
ship.internal[i].priority = internalJson.Priority;
|
||||||
|
//throw 'Unknown internal module: "' + module.Item + '"';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ship.use(ship.internal[i], internal, true);
|
||||||
|
ship.internal[i].enabled = internalJson.On === true;
|
||||||
|
ship.internal[i].priority = internalJson.Priority;
|
||||||
|
modsToAdd.push({ coriolisMod: internal, json: internalSlot });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,6 +349,7 @@ function _addModifications(module, modifiers, quality, blueprint, grade, special
|
|||||||
// Add the blueprint definition, grade and special
|
// Add the blueprint definition, grade and special
|
||||||
if (blueprint) {
|
if (blueprint) {
|
||||||
module.blueprint = getBlueprint(blueprint, module);
|
module.blueprint = getBlueprint(blueprint, module);
|
||||||
|
|
||||||
if (grade) {
|
if (grade) {
|
||||||
module.blueprint.grade = Number(grade);
|
module.blueprint.grade = Number(grade);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -183,4 +183,5 @@ footer {
|
|||||||
.announcement {
|
.announcement {
|
||||||
border: 1px @secondary solid;
|
border: 1px @secondary solid;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
margin: 5px;
|
||||||
|
}
|
||||||
@@ -41,24 +41,67 @@
|
|||||||
h2 {
|
h2 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
h4 {
|
||||||
background: @primary-bg;
|
text-transform: uppercase;
|
||||||
border: none;
|
font-family: @fStandard;
|
||||||
outline: none;
|
font-weight: normal;
|
||||||
color: @primary-disabled;
|
font-size: 1em;
|
||||||
|
margin: 1em;
|
||||||
&.json {
|
color: @warning;
|
||||||
display:block;
|
|
||||||
width:100%;
|
|
||||||
min-height: 10em;
|
|
||||||
resize: vertical;
|
|
||||||
user-select: text;
|
|
||||||
margin:2em 0;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.dismiss {
|
p {
|
||||||
background-color: @primary-bg;
|
margin: 1em;
|
||||||
}
|
text-wrap: pretty;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
clear: bottom;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
clear: both;
|
||||||
|
margin: 15px, 10px, 15px, 10px;
|
||||||
|
padding: top, 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
clear: bottom;
|
||||||
|
margin: 10px;
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
clear: bottom;
|
||||||
|
margin: 20px;
|
||||||
|
color: @primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.groll {
|
||||||
|
width: 6%;
|
||||||
|
margin: 5px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
background: @primary-bg;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
color: @primary-disabled;
|
||||||
|
|
||||||
|
&.json {
|
||||||
|
display:block;
|
||||||
|
width:100%;
|
||||||
|
min-height: 10em;
|
||||||
|
resize: vertical;
|
||||||
|
user-select: text;
|
||||||
|
margin:1em 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dismiss {
|
||||||
|
background-color: @primary-bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ const path = require('path');
|
|||||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
const { InjectManifest } = require('workbox-webpack-plugin');
|
const { InjectManifest } = require('workbox-webpack-plugin');
|
||||||
|
const { max } = require('lodash');
|
||||||
|
|
||||||
module.exports = merge(common, {
|
module.exports = merge(common, {
|
||||||
// devtool: 'source-map',
|
// devtool: 'source-map',
|
||||||
@@ -18,9 +19,9 @@ module.exports = merge(common, {
|
|||||||
plugins: [
|
plugins: [
|
||||||
new CopyWebpackPlugin({
|
new CopyWebpackPlugin({
|
||||||
patterns: [
|
patterns: [
|
||||||
'src/.htaccess',
|
'src/.htaccess',
|
||||||
'src/iframe.html',
|
'src/iframe.html',
|
||||||
'src/xdLocalStoragePostMessageApi.min.js',
|
'src/xdLocalStoragePostMessageApi.min.js',
|
||||||
{ from: 'src/schemas', to: 'schemas' },
|
{ from: 'src/schemas', to: 'schemas' },
|
||||||
{
|
{
|
||||||
from: 'src/images/logo/*',
|
from: 'src/images/logo/*',
|
||||||
@@ -42,11 +43,11 @@ module.exports = merge(common, {
|
|||||||
// overwrite: true,
|
// overwrite: true,
|
||||||
// appVersion: `${pkgJson.version}-${buildDate.toISOString()}`
|
// appVersion: `${pkgJson.version}-${buildDate.toISOString()}`
|
||||||
// }),
|
// }),
|
||||||
|
|
||||||
new InjectManifest({
|
new InjectManifest({
|
||||||
swSrc: './src/sw.js',
|
swSrc: './src/sw.js',
|
||||||
swDest: 'service-worker.js'
|
swDest: 'service-worker.js'
|
||||||
}),
|
}),
|
||||||
|
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user