import React from 'react';
import PropTypes from 'prop-types';
import { chain, flatMap, keys } from 'lodash';
import TranslatedComponent from './TranslatedComponent';
import { stopCtxPropagation } from '../utils/UtilityFunctions';
import cn from 'classnames';
import Modification from './Modification';
import {
blueprintTooltip,
specialToolTip
} from '../utils/BlueprintFunctions';
import { getBlueprintInfo, getExperimentalInfo } from 'ed-forge/lib/src/data/blueprints';
import { getModuleInfo } from 'ed-forge/lib/src/data/items';
import { SHOW } from '../shipyard/StatsMapping';
/**
* Modifications menu
*/
export default class ModificationsMenu extends TranslatedComponent {
static propTypes = {
className: PropTypes.string,
m: PropTypes.object.isRequired,
propsToShow: PropTypes.object.isRequired,
onPropToggle: PropTypes.func.isRequired,
};
/**
* Constructor
* @param {Object} props React Component properties
* @param {Object} context React Component context
*/
constructor(props, context) {
super(props);
this._toggleBlueprintsMenu = this._toggleBlueprintsMenu.bind(this);
this._toggleSpecialsMenu = this._toggleSpecialsMenu.bind(this);
this.selectedModRef = null;
this.selectedSpecialRef = null;
const { m } = props;
this.state = {
blueprintProgress: m.getBlueprintProgress(),
blueprintMenuOpened: !m.getBlueprint(),
specialMenuOpened: false
};
}
/**
* Render the blueprints
* @return {Object} list: Array of React Components
*/
_renderBlueprints() {
const { m } = this.props;
const { language, tooltip, termtip } = this.context;
const { translate } = language;
const blueprints = m.getApplicableBlueprints().map(blueprint => {
const info = getBlueprintInfo(blueprint);
let blueprintGrades = keys(info.features).map(grade => {
// Grade is a string in the JSON so make it a number
grade = Number(grade);
const active = m.getBlueprint() === blueprint && m.getBlueprintGrade() === grade;
const key = blueprint + ':' + grade;
return
{
m.setBlueprint(blueprint, grade, 1);
this.setState({
blueprintMenuOpened: false,
specialMenuOpened: true,
});
}}
ref={active ? (ref) => { this.selectedModRef = ref; } : undefined}
>{grade};
});
return [
{translate(blueprint)}
,
];
});
return flatMap(blueprints);
}
/**
* Render the specials
* @param {Object} props React component properties
* @param {Object} context React component context
* @return {Object} list: Array of React Components
*/
_renderSpecials() {
const { m } = this.props;
const { language, tooltip, termtip } = this.context;
const translate = language.translate;
const applied = m.getExperimental();
const experimentals = [];
for (const experimental of m.getApplicableExperimentals()) {
const active = experimental === applied;
let specialTt = specialToolTip(language, m, experimental);
experimentals.push(
{ this.selectedSpecialRef = ref; } : undefined}
onMouseOver={termtip.bind(null, specialTt)}
onMouseOut={tooltip.bind(null, null)}
>{translate(experimental)}
);
}
if (experimentals.length) {
experimentals.unshift(
{ this.selectedSpecialRef = ref; } : undefined}
>{translate('PHRASE_NO_SPECIAL')}
);
}
return experimentals;
}
/**
* Create a modification component
*/
_mkModification(property, highlight) {
const { translate } = this.context.language;
const { m, propsToShow, onPropToggle } = this.props;
let onSet = m.set.bind(m);
// Show resistance instead of effectiveness
const mapped = SHOW[property];
if (mapped) {
property = mapped.as;
onSet = mapped.setter.bind(undefined, m);
}
return [
|
{translate(property)}
|
,
];
}
/**
* Render the modifications
* @return {Array} Array of React Components
*/
_renderModifications() {
const { m } = this.props;
const blueprintFeatures = getBlueprintInfo(m.getBlueprint()).features[
m.getBlueprintGrade()
];
const blueprintModifications = chain(keys(blueprintFeatures))
.map((feature) => this._mkModification(feature, true))
.filter(([_, mod]) => Boolean(mod))
.flatMap()
.value();
const moduleModifications = chain(keys(getModuleInfo(m.getItem()).props))
.filter((prop) => !blueprintFeatures[prop])
.map((prop) => this._mkModification(prop, false))
.flatMap()
.value();
return blueprintModifications.concat(moduleModifications);
}
/**
* Toggle the blueprints menu
*/
_toggleBlueprintsMenu() {
this.setState({ blueprintMenuOpened: !this.state.blueprintMenuOpened });
}
/**
* Toggle the specials menu
*/
_toggleSpecialsMenu() {
this.setState({ specialMenuOpened: !this.state.specialMenuOpened });
}
/**
* Creates a callback for when a special effect is being selected
* @param {string} special The name of the selected special
* @returns {function} Callback
*/
_specialSelected(special) {
return () => {
const { m } = this.props;
m.setExperimental(special);
this.setState({ specialMenuOpened: false });
};
}
/**
* Set focus on first element in modifications menu
* if component updates, unless update is due to value change
* in a modification
*/
componentDidUpdate() {
if (this.selectedModRef) {
this.selectedModRef.focus();
return;
} else if (this.selectedSpecialRef) {
this.selectedSpecialRef.focus();
return;
}
}
/**
* Render the list
* @return {React.Component} List
*/
render() {
const { language, tooltip, termtip } = this.context;
const translate = language.translate;
const { m } = this.props;
const {
blueprintProgress, blueprintMenuOpened, specialMenuOpened,
} = this.state;
const appliedBlueprint = m.getBlueprint();
const appliedGrade = m.getBlueprintGrade();
const appliedExperimental = m.getExperimental();
let renderComponents = [];
switch (true) {
case !appliedBlueprint || blueprintMenuOpened:
renderComponents = this._renderBlueprints();
break;
case specialMenuOpened:
renderComponents = this._renderSpecials();
break;
default:
// Since the first case didn't apply, there is a blueprint applied so
// we render the modifications
let blueprintTt = blueprintTooltip(language, m, appliedBlueprint, appliedGrade);
renderComponents.push(
{translate(appliedBlueprint)} {translate('grade')} {appliedGrade}
);
if (m.getApplicableExperimentals().length) {
let specialLabel = translate('PHRASE_SELECT_SPECIAL');
let specialTt;
if (appliedExperimental) {
specialLabel = appliedExperimental;
specialTt = specialToolTip(language, m, appliedExperimental);
}
renderComponents.push(
{specialLabel}
);
}
renderComponents.push(
{
m.resetEngineering();
this.selectedModRef = null;
this.selectedSpecialRef = null;
tooltip(null);
this.setState({
blueprintMenuOpened: true,
blueprintProgress: undefined,
});
}}
onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_RESET')}
onMouseOut={tooltip.bind(null, null)}
>{translate('reset')}
,
| {translate('mroll')}: |
{
m.setBlueprintProgress(0);
this.setState({ blueprintProgress: 0 });
}}
onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_WORST')}
onMouseOut={tooltip.bind(null, null)}
>{translate('0%')} |
{
m.setBlueprintProgress(0.5);
this.setState({ blueprintProgress: 0.5 });
}}
onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_FIFTY')}
onMouseOut={tooltip.bind(null, null)}
>{translate('50%')} |
{
m.setBlueprintProgress(1);
this.setState({ blueprintProgress: 1 });
}}
onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_BEST')}
onMouseOut={tooltip.bind(null, null)}
>{translate('100%')} |
{
const blueprintProgress = Math.random();
m.setBlueprintProgress(blueprintProgress);
this.setState({ blueprintProgress });
}}
onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_RANDOM')}
onMouseOut={tooltip.bind(null, null)}
>{translate('random')} |
,
,
{this._renderModifications()}
);
}
return (
e.stopPropagation()}
onContextMenu={stopCtxPropagation}
>
{renderComponents}
);
}
}