diff --git a/ChangeLog.md b/ChangeLog.md
index 4100f9b1..c7ddf17b 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,6 @@
+#2.3.6
+ * Update miner role to provide better defaults
+
#2.3.5
* Ensure that hidden blueprint effects are applied when a blueprint is selected
* Handle display when summary values show thrusters disabled but current mass keeps them enabled
diff --git a/src/app/components/SlotSection.jsx b/src/app/components/SlotSection.jsx
index e6f75da4..41dff6e3 100644
--- a/src/app/components/SlotSection.jsx
+++ b/src/app/components/SlotSection.jsx
@@ -15,6 +15,8 @@ export default class SlotSection extends TranslatedComponent {
static propTypes = {
ship: PropTypes.object.isRequired,
onChange: PropTypes.func.isRequired,
+ onCargoChange: PropTypes.func.isRequired,
+ onFuelChange: PropTypes.func.isRequired,
code: PropTypes.string.isRequired,
togglePwr: PropTypes.func
};
diff --git a/src/app/components/StandardSlotSection.jsx b/src/app/components/StandardSlotSection.jsx
index 30b4ff66..cba5511f 100644
--- a/src/app/components/StandardSlotSection.jsx
+++ b/src/app/components/StandardSlotSection.jsx
@@ -28,6 +28,8 @@ export default class StandardSlotSection extends SlotSection {
_optimizeStandard() {
this.props.ship.useLightestStandard();
this.props.onChange();
+ this.props.onCargoChange(this.props.ship.cargoCapacity);
+ this.props.onFuelChange(this.props.ship.fuelCapacity);
this._close();
}
@@ -39,6 +41,8 @@ export default class StandardSlotSection extends SlotSection {
_multiPurpose(shielded, bulkheadIndex) {
ShipRoles.multiPurpose(this.props.ship, shielded, bulkheadIndex);
this.props.onChange();
+ this.props.onCargoChange(this.props.ship.cargoCapacity);
+ this.props.onFuelChange(this.props.ship.fuelCapacity);
this._close();
}
@@ -49,6 +53,8 @@ export default class StandardSlotSection extends SlotSection {
_optimizeCargo(shielded) {
ShipRoles.trader(this.props.ship, shielded);
this.props.onChange();
+ this.props.onCargoChange(this.props.ship.cargoCapacity);
+ this.props.onFuelChange(this.props.ship.fuelCapacity);
this._close();
}
@@ -59,6 +65,8 @@ export default class StandardSlotSection extends SlotSection {
_optimizeMiner(shielded) {
ShipRoles.miner(this.props.ship, shielded);
this.props.onChange();
+ this.props.onCargoChange(this.props.ship.cargoCapacity);
+ this.props.onFuelChange(this.props.ship.fuelCapacity);
this._close();
}
@@ -69,6 +77,8 @@ export default class StandardSlotSection extends SlotSection {
_optimizeExplorer(planetary) {
ShipRoles.explorer(this.props.ship, planetary);
this.props.onChange();
+ this.props.onCargoChange(this.props.ship.cargoCapacity);
+ this.props.onFuelChange(this.props.ship.fuelCapacity);
this._close();
}
@@ -78,6 +88,8 @@ export default class StandardSlotSection extends SlotSection {
_optimizeRacer() {
ShipRoles.racer(this.props.ship);
this.props.onChange();
+ this.props.onCargoChange(this.props.ship.cargoCapacity);
+ this.props.onFuelChange(this.props.ship.fuelCapacity);
this._close();
}
diff --git a/src/app/pages/OutfittingPage.jsx b/src/app/pages/OutfittingPage.jsx
index f61df22c..17af3290 100644
--- a/src/app/pages/OutfittingPage.jsx
+++ b/src/app/pages/OutfittingPage.jsx
@@ -446,7 +446,10 @@ export default class OutfittingPage extends Page {
fuel = ship.fuelCapacity;
}
const code = this._fullCode(ship, fuel, cargo);
- this.setState({ code, cargo, fuel }, () => this._updateRoute(shipId, buildName, code));
+ // Only update the state if this really has been updated
+ if (this.state.code != code || this.state.cargo != cargo || this.state.fuel != fuel) {
+ this.setState({ code, cargo, fuel }, () => this._updateRoute(shipId, buildName, code));
+ }
}
/**
@@ -551,7 +554,7 @@ export default class OutfittingPage extends Page {
const internalSlotMarker = `${ship.name}${_iStr}${_pStr}${_mStr}`;
const hardpointsSlotMarker = `${ship.name}${_hStr}${_pStr}${_mStr}`;
const boostMarker = `${ship.canBoost(cargo, fuel)}`;
- const shipSummaryMarker = `${ship.name}${_sStr}${_iStr}${_hStr}${_pStr}${_mStr}${ship.ladenMass}${ship.cargo}${ship.fuel}`;
+ const shipSummaryMarker = `${ship.name}${_sStr}${_iStr}${_hStr}${_pStr}${_mStr}${ship.ladenMass}${cargo}${fuel}`;
return (
@@ -588,10 +591,10 @@ export default class OutfittingPage extends Page {
{/* Main tables */}
-
-
-
-
+
+
+
+
{/* Control of ship and opponent */}
diff --git a/src/app/shipyard/ModuleSet.js b/src/app/shipyard/ModuleSet.js
index 211df63f..d1bc3c90 100755
--- a/src/app/shipyard/ModuleSet.js
+++ b/src/app/shipyard/ModuleSet.js
@@ -132,6 +132,20 @@ export default class ModuleSet {
return new Module({ template: pd });
};
+ /** Find the power distributor that matches the requirements
+ * @param {Object} requirements The requirements to be met (currently only support 'weprate')
+ * @return {Object} Power distributor
+ */
+ matchingPowerDist(requirements) {
+ let pd = this.standard[4][0];
+ for (let p of this.standard[4]) {
+ if (p.weprate >= requirements.weprate || p.weprate >= pd.weprate) {
+ pd = p;
+ }
+ }
+ return new Module({ template: pd });
+ }
+
/**
* Finds the lightest Thruster that can handle the specified tonnage
* @param {number} ladenMass Ship laden mass (mass + cargo + fuel)
diff --git a/src/app/shipyard/ShipRoles.js b/src/app/shipyard/ShipRoles.js
index 84b15f55..73fb132f 100644
--- a/src/app/shipyard/ShipRoles.js
+++ b/src/app/shipyard/ShipRoles.js
@@ -252,24 +252,6 @@ export function miner(ship, shielded) {
}
}
- // Collector limpet controller if there are enough internals left
- let collectorLimpetsRequired = Math.max(ship.internal.filter(a => (!a.eligible) || a.eligible.cr).length - 6, 0);
- if (collectorLimpetsRequired > 0) {
- const collectorOrder = [1, 2, 3, 4, 5, 6, 7, 8];
- const collectorInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
- .filter(a => (!a.eligible) || a.eligible.cc)
- .sort((a,b) => collectorOrder.indexOf(a.maxClass) - collectorOrder.indexOf(b.maxClass));
- for (let i = 0; i < collectorInternals.length && collectorLimpetsRequired > 0; i++) {
- if (canMount(ship, collectorInternals[i], 'cc')) {
- // Collector only has odd classes
- const collectorClass = collectorInternals[i].maxClass % 2 === 0 ? collectorInternals[i].maxClass - 1 : collectorInternals[i].maxClass;
- ship.use(collectorInternals[i], ModuleUtils.findInternal('cc', collectorClass, 'A'));
- usedSlots.push(collectorInternals[i]);
- collectorLimpetsRequired -= collectorInternals[i].m.maximum;
- }
- }
- }
-
// 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) {
@@ -284,6 +266,45 @@ 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) {
+ return a + b.m.getDps();
+ }, 0);
+ // Find out how many internal slots we have, and their potential cargo size
+ const potentialCargo = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
+ .filter(a => (!a.eligible) || a.eligible.cr)
+ .map(b => Math.pow(2, b.maxClass));
+ // One collector for each 1.25 DPS, multiply by 1.25 for medium ships and 1.5 for large ships as they have further to travel
+ // 0 if we only have 1 cargo slot, otherwise minium of 1 and maximum of 6 (excluding size modifier)
+ const sizeModifier = ship.class == 2 ? 1.2 : ship.class == 3 ? 1.5 : 1;
+ let collectorLimpetsRequired = potentialCargo.length == 1 ? 0 : Math.ceil(sizeModifier * Math.min(6, Math.floor(miningLaserDps / 1.25)));
+ console.log(`${collectorLimpetsRequired}`);
+
+ if (collectorLimpetsRequired > 0) {
+ const collectorOrder = [1, 2, 3, 4, 5, 6, 7, 8];
+ const collectorInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
+ .filter(a => (!a.eligible) || a.eligible.cc)
+ .sort((a,b) => collectorOrder.indexOf(a.maxClass) - collectorOrder.indexOf(b.maxClass));
+ // Always keep at least 2 slots free for cargo racks (1 for shielded)
+ for (let i = 0; i < collectorInternals.length - (shielded ? 1 : 2) && collectorLimpetsRequired > 0; i++) {
+ if (canMount(ship, collectorInternals[i], 'cc')) {
+ // Collector only has odd classes
+ const collectorClass = collectorInternals[i].maxClass % 2 === 0 ? collectorInternals[i].maxClass - 1 : collectorInternals[i].maxClass;
+ ship.use(collectorInternals[i], ModuleUtils.findInternal('cc', collectorClass, 'D'));
+ usedSlots.push(collectorInternals[i]);
+ collectorLimpetsRequired -= collectorInternals[i].m.maximum;
+ }
+ }
+ }
+
+ // Power distributor to power the mining lasers indefinitely
+ const wepRateRequired = ship.hardpoints.filter(h => h.m != null)
+ .reduce(function(a, b) {
+ return a + b.m.getEps();
+ }, 0);
+ standardOpts.pd = ship.getAvailableModules().matchingPowerDist({weprate: wepRateRequired}).id;
+
// Fill the empty internals with cargo racks
for (let i = ship.internal.length; i--;) {
let slot = ship.internal[i];