mirror of
https://github.com/EDCD/coriolis.git
synced 2025-12-08 22:33:24 +00:00
Add ability to import directly from companion API output
This commit is contained in:
@@ -6,6 +6,8 @@
|
||||
* Add initial loadout passenger cabins for Beluga
|
||||
* Add initial loadout passenger cabins for Orca
|
||||
* Update costs and initial loadouts for Keelback and Type-7
|
||||
* Add resistances for hull reinforcement packages
|
||||
* Added modifier actions to create modifications from raw data
|
||||
* Show modification icon for modified modules
|
||||
* Take modifications in to account when deciding whether to issue a warning on a standard module
|
||||
* Fix hardpoint comparison DPS number when selecting an alternate module
|
||||
@@ -14,3 +16,4 @@
|
||||
* Enable boost display even if power distributor is disabled
|
||||
* Calculate breakdown of ship offensive and defensive stats
|
||||
* Add 'Offence summary' and 'Defence summary' components
|
||||
* Add ability to import directly from companion API output
|
||||
|
||||
1288
__tests__/fixtures/companion-api-import-1.json
Normal file
1288
__tests__/fixtures/companion-api-import-1.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -196,6 +196,23 @@ describe('Import Modal', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Import Companion API Build', function() {
|
||||
|
||||
beforeEach(reset);
|
||||
|
||||
it('imports a valid v4 build', function() {
|
||||
const importData = require('./fixtures/companion-api-import-1');
|
||||
pasteText(JSON.stringify(importData));
|
||||
|
||||
expect(modal.state.importValid).toBeTruthy();
|
||||
expect(modal.state.errorMsg).toEqual(null);
|
||||
expect(modal.state.singleBuild).toBe(true);
|
||||
clickProceed();
|
||||
expect(MockRouter.go.mock.calls.length).toBe(1);
|
||||
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/federal_corvette/2putsFklndzsxf50x0x7l28281919040404040402020l060606f6f65i5iv6v62f.AwRj4zNaZI==.CwJgjBkAw7eyKkI0kA==.H4sIAAAAAAAAA22Qvy5EURDG5+51-+w94uweF0dY--aiICQrwSPYYt9AS3XjARQKiWb1nkCioZEoRKfZmlLES6xCLMb3KSQSzZeZ85v5ZuYE43EkYi9VNd0TEa2M9WKRpstF-HUFaGagmq9-qbrTEDx0Zw6vB++qPq+K5CUqNVpMjMjSHSrme0AL+2ioXnyoZk9I7SacNJ08TESi-qtq3EalOw8wpIMizaISXnHuRRpItbaNXZrlrsjEM3MT3WfgR1N-+BtM7C0m6XDU-en-5VvkV0PgLUS8Rnwb49T6HcRmBV11SkGxXZrU-AAVpkNEKSj2kaju+0QbRJSCYkdAZo9TuDr-ggvNKrmQM7InbB31a1jTFJ9AlIJiDbecnrvB8ckDypZD+Act-nDj31f9Bizb3eiqAQAA?bn=Imported%20Federal%20Corvette');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Import E:D Shipyard Builds', function() {
|
||||
|
||||
it('imports a valid builds', function() {
|
||||
|
||||
@@ -11,6 +11,7 @@ import * as ModuleUtils from '../shipyard/ModuleUtils';
|
||||
import { fromDetailedBuild } from '../shipyard/Serializer';
|
||||
import { Download } from './SvgIcons';
|
||||
import { outfitURL } from '../utils/UrlGenerators';
|
||||
import * as CompanionApiUtils from '../utils/CompanionApiUtils';
|
||||
|
||||
const textBuildRegex = new RegExp('^\\[([\\w \\-]+)\\]\n');
|
||||
const lineRegex = new RegExp('^([\\dA-Z]{1,2}): (\\d)([A-I])[/]?([FGT])?([SD])? ([\\w\\- ]+)');
|
||||
@@ -112,6 +113,7 @@ export default class ModalImport extends TranslatedComponent {
|
||||
this._importBackup = this._importBackup.bind(this);
|
||||
this._importDetailedArray = this._importDetailedArray.bind(this);
|
||||
this._importTextBuild = this._importTextBuild.bind(this);
|
||||
this._importCompanionApiBuild = this._importCompanionApiBuild.bind(this);
|
||||
this._validateImport = this._validateImport.bind(this);
|
||||
}
|
||||
|
||||
@@ -183,6 +185,21 @@ export default class ModalImport extends TranslatedComponent {
|
||||
this.setState({ builds });
|
||||
}
|
||||
|
||||
/**
|
||||
* Import a build direct from the companion API
|
||||
* @param {string} build JSON from the companion API information
|
||||
* @throws {string} if parse/import fails
|
||||
*/
|
||||
_importCompanionApiBuild(build) {
|
||||
const shipModel = CompanionApiUtils.shipModelFromJson(build);
|
||||
const ship = CompanionApiUtils.shipFromJson(build);
|
||||
|
||||
let builds = {};
|
||||
builds[shipModel] = {};
|
||||
builds[shipModel]['Imported ' + Ships[shipModel].properties.name] = ship.toString();
|
||||
this.setState({ builds, singleBuild: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Import a text build from ED Shipyard
|
||||
* @param {string} buildStr Build string
|
||||
@@ -315,7 +332,11 @@ export default class ModalImport extends TranslatedComponent {
|
||||
throw 'Must be an object or array!';
|
||||
}
|
||||
|
||||
if (importData instanceof Array) { // Must be detailed export json
|
||||
if (importData.cockpitBreached != null) { // Only the companion API has this information
|
||||
this._importCompanionApiBuild(importData); // Single sihp definition
|
||||
} else if (importData.ship != null && importData.ship.cockpitBreached != null) { // Only the companion API has this information
|
||||
this._importCompanionApiBuild(importData.ship); // Complete API dump
|
||||
} else if (importData instanceof Array) { // Must be detailed export json
|
||||
this._importDetailedArray(importData);
|
||||
} else if (importData.ship && typeof importData.name !== undefined) { // Using JSON from a single ship build export
|
||||
this._importDetailedArray([importData]); // Convert to array with singleobject
|
||||
|
||||
@@ -1233,7 +1233,7 @@ export default class Ship {
|
||||
let bulkheadMods = new Array();
|
||||
if (this.bulkheads.m && this.bulkheads.m.mods) {
|
||||
for (let modKey in this.bulkheads.m.mods) {
|
||||
bulkheadMods.push(Modifications.modifiers.indexOf(modKey) + ':' + this.bulkheads.m.getModValue(modKey));
|
||||
bulkheadMods.push(Modifications.modifications.indexOf(modKey) + ':' + this.bulkheads.m.getModValue(modKey));
|
||||
}
|
||||
}
|
||||
allMods.push(bulkheadMods.join(';'));
|
||||
@@ -1242,7 +1242,7 @@ export default class Ship {
|
||||
let slotMods = new Array();
|
||||
if (slot.m && slot.m.mods) {
|
||||
for (let modKey in slot.m.mods) {
|
||||
slotMods.push(Modifications.modifiers.indexOf(modKey) + ':' + slot.m.getModValue(modKey));
|
||||
slotMods.push(Modifications.modifications.indexOf(modKey) + ':' + slot.m.getModValue(modKey));
|
||||
}
|
||||
}
|
||||
allMods.push(slotMods.join(';'));
|
||||
@@ -1251,7 +1251,7 @@ export default class Ship {
|
||||
let slotMods = new Array();
|
||||
if (slot.m && slot.m.mods) {
|
||||
for (let modKey in slot.m.mods) {
|
||||
slotMods.push(Modifications.modifiers.indexOf(modKey) + ':' + slot.m.getModValue(modKey));
|
||||
slotMods.push(Modifications.modifications.indexOf(modKey) + ':' + slot.m.getModValue(modKey));
|
||||
}
|
||||
}
|
||||
allMods.push(slotMods.join(';'));
|
||||
@@ -1260,7 +1260,7 @@ export default class Ship {
|
||||
let slotMods = new Array();
|
||||
if (slot.m && slot.m.mods) {
|
||||
for (let modKey in slot.m.mods) {
|
||||
slotMods.push(Modifications.modifiers.indexOf(modKey) + ':' + slot.m.getModValue(modKey));
|
||||
slotMods.push(Modifications.modifications.indexOf(modKey) + ':' + slot.m.getModValue(modKey));
|
||||
}
|
||||
}
|
||||
allMods.push(slotMods.join(';'));
|
||||
@@ -1283,7 +1283,7 @@ export default class Ship {
|
||||
for (let j = 0; j < mods.length; j++) {
|
||||
let modElements = mods[j].split(':');
|
||||
if (modElements[0].match('[0-9]+')) {
|
||||
arr[i][Modifications.modifiers[modElements[0]]] = Number(modElements[1]);
|
||||
arr[i][Modifications.modifications[modElements[0]]] = Number(modElements[1]);
|
||||
} else {
|
||||
arr[i][modElements[0]] = Number(modElements[1]);
|
||||
}
|
||||
@@ -1297,7 +1297,7 @@ export default class Ship {
|
||||
* This is a binary structure. It starts with a byte that identifies a slot, with bulkheads being ID 0 and moving through
|
||||
* standard modules, hardpoints, and finally internal modules. It then contains one or more modifications, with each
|
||||
* modification being a one-byte modification ID and at two-byte modification value. Modification IDs are based on the array
|
||||
* in Modifications.modifiers. The list of modifications is terminated by a modification ID of -1. The structure then repeats
|
||||
* in Modifications.modifications. The list of modifications is terminated by a modification ID of -1. The structure then repeats
|
||||
* for the next module, and the next, and is terminated by a slot ID of -1.
|
||||
* @return {this} The ship instance (for chaining operations)
|
||||
*/
|
||||
@@ -1310,7 +1310,7 @@ export default class Ship {
|
||||
for (let modKey in this.bulkheads.m.mods) {
|
||||
// Filter out invalid modifications
|
||||
if (Modifications.validity['bh'] && Modifications.validity['bh'].indexOf(modKey) != -1) {
|
||||
bulkheadMods.push({ id: Modifications.modifiers.indexOf(modKey), value: this.bulkheads.m.getModValue(modKey) });
|
||||
bulkheadMods.push({ id: Modifications.modifications.indexOf(modKey), value: this.bulkheads.m.getModValue(modKey) });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1322,7 +1322,7 @@ export default class Ship {
|
||||
for (let modKey in slot.m.mods) {
|
||||
// Filter out invalid modifications
|
||||
if (Modifications.validity[slot.m.grp] && Modifications.validity[slot.m.grp].indexOf(modKey) != -1) {
|
||||
slotMods.push({ id: Modifications.modifiers.indexOf(modKey), value: slot.m.getModValue(modKey) });
|
||||
slotMods.push({ id: Modifications.modifications.indexOf(modKey), value: slot.m.getModValue(modKey) });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1335,7 +1335,7 @@ export default class Ship {
|
||||
for (let modKey in slot.m.mods) {
|
||||
// Filter out invalid modifications
|
||||
if (Modifications.validity[slot.m.grp] && Modifications.validity[slot.m.grp].indexOf(modKey) != -1) {
|
||||
slotMods.push({ id: Modifications.modifiers.indexOf(modKey), value: slot.m.getModValue(modKey) });
|
||||
slotMods.push({ id: Modifications.modifications.indexOf(modKey), value: slot.m.getModValue(modKey) });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1348,7 +1348,7 @@ export default class Ship {
|
||||
for (let modKey in slot.m.mods) {
|
||||
// Filter out invalid modifications
|
||||
if (Modifications.validity[slot.m.grp] && Modifications.validity[slot.m.grp].indexOf(modKey) != -1) {
|
||||
slotMods.push({ id: Modifications.modifiers.indexOf(modKey), value: slot.m.getModValue(modKey) });
|
||||
slotMods.push({ id: Modifications.modifications.indexOf(modKey), value: slot.m.getModValue(modKey) });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1375,7 +1375,7 @@ export default class Ship {
|
||||
for (let slotMod of slot) {
|
||||
buffer.writeInt8(slotMod.id, curpos++);
|
||||
buffer.writeInt32LE(slotMod.value, curpos);
|
||||
// console.log('ENCODE Slot ' + i + ': ' + Modifications.modifiers[slotMod.id] + ' = ' + slotMod.value);
|
||||
// console.log('ENCODE Slot ' + i + ': ' + Modifications.modifications[slotMod.id] + ' = ' + slotMod.value);
|
||||
curpos += 4;
|
||||
}
|
||||
buffer.writeInt8(-1, curpos++);
|
||||
@@ -1408,8 +1408,8 @@ export default class Ship {
|
||||
while (modificationId != -1) {
|
||||
let modificationValue = buffer.readInt32LE(curpos);
|
||||
curpos += 4;
|
||||
// console.log('DECODE Slot ' + slot + ': ' + Modifications.modifiers[modificationId] + ' = ' + modificationValue);
|
||||
modifications[Modifications.modifiers[modificationId]] = modificationValue;
|
||||
// console.log('DECODE Slot ' + slot + ': ' + Modifications.modifications[modificationId] + ' = ' + modificationValue);
|
||||
modifications[Modifications.modifications[modificationId]] = modificationValue;
|
||||
modificationId = buffer.readInt8(curpos++);
|
||||
}
|
||||
arr[slot] = modifications;
|
||||
|
||||
317
src/app/utils/CompanionApiUtils.js
Normal file
317
src/app/utils/CompanionApiUtils.js
Normal file
@@ -0,0 +1,317 @@
|
||||
import React from 'react';
|
||||
import { Modifications, Modules, Ships } from 'coriolis-data/dist';
|
||||
import Module from '../shipyard/Module';
|
||||
import Ship from '../shipyard/Ship';
|
||||
import * as ModuleUtils from '../shipyard/ModuleUtils';
|
||||
|
||||
|
||||
// mapping from fd's ship model names to coriolis'
|
||||
const SHIP_FD_NAME_TO_CORIOLIS_NAME = {
|
||||
'Adder': 'adder',
|
||||
'Anaconda': 'anaconda',
|
||||
'Asp': 'asp',
|
||||
'Asp_Scout': 'asp_scout',
|
||||
'BelugaLiner': 'beluga',
|
||||
'CobraMkIII': 'cobra_mk_iii',
|
||||
'CobraMkIV': 'cobra_mk_iv',
|
||||
'Cutter': 'imperial_cutter',
|
||||
'DiamondBack': 'diamondback_explorer',
|
||||
'DiamondBackXL': 'diamondback',
|
||||
'Eagle': 'eagle',
|
||||
'Empire_Courier': 'imperial_courier',
|
||||
'Empire_Eagle': 'imperial_eagle',
|
||||
'Empire_Trader': 'imperial_clipper',
|
||||
'Federation_Corvette': 'federal_corvette',
|
||||
'Federation_Dropship': 'federal_dropship',
|
||||
'Federation_Dropship_MkII': 'federal_assault_ship',
|
||||
'Federation_Gunship': 'federal_gunship',
|
||||
'FerDeLance': 'fer_de_lance',
|
||||
'Hauler': 'hauler',
|
||||
'Independant_Trader': 'keelback',
|
||||
'Orca': 'orca',
|
||||
'Python': 'python',
|
||||
'SideWinder': 'sidewinder',
|
||||
'Type6': 'type_6_transporter',
|
||||
'Type7': 'type_7_transport',
|
||||
'Type9': 'type_9_heavy',
|
||||
'Viper': 'viper',
|
||||
'Viper_MKIV': 'viper_mk_iv',
|
||||
'Vulture': 'vulture'
|
||||
};
|
||||
|
||||
// Mapping from hardpoint class to name in companion API
|
||||
const HARDPOINT_NUM_TO_CLASS = {
|
||||
0: 'Tiny',
|
||||
1: 'Small',
|
||||
2: 'Medium',
|
||||
3: 'Large',
|
||||
4: 'Huge'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Obtain a module given its ED ID
|
||||
* @param {Integer} edId the Elite ID of the module
|
||||
* @return {Module} the module
|
||||
*/
|
||||
function _moduleFromEdId(edId) {
|
||||
if (!edId) return null;
|
||||
|
||||
// Check standard modules
|
||||
for (const grp in Modules.standard) {
|
||||
if (Modules.standard.hasOwnProperty(grp)) {
|
||||
for (const i in Modules.standard[grp]) {
|
||||
if (Modules.standard[grp][i].edID === edId) {
|
||||
// Found it
|
||||
return new Module({ template: Modules.standard[grp][i] });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check hardpoint modules
|
||||
for (const grp in Modules.hardpoints) {
|
||||
if (Modules.hardpoints.hasOwnProperty(grp)) {
|
||||
for (const i in Modules.hardpoints[grp]) {
|
||||
if (Modules.hardpoints[grp][i].edID === edId) {
|
||||
// Found it
|
||||
return new Module({ template: Modules.hardpoints[grp][i] });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check internal modules
|
||||
for (const grp in Modules.internal) {
|
||||
if (Modules.internal.hasOwnProperty(grp)) {
|
||||
for (const i in Modules.internal[grp]) {
|
||||
if (Modules.internal[grp][i].edID === edId) {
|
||||
// Found it
|
||||
return new Module({ template: Modules.internal[grp][i] });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not found
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the model of a ship given its ED name
|
||||
* @param {string} edName the Elite name of the ship
|
||||
* @return {string} the Coriolis model of the ship
|
||||
*/
|
||||
function _shipModelFromEDName(edName) {
|
||||
return SHIP_FD_NAME_TO_CORIOLIS_NAME[edName];
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a ship's model from the companion API JSON
|
||||
* @param {object} json the companion API JSON
|
||||
* @return {string} the Coriolis model of the ship
|
||||
*/
|
||||
export function shipModelFromJson(json) {
|
||||
return _shipModelFromEDName(json.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a ship from the companion API JSON
|
||||
* @param {object} json the companion API JSON
|
||||
* @return {Ship} the built ship
|
||||
*/
|
||||
export function shipFromJson(json) {
|
||||
// Start off building a basic ship
|
||||
const shipModel = shipModelFromJson(json);
|
||||
if (!shipModel) {
|
||||
throw 'No such ship found: "' + json.name + '"';
|
||||
}
|
||||
const shipTemplate = Ships[shipModel];
|
||||
|
||||
let ship = new Ship(shipModel, shipTemplate.properties, shipTemplate.slots);
|
||||
ship.buildWith(null);
|
||||
|
||||
// Set the cargo hatch. We don't have any information on it so guess it's priority 5 and disabled
|
||||
ship.cargoHatch.enabled = false;
|
||||
ship.cargoHatch.priority = 4;
|
||||
|
||||
// Add the bulkheads
|
||||
const armourJson = json.modules.Armour.module;
|
||||
if (armourJson.name.endsWith('_Armour_Grade1')) {
|
||||
ship.useBulkhead(0, true);
|
||||
} else if (armourJson.name.endsWith('_Armour_Grade2')) {
|
||||
ship.useBulkhead(1, true);
|
||||
} else if (armourJson.name.endsWith('_Armour_Grade3')) {
|
||||
ship.useBulkhead(2, true);
|
||||
} else if (armourJson.name.endsWith('_Armour_Mirrored')) {
|
||||
ship.useBulkhead(3, true);
|
||||
} else if (armourJson.name.endsWith('_Armour_Reactive')) {
|
||||
ship.useBulkhead(4, true);
|
||||
} else {
|
||||
throw 'Unknown bulkheads "' + armourJson.name + '"';
|
||||
}
|
||||
ship.bulkheads.enabled = true;
|
||||
|
||||
// Add the standard modules
|
||||
// Power plant
|
||||
const powerplantJson = json.modules.PowerPlant.module;
|
||||
const powerplant = _moduleFromEdId(powerplantJson.id);
|
||||
if (powerplantJson.modifiers) _addModifications(powerplant, powerplantJson.modifiers);
|
||||
ship.use(ship.standard[0], powerplant, true);
|
||||
ship.standard[0].enabled = powerplantJson.on === true;
|
||||
ship.standard[0].priority = powerplantJson.priority + 1;
|
||||
|
||||
// Thrusters
|
||||
const thrustersJson = json.modules.MainEngines.module;
|
||||
const thrusters = _moduleFromEdId(thrustersJson.id);
|
||||
if (thrustersJson.modifiers) _addModifications(thrusters, thrustersJson.modifiers);
|
||||
ship.use(ship.standard[1], thrusters, true);
|
||||
ship.standard[1].enabled = thrustersJson.on === true;
|
||||
ship.standard[1].priority = thrustersJson.priority + 1;
|
||||
|
||||
// FSD
|
||||
const frameshiftdriveJson = json.modules.FrameShiftDrive.module;
|
||||
const frameshiftdrive = _moduleFromEdId(frameshiftdriveJson.id);
|
||||
if (frameshiftdriveJson.modifiers) _addModifications(frameshiftdrive, frameshiftdriveJson.modifiers);
|
||||
ship.use(ship.standard[2], frameshiftdrive, true);
|
||||
ship.standard[2].enabled = frameshiftdriveJson.on === true;
|
||||
ship.standard[2].priority = frameshiftdriveJson.priority + 1;
|
||||
|
||||
// Life support
|
||||
const lifesupportJson = json.modules.LifeSupport.module;
|
||||
const lifesupport = _moduleFromEdId(lifesupportJson.id);
|
||||
if (lifesupportJson.modifiers)_addModifications(lifesupport, lifesupportJson.modifiers);
|
||||
ship.use(ship.standard[3], lifesupport, true);
|
||||
ship.standard[3].enabled = lifesupportJson.on === true;
|
||||
ship.standard[3].priority = lifesupportJson.priority + 1;
|
||||
|
||||
// Power distributor
|
||||
const powerdistributorJson = json.modules.PowerDistributor.module;
|
||||
const powerdistributor = _moduleFromEdId(powerdistributorJson.id);
|
||||
if (powerdistributorJson.modifiers) _addModifications(powerdistributor, powerdistributorJson.modifiers);
|
||||
ship.use(ship.standard[4], powerdistributor, true);
|
||||
ship.standard[4].enabled = powerdistributorJson.on === true;
|
||||
ship.standard[4].priority = powerdistributorJson.priority + 1;
|
||||
|
||||
// Sensors
|
||||
const sensorsJson = json.modules.Radar.module;
|
||||
const sensors = _moduleFromEdId(sensorsJson.id);
|
||||
if (sensorsJson.modifiers) _addModifications(sensors, sensorsJson.modifiers);
|
||||
ship.use(ship.standard[5], sensors, true);
|
||||
ship.standard[5].enabled = sensorsJson.on === true;
|
||||
ship.standard[5].priority = sensorsJson.priority + 1;
|
||||
|
||||
// Fuel tank
|
||||
const fueltankJson = json.modules.FuelTank.module;
|
||||
const fueltank = _moduleFromEdId(fueltankJson.id);
|
||||
ship.use(ship.standard[6], fueltank, true);
|
||||
ship.standard[6].enabled = true;
|
||||
ship.standard[6].priority = 1;
|
||||
|
||||
// Add hardpoints
|
||||
let hardpointClassNum = -1;
|
||||
let hardpointSlotNum = -1;
|
||||
let hardpointArrayNum = 0;
|
||||
for (let i in shipTemplate.slots.hardpoints) {
|
||||
if (shipTemplate.slots.hardpoints[i] === hardpointClassNum) {
|
||||
// Another slot of the same class
|
||||
hardpointSlotNum++;
|
||||
} else {
|
||||
// The first slot of a new class
|
||||
hardpointClassNum = shipTemplate.slots.hardpoints[i];
|
||||
hardpointSlotNum = 1;
|
||||
}
|
||||
|
||||
// Now that we know what we're looking for, find it
|
||||
const hardpointName = HARDPOINT_NUM_TO_CLASS[hardpointClassNum] + 'Hardpoint' + hardpointSlotNum;
|
||||
const hardpointSlot = json.modules[hardpointName];
|
||||
if (!hardpointSlot.module) {
|
||||
// No module
|
||||
} else {
|
||||
const hardpointJson = hardpointSlot.module;
|
||||
const hardpoint = _moduleFromEdId(hardpointJson.id);
|
||||
if (hardpointJson.modifiers) _addModifications(hardpoint, hardpointJson.modifiers);
|
||||
ship.use(ship.hardpoints[hardpointArrayNum], hardpoint, true);
|
||||
ship.hardpoints[hardpointArrayNum].enabled = hardpointJson.on === true;
|
||||
ship.hardpoints[hardpointArrayNum].priority = hardpointJson.priority;
|
||||
}
|
||||
hardpointArrayNum++;
|
||||
}
|
||||
|
||||
// Add internal compartments
|
||||
let internalClassNum = -1;
|
||||
let internalSlotNum = 1;
|
||||
for (let i in shipTemplate.slots.internal) {
|
||||
const internalClassNum = shipTemplate.slots.internal[i];
|
||||
|
||||
let internalSlot = null;
|
||||
while (internalSlot === null && internalSlotNum < 99) {
|
||||
// Slot numbers are not contiguous so handle skips
|
||||
const internalName = 'Slot' + (internalSlotNum < 9 ? '0' : '') + internalSlotNum + '_Size' + internalClassNum;
|
||||
if (json.modules[internalName]) {
|
||||
internalSlot = json.modules[internalName];
|
||||
} else {
|
||||
internalSlotNum++;
|
||||
}
|
||||
}
|
||||
if (!internalSlot.module) {
|
||||
// No module
|
||||
} else {
|
||||
const internalJson = internalSlot.module;
|
||||
const internal = _moduleFromEdId(internalJson.id);
|
||||
if (internalJson.modifiers) _addModifications(internal, internalJson.modifiers);
|
||||
ship.use(ship.internal[i], internal, true);
|
||||
ship.internal[i].enabled = internalJson.on === true;
|
||||
ship.internal[i].priority = internalJson.priority;
|
||||
}
|
||||
}
|
||||
|
||||
// Now update the ship's codes before returning it
|
||||
return ship.updatePowerPrioritesString().updatePowerEnabledString().updateModificationsString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the modifications for a module
|
||||
* @param {Module} module the module
|
||||
* @param {Object} modifiers the modifiers
|
||||
*/
|
||||
function _addModifications(module, modifiers) {
|
||||
if (!modifiers || !modifiers.modifiers) return;
|
||||
|
||||
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;
|
||||
|
||||
// Carry out the required changes
|
||||
for (const action in modifierActions) {
|
||||
const actionValue = modifierActions[action] * value;
|
||||
let mod = module.getModValue(action);
|
||||
if (!mod) {
|
||||
mod = 0;
|
||||
}
|
||||
module.setModValue(action, ((1 + mod / 10000) * (1 + actionValue) - 1) * 10000);
|
||||
}
|
||||
}
|
||||
|
||||
// Need to fix up a few items
|
||||
|
||||
// Shield boosters are treated internally as straight modifiers, so rather than (for example)
|
||||
// being a 4% boost they are a 104% multiplier. Unfortunately this means that our % modification
|
||||
// is incorrect so we fix it
|
||||
if (module.grp === 'sb' && module.getModValue('shieldboost')) {
|
||||
const alteredBoost = (1 + module.shieldboost) * (module.getModValue('shieldboost'));
|
||||
module.setModValue('shieldboost', alteredBoost / module.shieldboost);
|
||||
}
|
||||
|
||||
// Jitter is in degrees not % so need to divide it by 100 to obtain the correct number
|
||||
if (module.getModValue('jitter')) {
|
||||
module.setModValue('jitter', module.getModValue('jitter') / 100);
|
||||
}
|
||||
|
||||
// FD uses interval between bursts internally, so we need to translate this to a real rate of fire
|
||||
if (module.getModValue('rof')) {
|
||||
module.setModValue('rof', (1 / (1 + module.getModValue('jitter'))) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user