mirror of
https://github.com/EDCD/coriolis.git
synced 2025-12-08 14:33:22 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9abb4f6d05 | ||
|
|
38038fcc32 | ||
|
|
9fa740f54e | ||
|
|
d37d69c3a7 | ||
|
|
78d8779641 | ||
|
|
352023f0fb | ||
|
|
3ea194d43e | ||
|
|
c6269192f0 | ||
|
|
841e6c3348 | ||
|
|
0febc581d1 | ||
|
|
dc6e398526 | ||
|
|
cb24c1fc69 | ||
|
|
90ad9de831 | ||
|
|
9360b1d574 | ||
|
|
08d2573d1f | ||
|
|
427b9af7de | ||
|
|
318d06d9f9 | ||
|
|
1f3c3726f2 | ||
|
|
71beda3a6c | ||
|
|
1d6644b531 |
@@ -43,6 +43,9 @@ services:
|
||||
- "traefik.basic.port=80"
|
||||
- "traefik.basic.protocol=http"
|
||||
|
||||
|
||||
|
||||
|
||||
networks:
|
||||
web:
|
||||
external: true
|
||||
|
||||
@@ -20,16 +20,28 @@ export default class StandardSlotSection extends SlotSection {
|
||||
super(props, context, 'standard', 'core internal');
|
||||
this._optimizeStandard = this._optimizeStandard.bind(this);
|
||||
this._selectBulkhead = this._selectBulkhead.bind(this);
|
||||
this._showDW2Menu = this._showDW2Menu.bind(this);
|
||||
this._dw2 = this._dw2.bind(this);
|
||||
this.selectedRefId = null;
|
||||
this.firstRefId = 'maxjump';
|
||||
this.lastRefId = 'racer';
|
||||
this.lastRefId = 'dw2';
|
||||
this.state = {
|
||||
showDW2: false,
|
||||
DW2Tier: -1,
|
||||
DW2Eng: -1,
|
||||
DW2Role: '',
|
||||
DW2Gfsb: false,
|
||||
DW2Gpp: false,
|
||||
DW2Fighter: false
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle focus if the component updates
|
||||
* @param {Object} prevProps React Component properties
|
||||
*/
|
||||
componentDidUpdate(prevProps) {
|
||||
this._handleSectionFocus(prevProps,this.firstRefId, this.lastRefId);
|
||||
this._handleSectionFocus(prevProps, this.firstRefId, this.lastRefId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,6 +84,114 @@ export default class StandardSlotSection extends SlotSection {
|
||||
this._close();
|
||||
}
|
||||
|
||||
/**
|
||||
* DW2 Build
|
||||
*/
|
||||
_dw2() {
|
||||
this.selectedRefId = 'dw2';
|
||||
this.setState({ showDW2: false });
|
||||
ShipRoles.dw2Build(this.props.ship, this.state.DW2Tier, this.state.DW2Eng, this.state.DW2Role, this.state.DW2Gfsb, this.state.DW2Gpp, this.state.DW2Fighter);
|
||||
this.props.ship.updateModificationsString();
|
||||
this.props.onChange();
|
||||
this.props.onCargoChange(this.props.ship.cargoCapacity);
|
||||
this.props.onFuelChange(this.props.ship.fuelCapacity);
|
||||
this._close();
|
||||
}
|
||||
|
||||
_showDW2Menu(translate) {
|
||||
return (
|
||||
<div className='select' onClick={(e) => e.stopPropagation()} onContextMenu={stopCtxPropagation}>
|
||||
<div className='select-group cap'>{translate('Tier')}</div>
|
||||
<ul id={'tier'}>
|
||||
<li className={cn({ active: this.state.DW2Tier === 1 }, 'lc')} tabIndex="0"
|
||||
onClick={() => this.setState({ DW2Tier: 1 })} onKeyDown={this._keyDown}
|
||||
>{translate('1 - Max. Jump Range, Unshielded')}</li>
|
||||
<li className={cn({ active: this.state.DW2Tier === 2 }, 'lc')} tabIndex="0"
|
||||
onClick={() => this.setState({ DW2Tier: 2 })} onKeyDown={this._keyDown}
|
||||
>{translate('2 - Max. Jump Range, Minimal Shields')}</li>
|
||||
<li className={cn({ active: this.state.DW2Tier === 3 }, 'lc')} tabIndex="0"
|
||||
onClick={() => this.setState({ DW2Tier: 3 })} onKeyDown={this._keyDown}
|
||||
>{translate('3 - Max. Jump Range, Optimal Shields')}</li>
|
||||
<li className={cn({ active: this.state.DW2Tier === 4 }, 'lc')} tabIndex="0"
|
||||
onClick={() => this.setState({ DW2Tier: 4 })} onKeyDown={this._keyDown}
|
||||
>{translate('4 - Max. Jump Range, Optimal Shields & Thrusters')}</li>
|
||||
</ul>
|
||||
<hr/>
|
||||
<div className='select-group cap'>{translate('Engineering Level')}</div>
|
||||
<ul id={'engLevel'}>
|
||||
<li className={cn({ active: this.state.DW2Eng === 1 }, 'lc')} tabIndex="0"
|
||||
onClick={() => this.setState({ DW2Eng: 1 })} onKeyDown={this._keyDown}
|
||||
>{translate('No engineering')}</li>
|
||||
<li className={cn({ active: this.state.DW2Eng === 2 }, 'lc')} tabIndex="0"
|
||||
onClick={() => this.setState({ DW2Eng: 2 })} onKeyDown={this._keyDown}
|
||||
>{translate('Only Felicity Farseer and Elvira Martuuk')}</li>
|
||||
<li className={cn({ active: this.state.DW2Eng === 3 }, 'lc')} tabIndex="0"
|
||||
onClick={() => this.setState({ DW2Eng: 3 })} onKeyDown={this._keyDown}
|
||||
>{translate('All exploration engineers')}</li>
|
||||
</ul>
|
||||
<hr/>
|
||||
<div className='select-group cap'>{translate('Role')}</div>
|
||||
<ul id={'role'}>
|
||||
<li className={cn({ active: this.state.DW2Role === 'exploration' }, 'lc')} tabIndex="0"
|
||||
onClick={() => this.setState({ DW2Role: 'exploration' })}
|
||||
onKeyDown={this._keyDown}
|
||||
>{translate('Space exploration')}</li>
|
||||
<li className={cn({ active: this.state.DW2Role === 'surface' }, 'lc')} tabIndex="0"
|
||||
onClick={() => this.setState({ DW2Role: 'surface' })}
|
||||
onKeyDown={this._keyDown}
|
||||
>{translate('Surface exploration')}</li>
|
||||
<li className={cn({ active: this.state.DW2Role === 'materialProspector' }, 'lc')} tabIndex="0"
|
||||
onClick={() => this.setState({ DW2Role: 'materialProspector' })}
|
||||
onKeyDown={this._keyDown}
|
||||
>{translate('Material prospector')}</li>
|
||||
<li className={cn({ active: this.state.DW2Role === 'propectorMining' }, 'lc')} tabIndex="0"
|
||||
onClick={() => this.setState({ DW2Role: 'propectorMining' })}
|
||||
onKeyDown={this._keyDown}
|
||||
>{translate('Prospector/Sapper Miner')}</li>
|
||||
<li className={cn({ active: this.state.DW2Role === 'bigRigMining' }, 'lc')} tabIndex="0"
|
||||
onClick={() => this.setState({ DW2Role: 'bigRigMining' })}
|
||||
onKeyDown={this._keyDown}
|
||||
>{translate('Big Rig, full mining')}</li>
|
||||
<li className={cn({ active: this.state.DW2Role === 'fuelRat' }, 'lc')} tabIndex="0"
|
||||
onClick={() => this.setState({ DW2Role: 'fuelRat' })} onKeyDown={this._keyDown}
|
||||
>{translate('Fuel Rat')}</li>
|
||||
<li className={cn({ active: this.state.DW2Role === 'mechanic' }, 'lc')} tabIndex="0"
|
||||
onClick={() => this.setState({ DW2Role: 'mechanic' })} onKeyDown={this._keyDown}
|
||||
>{translate('Mechanic')}</li>
|
||||
<li className={cn({ active: this.state.DW2Role === 'trucker' }, 'lc')} tabIndex="0"
|
||||
onClick={() => this.setState({ DW2Role: 'trucker' })} onKeyDown={this._keyDown}
|
||||
>{translate('Trucker')}</li>
|
||||
</ul>
|
||||
<hr/>
|
||||
<ul>
|
||||
<li className={cn({ active: this.state.DW2Gfsb === true }, 'lc')}
|
||||
onClick={() => this.setState({ DW2Gfsb: this.state.DW2Gfsb !== true })}>
|
||||
Add Guardian FSD Booster
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li className={cn({ active: this.state.DW2Gpp === true }, 'lc')}
|
||||
onClick={() => this.setState({ DW2Gpp: this.state.DW2Gpp !== true })}>
|
||||
Add Guardian Power Plant
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li className={cn({ active: this.state.DW2Fighter === true }, 'lc')}
|
||||
onClick={() => this.setState({ DW2Fighter: this.state.DW2Fighter !== true })}>
|
||||
Add Fighter
|
||||
</li>
|
||||
</ul>
|
||||
<hr/>
|
||||
<ul>
|
||||
<li onClick={this._dw2} className={cn('lc')} tabIndex="0"
|
||||
onKeyDown={this._keyDown}>
|
||||
<button className="button">Apply</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Miner Build
|
||||
* @param {Boolean} shielded True if shield generator should be included
|
||||
@@ -177,7 +297,6 @@ export default class StandardSlotSection extends SlotSection {
|
||||
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)}
|
||||
/>;
|
||||
|
||||
|
||||
slots[3] = <StandardSlot
|
||||
key='fsd'
|
||||
slot={st[2]}
|
||||
@@ -232,7 +351,7 @@ export default class StandardSlotSection extends SlotSection {
|
||||
selected={currentMenu == st[6]}
|
||||
onChange={this.props.onChange}
|
||||
ship={ship}
|
||||
warning= {m => m.fuel < st[2].m.maxfuel} // Show warning when fuel tank is smaller than FSD Max Fuel
|
||||
warning={m => m.fuel < st[2].m.maxfuel} // Show warning when fuel tank is smaller than FSD Max Fuel
|
||||
/>;
|
||||
|
||||
return slots;
|
||||
@@ -245,19 +364,34 @@ export default class StandardSlotSection extends SlotSection {
|
||||
*/
|
||||
_getSectionMenu(translate) {
|
||||
let planetaryDisabled = this.props.ship.internal.length < 4;
|
||||
if (this.state.showDW2 === true) {
|
||||
return this._showDW2Menu(translate);
|
||||
}
|
||||
return <div className='select' onClick={(e) => e.stopPropagation()} onContextMenu={stopCtxPropagation}>
|
||||
<ul>
|
||||
<li className='lc' tabIndex="0" onClick={this._optimizeStandard} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['maxjump'] = smRef}>{translate('Maximize Jump Range')}</li>
|
||||
<li className='lc' tabIndex="0" onClick={this._optimizeStandard} onKeyDown={this._keyDown}
|
||||
ref={smRef => this.sectionRefArr['maxjump'] = smRef}>{translate('Maximize Jump Range')}</li>
|
||||
</ul>
|
||||
<div className='select-group cap'>{translate('roles')}</div>
|
||||
<ul>
|
||||
<li className='lc' tabIndex="0" onClick={this._multiPurpose.bind(this, false, 0)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['multipurpose'] = smRef}>{translate('Multi-purpose')}</li>
|
||||
<li className='lc' tabIndex="0" onClick={this._multiPurpose.bind(this, true, 2)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['combat'] = smRef}>{translate('Combat')}</li>
|
||||
<li className='lc' tabIndex="0" onClick={this._optimizeCargo.bind(this, true)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['trader'] = smRef}>{translate('Trader')}</li>
|
||||
<li className='lc' tabIndex="0" onClick={this._optimizeExplorer.bind(this, false)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['explorer'] = smRef}>{translate('Explorer')}</li>
|
||||
<li className={cn('lc', { disabled: planetaryDisabled })} tabIndex={planetaryDisabled ? '' : '0'} onClick={!planetaryDisabled && this._optimizeExplorer.bind(this, true)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['planetary'] = smRef}>{translate('Planetary Explorer')}</li>
|
||||
<li className='lc' tabIndex="0" onClick={this._optimizeMiner.bind(this, true)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['miner'] = smRef}>{translate('Miner')}</li>
|
||||
<li className='lc' tabIndex="0" onClick={this._optimizeRacer.bind(this)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['racer'] = smRef}>{translate('Racer')}</li>
|
||||
<li className='lc' tabIndex="0" onClick={this._multiPurpose.bind(this, false, 0)} onKeyDown={this._keyDown}
|
||||
ref={smRef => this.sectionRefArr['multipurpose'] = smRef}>{translate('Multi-purpose')}</li>
|
||||
<li className='lc' tabIndex="0" onClick={this._multiPurpose.bind(this, true, 2)} onKeyDown={this._keyDown}
|
||||
ref={smRef => this.sectionRefArr['combat'] = smRef}>{translate('Combat')}</li>
|
||||
<li className='lc' tabIndex="0" onClick={this._optimizeCargo.bind(this, true)} onKeyDown={this._keyDown}
|
||||
ref={smRef => this.sectionRefArr['trader'] = smRef}>{translate('Trader')}</li>
|
||||
<li className='lc' tabIndex="0" onClick={this._optimizeExplorer.bind(this, false)} onKeyDown={this._keyDown}
|
||||
ref={smRef => this.sectionRefArr['explorer'] = smRef}>{translate('Explorer')}</li>
|
||||
<li className={cn('lc', { disabled: planetaryDisabled })} tabIndex={planetaryDisabled ? '' : '0'}
|
||||
onClick={!planetaryDisabled && this._optimizeExplorer.bind(this, true)} onKeyDown={this._keyDown}
|
||||
ref={smRef => this.sectionRefArr['planetary'] = smRef}>{translate('Planetary Explorer')}</li>
|
||||
<li className='lc' tabIndex="0" onClick={this._optimizeMiner.bind(this, true)} onKeyDown={this._keyDown}
|
||||
ref={smRef => this.sectionRefArr['miner'] = smRef}>{translate('Miner')}</li>
|
||||
<li className='lc' tabIndex="0" onClick={this._optimizeRacer.bind(this)} onKeyDown={this._keyDown}
|
||||
ref={smRef => this.sectionRefArr['racer'] = smRef}>{translate('Racer')}</li>
|
||||
<li className='lc' tabIndex="0" onClick={() => this.setState({ showDW2: !this.state.showDW2 })}
|
||||
onKeyDown={this._keyDown}
|
||||
ref={smRef => this.sectionRefArr['dw2'] = smRef}>{translate('DW2')}</li>
|
||||
</ul>
|
||||
</div>;
|
||||
}
|
||||
|
||||
@@ -164,13 +164,13 @@ export default class ModuleSet {
|
||||
/**
|
||||
* Finds the lightest usable Shield Generator
|
||||
* @param {number} hullMass Ship hull mass
|
||||
* @return {Object} Thruster
|
||||
* @param {string} rating The optional rating of the shield
|
||||
* @return {Object} Shield Generator
|
||||
*/
|
||||
lightestShieldGenerator(hullMass) {
|
||||
lightestShieldGenerator(hullMass, rating) {
|
||||
let sg = this.internal.sg[0];
|
||||
|
||||
for (let s of this.internal.sg) {
|
||||
if (s.mass < sg.mass && s.maxmass > hullMass) {
|
||||
if ((!rating || rating === s.rating) && s.mass <= sg.mass && s.maxmass > hullMass) {
|
||||
sg = s;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import * as ModuleUtils from './ModuleUtils';
|
||||
import { Modifications } from 'coriolis-data/dist';
|
||||
import { canMount } from '../utils/SlotFunctions';
|
||||
import { getBlueprint, setPercent } from '../utils/BlueprintFunctions';
|
||||
|
||||
/**
|
||||
* Standard / typical role for multi-purpose or combat (if shielded with better bulkheads)
|
||||
@@ -14,7 +16,7 @@ export function multiPurpose(ship, shielded, bulkheadIndex) {
|
||||
.useBulkhead(bulkheadIndex);
|
||||
|
||||
if (shielded) {
|
||||
ship.internal.some(function(slot) {
|
||||
ship.internal.some(function (slot) {
|
||||
if (canMount(ship, slot, 'sg')) { // Assuming largest slot can hold an eligible shield
|
||||
ship.use(slot, ModuleUtils.findInternal('sg', slot.maxClass, 'A'));
|
||||
ship.setSlotEnabled(slot, true);
|
||||
@@ -24,6 +26,577 @@ export function multiPurpose(ship, shielded, bulkheadIndex) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Distant Worlds 2 role
|
||||
* Tiers:
|
||||
* 1- Max. Jump Range, Unshielded
|
||||
* 2- Max. Jump Range, Minimal Shields
|
||||
* 3- Max. Jump Range, Optimal Shields
|
||||
* 4- Max. Jump Range, Optimal Shields & Thrusters
|
||||
*
|
||||
* Engineering level:
|
||||
* No engineering
|
||||
* Only Felicity Farseer and Elvira Martuuk
|
||||
* All exploration related engineers
|
||||
*
|
||||
* Role
|
||||
* Exploration
|
||||
* Surface exploration
|
||||
* Big Rig, full mining
|
||||
* Saper / Prospector mining
|
||||
* Fuel rat
|
||||
* Repair rat
|
||||
* Mechanic
|
||||
* Trucker
|
||||
*
|
||||
* @param ship {Ship} Ship instance
|
||||
* @param tier {Number}
|
||||
* @param engineeringLevel {Number}
|
||||
* @param role {String}
|
||||
* @param gfsb {Boolean} add Guardian FSD Booster
|
||||
* @param gpp {Boolean} add Guardian Power Plant
|
||||
* @param fighter {Boolean} add fighter if supported
|
||||
*/
|
||||
export function dw2Build(ship, tier, engineeringLevel, role, gfsb, gpp, fighter) {
|
||||
ship
|
||||
.emptyInternal()
|
||||
.emptyHardpoints()
|
||||
.emptyUtility();
|
||||
const fsd = ModuleUtils.findStandard('fsd', ship.standard[2].maxClass, 'A');
|
||||
ship.use(ship.standard[2], fsd);
|
||||
ship.use(ship.standard[3], ModuleUtils.findStandard('ls', ship.standard[3].maxClass, 'D'));
|
||||
ship.use(ship.standard[4], ModuleUtils.findStandard('pd', 1, 'D'));
|
||||
ship.use(ship.standard[5], ModuleUtils.findStandard('s', ship.standard[5].maxClass, 'D'));
|
||||
const fuelNeeded = ship.standard[2].m.maxfuel * 2;
|
||||
const fuelTank = ship.availCS.standard[6]
|
||||
.filter(e => e.fuel)
|
||||
.filter(e => e.fuel >= fuelNeeded);
|
||||
ship.use(ship.standard[6], fuelTank[0]);
|
||||
ship.useBulkhead(0, false);
|
||||
if (engineeringLevel === 2) {
|
||||
const bp = getBlueprint('FSD_LongRange', ship.standard[2]);
|
||||
bp.grade = 5;
|
||||
bp.special = Modifications.specials['special_fsd_heavy'];
|
||||
ship.standard[2].m.blueprint = bp;
|
||||
setPercent(ship, ship.standard[2].m, 100);
|
||||
// Sensors G3 LW
|
||||
const sBP = getBlueprint('Sensor_Sensor_LightWeight', ship.standard[5]);
|
||||
sBP.grade = 3;
|
||||
ship.standard[5].m.blueprint = sBP;
|
||||
setPercent(ship, ship.standard[5].m, 100);
|
||||
} else if (engineeringLevel === 3) {
|
||||
// Armour G5 HD + Deep Plating
|
||||
const armourBP = getBlueprint('Armour_HeavyDuty', ship.bulkheads);
|
||||
armourBP.grade = 5;
|
||||
armourBP.special = Modifications.specials['special_armour_chunky'];
|
||||
ship.bulkheads.m.blueprint = armourBP;
|
||||
setPercent(ship, ship.bulkheads.m, 100);
|
||||
// FSD G5 IR + Mass Manager
|
||||
const fsdBP = getBlueprint('FSD_LongRange', ship.standard[2]);
|
||||
fsdBP.grade = 5;
|
||||
fsdBP.special = Modifications.specials['special_fsd_heavy'];
|
||||
ship.standard[2].m.blueprint = fsdBP;
|
||||
setPercent(ship, ship.standard[2].m, 100);
|
||||
// LS G4 LW
|
||||
const lsBP = getBlueprint('LifeSupport_LightWeight', ship.standard[3]);
|
||||
lsBP.grade = 4;
|
||||
ship.standard[3].m.blueprint = lsBP;
|
||||
setPercent(ship, ship.standard[3].m, 100);
|
||||
// Sensors G5 LW
|
||||
const sBP = getBlueprint('Sensor_Sensor_LightWeight', ship.standard[5]);
|
||||
sBP.grade = 5;
|
||||
ship.standard[5].m.blueprint = sBP;
|
||||
setPercent(ship, ship.standard[5].m, 100);
|
||||
}
|
||||
|
||||
if (ship.id === 'imperial_clipper') {
|
||||
const fs = ModuleUtils.findInternal('fs', 4, 'A');
|
||||
const slot = ship.internal.filter(a => a.maxClass === 4)[0];
|
||||
ship.use(slot, fs);
|
||||
} else if (ship.id === 'imperial_cutter') {
|
||||
const fs = ModuleUtils.findInternal('fs', 6, 'A');
|
||||
const slot = ship.internal.filter(a => a.maxClass === 6)[0];
|
||||
ship.use(slot, fs);
|
||||
} else if (fsd.class === 2 && fsd.rating === 'A') {
|
||||
let fs = ModuleUtils.findInternal('fs', 2, 'A');
|
||||
let slot = ship.internal.filter(a => a.maxClass >= 2).filter(a => a.maxClass >= fs.class)
|
||||
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||
[0];
|
||||
if (slot.m) {
|
||||
fs = ModuleUtils.findInternal('fs', 1, 'A');
|
||||
slot = ship.internal.filter(a => a.maxClass === 1)[0];
|
||||
ship.use(slot, fs);
|
||||
} else {
|
||||
ship.use(slot, fs);
|
||||
}
|
||||
} else if (fsd.class === 3 && fsd.rating === 'A') {
|
||||
let fs = ModuleUtils.findInternal('fs', 3, 'B');
|
||||
let slot = ship.internal.filter(a => a.maxClass >= 3).filter(a => a.maxClass >= fs.class)
|
||||
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||
[0];
|
||||
if (slot.m) {
|
||||
fs = ModuleUtils.findInternal('fs', 2, 'A');
|
||||
slot = ship.internal.filter(a => a.maxClass === 2)[0];
|
||||
ship.use(slot, fs);
|
||||
} else {
|
||||
ship.use(slot, fs);
|
||||
}
|
||||
} else if (fsd.class === 4 && fsd.rating === 'A') {
|
||||
let fs = ModuleUtils.findInternal('fs', 4, 'b');
|
||||
let slot = ship.internal.filter(a => a.maxClass >= 4).filter(a => a.maxClass >= fs.class)
|
||||
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||
[0];
|
||||
if (slot.m) {
|
||||
fs = ModuleUtils.findInternal('fs', 3, 'A');
|
||||
slot = ship.internal.filter(a => a.maxClass === 3)[0];
|
||||
ship.use(slot, fs);
|
||||
} else {
|
||||
ship.use(slot, fs);
|
||||
}
|
||||
} else if (fsd.class === 5 && fsd.rating === 'A') {
|
||||
let fs = ModuleUtils.findInternal('fs', 5, 'B');
|
||||
let slot = ship.internal.filter(a => a.maxClass >= 5).filter(a => a.maxClass >= fs.class)
|
||||
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||
[0];
|
||||
if (slot.m) {
|
||||
fs = ModuleUtils.findInternal('fs', 4, 'A');
|
||||
slot = ship.internal.filter(a => a.maxClass === 4).filter(a => a.maxClass >= fs.class)
|
||||
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||
[0];
|
||||
if (fs) {
|
||||
ship.use(slot, fs);
|
||||
}
|
||||
} else {
|
||||
if (fs) {
|
||||
ship.use(slot, fs);
|
||||
}
|
||||
}
|
||||
} else if (fsd.class === 6 && fsd.rating === 'A') {
|
||||
let fs = ModuleUtils.findInternal('fs', 6, 'B');
|
||||
let slot = ship.internal.filter(a => a.maxClass >= 6)
|
||||
.filter(a => a.maxClass >= fs.class)
|
||||
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||
[0];
|
||||
if (slot.m) {
|
||||
fs = ModuleUtils.findInternal('fs', 5, 'A');
|
||||
slot = ship.internal.filter(a => a.maxClass === 5)[0];
|
||||
if (fs) {
|
||||
ship.use(slot, fs);
|
||||
}
|
||||
} else {
|
||||
if (fs) {
|
||||
ship.use(slot, fs);
|
||||
}
|
||||
}
|
||||
} else if (fsd.class === 7 && fsd.rating === 'A') {
|
||||
let fs = ModuleUtils.findInternal('fs', 7, 'B');
|
||||
let slot = ship.internal.filter(a => a.maxClass >= 7).filter(a => a.maxClass >= fs.class)
|
||||
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||
[0];
|
||||
if (slot && slot.m) {
|
||||
fs = ModuleUtils.findInternal('fs', 6, 'A');
|
||||
slot = ship.internal.filter(a => a.maxClass === 6)[0];
|
||||
if (fs) {
|
||||
ship.use(slot, fs);
|
||||
}
|
||||
} else {
|
||||
if (fs) {
|
||||
ship.use(slot, fs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tier !== 1) {
|
||||
const fuelNeeded = ship.standard[2].m.maxfuel * 3;
|
||||
const fuelTank = ship.availCS.standard[6]
|
||||
.filter(e => e.fuel)
|
||||
.filter(e => e.fuel >= fuelNeeded);
|
||||
if (fuelTank[0]) {
|
||||
ship.use(ship.standard[6], fuelTank[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if (tier === 2) {
|
||||
if (ship.id === 'alliance_chieftain' || ship.id === 'alliance_crusader' || ship.id === 'federal_gunship' || ship.id === 'vulture') {
|
||||
const hrp = ModuleUtils.findInternal('hrp', 3, 'D');
|
||||
const slot = ship.internal.filter(e => e.eligible && e.maxClass === 3);
|
||||
if (hrp) {
|
||||
ship.use(slot, hrp);
|
||||
}
|
||||
} else {
|
||||
const sg = ship.getAvailableModules().lightestShieldGenerator(ship.ladenMass);
|
||||
const slot = ship.internal.filter(a => !a.m)
|
||||
.filter(a => a.maxClass >= sg.class)
|
||||
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||
[0];
|
||||
if (sg) {
|
||||
ship.use(slot, sg);
|
||||
}
|
||||
if (engineeringLevel === 2) {
|
||||
// ELP G3
|
||||
const shieldBP = getBlueprint('ShieldGenerator_Optimised', ship.findShieldGenerator());
|
||||
shieldBP.grade = 3;
|
||||
ship.findShieldGenerator().blueprint = shieldBP;
|
||||
setPercent(ship, ship.findShieldGenerator(), 100);
|
||||
} else if (engineeringLevel === 3) {
|
||||
// ELP G5
|
||||
const shieldBP = getBlueprint('ShieldGenerator_Optimised', ship.findShieldGenerator());
|
||||
shieldBP.grade = 5;
|
||||
ship.findShieldGenerator().blueprint = shieldBP;
|
||||
setPercent(ship, ship.findShieldGenerator(), 100);
|
||||
}
|
||||
// const shieldOrder = [1, 2, 3, 4, 5, 6, 7, 8].reverse();
|
||||
// const shieldInternals = ship.internal.filter(a => !a.m)
|
||||
// .filter(a => (!a.eligible) || a.eligible.sg)
|
||||
// .filter(a => a.maxClass >= sg.class)
|
||||
// .sort((a, b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass));
|
||||
// for (let i = 0; i < shieldInternals.length; i++) {
|
||||
// if (canMount(ship, shieldInternals[i], 'sg')) {
|
||||
// ship.use(shieldInternals[i], sg);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
} else if (tier === 3 || tier === 4) {
|
||||
const sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass, 'A');
|
||||
const slot = ship.internal.filter(a => !a.m)
|
||||
.filter(a => a.maxClass >= sg.class)
|
||||
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||
[0];
|
||||
if (sg) {
|
||||
ship.use(slot, sg);
|
||||
}
|
||||
if (engineeringLevel === 1) {
|
||||
// ELP G3
|
||||
const shieldBP = getBlueprint('ShieldGenerator_Optimised', ship.findShieldGenerator());
|
||||
shieldBP.grade = 3;
|
||||
shieldBP.special = Modifications.specials['special_shield_lightweight'];
|
||||
ship.findShieldGenerator().blueprint = shieldBP;
|
||||
setPercent(ship, ship.findShieldGenerator(), 100);
|
||||
} else if (engineeringLevel === 2) {
|
||||
// ELP G5
|
||||
const shieldBP = getBlueprint('ShieldGenerator_Optimised', ship.findShieldGenerator());
|
||||
shieldBP.grade = 5;
|
||||
shieldBP.special = Modifications.specials['special_shield_lightweight'];
|
||||
ship.findShieldGenerator().blueprint = shieldBP;
|
||||
setPercent(ship, ship.findShieldGenerator(), 100);
|
||||
}
|
||||
}
|
||||
|
||||
if (tier === 4) {
|
||||
let t;
|
||||
if (canMount(ship, ship.standard[1], 't', ship.standard[1].maxClass - 1)) {
|
||||
t = ModuleUtils.findStandard('t', ship.standard[1].maxClass - 1, 'A');
|
||||
} else {
|
||||
t = ModuleUtils.findStandard('t', ship.standard[1].maxClass, 'A');
|
||||
}
|
||||
if (t) {
|
||||
ship.use(ship.standard[1], t);
|
||||
}
|
||||
if (engineeringLevel === 1) {
|
||||
// DD G3
|
||||
const tBP = getBlueprint('Engine_Dirty', ship.standard[1]);
|
||||
tBP.grade = 3;
|
||||
tBP.special = Modifications.specials['special_engine_lightweight'];
|
||||
ship.standard[1].m.blueprint = tBP;
|
||||
setPercent(ship, ship.standard[1].m, 100);
|
||||
} else if (engineeringLevel === 2) {
|
||||
// DD G5
|
||||
const tBP = getBlueprint('Engine_Dirty', ship.standard[1]);
|
||||
tBP.grade = 5;
|
||||
tBP.special = Modifications.specials['special_engine_lightweight'];
|
||||
ship.standard[1].m.blueprint = tBP;
|
||||
setPercent(ship, ship.standard[1].m, 100);
|
||||
}
|
||||
}
|
||||
|
||||
if (tier === 4 || tier === 3) {
|
||||
if (engineeringLevel === 3) {
|
||||
const pd = ship.availCS.standard[4]
|
||||
.filter(d => d.rating === 'D')
|
||||
.filter(d => (d.engcap * 1.728) >= ship.boostEnergy)
|
||||
.sort((a, b) => a.class.toString().localeCompare(b.class.toString()))[0];
|
||||
if (pd) {
|
||||
ship.use(ship.standard[4], pd);
|
||||
}
|
||||
// CE G5
|
||||
const pdBP = getBlueprint('PowerDistributor_HighFrequency', ship.standard[4]);
|
||||
pdBP.grade = 5;
|
||||
pdBP.special = Modifications.specials['special_powerdistributor_capacity'];
|
||||
ship.standard[4].m.blueprint = pdBP;
|
||||
setPercent(ship, ship.standard[4].m, 100);
|
||||
} else {
|
||||
const pd = ship.availCS.standard[4]
|
||||
.filter(d => d.rating === 'D')
|
||||
.sort((a, b) => a.engcap > b.engcap)
|
||||
[0];
|
||||
if (pd) {
|
||||
ship.use(ship.standard[4], pd);
|
||||
}
|
||||
}
|
||||
} else if (tier === 4) {
|
||||
if (engineeringLevel === 3) {
|
||||
const pd = ship.availCS.standard[4]
|
||||
.filter(d => d.rating === 'D')
|
||||
.sort((a, b) => b.class.toString().localeCompare(a.class.toString()))[0];
|
||||
if (pd) {
|
||||
ship.use(ship.standard[4], pd);
|
||||
}
|
||||
// CE G5
|
||||
const pdBP = getBlueprint('PowerDistributor_HighFrequency', ship.standard[4]);
|
||||
pdBP.grade = 5;
|
||||
pdBP.special = Modifications.specials['special_powerdistributor_capacity'];
|
||||
ship.standard[4].m.blueprint = pdBP;
|
||||
setPercent(ship, ship.standard[4].m, 100);
|
||||
} else {
|
||||
const pd = ship.availCS.standard[4]
|
||||
.filter(d => d.rating === 'D')
|
||||
.sort((a, b) => b.class.toString().localeCompare(a.class.toString()))[0];
|
||||
if (pd) {
|
||||
ship.use(ship.standard[4], pd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ship.fighterHangars && fighter) {
|
||||
const slot = ship.internal.filter(s => s.maxClass >= 5 && !s.m)
|
||||
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||
[0];
|
||||
const mod = ModuleUtils.findInternal('fh', 5, 'D');
|
||||
if (slot && mod) {
|
||||
ship.use(slot, mod);
|
||||
}
|
||||
}
|
||||
|
||||
if (tier === 1) {
|
||||
const pd = ModuleUtils.findStandard('pd', 1, 'D');
|
||||
if (pd) {
|
||||
ship.use(ship.standard[4]);
|
||||
}
|
||||
}
|
||||
|
||||
let dssPriority = 0;
|
||||
let srvPriority = 0;
|
||||
let afmu = true;
|
||||
let cargo = false;
|
||||
let miningLaserPriority = 0;
|
||||
let refinery = false;
|
||||
let collector = false;
|
||||
let prospector = false;
|
||||
let miningTools = false;
|
||||
let refuelLimpets = false;
|
||||
let repairLimpets = false;
|
||||
console.log(role);
|
||||
if (role === 'exploration') {
|
||||
dssPriority = 2;
|
||||
afmu = true;
|
||||
} else if (role === 'surface') {
|
||||
dssPriority = 2;
|
||||
srvPriority = 2;
|
||||
} else if (role === 'materialProspector') {
|
||||
miningLaserPriority = 2;
|
||||
srvPriority = 1;
|
||||
} else if (role === 'propectorMining') {
|
||||
dssPriority = 1;
|
||||
prospector = true;
|
||||
miningLaserPriority = 1;
|
||||
cargo = true;
|
||||
miningTools = true;
|
||||
|
||||
} else if (role === 'bigRigMining') {
|
||||
dssPriority = 1;
|
||||
miningLaserPriority = 2;
|
||||
cargo = true;
|
||||
collector = true;
|
||||
refinery = true;
|
||||
miningTools = true;
|
||||
|
||||
} else if (role === 'fuelRat') {
|
||||
refuelLimpets = true;
|
||||
cargo = true;
|
||||
srvPriority = 1;
|
||||
|
||||
} else if (role === 'mechanic') {
|
||||
repairLimpets = true;
|
||||
cargo = true;
|
||||
srvPriority = 1;
|
||||
} else if (role === 'trucker') {
|
||||
cargo = true;
|
||||
}
|
||||
|
||||
if (dssPriority === 2) {
|
||||
const mod = ModuleUtils.findModule('ss', '2i');
|
||||
const slot = ship.internal.filter(s => !s.m)
|
||||
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||
console.log(slot);
|
||||
console.log(mod);
|
||||
ship.use(slot, mod);
|
||||
}
|
||||
|
||||
if (srvPriority === 2) {
|
||||
let mod;
|
||||
let slot = ship.internal.filter(s => !s.m)
|
||||
.filter(s => s.maxClass >= 6)
|
||||
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||
if (slot) {
|
||||
mod = ModuleUtils.findModule('pv', 'v2');
|
||||
ship.use(slot, mod);
|
||||
} else if (!slot) {
|
||||
slot = ship.internal.filter(s => !s.m)
|
||||
.filter(s => s.maxClass >= 4)
|
||||
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||
if (slot) {
|
||||
mod = ModuleUtils.findModule('pv', 'v4');
|
||||
ship.use(slot, mod);
|
||||
} else {
|
||||
slot = ship.internal.filter(s => !s.m)
|
||||
.filter(s => s.maxClass >= 2)
|
||||
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||
if (slot) {
|
||||
mod = ModuleUtils.findModule('pv', 'v6');
|
||||
ship.use(slot, mod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (cargo === true) {
|
||||
const slot = ship.internal.filter(s => !s.m)
|
||||
.sort((a, b) => b.maxClass.toString().localeCompare(a.maxClass.toString()))[0];
|
||||
const mod = ModuleUtils.findInternal('cr', slot.maxClass, 'E');
|
||||
ship.use(slot, mod);
|
||||
}
|
||||
|
||||
if (refuelLimpets === true) {
|
||||
const mod = ModuleUtils.findModule('fx', 'F4');
|
||||
const slot = ship.internal.filter(s => !s.m)
|
||||
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||
ship.use(mod, slot);
|
||||
}
|
||||
|
||||
if (repairLimpets === true) {
|
||||
const slot = ship.internal.filter(s => !s.m)
|
||||
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||
let mod;
|
||||
if (slot.maxClass >= 3) {
|
||||
mod = ModuleUtils.findModule('rpl', '9e');
|
||||
} else {
|
||||
mod = ModuleUtils.findModule('rpl', '9s');
|
||||
}
|
||||
ship.use(mod, slot);
|
||||
}
|
||||
|
||||
if (prospector === true) {
|
||||
const slot = ship.internal.filter(s => !s.m)
|
||||
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||
let mod;
|
||||
if (slot.maxClass >= 3) {
|
||||
mod = ModuleUtils.findModule('pc', 'P9');
|
||||
} else {
|
||||
mod = ModuleUtils.findModule('pc', 'P4');
|
||||
}
|
||||
ship.use(mod, slot);
|
||||
}
|
||||
|
||||
if (collector === true) {
|
||||
const slots = ship.internal.filter(s => !s.m)
|
||||
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()));
|
||||
if (slots.length >= 2) {
|
||||
let slot = slots.find(s => s.maxClass >= 5);
|
||||
let mod;
|
||||
if (slot) {
|
||||
mod = ModuleUtils.findInternal('cc', slot.maxClass, 'D');
|
||||
} else if (slots.find(s => s.maxClass <= 4)) {
|
||||
slot = slots.find(s => s.maxClass <= 4);
|
||||
mod = ModuleUtils.findInternal('cc', slot.maxClass, 'D');
|
||||
}
|
||||
ship.use(slot, mod);
|
||||
}
|
||||
}
|
||||
|
||||
if (refinery === true) {
|
||||
const slots = ship.internal.filter(s => !s.m)
|
||||
.filter(s => s.maxClass >= 4)
|
||||
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||
if (slots) {
|
||||
const mod = ModuleUtils.findInternal('rf', 4, 'A');
|
||||
ship.use(slots, mod);
|
||||
} else {
|
||||
const slot = ship.internal.filter(s => !s.m)
|
||||
.filter(s => s.maxClass <= 3)
|
||||
.sort((a, b) => b.maxClass.toString().localeCompare(a.maxClass.toString()))[0];
|
||||
const mod = ModuleUtils.findInternal('rf', slot.maxClass, 'A');
|
||||
ship.use(slots, mod);
|
||||
}
|
||||
}
|
||||
|
||||
if (dssPriority === 1) {
|
||||
const slot = ship.internal.filter(s => !s.m)
|
||||
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||
const dss = ModuleUtils.findInternal('ss', 1, 'C')
|
||||
if (slot) {
|
||||
ship.use(slot, dss);
|
||||
}
|
||||
}
|
||||
|
||||
if (srvPriority === 1) {
|
||||
const slot = ship.internal.filter(s => !s.m)
|
||||
.filter(s => s.maxClass >= 2)
|
||||
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()));
|
||||
if (slot.find(s => s.maxClass >= 4)) {
|
||||
const slot = slot.find(s => s.maxClass >= 4);
|
||||
const srv = ModuleUtils.findInternal('pv', 4, 'G')
|
||||
ship.use(slot, srv);
|
||||
} else if (slot.find(s => s.maxClass >= 2)) {
|
||||
const slot = slot.find(s => s.maxClass >= 2);
|
||||
const srv = ModuleUtils.findInternal('pv', 2, 'G')
|
||||
ship.use(slot, srv);
|
||||
}
|
||||
}
|
||||
|
||||
if (gfsb === true) {
|
||||
const slots = ship.internal.filter(s => !s.m)
|
||||
.filter(s => s.maxClass >= 1)
|
||||
.sort((a, b) => b.maxClass.toString().localeCompare(a.maxClass.toString()));
|
||||
if (slots.find(s => s.maxClass >= 5)) {
|
||||
const mod = ModuleUtils.findInternal('gfsb', 5, 'H');
|
||||
ship.use(slots.find(s => s.maxClass >= 5), mod)
|
||||
} else if (slots.find(s => s.maxClass >= 4)) {
|
||||
const mod = ModuleUtils.findInternal('gfsb', 4, 'H');
|
||||
ship.use(slots.find(s => s.maxClass >= 4), mod)
|
||||
} else if (slots.find(s => s.maxClass >= 3)) {
|
||||
const mod = ModuleUtils.findInternal('gfsb', 3, 'H');
|
||||
ship.use(slots.find(s => s.maxClass >= 3), mod)
|
||||
} else if (slots.find(s => s.maxClass >= 2)) {
|
||||
const mod = ModuleUtils.findInternal('gfsb', 2, 'H');
|
||||
ship.use(slots.find(s => s.maxClass >= 2), mod)
|
||||
} else if (slots.find(s => s.maxClass >= 1)) {
|
||||
const mod = ModuleUtils.findInternal('gfsb', 1, 'H');
|
||||
ship.use(slots.find(s => s.maxClass >= 1), mod)
|
||||
}
|
||||
}
|
||||
|
||||
// const pp = ship.getAvailableModules().lightestPowerPlant(Math.max(ship.powerRetracted, ship.powerDeployed), 'A');
|
||||
// const t = ship.getAvailableModules().lightestThruster(ship.ladenMass);
|
||||
// ship.use(ship.standard[0], pp);
|
||||
// ship.use(ship.standard[1], t);
|
||||
|
||||
// ship.useLightestStandard(standardOpts);
|
||||
ship.updatePowerGenerated()
|
||||
.updatePowerUsed()
|
||||
.recalculateMass()
|
||||
.updateJumpStats()
|
||||
.recalculateShield()
|
||||
.recalculateShieldCells()
|
||||
.recalculateArmour()
|
||||
.recalculateDps()
|
||||
.recalculateEps()
|
||||
.recalculateHps()
|
||||
.updateMovement()
|
||||
.updateModificationsString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Trader Role
|
||||
* @param {Ship} ship Ship instance
|
||||
@@ -36,7 +609,7 @@ export function trader(ship, shielded, standardOpts) {
|
||||
let sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
|
||||
ship.useStandard('A')
|
||||
.use(ship.standard[3], ModuleUtils.standard(3, ship.standard[3].maxClass + 'D')) // D Life Support
|
||||
.use(ship.standard[1], ModuleUtils.standard(1, ship.standard[1].maxClass + 'D')) // D Life Support
|
||||
.use(ship.standard[1], ModuleUtils.standard(1, ship.standard[1].maxClass + 'D')) // D Power Plant
|
||||
.use(ship.standard[4], ModuleUtils.standard(4, ship.standard[4].maxClass + 'D')) // D Life Support
|
||||
.use(ship.standard[5], ModuleUtils.standard(5, ship.standard[5].maxClass + 'D')); // D Sensors
|
||||
|
||||
@@ -45,7 +618,7 @@ export function trader(ship, shielded, standardOpts) {
|
||||
.filter(a => (!a.eligible) || a.eligible.sg)
|
||||
.filter(a => a.maxClass >= sg.class)
|
||||
.sort((a, b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass));
|
||||
shieldInternals.some(function(slot) {
|
||||
shieldInternals.some(function (slot) {
|
||||
if (canMount(ship, slot, 'sg')) { // Assuming largest slot can hold an eligible shield
|
||||
const shield = ModuleUtils.findInternal('sg', slot.maxClass, 'A');
|
||||
if (shield && shield.maxmass > ship.hullMass) {
|
||||
@@ -87,11 +660,11 @@ export function trader(ship, shielded, standardOpts) {
|
||||
*/
|
||||
export function explorer(ship, planetary) {
|
||||
let standardOpts = { ppRating: 'A' },
|
||||
heatSinkCount = 2, // Fit 2 heat sinks if possible
|
||||
usedSlots = [],
|
||||
sgSlot,
|
||||
fuelScoopSlot,
|
||||
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
|
||||
heatSinkCount = 2, // Fit 2 heat sinks if possible
|
||||
usedSlots = [],
|
||||
sgSlot,
|
||||
fuelScoopSlot,
|
||||
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
|
||||
|
||||
if (!planetary) { // Non-planetary explorers don't really need to boost
|
||||
standardOpts.pd = '1D';
|
||||
@@ -216,9 +789,9 @@ export function explorer(ship, planetary) {
|
||||
export function miner(ship, shielded) {
|
||||
shielded = true;
|
||||
let standardOpts = { ppRating: 'A' },
|
||||
miningLaserCount = 2,
|
||||
usedSlots = [],
|
||||
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
|
||||
miningLaserCount = 2,
|
||||
usedSlots = [],
|
||||
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
|
||||
|
||||
// Cargo hatch should be enabled
|
||||
ship.setSlotEnabled(ship.cargoHatch, true);
|
||||
@@ -269,7 +842,7 @@ export function miner(ship, shielded) {
|
||||
|
||||
// Dual mining lasers of highest possible class; remove anything else
|
||||
const miningLaserOrder = [2, 3, 4, 1, 0];
|
||||
const miningLaserHardpoints = ship.hardpoints.concat().sort(function(a, b) {
|
||||
const miningLaserHardpoints = ship.hardpoints.concat().sort(function (a, b) {
|
||||
return miningLaserOrder.indexOf(a.maxClass) - miningLaserOrder.indexOf(b.maxClass);
|
||||
});
|
||||
for (let s of miningLaserHardpoints) {
|
||||
@@ -283,7 +856,7 @@ export function miner(ship, shielded) {
|
||||
|
||||
// Number of collector limpets required to be active is a function of the size of the ship and the power of the lasers
|
||||
const miningLaserDps = ship.hardpoints.filter(h => h.m != null)
|
||||
.reduce(function(a, b) {
|
||||
.reduce(function (a, b) {
|
||||
return a + b.m.getDps();
|
||||
}, 0);
|
||||
// Find out how many internal slots we have, and their potential cargo size
|
||||
@@ -314,7 +887,7 @@ export function miner(ship, shielded) {
|
||||
|
||||
// Power distributor to power the mining lasers indefinitely
|
||||
const wepRateRequired = ship.hardpoints.filter(h => h.m != null)
|
||||
.reduce(function(a, b) {
|
||||
.reduce(function (a, b) {
|
||||
return a + b.m.getEps();
|
||||
}, 0);
|
||||
standardOpts.pd = ship.getAvailableModules().matchingPowerDist({ weprate: wepRateRequired }).id;
|
||||
@@ -336,9 +909,9 @@ export function miner(ship, shielded) {
|
||||
*/
|
||||
export function racer(ship) {
|
||||
let standardOpts = {},
|
||||
usedSlots = [],
|
||||
sgSlot,
|
||||
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
|
||||
usedSlots = [],
|
||||
sgSlot,
|
||||
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
|
||||
|
||||
// Cargo hatch can be disabled
|
||||
ship.setSlotEnabled(ship.cargoHatch, false);
|
||||
|
||||
@@ -1,417 +1,417 @@
|
||||
import React from 'react';
|
||||
import { Modifications } from 'coriolis-data/dist';
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
const features = m.blueprint.grades[m.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]) * mult);
|
||||
} else {
|
||||
value = features[featureName][0] + ((features[featureName][1] - features[featureName][0]) * mult);
|
||||
}
|
||||
} 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]) * mult);
|
||||
} else {
|
||||
value = features[featureName][1] + ((features[featureName][0] - features[featureName][1]) * mult);
|
||||
}
|
||||
}
|
||||
|
||||
_setValue(ship, m, 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a modification feature value
|
||||
* @param {Object} ship The ship for which to perform the modifications
|
||||
* @param {Object} m The module for which to perform the modifications
|
||||
* @param {string} featureName The feature being set
|
||||
* @param {number} value The value being set for the feature
|
||||
*/
|
||||
function _setValue(ship, m, featureName, value) {
|
||||
if (Modifications.modifications[featureName].type == 'percentage') {
|
||||
ship.setModification(m, featureName, value * 10000);
|
||||
} else if (Modifications.modifications[featureName].type == 'numeric') {
|
||||
ship.setModification(m, featureName, value * 100);
|
||||
} else {
|
||||
ship.setModification(m, featureName, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (featureName == 'shieldboost') {
|
||||
mult = ((1 + value) * (1 + m.shieldboost)) - 1 - m.shieldboost;
|
||||
} else 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';
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
const features = m.blueprint.grades[m.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]) * mult);
|
||||
} else {
|
||||
value = features[featureName][0] + ((features[featureName][1] - features[featureName][0]) * mult);
|
||||
}
|
||||
} 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]) * mult);
|
||||
} else {
|
||||
value = features[featureName][1] + ((features[featureName][0] - features[featureName][1]) * mult);
|
||||
}
|
||||
}
|
||||
|
||||
_setValue(ship, m, 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a modification feature value
|
||||
* @param {Object} ship The ship for which to perform the modifications
|
||||
* @param {Object} m The module for which to perform the modifications
|
||||
* @param {string} featureName The feature being set
|
||||
* @param {number} value The value being set for the feature
|
||||
*/
|
||||
function _setValue(ship, m, featureName, value) {
|
||||
if (Modifications.modifications[featureName].type == 'percentage') {
|
||||
ship.setModification(m, featureName, value * 10000);
|
||||
} else if (Modifications.modifications[featureName].type == 'numeric') {
|
||||
ship.setModification(m, featureName, value * 100);
|
||||
} else {
|
||||
ship.setModification(m, featureName, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (featureName == 'shieldboost') {
|
||||
mult = ((1 + value) * (1 + m.shieldboost)) - 1 - m.shieldboost;
|
||||
} else 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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user