diff --git a/src/app/components/HardpointSlot.jsx b/src/app/components/HardpointSlot.jsx
index 18436ec1..18f35d36 100644
--- a/src/app/components/HardpointSlot.jsx
+++ b/src/app/components/HardpointSlot.jsx
@@ -56,14 +56,14 @@ export default class HardpointSlot extends Slot {
- { m.dps ?
{translate('DPS')}: {formats.round1(m.dps)} { m.clip ? ({formats.round1((m.clip * m.dps / m.rof) / ((m.clip / m.rof) + m.reload)) }) : null }
: null }
- { m.eps ?
{translate('EPS')}: {formats.round1(m.eps)}{u.MW} { m.clip ? ({formats.round1((m.clip * m.eps / m.rof) / ((m.clip / m.rof) + m.reload)) }{u.MW}) : null }
: null }
- { m.hps ?
{translate('HPS')}: {formats.round1(m.hps)} { m.clip ? ({formats.round1((m.clip * m.hps / m.rof) / ((m.clip / m.rof) + m.reload)) }) : null }
: null }
- { m.dps && m.eps ?
{translate('DPE')}: {formats.round1(m.dps / m.eps)}
: null }
- { m.rof ?
{translate('ROF')}: {m.rof}{u.ps}
: null }
- { m.range && !m.dps ?
{translate('Range')} : {formats.round(m.range / 1000)}{u.km}
: null }
- { m.shieldmul ?
+{formats.rPct(m.shieldmul)}
: null }
- { m.ammo >= 0 ?
{translate('ammo')}: {formats.int(m.clip)}/{formats.int(m.ammo)}
: null }
+ { m.getDps() ?
{translate('DPS')}: {formats.round1(m.getDps())} { m.getClip() ? ({formats.round1((m.getClip() * m.getDps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload())) }) : null }
: null }
+ { m.getEps() ?
{translate('EPS')}: {formats.round1(m.getEps())}{u.MW} { m.getClip() ? ({formats.round1((m.getClip() * m.getEps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload())) }{u.MW}) : null }
: null }
+ { m.getHps() ?
{translate('HPS')}: {formats.round1(m.getHps())} { m.getClip() ? ({formats.round1((m.getClip() * m.getHps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload())) }) : null }
: null }
+ { m.getDps() && m.getEps() ?
{translate('DPE')}: {formats.round1(m.getDps() / m.getEps())}
: null }
+ { m.getRoF() ?
{translate('ROF')}: {m.getRoF()}{u.ps}
: null }
+ { m.getRange() && !m.getDps() ?
{translate('Range')} : {formats.round(m.getRange() / 1000)}{u.km}
: null }
+ { m.getShieldMul() ?
+{formats.rPct(m.getShieldMul())}
: null }
+ { m.getAmmo() ?
{translate('ammunition')}: {formats.int(m.getClip())}/{formats.int(m.getAmmo())}
: null }
{ m && validMods.length > 0 ?
: null }
;
diff --git a/src/app/components/HardpointsSlotSection.jsx b/src/app/components/HardpointsSlotSection.jsx
index 3c51b3f2..378300ee 100644
--- a/src/app/components/HardpointsSlotSection.jsx
+++ b/src/app/components/HardpointsSlotSection.jsx
@@ -69,6 +69,7 @@ export default class HardpointsSlotSection extends SlotSection {
availableModules={() => availableModules.getHps(h.maxClass)}
onOpen={this._openMenu.bind(this, h)}
onSelect={this._selectModule.bind(this, h)}
+ onChange={this.props.onChange}
selected={currentMenu == h}
drag={this._drag.bind(this, h)}
dragOver={this._dragOverSlot.bind(this, h)}
diff --git a/src/app/components/InternalSlot.jsx b/src/app/components/InternalSlot.jsx
index 84fbc1c5..19b5b0c2 100644
--- a/src/app/components/InternalSlot.jsx
+++ b/src/app/components/InternalSlot.jsx
@@ -30,16 +30,16 @@ export default class InternalSlot extends Slot {
- { m.optmass ?
{translate('optimal mass')}: {m.optmass}{u.T}
: null }
- { m.maxmass ?
{translate('max mass')}: {m.maxmass}{u.T}
: null }
+ { m.getOptMass() ?
{translate('optimal mass')}: {m.getOptMass()}{u.T}
: null }
+ { m.getMaxMass() ?
{translate('max mass')}: {m.getMaxMass()}{u.T}
: null }
{ m.bins ?
{m.bins} {translate('bins')}
: null }
{ m.bays ?
{translate('bays')}: {m.bays}
: null }
{ m.rate ?
{translate('rate')}: {m.rate}{u.kgs} {translate('refuel time')}: {formats.time(this.props.fuel * 1000 / m.rate)}
: null }
- { m.ammo ?
{translate('ammo')}: {formats.gen(m.ammo)}
: null }
+ { m.getAmmo() ?
{translate('ammunition')}: {formats.gen(m.getAmmo())}
: null }
{ m.cells ?
{translate('cells')}: {m.cells}
: null }
{ m.recharge ?
{translate('recharge')}: {m.recharge} MJ {translate('total')}: {m.cells * m.recharge}{u.MJ}
: null }
{ m.repair ?
{translate('repair')}: {m.repair}
: null }
- { m.range ?
{translate('range')} {m.range}{u.km}
: null }
+ { m.getRange() ?
{translate('range')} {m.getRange()}{u.km}
: null }
{ m.time ?
{translate('time')}: {formats.time(m.time)}
: null }
{ m.maximum ?
{translate('max')}: {(m.maximum)}
: null }
{ m.rangeLS ?
{translate('range')}: {m.rangeLS}{u.Ls}
: null }
diff --git a/src/app/components/InternalSlotSection.jsx b/src/app/components/InternalSlotSection.jsx
index 66beab58..90e2ca73 100644
--- a/src/app/components/InternalSlotSection.jsx
+++ b/src/app/components/InternalSlotSection.jsx
@@ -114,6 +114,7 @@ export default class InternalSlotSection extends SlotSection {
onSelect={this._selectModule.bind(this, s)}
selected={currentMenu == s}
enabled={s.enabled}
+ eligible={s.eligible}
m={s.m}
drag={this._drag.bind(this, s)}
dragOver={this._dragOverSlot.bind(this, s)}
diff --git a/src/app/components/ModificationsMenu.jsx b/src/app/components/ModificationsMenu.jsx
index c844f253..9be631ac 100644
--- a/src/app/components/ModificationsMenu.jsx
+++ b/src/app/components/ModificationsMenu.jsx
@@ -41,15 +41,18 @@ export default class ModificationsMenu extends TranslatedComponent {
let formats = context.language.formats;
let { m } = props;
let list = [];
+ let values = {};
for (let modName of Modifications.validity[m.grp]) {
+ values[modName] = m.getModValue(modName) * 100;
list.push(
{translate(modName)}{' (%)'}
-
+
);
}
+ //
- return { list };
+ return { list, values };
}
/**
@@ -61,19 +64,30 @@ export default class ModificationsMenu extends TranslatedComponent {
this.setState(this._initState(nextProps, nextContext));
}
+ _getValue(name, defaultValue) {
+ let values = this.state ? this.state.values : null;
+ return values ? values[name] : defaultValue;
+ }
+
/**
* Update modification given a value.
* @param {Number} name The name of the modification
* @param {Number} value The value to set, in the range [0,1]
*/
_updateValue(name, value) {
- let scaledValue = Math.floor(value * 100) / 10000;
- let m = this.props.m;
- let ship = this.props.ship;
+ let values = this.state.values;
+ values[name] = value;
- ship.setModification(m, name, scaledValue);
+ // Only update the modification if this is a valid number
+ if (!isNaN(Number(value)) && !value.endsWith('.')) {
+ let scaledValue = Math.floor(Number(value) * 100) / 10000;
+ let m = this.props.m;
+ let ship = this.props.ship;
+ ship.setModification(m, name, scaledValue);
+ }
this.props.onChange();
+ this.setState({values});
}
/**
diff --git a/src/app/components/Slot.jsx b/src/app/components/Slot.jsx
index 6310ac15..7df6808a 100644
--- a/src/app/components/Slot.jsx
+++ b/src/app/components/Slot.jsx
@@ -22,6 +22,7 @@ export default class Slot extends TranslatedComponent {
selected: React.PropTypes.bool,
m: React.PropTypes.object,
ship: React.PropTypes.object.isRequired,
+ eligible: React.PropTypes.object,
warning: React.PropTypes.func,
drag: React.PropTypes.func,
drop: React.PropTypes.func,
@@ -80,7 +81,7 @@ export default class Slot extends TranslatedComponent {
let language = this.context.language;
let { termtip, tooltip } = this.context;
let translate = language.translate;
- let { ship, m, dropClass, dragOver, onOpen, onChange, selected, onSelect, warning, shipMass, availableModules } = this.props;
+ let { ship, m, dropClass, dragOver, onOpen, onChange, selected, eligible, onSelect, warning, shipMass, availableModules } = this.props;
let slotDetails, menu;
let validMods = m == null ? [] : (Modifications.validity[m.grp] || []);
@@ -92,7 +93,7 @@ export default class Slot extends TranslatedComponent {
if (m) {
slotDetails = this._getSlotDetails(m, translate, language.formats, language.units); // Must be implemented by sub classes
} else {
- slotDetails =
{translate('empty')}
;
+ slotDetails =
{translate(eligible ? 'emptyrestricted' : 'empty')}
;
}
if (selected) {
diff --git a/src/app/components/StandardSlot.jsx b/src/app/components/StandardSlot.jsx
index 49ae73fd..83492b90 100644
--- a/src/app/components/StandardSlot.jsx
+++ b/src/app/components/StandardSlot.jsx
@@ -75,20 +75,20 @@ export default class StandardSlot extends TranslatedComponent {
{slot.maxClass}
{classRating} {translate(m.grp == 'bh' ? m.grp : m.name || m.grp)}
-
{formats.round1(m.getMass()) || m.fuel || 0}{units.T}
+
{formats.round(m.getMass()) || m.fuel || 0}{units.T}
{ m.grp == 'bh' && m.name ?
{translate(m.name)}
: null }
- { m.getOptimalMass() ?
{translate('optimal mass')}: {m.getOptimalMass()}{units.T}
: null }
- { m.getMaxMass() ?
{translate('max mass')}: {m.getMaxMass()}{units.T}
: null }
- { m.getRange() ?
{translate('range')}: {m.getRange()}{units.km}
: null }
+ { m.getOptimalMass() ?
{translate('optimal mass')}: {formats.round(m.getOptimalMass())}{units.T}
: null }
+ { m.getMaxMass() ?
{translate('max mass')}: {formats.round(m.getMaxMass())}{units.T}
: null }
+ { m.getRange() ?
{translate('range')}: {formats.round(m.getRange())}{units.km}
: null }
{ m.time ?
{translate('time')}: {formats.time(m.time)}
: null }
- { m.getThermalEfficiency() ?
{translate('efficiency')}: {m.getThermalEfficiency()}
: null }
+ { m.getThermalEfficiency() ?
{translate('efficiency')}: {formats.round(m.getThermalEfficiency())}
: null }
{ m.getPowerGeneration() > 0 ?
{translate('pGen')}: {formats.round(m.getPowerGeneration())}{units.MW}
: null }
- { m.getMaxFuelPerJump() ?
{translate('max')} {translate('fuel')}: {m.getMaxFuelPerJump()}{units.T}
: null }
- { m.getWeaponsCapacity() ?
{translate('WEP')}: {m.getWeaponsCapacity()}{units.MJ} / {m.getWeaponsRechargeRate()}{units.MW}
: null }
- { m.getSystemsCapacity() ?
{translate('SYS')}: {m.getSystemsCapacity()}{units.MJ} / {m.getSystemsRechargeRate()}{units.MW}
: null }
- { m.getEnginesCapacity() ?
{translate('ENG')}: {m.getEnginesCapacity()}{units.MJ} / {m.getEnginesRechargeRate()}{units.MW}
: null }
+ { m.getMaxFuelPerJump() ?
{translate('max')} {translate('fuel')}: {formats.round(m.getMaxFuelPerJump())}{units.T}
: null }
+ { m.getWeaponsCapacity() ?
{translate('WEP')}: {formats.round(m.getWeaponsCapacity())}{units.MJ} / {formats.round(m.getWeaponsRechargeRate())}{units.MW}
: null }
+ { m.getSystemsCapacity() ?
{translate('SYS')}: {formats.round(m.getSystemsCapacity())}{units.MJ} / {formats.round(m.getSystemsRechargeRate())}{units.MW}
: null }
+ { m.getEnginesCapacity() ?
{translate('ENG')}: {formats.round(m.getEnginesCapacity())}{units.MJ} / {formats.round(m.getEnginesRechargeRate())}{units.MW}
: null }
{ validMods.length > 0 ?
: null }
diff --git a/src/app/components/UtilitySlotSection.jsx b/src/app/components/UtilitySlotSection.jsx
index 0e922f83..7741a2c4 100644
--- a/src/app/components/UtilitySlotSection.jsx
+++ b/src/app/components/UtilitySlotSection.jsx
@@ -68,6 +68,7 @@ export default class UtilitySlotSection extends SlotSection {
availableModules={() => availableModules.getHps(h.maxClass)}
onOpen={this._openMenu.bind(this,h)}
onSelect={this._selectModule.bind(this, h)}
+ onChange={this.props.onChange}
selected={currentMenu == h}
drag={this._drag.bind(this, h)}
dragOver={this._dragOverSlot.bind(this, h)}
diff --git a/src/app/i18n/en.js b/src/app/i18n/en.js
index ce8a535f..1c9a7de6 100644
--- a/src/app/i18n/en.js
+++ b/src/app/i18n/en.js
@@ -80,41 +80,48 @@ export const terms = {
ul: 'Burst Laser',
ws: 'Frame Shift Wake Scanner',
+ // Items on the outfitting page
+ // Notification of restricted slot for Orca/Beluga
+ emptyrestricted: 'empty (restricted)',
+ // 'ammo' was overloaded for outfitting page and modul info, so changed to ammunition for outfitting page
+ ammunition: 'Ammo',
+
// Modifications
- mass: 'Mass',
- integrity: 'Integrity',
- pGen: 'Power generation',
+ ammo: 'Ammunition maximum',
+ armourpen: 'Armour penetration',
+ boot: 'Boot time',
+ brokenregen: 'Broken regeneration rate',
+ burst: 'Burst',
+ clip: 'Ammunition clip',
+ damage: 'Damage',
+ delay: 'Delay',
+ dps: 'Damage per second',
+ distdraw: 'Distributor draw',
+ duration: 'Duration',
eff: 'Efficiency',
- power: 'Power draw',
+ engcap: 'Engines capacity',
+ engrate: 'Engines recharge rate',
+ eps: 'Energy per second',
+ explres: 'Explosive resistance',
+ integrity: 'Integrity',
+ jitter: 'Jitter',
+ kinres: 'Kinetic resistance',
+ maxfuel: 'Maximum fuel per jump',
+ mass: 'Mass',
optmass: 'Optimal mass',
optmul: 'Optimal multiplier',
- dps: 'Damage per second',
- eps: 'Energy per second',
- thermload: 'Thermal load',
- boot: 'Boot time',
- maxfuel: 'Maximum fuel per jump',
- syscap: 'Systems capacity',
- engcap: 'Engines capacity',
- wepcap: 'Weapons capacity',
- sysrate: 'Systems recharge rate',
- engrate: 'Engines recharge rate',
- weprate: 'Weapons recharge rate',
- kinres: 'Kinetic resistance',
- thermres: 'Thermal resistance',
- explres: 'Explosive resistance',
- regen: 'Regeneration rate',
- brokenregen: 'Broken regeneration rate',
- delay: 'Delay',
- duration: 'Duration',
- shield: 'Shield',
- shieldboost: 'Shield boost',
- distdraw: 'Distributor draw',
- damage: 'Damage',
- armourpen: 'Armour penetration',
+ pGen: 'Power generation',
+ power: 'Power draw',
range: 'Range',
+ regen: 'Regeneration rate',
+ reload: 'Reload time',
rof: 'Rate of fire',
- clip: 'Ammunition clip',
- ammo: 'Ammunition maximum',
- jitter: 'Jitter',
- reload: 'Reload time'
+ shield: 'Shield',
+ shieldmul: 'Shield boost',
+ syscap: 'Systems capacity',
+ sysrate: 'Systems recharge rate',
+ thermload: 'Thermal load',
+ thermres: 'Thermal resistance',
+ wepcap: 'Weapons capacity',
+ weprate: 'Weapons recharge rate',
};
diff --git a/src/app/shipyard/Calculations.js b/src/app/shipyard/Calculations.js
index 6fa9c88d..21d818d6 100644
--- a/src/app/shipyard/Calculations.js
+++ b/src/app/shipyard/Calculations.js
@@ -60,11 +60,8 @@ export function shieldStrength(mass, baseShield, sg, multiplier) {
let exponent = Math.log((optMul - minMul) / (maxMul - minMul)) / Math.log(Math.min(1, (maxMass - optMass) / (maxMass - minMass)))
let ynorm = Math.pow(xnorm, exponent);
let mul = minMul + ynorm * (maxMul - minMul);
- let strength = baseShield * mul;
- // TODO handle multiplier
-
- return strength;
+ return baseShield * mul * multiplier;
}
/**
diff --git a/src/app/shipyard/Module.js b/src/app/shipyard/Module.js
index efae87ca..c4eccac6 100755
--- a/src/app/shipyard/Module.js
+++ b/src/app/shipyard/Module.js
@@ -32,7 +32,7 @@ export default class Module {
* @return {Number} The value of the modification, as a decimal value from -1 to 1
*/
getModValue(name) {
- return this.mods ? this.mods[name] / 10000 : null;
+ return this.mods && this.mods[name] ? this.mods[name] / 10000 : null;
}
/**
@@ -390,4 +390,72 @@ export default class Module {
}
return result;
}
+
+ /**
+ * Get the shield multiplier for this module, taking in to account modifications
+ * @return {Number} the shield multiplier of this module
+ */
+ getShieldMul() {
+ return this._getModifiedValue('shieldmul');
+ }
+
+
+ /**
+ * Get the DPS for this module, taking in to account modifications
+ * @return {Number} the DPS of this module
+ */
+ getDps() {
+ // TODO this is not correct; need to include other factors such as rate of fire, damage, etc.
+ return this._getModifiedValue('dps');
+ }
+
+ /**
+ * Get the heat generated per second for this module, taking in to account modifications
+ * @return {Number} the heat generated per second of this module
+ */
+ getHps() {
+ // TODO this is not correct; need to include other factors such as rate of fire, damage, etc.
+ return this._getModifiedValue('hps');
+ }
+
+ /**
+ * Get the energy used per second for this module, taking in to account modifications
+ * @return {Number} the energy used per second of this module
+ */
+ getEps() {
+ // TODO this is not correct; need to include other factors such as rate of fire, damage, etc.
+ return this._getModifiedValue('eps');
+ }
+
+ /**
+ * Get the clip size for this module, taking in to account modifications
+ * @return {Number} the clip size of this module
+ */
+ getClip() {
+ return this._getModifiedValue('clip');
+ }
+
+ /**
+ * Get the ammo size for this module, taking in to account modifications
+ * @return {Number} the ammo size of this module
+ */
+ getAmmo() {
+ return this._getModifiedValue('ammo');
+ }
+
+ /**
+ * Get the reload time for this module, taking in to account modifications
+ * @return {Number} the reload time of this module
+ */
+ getReload() {
+ return this._getModifiedValue('reload');
+ }
+
+ /**
+ * Get the rate of fire for this module, taking in to account modifications
+ * @return {Number} the rate of fire for this module
+ */
+ getRoF() {
+ return this._getModifiedValue('rof');
+ }
}
diff --git a/src/app/shipyard/ModuleSet.js b/src/app/shipyard/ModuleSet.js
index b3ddf314..9fa480ee 100755
--- a/src/app/shipyard/ModuleSet.js
+++ b/src/app/shipyard/ModuleSet.js
@@ -126,7 +126,7 @@ export default class ModuleSet {
let pd = this.standard[4][0];
for (let p of this.standard[4]) {
- if (p.mass < pd.mass && p.getEnginesCapacity() >= boostEnergy) {
+ if (p.mass < pd.mass && p.engcap >= boostEnergy) {
pd = p;
}
}
diff --git a/src/app/shipyard/Ship.js b/src/app/shipyard/Ship.js
index 09085b9a..6d1720dd 100755
--- a/src/app/shipyard/Ship.js
+++ b/src/app/shipyard/Ship.js
@@ -441,6 +441,9 @@ export default class Ship {
// Could be for either thrusters or FSD
this.updateTopSpeed();
this.updateJumpStats();
+ } else if (name == 'shieldmul') {
+ m.setModValue(name, value);
+ this.updateShieldStrength();
} else {
// Generic
m.setModValue(name, value);
@@ -686,7 +689,7 @@ export default class Ship {
if (ModuleUtils.isShieldGenerator(slot.m.grp)) {
this.updateShieldStrength();
} else if (slot.m.grp == 'sb') {
- this.shieldMultiplier += slot.m.shieldmul * (enabled ? 1 : -1);
+ this.shieldMultiplier += slot.m.getShieldMul() * (enabled ? 1 : -1);
this.updateShieldStrength();
}
if (slot.m.dps) {
@@ -752,7 +755,7 @@ export default class Ship {
this.armourAdded -= old.armouradd;
break;
case 'sb':
- this.shieldMultiplier -= slot.enabled ? old.shieldmul : 0;
+ this.shieldMultiplier -= slot.enabled ? old.getShieldMul() : 0;
break;
}
@@ -794,7 +797,7 @@ export default class Ship {
this.armourAdded += n.armouradd;
break;
case 'sb':
- this.shieldMultiplier += slot.enabled ? n.shieldmul : 0;
+ this.shieldMultiplier += slot.enabled ? n.getShieldMul() : 0;
break;
}