Fix display and selection of modules near weight limit in menu

This commit is contained in:
Cmdr McDonald
2017-04-04 23:55:08 +01:00
parent 42c43d3f2d
commit 2fa2625a8f
10 changed files with 44 additions and 36 deletions

View File

@@ -1,4 +1,5 @@
import React from 'react';
import * as ModuleUtils from '../shipyard/ModuleUtils';
import { findDOMNode } from 'react-dom';
import TranslatedComponent from './TranslatedComponent';
import { stopCtxPropagation } from '../utils/UtilityFunctions';
@@ -213,7 +214,14 @@ export default class AvailableModulesMenu extends TranslatedComponent {
for (let i = 0; i < sortedModules.length; i++) {
let m = sortedModules[i];
let mount = null;
let disabled = m.maxmass && (mass + (m.mass ? m.mass : 0)) > m.maxmass;
let disabled = false;
if (ModuleUtils.isShieldGenerator(m.grp)) {
// Shield generators care about maximum hull mass
disabled = mass > m.maxmass;
} else if (m.maxmass) {
// Thrusters care about total mass
disabled = mass + m.mass > m.maxmass;
}
let active = mountedModule && mountedModule.id === m.id;
let classes = cn(m.name ? 'lc' : 'c', {
warning: !disabled && warningFunc && warningFunc(m),

View File

@@ -85,12 +85,12 @@ export default class OutfittingSubpages extends TranslatedComponent {
_profilesTab() {
const { ship, opponent, cargo, fuel, eng, boost, engagementRange, opponentSys } = this.props;
const { translate } = this.context.language;
let realBoost = boost && ship.canBoost();
let realBoost = boost && ship.canBoost(cargo, fuel);
Persist.setOutfittingTab('profiles');
const engineProfileMarker = `${ship.toString()}:${cargo}:${fuel}:${eng}:${realBoost}`;
const fsdProfileMarker = `${ship.toString()}:${cargo}:${fuel}`;
const movementMarker = `${ship.topSpeed}:${ship.pitch}:${ship.roll}:${ship.yaw}:${ship.canBoost()}`;
const movementMarker = `${ship.topSpeed}:${ship.pitch}:${ship.roll}:${ship.yaw}:${ship.canBoost(cargo, fuel)}`;
const damageMarker = `${ship.toString()}:${opponent.toString()}:${engagementRange}:${opponentSys}`;
return <div>

View File

@@ -11,6 +11,8 @@ export default class ShipSummaryTable extends TranslatedComponent {
static propTypes = {
ship: React.PropTypes.object.isRequired,
cargo: React.PropTypes.number.isRequired,
fuel: React.PropTypes.number.isRequired,
marker: React.PropTypes.string.isRequired,
};
@@ -19,7 +21,7 @@ export default class ShipSummaryTable extends TranslatedComponent {
* @return {React.Component} Summary table
*/
render() {
const { ship } = this.props;
const { ship, cargo, fuel } = this.props;
let { language, tooltip, termtip } = this.context;
let translate = language.translate;
let u = language.units;
@@ -31,9 +33,9 @@ export default class ShipSummaryTable extends TranslatedComponent {
const sgClassNames = cn({ warning: shieldGenerator && !ship.shield, muted: !shieldGenerator });
const sgTooltip = shieldGenerator ? 'TT_SUMMARY_SHIELDS' : 'TT_SUMMARY_SHIELDS_NONFUNCTIONAL';
const timeToDrain = Calc.timeToDrainWep(ship, 4);
const canThrust = ship.canThrust();
const canThrust = ship.canThrust(cargo, fuel);
const speedTooltip = canThrust ? 'TT_SUMMARY_SPEED' : 'TT_SUMMARY_SPEED_NONFUNCTIONAL';
const canBoost = ship.canBoost();
const canBoost = ship.canBoost(cargo, fuel);
const boostTooltip = canBoost ? 'TT_SUMMARY_BOOST' : canThrust ? 'TT_SUMMARY_BOOST_NONFUNCTIONAL' : 'TT_SUMMARY_SPEED_NONFUNCTIONAL';
return <div id='summary'>

View File

@@ -5,6 +5,7 @@ import TranslatedComponent from './TranslatedComponent';
import { diffDetails } from '../utils/SlotFunctions';
import AvailableModulesMenu from './AvailableModulesMenu';
import ModificationsMenu from './ModificationsMenu';
import * as ModuleUtils from '../shipyard/ModuleUtils';
import { ListModifications, Modified } from './SvgIcons';
import { Modifications } from 'coriolis-data/dist';
import { stopCtxPropagation } from '../utils/UtilityFunctions';
@@ -82,7 +83,7 @@ export default class StandardSlot extends TranslatedComponent {
menu = <AvailableModulesMenu
className='standard'
modules={modules}
shipMass={ship.ladenMass}
shipMass={ModuleUtils.isShieldGenerator(m.grp) ? ship.hullMass : ship.unladenMass}
m={m}
onSelect={onSelect}
warning={warning}

View File

@@ -95,7 +95,7 @@ export default class StandardSlotSection extends SlotSection {
* @return {Array} Array of Slots
*/
_getSlots() {
let { ship, currentMenu } = this.props;
let { ship, currentMenu, cargo, fuel } = this.props;
let slots = new Array(8);
let open = this._openMenu;
let select = this._selectModule;
@@ -135,7 +135,7 @@ export default class StandardSlotSection extends SlotSection {
selected={currentMenu == st[1]}
onChange={this.props.onChange}
ship={ship}
warning={m => m instanceof Module ? m.getMaxMass() < (ship.ladenMass - st[1].mass + m.mass) : m.maxmass < (ship.ladenMass - st[1].mass + m.mass)}
warning={m => m instanceof Module ? m.getMaxMass() < (ship.unladenMass + cargo + fuel - st[1].m.mass + m.mass) : m.maxmass < (ship.unladenMass + cargo + fuel - st[1].m.mass + m.mass)}
/>;

View File

@@ -545,11 +545,11 @@ export default class OutfittingPage extends Page {
const _pStr = `${ship.getPowerEnabledString()}${ship.getPowerPrioritiesString()}`;
const _mStr = ship.getModificationsString();
const standardSlotMarker = `${ship.name}${_sStr}${_pStr}${_mStr}`;
const standardSlotMarker = `${ship.name}${_sStr}${_pStr}${_mStr}${ship.ladenMass}${cargo}${fuel}`;
const internalSlotMarker = `${ship.name}${_iStr}${_pStr}${_mStr}`;
const hardpointsSlotMarker = `${ship.name}${_hStr}${_pStr}${_mStr}`;
const boostMarker = `${ship.canBoost()}`;
const shipSummaryMarker = `${ship.name}${_sStr}${_iStr}${_hStr}${_pStr}${_mStr}`;
const boostMarker = `${ship.canBoost(cargo, fuel)}`;
const shipSummaryMarker = `${ship.name}${_sStr}${_iStr}${_hStr}${_pStr}${_mStr}${ship.ladenMass}${ship.cargo}${ship.fuel}`;
return (
<div id='outfit' className={'page'} style={{ fontSize: (sizeRatio * 0.9) + 'em' }}>
@@ -585,8 +585,8 @@ export default class OutfittingPage extends Page {
</div>
{/* Main tables */}
<ShipSummaryTable ship={ship} marker={shipSummaryMarker} />
<StandardSlotSection ship={ship} code={standardSlotMarker} onChange={shipUpdated} currentMenu={menu} />
<ShipSummaryTable ship={ship} fuel={fuel} cargo={cargo} marker={shipSummaryMarker} />
<StandardSlotSection ship={ship} fuel={fuel} cargo={cargo} code={standardSlotMarker} onChange={shipUpdated} currentMenu={menu} />
<InternalSlotSection ship={ship} code={internalSlotMarker} onChange={shipUpdated} currentMenu={menu} />
<HardpointSlotSection ship={ship} code={hardpointsSlotMarker} onChange={shipUpdated} currentMenu={menu} />
<UtilitySlotSection ship={ship} code={hardpointsSlotMarker} onChange={shipUpdated} currentMenu={menu} />

View File

@@ -162,14 +162,6 @@ export default class Module {
return result;
}
/**
* Return true if this is a shield generator
* @return {Boolean} if this is a shield generator
*/
isShieldGenerator() {
return (this.grp === 'sg' || this.grp === 'psg' || this.grp === 'bsg');
}
/**
* Get the power generation of this module, taking in to account modifications
* @return {Number} the power generation of this module

View File

@@ -123,19 +123,23 @@ export default class Ship {
/**
* Can the ship thrust/move
* @param {Number} cargo Amount of cargo in the ship
* @param {Number} fuel Amount of fuel in the ship
* @return {[type]} True if thrusters operational
*/
canThrust() {
canThrust(cargo, fuel) {
return this.getSlotStatus(this.standard[1]) == 3 && // Thrusters are powered
this.ladenMass < this.standard[1].m.getMaxMass(); // Max mass not exceeded
this.unladenMass + cargo + fuel < this.standard[1].m.getMaxMass(); // Max mass not exceeded
}
/**
* Can the ship boost
* @param {Number} cargo Amount of cargo in the ship
* @param {Number} fuel Amount of fuel in the ship
* @return {[type]} True if boost capable
*/
canBoost() {
return this.canThrust() && // Thrusters operational
canBoost(cargo, fuel) {
return this.canThrust(cargo, fuel) && // Thrusters operational
this.standard[4].m.getEnginesCapacity() > this.boostEnergy; // PD capacitor is sufficient for boost
}
@@ -1185,7 +1189,7 @@ export default class Ship {
updateMovement() {
this.speeds = Calc.speed(this.unladenMass + this.fuelCapacity, this.speed, this.standard[1].m, this.pipSpeed);
this.topSpeed = this.speeds[4];
this.topBoost = this.canBoost() ? this.speeds[4] * this.boost / this.speed : 0;
this.topBoost = this.canBoost(0, 0) ? this.speeds[4] * this.boost / this.speed : 0;
this.pitches = Calc.pitch(this.unladenMass + this.fuelCapacity, this.pitch, this.standard[1].m, this.pipSpeed);
this.topPitch = this.pitches[4];
@@ -1207,7 +1211,7 @@ export default class Ship {
// Obtain shield metrics with 0 pips to sys (parts affected by SYS aren't used here)
const metrics = Calc.shieldMetrics(this, 0);
this.shield = metrics.generator + metrics.boosters;
this.shield = metrics.generator ? metrics.generator + metrics.boosters : 0;
this.shieldExplRes = this.shield > 0 ? 1 - metrics.explosive.total : null;
this.shieldKinRes = this.shield > 0 ? 1 - metrics.kinetic.total : null;
this.shieldThermRes = this.shield > 0 ? 1 - metrics.thermal.total : null;
@@ -1639,11 +1643,11 @@ export default class Ship {
let mass = this.hullMass;
mass += m.pp ? m.pp.getMass() : ModuleUtils.standard(0, '2D').getMass();
mass += m.th ? m.th.getMass() : ModuleUtils.standard(1, '2D').getMass();
mass += m.fsd ? m.fsd.getMass() : ModuleUtils.standard(2, this.standard[2].maxClass + 'D').getMass();
mass += m.fsd ? m.fsd.getMass() : ModuleUtils.standard(2, '2D').getMass();
mass += m.ls ? m.ls.getMass() : ModuleUtils.standard(3, this.standard[3].maxClass + 'D').getMass() * 0.3; // Lightweight grade 4 mod reduces mass by up to 70%
mass += m.pd ? m.pd.getMass() : ModuleUtils.standard(4, '2D').getMass();
mass += m.s ? m.s.getMass() : ModuleUtils.standard(5, this.standard[5].maxClass + 'D').getMass();
mass += m.ft ? m.ft.getMass() : ModuleUtils.standard(6, '1C').getMass();
mass += m.pd ? m.pd.getMass() : ModuleUtils.standard(4, '1D').getMass();
mass += m.s ? m.s.getMass() : ModuleUtils.standard(5, this.standard[5].maxClass + 'D').getMass() * 0.2; // Lightweight grade 5 mod reduces mass by up to 80%
// Ignore fuel tank as it could be empty
return mass;
}

View File

@@ -3,6 +3,7 @@ import { Modifications, Modules, Ships } from 'coriolis-data/dist';
import Module from '../shipyard/Module';
import Ship from '../shipyard/Ship';
import { getBlueprint } from '../utils/BlueprintFunctions';
import * as ModuleUtils from '../shipyard/ModuleUtils';
// mapping from fd's ship model names to coriolis'
const SHIP_FD_NAME_TO_CORIOLIS_NAME = {
@@ -378,7 +379,7 @@ function _addModifications(module, modifiers, blueprint, grade) {
// Shield generator resistance is actually a damage modifier, so needs to be inverted.
// In addition, the modification is based off the inherent resistance of the module
if (module.isShieldGenerator()) {
if (ModuleUtils.isShieldGenerator(module.grp)) {
if (module.getModValue('explres')) {
module.setModValue('explres', ((1 - (1 - module.explres) * (1 + module.getModValue('explres') / 10000)) - module.explres) * 10000);
}

View File

@@ -1,9 +1,9 @@
import React from 'react';
import cn from 'classnames';
import { isShieldGenerator } from '../shipyard/ModuleUtils';
import Module from '../shipyard/Module';
import { Infinite } from '../components/SvgIcons';
import Persist from '../stores/Persist';
import * as ModuleUtils from '../shipyard/ModuleUtils';
/**
* Determine if a slot on a ship can mount a module of a particular class and group
@@ -159,8 +159,8 @@ export function diffDetails(language, m, mm) {
let mmDps = mm ? mm.getDps() || 0 : 0;
if (mDps && mDps != mmDps) propDiffs.push(<div key='dps'>{translate('dps')}: <span className={diffClass(mmDps, mDps, true)}>{diff(formats.round, mDps, mmDps)}</span></div>);
let mAffectsShield = isShieldGenerator(m.grp) || m.grp == 'sb';
let mmAffectsShield = isShieldGenerator(mm ? mm.grp : null) || mm && mm.grp == 'sb';
let mAffectsShield = ModuleUtils.isShieldGenerator(m.grp) || m.grp == 'sb';
let mmAffectsShield = mm ? ModuleUtils.isShieldGenerator(m.grp) || mm.grp == 'sb' : false;
if (mAffectsShield || mmAffectsShield) {
let shield = this.calcShieldStrengthWith(); // Get shield strength regardless of slot active / inactive
let newShield = 0;