mirror of
https://github.com/EDCD/coriolis.git
synced 2025-12-08 22:33:24 +00:00
Adds valid module checking to all types of modules on import
This commit is contained in:
@@ -213,16 +213,30 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
||||
if (categories.length === 1) {
|
||||
// Show category header instead of group header
|
||||
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>);
|
||||
}
|
||||
} else {
|
||||
list.push(<div key={category} className={'select-category upp'}>{translate(category)}</div>);
|
||||
if (category == "mh"){
|
||||
continue;
|
||||
} else {
|
||||
list.push(<div key={category} className={'select-category upp'}>{translate(category)}</div>);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Show category header as well as group header
|
||||
if (!categoryHeader) {
|
||||
list.push(<div key={category} className={'select-category upp'}>{translate(category)}</div>);
|
||||
categoryHeader = true;
|
||||
if (category == "mh"){
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
list.push(<div key={category} className={'select-category upp'}>{translate(category)}</div>);
|
||||
categoryHeader = true;
|
||||
}
|
||||
}
|
||||
if (m && grp == m.grp) {
|
||||
list.push(<div ref={(elem) => this.groupElem = elem} key={grp}
|
||||
@@ -298,6 +312,10 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
||||
let itemsOnThisRow = 0;
|
||||
for (let i = 0; i < sortedModules.length; i++) {
|
||||
let m = sortedModules[i];
|
||||
if (ModuleUtils.isMissingModule(m.info)) {
|
||||
// If this is a missing module, skip it
|
||||
continue;
|
||||
}
|
||||
let mount = null;
|
||||
let disabled = false;
|
||||
prevName = m.name;
|
||||
@@ -312,6 +330,7 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
||||
disabled = 1 <= ship.internal.filter(o => o.m && o.m.grp === 'mlc').length;
|
||||
}
|
||||
let active = mountedModule && mountedModule.id === m.id;
|
||||
|
||||
let classes = cn(m.name ? 'lc' : 'c', {
|
||||
warning: !disabled && warningFunc && warningFunc(m),
|
||||
active,
|
||||
|
||||
@@ -136,6 +136,7 @@ export default class HardpointSlot extends Slot {
|
||||
{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.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)}>
|
||||
|
||||
@@ -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.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.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 }
|
||||
</div>
|
||||
</div>;
|
||||
|
||||
@@ -99,6 +99,7 @@ export default class Slot extends TranslatedComponent {
|
||||
let translate = language.translate;
|
||||
let { ship, m, enabled, dropClass, dragOver, onOpen, onChange, selected, eligible, onSelect, warning, availableModules } = this.props;
|
||||
let slotDetails, modificationsMarker, menu;
|
||||
let missing = false;
|
||||
|
||||
if (!selected) {
|
||||
// If not selected then sure that modifications flag is unset
|
||||
@@ -108,6 +109,11 @@ export default class Slot extends TranslatedComponent {
|
||||
if (m) {
|
||||
slotDetails = this._getSlotDetails(m, enabled, translate, language.formats, language.units); // Must be implemented by sub classes
|
||||
modificationsMarker = JSON.stringify(m);
|
||||
if(typeof m.grp !== 'undefined' || m.grp !== null) {
|
||||
if(m.grp == "mh" || m.grp == "mm") {
|
||||
missing = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
slotDetails = <div className={'empty'}>{translate(eligible ? 'emptyrestricted' : 'empty')}</div>;
|
||||
modificationsMarker = '';
|
||||
@@ -138,13 +144,16 @@ export default class Slot extends TranslatedComponent {
|
||||
}
|
||||
|
||||
// TODO: implement touch dragging
|
||||
|
||||
|
||||
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='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>
|
||||
{slotDetails}
|
||||
</div>
|
||||
</div>
|
||||
{menu}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -93,6 +93,10 @@ export default class StandardSlot extends TranslatedComponent {
|
||||
this._modificationsSelected = false;
|
||||
}
|
||||
|
||||
if (m.info) {
|
||||
warning = () => true;
|
||||
}
|
||||
|
||||
const modificationsMarker = JSON.stringify(m);
|
||||
|
||||
if (selected) {
|
||||
@@ -124,7 +128,7 @@ export default class StandardSlot extends TranslatedComponent {
|
||||
<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>
|
||||
<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/>
|
||||
<div className={'cb'}>
|
||||
@@ -144,7 +148,8 @@ export default class StandardSlot extends TranslatedComponent {
|
||||
{ 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 }
|
||||
{ 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>
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
"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_FIREFOX_EDENGINEER": "Sending to EDEngineer is not compatible with Firefox's security settings. Please try again with Chrome.",
|
||||
"MISSING_MODULES": "Missing Modules",
|
||||
"am": "Auto Field-Maintenance Unit",
|
||||
"bh": "Bulkheads",
|
||||
"bl": "Beam Laser",
|
||||
@@ -109,6 +110,8 @@
|
||||
"kw": "Kill Warrant Scanner",
|
||||
"ls": "Life Support",
|
||||
"mc": "Multi-cannon",
|
||||
"mh": "Missing Weapon/Utility",
|
||||
"mm": "Missing Module",
|
||||
"axmc": "AX Multi-cannon",
|
||||
"ml": "Mining Laser",
|
||||
"mlc": "Multi Limpet Controller",
|
||||
@@ -212,6 +215,7 @@
|
||||
"boost interval": "Boost interval",
|
||||
"total": "Total",
|
||||
"ammo": "Ammunition maximum",
|
||||
"info": "Info",
|
||||
"boot": "Boot time",
|
||||
"hacktime": "Hack time",
|
||||
"brokenregen": "Broken regeneration rate",
|
||||
|
||||
@@ -45,6 +45,9 @@ export default class ErrorDetails extends React.Component {
|
||||
return <div className='error'>
|
||||
<h1>Jameson, we have a problem..</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/>
|
||||
{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/>
|
||||
|
||||
@@ -439,6 +439,15 @@ export default class Module {
|
||||
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
|
||||
* @param {Boolean} [modified=true] Whether to take modifications into account
|
||||
|
||||
@@ -322,6 +322,15 @@ export function isShieldGenerator(g) {
|
||||
return g == 'sg' || g == 'psg' || g == 'bsg';
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a module group is a missing module
|
||||
* @param {String} info Module Group name
|
||||
* @return {Boolean} True if the group is a missing module
|
||||
*/
|
||||
export function isMissingModule(info) {
|
||||
return info == 'Not in Coriolis yet. Check GitHub issues. Add Issue if needed.';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ModuleSet that contains all available modules
|
||||
* that the specified ship is eligible to use.
|
||||
|
||||
@@ -1,435 +1,435 @@
|
||||
import React from 'react';
|
||||
import { Modifications } from 'coriolis-data/dist';
|
||||
import { STATS_FORMATTING } from '../shipyard/StatsFormatting';
|
||||
|
||||
/**
|
||||
* Generate a tooltip with details of a blueprint's specials
|
||||
* @param {Object} translate The translate object
|
||||
* @param {Object} blueprint The blueprint at the required grade
|
||||
* @param {string} grp The group of the module
|
||||
* @param {Object} m The module to compare with
|
||||
* @param {string} specialName The name of the special
|
||||
* @returns {Object} The react components
|
||||
*/
|
||||
export function specialToolTip(translate, blueprint, grp, m, specialName) {
|
||||
const effects = [];
|
||||
if (!blueprint || !blueprint.features) {
|
||||
return undefined;
|
||||
}
|
||||
if (m) {
|
||||
// We also add in any benefits from specials that aren't covered above
|
||||
if (m.blueprint) {
|
||||
for (const feature in Modifications.modifierActions[specialName]) {
|
||||
// if (!blueprint.features[feature] && !m.mods.feature) {
|
||||
const featureDef = Modifications.modifications[feature];
|
||||
if (featureDef && !featureDef.hidden) {
|
||||
let symbol = '';
|
||||
if (feature === 'jitter') {
|
||||
symbol = '°';
|
||||
} else if (featureDef.type === 'percentage') {
|
||||
symbol = '%';
|
||||
}
|
||||
let current = m.getModValue(feature) - m.getModValue(feature, true);
|
||||
if (featureDef.type === 'percentage') {
|
||||
current = Math.round(current / 10) / 10;
|
||||
} else if (featureDef.type === 'numeric') {
|
||||
current /= 100;
|
||||
}
|
||||
const currentIsBeneficial = isValueBeneficial(feature, current);
|
||||
|
||||
effects.push(
|
||||
<tr key={feature + '_specialTT'}>
|
||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
||||
<td> </td>
|
||||
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'}
|
||||
style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<table width='100%'>
|
||||
<tbody>
|
||||
{effects}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a tooltip with details of a blueprint's effects
|
||||
* @param {Object} translate The translate object
|
||||
* @param {Object} blueprint The blueprint at the required grade
|
||||
* @param {Array} engineers The engineers supplying this blueprint
|
||||
* @param {string} grp The group of the module
|
||||
* @param {Object} m The module to compare with
|
||||
* @returns {Object} The react components
|
||||
*/
|
||||
export function blueprintTooltip(translate, blueprint, engineers, grp, m) {
|
||||
const effects = [];
|
||||
if (!blueprint || !blueprint.features) {
|
||||
return undefined;
|
||||
}
|
||||
for (const feature in blueprint.features) {
|
||||
const featureIsBeneficial = isBeneficial(feature, blueprint.features[feature]);
|
||||
const featureDef = Modifications.modifications[feature];
|
||||
if (!featureDef.hidden) {
|
||||
let symbol = '';
|
||||
if (feature === 'jitter') {
|
||||
symbol = '°';
|
||||
} else if (featureDef.type === 'percentage') {
|
||||
symbol = '%';
|
||||
}
|
||||
let lowerBound = blueprint.features[feature][0];
|
||||
let upperBound = blueprint.features[feature][1];
|
||||
if (featureDef.type === 'percentage') {
|
||||
lowerBound = Math.round(lowerBound * 1000) / 10;
|
||||
upperBound = Math.round(upperBound * 1000) / 10;
|
||||
}
|
||||
const lowerIsBeneficial = isValueBeneficial(feature, lowerBound);
|
||||
const upperIsBeneficial = isValueBeneficial(feature, upperBound);
|
||||
if (m) {
|
||||
// We have a module - add in the current value
|
||||
let current = m.getModValue(feature);
|
||||
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
|
||||
current = Math.round(current / 10) / 10;
|
||||
} else if (featureDef.type === 'numeric') {
|
||||
current /= 100;
|
||||
}
|
||||
const currentIsBeneficial = isValueBeneficial(feature, current);
|
||||
effects.push(
|
||||
<tr key={feature}>
|
||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
||||
<td 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={upperBound === 0 ? '' : upperIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{upperBound}{symbol}</td>
|
||||
</tr>
|
||||
);
|
||||
} else {
|
||||
// We do not have a module, no value
|
||||
effects.push(
|
||||
<tr key={feature}>
|
||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</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>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m) {
|
||||
// Because we have a module add in any benefits that aren't part of the primary blueprint
|
||||
for (const feature in m.mods) {
|
||||
if (!blueprint.features[feature]) {
|
||||
const featureDef = Modifications.modifications[feature];
|
||||
if (featureDef && !featureDef.hidden) {
|
||||
let symbol = '';
|
||||
if (feature === 'jitter') {
|
||||
symbol = '°';
|
||||
} else if (featureDef.type === 'percentage') {
|
||||
symbol = '%';
|
||||
}
|
||||
let current = m.getModValue(feature);
|
||||
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
|
||||
current = Math.round(current / 10) / 10;
|
||||
} else if (featureDef.type === 'numeric') {
|
||||
current /= 100;
|
||||
}
|
||||
const currentIsBeneficial = isValueBeneficial(feature, current);
|
||||
effects.push(
|
||||
<tr key={feature}>
|
||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
||||
<td> </td>
|
||||
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We also add in any benefits from specials that aren't covered above
|
||||
if (m.blueprint && m.blueprint.special) {
|
||||
for (const feature in Modifications.modifierActions[m.blueprint.special.edname]) {
|
||||
if (!blueprint.features[feature] && !m.mods.feature) {
|
||||
const featureDef = Modifications.modifications[feature];
|
||||
if (featureDef && !featureDef.hidden) {
|
||||
let symbol = '';
|
||||
if (feature === 'jitter') {
|
||||
symbol = '°';
|
||||
} else if (featureDef.type === 'percentage') {
|
||||
symbol = '%';
|
||||
}
|
||||
let current = m.getModValue(feature);
|
||||
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
|
||||
current = Math.round(current / 10) / 10;
|
||||
} else if (featureDef.type === 'numeric') {
|
||||
current /= 100;
|
||||
}
|
||||
const currentIsBeneficial = isValueBeneficial(feature, current);
|
||||
effects.push(
|
||||
<tr key={feature}>
|
||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
||||
<td> </td>
|
||||
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let components;
|
||||
if (!m) {
|
||||
components = [];
|
||||
for (const component in blueprint.components) {
|
||||
components.push(
|
||||
<tr key={component}>
|
||||
<td style={{ textAlign: 'left' }}>{translate(component)}</td>
|
||||
<td style={{ textAlign: 'right' }}>{blueprint.components[component]}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let engineersList;
|
||||
if (engineers) {
|
||||
engineersList = [];
|
||||
for (const engineer of engineers) {
|
||||
engineersList.push(
|
||||
<tr key={engineer}>
|
||||
<td style={{ textAlign: 'left' }}>{engineer}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<table width='100%'>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{translate('feature')}</td>
|
||||
<td>{translate('worst')}</td>
|
||||
{m ? <td>{translate('current')}</td> : null }
|
||||
<td>{translate('best')}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{effects}
|
||||
</tbody>
|
||||
</table>
|
||||
{ components ? <table width='100%'>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{translate('component')}</td>
|
||||
<td>{translate('amount')}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{components}
|
||||
</tbody>
|
||||
</table> : null }
|
||||
{ engineersList ? <table width='100%'>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{translate('engineers')}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{engineersList}
|
||||
</tbody>
|
||||
</table> : null }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this blueprint feature beneficial?
|
||||
* @param {string} feature The name of the feature
|
||||
* @param {array} values The value of the feature
|
||||
* @returns {boolean} True if this feature is beneficial
|
||||
*/
|
||||
export function isBeneficial(feature, values) {
|
||||
const fact = (values[0] < 0 || (values[0] === 0 && values[1] < 0));
|
||||
if (Modifications.modifications[feature].higherbetter) {
|
||||
return !fact;
|
||||
} else {
|
||||
return fact;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this feature value beneficial?
|
||||
* @param {string} feature The name of the feature
|
||||
* @param {number} value The value of the feature
|
||||
* @returns {boolean} True if this value is beneficial
|
||||
*/
|
||||
export function isValueBeneficial(feature, value) {
|
||||
if (Modifications.modifications[feature].higherbetter) {
|
||||
return value > 0;
|
||||
} else {
|
||||
return value < 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the change as shown beneficial?
|
||||
* @param {string} feature The name of the feature
|
||||
* @param {number} value The value of the feature as percentage change
|
||||
* @returns True if the value is beneficial
|
||||
*/
|
||||
export function isChangeValueBeneficial(feature, value) {
|
||||
let changeHigherBetter = STATS_FORMATTING[feature].higherbetter;
|
||||
if (changeHigherBetter === undefined) {
|
||||
return isValueBeneficial(feature, value);
|
||||
}
|
||||
|
||||
if (changeHigherBetter) {
|
||||
return value > 0;
|
||||
} else {
|
||||
return value < 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a blueprint with a given name and an optional module
|
||||
* @param {string} name The name of the blueprint
|
||||
* @param {Object} module The module for which to obtain this blueprint
|
||||
* @returns {Object} The matching blueprint
|
||||
*/
|
||||
export function getBlueprint(name, module) {
|
||||
// Start with a copy of the blueprint
|
||||
const findMod = val => Object.keys(Modifications.blueprints).find(elem => elem.toString().toLowerCase().search(val.toString().toLowerCase().replace(/(OutfittingFieldType_|persecond)/igm, '')) >= 0);
|
||||
const found = Modifications.blueprints[findMod(name)];
|
||||
if (!found || !found.fdname) {
|
||||
return {};
|
||||
}
|
||||
const blueprint = JSON.parse(JSON.stringify(found));
|
||||
return blueprint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide 'percent' primary modifications
|
||||
* @param {Object} ship The ship for which to perform the modifications
|
||||
* @param {Object} m The module for which to perform the modifications
|
||||
* @param {Number} percent The percent to set values to of full.
|
||||
*/
|
||||
export function setPercent(ship, m, percent) {
|
||||
ship.clearModifications(m);
|
||||
// Pick given value as multiplier
|
||||
const mult = percent / 100;
|
||||
setQualityCB(m.blueprint, mult, (featureName, value) => ship.setModification(m, featureName, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the blueprint quality and fires a callback for each property affected.
|
||||
* @param {Object} blueprint The ship for which to perform the modifications
|
||||
* @param {Number} quality The quality to apply - float number 0 to 1.
|
||||
* @param {Function} cb The Callback to run for each property. Function (featureName, value)
|
||||
*/
|
||||
export function setQualityCB(blueprint, quality, cb) {
|
||||
// Pick given value as multiplier
|
||||
const features = blueprint.grades[blueprint.grade].features;
|
||||
for (const featureName in features) {
|
||||
let value;
|
||||
if (Modifications.modifications[featureName].higherbetter) {
|
||||
// Higher is better, but is this making it better or worse?
|
||||
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
||||
value = features[featureName][1] + ((features[featureName][0] - features[featureName][1]) * quality);
|
||||
} else {
|
||||
value = features[featureName][0] + ((features[featureName][1] - features[featureName][0]) * quality);
|
||||
}
|
||||
} else {
|
||||
// Higher is worse, but is this making it better or worse?
|
||||
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
||||
value = features[featureName][0] + ((features[featureName][1] - features[featureName][0]) * quality);
|
||||
} else {
|
||||
value = features[featureName][1] + ((features[featureName][0] - features[featureName][1]) * quality);
|
||||
}
|
||||
}
|
||||
|
||||
if (Modifications.modifications[featureName].type == 'percentage') {
|
||||
value = value * 10000;
|
||||
} else if (Modifications.modifications[featureName].type == 'numeric') {
|
||||
value = value * 100;
|
||||
}
|
||||
|
||||
cb(featureName, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide 'random' primary modifications
|
||||
* @param {Object} ship The ship for which to perform the modifications
|
||||
* @param {Object} m The module for which to perform the modifications
|
||||
*/
|
||||
export function setRandom(ship, m) {
|
||||
// Pick a single value for our randomness
|
||||
setPercent(ship, m, Math.random() * 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
export function getPercent(m) {
|
||||
let result = null;
|
||||
const features = m.blueprint.grades[m.blueprint.grade].features;
|
||||
for (const featureName in features) {
|
||||
if (features[featureName][0] === features[featureName][1]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let value = _getValue(m, featureName);
|
||||
let mult;
|
||||
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);
|
||||
} else {
|
||||
mult = Math.round((value - features[featureName][0]) / (features[featureName][1] - features[featureName][0]) * 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)) {
|
||||
mult = Math.round((value - features[featureName][0]) / (features[featureName][1] - features[featureName][0]) * 100);
|
||||
} else {
|
||||
mult = Math.round((value - features[featureName][1]) / (features[featureName][0] - features[featureName][1]) * 100);
|
||||
}
|
||||
}
|
||||
|
||||
if (result && result != mult) {
|
||||
return null;
|
||||
} else if (result != mult) {
|
||||
result = mult;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
import React from 'react';
|
||||
import { Modifications } from 'coriolis-data/dist';
|
||||
import { STATS_FORMATTING } from '../shipyard/StatsFormatting';
|
||||
|
||||
/**
|
||||
* Generate a tooltip with details of a blueprint's specials
|
||||
* @param {Object} translate The translate object
|
||||
* @param {Object} blueprint The blueprint at the required grade
|
||||
* @param {string} grp The group of the module
|
||||
* @param {Object} m The module to compare with
|
||||
* @param {string} specialName The name of the special
|
||||
* @returns {Object} The react components
|
||||
*/
|
||||
export function specialToolTip(translate, blueprint, grp, m, specialName) {
|
||||
const effects = [];
|
||||
if (!blueprint || !blueprint.features) {
|
||||
return undefined;
|
||||
}
|
||||
if (m) {
|
||||
// We also add in any benefits from specials that aren't covered above
|
||||
if (m.blueprint) {
|
||||
for (const feature in Modifications.modifierActions[specialName]) {
|
||||
// if (!blueprint.features[feature] && !m.mods.feature) {
|
||||
const featureDef = Modifications.modifications[feature];
|
||||
if (featureDef && !featureDef.hidden) {
|
||||
let symbol = '';
|
||||
if (feature === 'jitter') {
|
||||
symbol = '°';
|
||||
} else if (featureDef.type === 'percentage') {
|
||||
symbol = '%';
|
||||
}
|
||||
let current = m.getModValue(feature) - m.getModValue(feature, true);
|
||||
if (featureDef.type === 'percentage') {
|
||||
current = Math.round(current / 10) / 10;
|
||||
} else if (featureDef.type === 'numeric') {
|
||||
current /= 100;
|
||||
}
|
||||
const currentIsBeneficial = isValueBeneficial(feature, current);
|
||||
|
||||
effects.push(
|
||||
<tr key={feature + '_specialTT'}>
|
||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
||||
<td> </td>
|
||||
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'}
|
||||
style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<table width='100%'>
|
||||
<tbody>
|
||||
{effects}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a tooltip with details of a blueprint's effects
|
||||
* @param {Object} translate The translate object
|
||||
* @param {Object} blueprint The blueprint at the required grade
|
||||
* @param {Array} engineers The engineers supplying this blueprint
|
||||
* @param {string} grp The group of the module
|
||||
* @param {Object} m The module to compare with
|
||||
* @returns {Object} The react components
|
||||
*/
|
||||
export function blueprintTooltip(translate, blueprint, engineers, grp, m) {
|
||||
const effects = [];
|
||||
if (!blueprint || !blueprint.features) {
|
||||
return undefined;
|
||||
}
|
||||
for (const feature in blueprint.features) {
|
||||
const featureIsBeneficial = isBeneficial(feature, blueprint.features[feature]);
|
||||
const featureDef = Modifications.modifications[feature];
|
||||
if (!featureDef.hidden) {
|
||||
let symbol = '';
|
||||
if (feature === 'jitter') {
|
||||
symbol = '°';
|
||||
} else if (featureDef.type === 'percentage') {
|
||||
symbol = '%';
|
||||
}
|
||||
let lowerBound = blueprint.features[feature][0];
|
||||
let upperBound = blueprint.features[feature][1];
|
||||
if (featureDef.type === 'percentage') {
|
||||
lowerBound = Math.round(lowerBound * 1000) / 10;
|
||||
upperBound = Math.round(upperBound * 1000) / 10;
|
||||
}
|
||||
const lowerIsBeneficial = isValueBeneficial(feature, lowerBound);
|
||||
const upperIsBeneficial = isValueBeneficial(feature, upperBound);
|
||||
if (m) {
|
||||
// We have a module - add in the current value
|
||||
let current = m.getModValue(feature);
|
||||
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
|
||||
current = Math.round(current / 10) / 10;
|
||||
} else if (featureDef.type === 'numeric') {
|
||||
current /= 100;
|
||||
}
|
||||
const currentIsBeneficial = isValueBeneficial(feature, current);
|
||||
effects.push(
|
||||
<tr key={feature}>
|
||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
||||
<td 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={upperBound === 0 ? '' : upperIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{upperBound}{symbol}</td>
|
||||
</tr>
|
||||
);
|
||||
} else {
|
||||
// We do not have a module, no value
|
||||
effects.push(
|
||||
<tr key={feature}>
|
||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</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>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m) {
|
||||
// Because we have a module add in any benefits that aren't part of the primary blueprint
|
||||
for (const feature in m.mods) {
|
||||
if (!blueprint.features[feature]) {
|
||||
const featureDef = Modifications.modifications[feature];
|
||||
if (featureDef && !featureDef.hidden) {
|
||||
let symbol = '';
|
||||
if (feature === 'jitter') {
|
||||
symbol = '°';
|
||||
} else if (featureDef.type === 'percentage') {
|
||||
symbol = '%';
|
||||
}
|
||||
let current = m.getModValue(feature);
|
||||
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
|
||||
current = Math.round(current / 10) / 10;
|
||||
} else if (featureDef.type === 'numeric') {
|
||||
current /= 100;
|
||||
}
|
||||
const currentIsBeneficial = isValueBeneficial(feature, current);
|
||||
effects.push(
|
||||
<tr key={feature}>
|
||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
||||
<td> </td>
|
||||
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We also add in any benefits from specials that aren't covered above
|
||||
if (m.blueprint && m.blueprint.special) {
|
||||
for (const feature in Modifications.modifierActions[m.blueprint.special.edname]) {
|
||||
if (!blueprint.features[feature] && !m.mods.feature) {
|
||||
const featureDef = Modifications.modifications[feature];
|
||||
if (featureDef && !featureDef.hidden) {
|
||||
let symbol = '';
|
||||
if (feature === 'jitter') {
|
||||
symbol = '°';
|
||||
} else if (featureDef.type === 'percentage') {
|
||||
symbol = '%';
|
||||
}
|
||||
let current = m.getModValue(feature);
|
||||
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
|
||||
current = Math.round(current / 10) / 10;
|
||||
} else if (featureDef.type === 'numeric') {
|
||||
current /= 100;
|
||||
}
|
||||
const currentIsBeneficial = isValueBeneficial(feature, current);
|
||||
effects.push(
|
||||
<tr key={feature}>
|
||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
||||
<td> </td>
|
||||
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let components;
|
||||
if (!m) {
|
||||
components = [];
|
||||
for (const component in blueprint.components) {
|
||||
components.push(
|
||||
<tr key={component}>
|
||||
<td style={{ textAlign: 'left' }}>{translate(component)}</td>
|
||||
<td style={{ textAlign: 'right' }}>{blueprint.components[component]}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let engineersList;
|
||||
if (engineers) {
|
||||
engineersList = [];
|
||||
for (const engineer of engineers) {
|
||||
engineersList.push(
|
||||
<tr key={engineer}>
|
||||
<td style={{ textAlign: 'left' }}>{engineer}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<table width='100%'>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{translate('feature')}</td>
|
||||
<td>{translate('worst')}</td>
|
||||
{m ? <td>{translate('current')}</td> : null }
|
||||
<td>{translate('best')}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{effects}
|
||||
</tbody>
|
||||
</table>
|
||||
{ components ? <table width='100%'>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{translate('component')}</td>
|
||||
<td>{translate('amount')}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{components}
|
||||
</tbody>
|
||||
</table> : null }
|
||||
{ engineersList ? <table width='100%'>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{translate('engineers')}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{engineersList}
|
||||
</tbody>
|
||||
</table> : null }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this blueprint feature beneficial?
|
||||
* @param {string} feature The name of the feature
|
||||
* @param {array} values The value of the feature
|
||||
* @returns {boolean} True if this feature is beneficial
|
||||
*/
|
||||
export function isBeneficial(feature, values) {
|
||||
const fact = (values[0] < 0 || (values[0] === 0 && values[1] < 0));
|
||||
if (Modifications.modifications[feature].higherbetter) {
|
||||
return !fact;
|
||||
} else {
|
||||
return fact;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this feature value beneficial?
|
||||
* @param {string} feature The name of the feature
|
||||
* @param {number} value The value of the feature
|
||||
* @returns {boolean} True if this value is beneficial
|
||||
*/
|
||||
export function isValueBeneficial(feature, value) {
|
||||
if (Modifications.modifications[feature].higherbetter) {
|
||||
return value > 0;
|
||||
} else {
|
||||
return value < 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the change as shown beneficial?
|
||||
* @param {string} feature The name of the feature
|
||||
* @param {number} value The value of the feature as percentage change
|
||||
* @returns True if the value is beneficial
|
||||
*/
|
||||
export function isChangeValueBeneficial(feature, value) {
|
||||
let changeHigherBetter = STATS_FORMATTING[feature].higherbetter;
|
||||
if (changeHigherBetter === undefined) {
|
||||
return isValueBeneficial(feature, value);
|
||||
}
|
||||
|
||||
if (changeHigherBetter) {
|
||||
return value > 0;
|
||||
} else {
|
||||
return value < 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a blueprint with a given name and an optional module
|
||||
* @param {string} name The name of the blueprint
|
||||
* @param {Object} module The module for which to obtain this blueprint
|
||||
* @returns {Object} The matching blueprint
|
||||
*/
|
||||
export function getBlueprint(name, module) {
|
||||
// Start with a copy of the blueprint
|
||||
const findMod = val => Object.keys(Modifications.blueprints).find(elem => elem.toString().toLowerCase().search(val.toString().toLowerCase().replace(/(OutfittingFieldType_|persecond)/igm, '')) >= 0);
|
||||
const found = Modifications.blueprints[findMod(name)];
|
||||
if (!found || !found.fdname) {
|
||||
return {};
|
||||
}
|
||||
const blueprint = JSON.parse(JSON.stringify(found));
|
||||
return blueprint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide 'percent' primary modifications
|
||||
* @param {Object} ship The ship for which to perform the modifications
|
||||
* @param {Object} m The module for which to perform the modifications
|
||||
* @param {Number} percent The percent to set values to of full.
|
||||
*/
|
||||
export function setPercent(ship, m, percent) {
|
||||
ship.clearModifications(m);
|
||||
// Pick given value as multiplier
|
||||
const mult = percent / 100;
|
||||
setQualityCB(m.blueprint, mult, (featureName, value) => ship.setModification(m, featureName, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the blueprint quality and fires a callback for each property affected.
|
||||
* @param {Object} blueprint The ship for which to perform the modifications
|
||||
* @param {Number} quality The quality to apply - float number 0 to 1.
|
||||
* @param {Function} cb The Callback to run for each property. Function (featureName, value)
|
||||
*/
|
||||
export function setQualityCB(blueprint, quality, cb) {
|
||||
// Pick given value as multiplier
|
||||
const features = blueprint.grades[blueprint.grade].features;
|
||||
for (const featureName in features) {
|
||||
let value;
|
||||
if (Modifications.modifications[featureName].higherbetter) {
|
||||
// Higher is better, but is this making it better or worse?
|
||||
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
||||
value = features[featureName][1] + ((features[featureName][0] - features[featureName][1]) * quality);
|
||||
} else {
|
||||
value = features[featureName][0] + ((features[featureName][1] - features[featureName][0]) * quality);
|
||||
}
|
||||
} else {
|
||||
// Higher is worse, but is this making it better or worse?
|
||||
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
||||
value = features[featureName][0] + ((features[featureName][1] - features[featureName][0]) * quality);
|
||||
} else {
|
||||
value = features[featureName][1] + ((features[featureName][0] - features[featureName][1]) * quality);
|
||||
}
|
||||
}
|
||||
|
||||
if (Modifications.modifications[featureName].type == 'percentage') {
|
||||
value = value * 10000;
|
||||
} else if (Modifications.modifications[featureName].type == 'numeric') {
|
||||
value = value * 100;
|
||||
}
|
||||
|
||||
cb(featureName, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide 'random' primary modifications
|
||||
* @param {Object} ship The ship for which to perform the modifications
|
||||
* @param {Object} m The module for which to perform the modifications
|
||||
*/
|
||||
export function setRandom(ship, m) {
|
||||
// Pick a single value for our randomness
|
||||
setPercent(ship, m, Math.random() * 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
export function getPercent(m) {
|
||||
let result = null;
|
||||
const features = m.blueprint.grades[m.blueprint.grade].features;
|
||||
for (const featureName in features) {
|
||||
if (features[featureName][0] === features[featureName][1]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let value = _getValue(m, featureName);
|
||||
let mult;
|
||||
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);
|
||||
} else {
|
||||
mult = Math.round((value - features[featureName][0]) / (features[featureName][1] - features[featureName][0]) * 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)) {
|
||||
mult = Math.round((value - features[featureName][0]) / (features[featureName][1] - features[featureName][0]) * 100);
|
||||
} else {
|
||||
mult = Math.round((value - features[featureName][1]) / (features[featureName][0] - features[featureName][1]) * 100);
|
||||
}
|
||||
}
|
||||
|
||||
if (result && result != mult) {
|
||||
return null;
|
||||
} else if (result != mult) {
|
||||
result = mult;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,22 @@ import { Modules } from 'coriolis-data/dist';
|
||||
import { Modifications } from 'coriolis-data/dist';
|
||||
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
|
||||
* @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);
|
||||
break;
|
||||
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.standard[0].enabled = module.On;
|
||||
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);
|
||||
break;
|
||||
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.standard[1].enabled = module.On;
|
||||
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);
|
||||
break;
|
||||
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.standard[2].enabled = module.On;
|
||||
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);
|
||||
break;
|
||||
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.standard[3].enabled = module.On === true;
|
||||
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);
|
||||
break;
|
||||
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.standard[4].enabled = module.On;
|
||||
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);
|
||||
break;
|
||||
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.standard[5].enabled = module.On;
|
||||
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);
|
||||
break;
|
||||
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.standard[6].enabled = true;
|
||||
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
|
||||
} else {
|
||||
hardpoint = _moduleFromFdName(hardpointSlot.Item);
|
||||
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 });
|
||||
// Check the hardpoint module returned is valid
|
||||
if (!_isValidImportedModule(hardpoint, 'hardpoint')){
|
||||
// Check if it's a Utility or Hardpoint
|
||||
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++;
|
||||
}
|
||||
@@ -187,13 +261,17 @@ export function shipFromLoadoutJSON(json) {
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
if (isMilitary) {
|
||||
const internalName = 'Military0' + militarySlotNum;
|
||||
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase());
|
||||
militarySlotNum++;
|
||||
} else if (isPlanetary) {
|
||||
const internalName = 'PlanetaryApproachSuite';
|
||||
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase());
|
||||
} else {
|
||||
// Slot numbers are not contiguous so handle skips.
|
||||
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
|
||||
} else {
|
||||
const internalJson = internalSlot;
|
||||
const internal = _moduleFromFdName(internalJson.Item);
|
||||
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 });
|
||||
let internal = _moduleFromFdName(internalJson.Item);
|
||||
// Check the internal module returned is valid
|
||||
if (!_isValidImportedModule(internal, 'internal'))
|
||||
{
|
||||
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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user