);
diff --git a/src/app/shipyard/Module.js b/src/app/shipyard/Module.js
index 6e8533da..bf38e8ec 100755
--- a/src/app/shipyard/Module.js
+++ b/src/app/shipyard/Module.js
@@ -1,5 +1,6 @@
import * as ModuleUtils from './ModuleUtils';
import * as _ from 'lodash';
+import { Modifications } from 'coriolis-data/dist';
/**
* Module - active module in a ship's buildout
@@ -65,8 +66,20 @@ export default class Module {
_getModifiedValue(name, additive) {
let result = this[name] || (additive ? 0 : null); // Additive NULL === 0
if (result != null) {
- // Jitter is special, being the only non-percentage value (it is in fact degrees)
- const modValue = name === 'jitter' ? this.getModValue(name) / 100 : this.getModValue(name) / 10000;
+ const modification = Modifications.modifications[name];
+ if (!modification) {
+ return result;
+ }
+ // We store percentages as decimals, so to get them back we need to divide by 10000. Otherwise
+ // we divide by 100. Both ways we end up with a value with two decimal places
+ let modValue;
+ if (modification.type === 'percentage') {
+ modValue = this.getModValue(name) / 10000;
+ } else if (modification.type === 'numeric') {
+ modValue = this.getModValue(name) / 100;
+ } else {
+ modValue = this.getModValue(name);
+ }
if (modValue) {
if (additive) {
result = result + modValue;
@@ -74,7 +87,18 @@ export default class Module {
result = result * (1 + modValue);
}
}
+ } else {
+ if (name === 'burst') {
+ // Burst is special, as if it can not exist but have a modification
+ const modValue = this.getModValue(name) / 100;
+ return modValue;
+ } else if (name === 'burstrof') {
+ // Burst rate of fire is special, as if it can not exist but have a modification
+ const modValue = this.getModValue(name) / 100;
+ return modValue;
+ }
}
+
return result;
}
@@ -425,7 +449,7 @@ export default class Module {
getDps() {
// DPS is a synthetic value
let damage = this.getDamage();
- let rpshot = this.getRoundsPerShot() || 1;
+ let rpshot = this.roundspershot || 1;
let rof = this.getRoF() || 1;
return damage * rpshot * rof;
@@ -438,7 +462,7 @@ export default class Module {
getEps() {
// EPS is a synthetic value
let distdraw = this.getDistDraw();
- let rpshot = this.getRoundsPerShot() || 1;
+ let rpshot = this.roundspershot || 1;
let rof = this.getRoF() || 1;
return distdraw * rpshot * rof;
@@ -451,7 +475,7 @@ export default class Module {
getHps() {
// HPS is a synthetic value
let heat = this.getThermalLoad();
- let rpshot = this.getRoundsPerShot() || 1;
+ let rpshot = this.roundspershot || 1;
let rof = this.getRoF() || 1;
return heat * rpshot * rof;
@@ -482,11 +506,35 @@ export default class Module {
}
/**
- * Get the rate of fire for this module, taking in to account modifications
+ * Get the burst size for this module, taking in to account modifications
+ * @return {Number} the burst size of this module
+ */
+ getBurst() {
+ return this._getModifiedValue('burst');
+ }
+
+ /**
+ * Get the burst rate of fire for this module, taking in to account modifications
+ * @return {Number} the burst rate of fire of this module
+ */
+ getBurstRoF() {
+ return this._getModifiedValue('burstrof');
+ }
+
+ /**
+ * Get the rate of fire for this module, taking in to account modifications.
+ * The rate of fire is a combination value, and needs to take in to account
+ * bursts of fire.
+ * Firing goes [burst 1] [burst interval] [burst 2] [burst interval] ... [burst n] [interval]
+ * where 'n' is 'burst', 'burst interval' is '1/burstrof' and 'interval' is '1/rof'
* @return {Number} the rate of fire for this module
*/
getRoF() {
- return this._getModifiedValue('rof');
+ const burst = this.getBurst() || 1;
+ const burstRoF = this.getBurstRoF() || 1;
+ const intRoF = this._getModifiedValue('rof');
+
+ return burst / (((burst - 1) / burstRoF) + 1 / intRoF);
}
/**
diff --git a/src/app/shipyard/Serializer.js b/src/app/shipyard/Serializer.js
index 6732049c..cd9951a6 100644
--- a/src/app/shipyard/Serializer.js
+++ b/src/app/shipyard/Serializer.js
@@ -8,7 +8,7 @@ import { outfitURL } from '../utils/UrlGenerators';
const STANDARD = ['powerPlant', 'thrusters', 'frameShiftDrive', 'lifeSupport', 'powerDistributor', 'sensors', 'fuelTank'];
-const STANDARD_GROUPS = {'powerPlant': 'pp', 'thrusters': 't', 'frameShiftDrive': 'fsd', 'lifeSupport': 'ls', 'powerDistributor': 'pd', 'sensors': 's', 'fuelTank': 'ft'};
+const STANDARD_GROUPS = { 'powerPlant': 'pp', 'thrusters': 't', 'frameShiftDrive': 'fsd', 'lifeSupport': 'ls', 'powerDistributor': 'pd', 'sensors': 's', 'fuelTank': 'ft' };
/**
* Generates ship-loadout JSON Schema standard object
diff --git a/src/app/shipyard/Ship.js b/src/app/shipyard/Ship.js
index 1a9a386e..be771cbc 100755
--- a/src/app/shipyard/Ship.js
+++ b/src/app/shipyard/Ship.js
@@ -458,7 +458,7 @@ export default class Ship {
} else if (name === 'shieldreinforcement') {
m.setModValue(name, value);
this.recalculateShieldCells();
- } else if (name === 'burst' || name === 'clip' || name === 'damage' || name === 'distdraw' || name === 'jitter' || name === 'piercing' || name === 'range' || name === 'reload' || name === 'rof' || name === 'thermload') {
+ } else if (name === 'burst' || name == 'burstrof' || name === 'clip' || name === 'damage' || name === 'distdraw' || name === 'jitter' || name === 'piercing' || name === 'range' || name === 'reload' || name === 'rof' || name === 'thermload') {
m.setModValue(name, value);
this.recalculateDps();
this.recalculateHps();
@@ -1260,7 +1260,7 @@ export default class Ship {
let modElements = mods[j].split(':');
if (modElements[0].match('[0-9]+')) {
const modification = _.find(Modifications.modifications, function(o) { return o.id === modElements[0]; });
- if (modification != null) arr[i][modification.name] = Number(modElements[1]);
+ if (modification != null) arr[i][modification.name] = Number(modElements[1]);
} else {
arr[i][modElements[0]] = Number(modElements[1]);
}
@@ -1297,7 +1297,7 @@ export default class Ship {
bulkheadBlueprint = this.bulkheads.m.blueprint;
}
slots.push(bulkheadMods);
- blueprints.push(bulkheadBlueprint)
+ blueprints.push(bulkheadBlueprint);
specials.push(bulkheadBlueprint ? bulkheadBlueprint.special : null);
for (let slot of this.standard) {
@@ -1356,7 +1356,7 @@ export default class Ship {
for (let special of specials) {
if (special) {
// Length is 5 for each special
- bufsize += 5;
+ bufsize += 5;
}
}
@@ -1376,20 +1376,20 @@ export default class Ship {
buffer.writeInt8(MODIFICATION_ID_GRADE, curpos++);
buffer.writeInt32LE(blueprints[i].grade, curpos);
curpos += 4;
- }
+ }
if (specials[i]) {
buffer.writeInt8(MODIFICATION_ID_SPECIAL, curpos++);
buffer.writeInt32LE(specials[i].id, curpos);
curpos += 4;
- }
+ }
for (let slotMod of slot) {
buffer.writeInt8(slotMod.id, curpos++);
- if (isNaN(slotMod.value)) {
- // Need to write the string with exactly four characters, so pad with whitespace
- buffer.write((" " + slotMod.value).slice(-4), curpos, 4);
- } else {
- buffer.writeInt32LE(slotMod.value, curpos);
- }
+ if (isNaN(slotMod.value)) {
+ // Need to write the string with exactly four characters, so pad with whitespace
+ buffer.write((' ' + slotMod.value).slice(-4), curpos, 4);
+ } else {
+ buffer.writeInt32LE(slotMod.value, curpos);
+ }
// const modification = _.find(Modifications.modifications, function(o) { return o.id === slotMod.id; });
// console.log('ENCODE Slot ' + i + ': ' + modification.name + ' = ' + slotMod.value);
curpos += 4;
@@ -1414,7 +1414,7 @@ export default class Ship {
* See updateModificationsString() for details of the structure.
* @param {String} buffer Buffer holding modification info
* @param {Array} modArr Modification array
- * @param {Array} bluprintArr Blueprint array
+ * @param {Array} blueprintArr Blueprint array
*/
decodeModificationsStruct(buffer, modArr, blueprintArr) {
let curpos = 0;
@@ -1428,22 +1428,22 @@ export default class Ship {
if (modificationId === 40) {
// Type is special, in that it's a character string
modificationValue = buffer.toString('utf8', curpos, curpos + 4).trim();
- } else {
+ } else {
modificationValue = buffer.readInt32LE(curpos);
- }
+ }
curpos += 4;
- // There are a number of 'special' modification IDs, check for them here
- if (modificationId === MODIFICATION_ID_BLUEPRINT) {
+ // There are a number of 'special' modification IDs, check for them here
+ if (modificationId === MODIFICATION_ID_BLUEPRINT) {
blueprint = Object.assign(blueprint, _.find(Modifications.blueprints, function(o) { return o.id === modificationValue; }));
- } else if (modificationId === MODIFICATION_ID_GRADE) {
+ } else if (modificationId === MODIFICATION_ID_GRADE) {
blueprint.grade = modificationValue;
- } else if (modificationId === MODIFICATION_ID_SPECIAL) {
+ } else if (modificationId === MODIFICATION_ID_SPECIAL) {
blueprint.special = _.find(Modifications.specials, function(o) { return o.id === modificationValue; });
- } else {
+ } else {
const modification = _.find(Modifications.modifications, function(o) { return o.id === modificationId; });
// console.log('DECODE Slot ' + slot + ': ' + modification.name + ' = ' + modificationValue);
modifications[modification.name] = modificationValue;
- }
+ }
modificationId = buffer.readInt8(curpos++);
}
modArr[slot] = modifications;
diff --git a/src/app/utils/CompanionApiUtils.js b/src/app/utils/CompanionApiUtils.js
index c11783ab..6d90bc7f 100644
--- a/src/app/utils/CompanionApiUtils.js
+++ b/src/app/utils/CompanionApiUtils.js
@@ -277,29 +277,43 @@ export function shipFromJson(json) {
function _addModifications(module, modifiers, blueprint, grade) {
if (!modifiers || !modifiers.modifiers) return;
- var special;
+ let special;
for (const i in modifiers.modifiers) {
- // Look up the modifiers to find what we need to do
- const modifierActions = Modifications.modifierActions[modifiers.modifiers[i].name];
- const value = modifiers.modifiers[i].value;
+ // Some special modifications
+ if (modifiers.modifiers[i].name === 'mod_weapon_clip_size_override') {
+ // This is a numeric addition to the clip size, but we need to work it out in terms of being a percentage so
+ // that it works the same as other modifications
+ const origClip = module.clip || 1;
+ module.setModValue('clip', ((modifiers.modifiers[i].value - origClip) / origClip) * 10000);
+ } else if (modifiers.modifiers[i].name === 'mod_weapon_burst_size') {
+ // This is an absolute number that acts as an override
+ module.setModValue('burst', modifiers.modifiers[i].value * 100);
+ } else if (modifiers.modifiers[i].name === 'mod_weapon_burst_rof') {
+ // For some reason this is a non-normalised percentage (i.e. 12.23% is 12.23 value rather than 0.1223 as everywhere else), so fix that here
+ module.setModValue('burstrof', modifiers.modifiers[i].value * 100);
+ } else {
+ // Look up the modifiers to find what we need to do
+ const modifierActions = Modifications.modifierActions[modifiers.modifiers[i].name];
+ const value = modifiers.modifiers[i].value;
- // Carry out the required changes
- for (const action in modifierActions) {
- if (isNaN(modifierActions[action])) {
- module.setModValue(action, modifierActions[action]);
- } else {
- const actionValue = modifierActions[action] * value;
- let mod = module.getModValue(action) / 10000;
- if (!mod) {
- mod = 0;
+ // Carry out the required changes
+ for (const action in modifierActions) {
+ if (isNaN(modifierActions[action])) {
+ module.setModValue(action, modifierActions[action]);
+ } else {
+ const actionValue = modifierActions[action] * value;
+ let mod = module.getModValue(action) / 10000;
+ if (!mod) {
+ mod = 0;
+ }
+ module.setModValue(action, ((1 + mod) * (1 + actionValue) - 1) * 10000);
}
- module.setModValue(action, ((1 + mod) * (1 + actionValue) - 1) * 10000);
}
}
// Note the special if present
if (modifiers.modifiers[i].name && modifiers.modifiers[i].name.startsWith('special_')) {
- special = Modifications.specials[modifiers.modifiers[i].name];
+ special = Modifications.specials[modifiers.modifiers[i].name];
}
}