);
- }
- list.push(buildGroup(g, modules[g]));
+ // Need to regroup the modules by our own categorisation
+ let catmodules = {};
+ // Pre-create to preserve ordering
+ for (let cat in CATEGORIES) {
+ catmodules[cat] = [];
+ }
+ for (let g in modules) {
+ const moduleCategory = GRPCAT[g] || g;
+ const existing = catmodules[moduleCategory] || [];
+ catmodules[moduleCategory] = existing.concat(modules[g]);
+ }
+
+ for (let category in catmodules) {
+ let categoryHeader = false;
+ // Order through CATEGORIES if present
+ const categories = CATEGORIES[category] || [category];
+ if (categories && categories.length) {
+ for (let n in categories) {
+ const grp = categories[n];
+ // We now have the group and the category. We might not have any modules, though...
+ if (modules[grp]) {
+ // Decide if we need a category header as well as a group header
+ if (categories.length === 1) {
+ // Show category header instead of group header
+ if (m && grp == m.grp) {
+ list.push(
: null }
From aea3e43e1cab6ff99fae3b6090c08a9ff70eb539 Mon Sep 17 00:00:00 2001
From: Cmdr McDonald
Date: Sun, 19 Feb 2017 20:49:31 +0000
Subject: [PATCH 08/24] Fixes and tidy-ups
---
src/app/components/AvailableModulesMenu.jsx | 19 +++++++-----
src/app/components/UtilitySlotSection.jsx | 8 ++---
src/app/utils/SlotFunctions.js | 34 ++++++++++++++++-----
3 files changed, 42 insertions(+), 19 deletions(-)
diff --git a/src/app/components/AvailableModulesMenu.jsx b/src/app/components/AvailableModulesMenu.jsx
index 661483da..9485eac3 100644
--- a/src/app/components/AvailableModulesMenu.jsx
+++ b/src/app/components/AvailableModulesMenu.jsx
@@ -41,6 +41,13 @@ const GRPCAT = {
'mr': 'ordnance',
'tp': 'ordnance',
'nl': 'ordnance',
+ // Utilities
+ 'cs': 'scanners',
+ 'kw': 'scanners',
+ 'ws': 'scanners',
+ 'ch': 'defence',
+ 'po': 'defence',
+ 'ec': 'defence',
};
// Order here is the order in which items will be shown in the modules menu
const CATEGORIES = {
@@ -64,12 +71,8 @@ const CATEGORIES = {
// Utilities
'sb': ['sb'],
'hs': ['hs'],
- 'ch': ['ch'],
- 'po': ['po'],
- 'ec': ['ec'],
- 'cs': ['cs'],
- 'kw': ['kw'],
- 'ws': ['ws'],
+ 'defence': ['ch', 'po', 'ec'],
+ 'scanners': ['cs', 'kw', 'ws'],
};
/**
@@ -128,7 +131,9 @@ export default class AvailableModulesMenu extends TranslatedComponent {
} else {
list = [];
// At present time slots with grouped options (Hardpoints and Internal) can be empty
- list.push(
{translate('empty')}
);
+ if (m) {
+ list.push(
{translate('empty')}
);
+ }
// Need to regroup the modules by our own categorisation
let catmodules = {};
diff --git a/src/app/components/UtilitySlotSection.jsx b/src/app/components/UtilitySlotSection.jsx
index 0351b4ab..95324219 100644
--- a/src/app/components/UtilitySlotSection.jsx
+++ b/src/app/components/UtilitySlotSection.jsx
@@ -99,11 +99,11 @@ export default class UtilitySlotSection extends SlotSection {
{translate('sb')}
-
E
-
D
-
C
-
B
A
+
B
+
C
+
D
+
E
{translate('hs')}
diff --git a/src/app/utils/SlotFunctions.js b/src/app/utils/SlotFunctions.js
index feff8a5b..fc0c7ee3 100644
--- a/src/app/utils/SlotFunctions.js
+++ b/src/app/utils/SlotFunctions.js
@@ -143,13 +143,7 @@ export function diffDetails(language, m, mm) {
let { formats, translate, units } = language;
let propDiffs = [];
- let mCost = m.cost || 0;
- let mmCost = mm ? mm.cost : 0;
- if (mCost != mmCost) propDiffs.push(
);
+
let massDiff = mMass - mmMass;
let mCap = m.fuel || m.cargo || 0;
let mmCap = mm ? mm.fuel || mm.cargo || 0 : 0;
From 77d3053ff880e83363d3fa95e737646678dca649 Mon Sep 17 00:00:00 2001
From: Cmdr McDonald
Date: Mon, 20 Feb 2017 14:05:19 +0000
Subject: [PATCH 09/24] Handle 'higher better' modifications when both min and
max are negative - fixes #80
---
src/app/components/ModificationsMenu.jsx | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/src/app/components/ModificationsMenu.jsx b/src/app/components/ModificationsMenu.jsx
index 76e088ad..0b25479b 100644
--- a/src/app/components/ModificationsMenu.jsx
+++ b/src/app/components/ModificationsMenu.jsx
@@ -218,7 +218,23 @@ export default class ModificationsMenu extends TranslatedComponent {
const { m, ship } = this.props;
const features = m.blueprint.grades[m.blueprint.grade].features;
for (const featureName in features) {
- const value = Modifications.modifications[featureName].higherbetter ? features[featureName][1] : features[featureName][0];
+ 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][0];
+ } else {
+ value = features[featureName][1];
+ }
+ } 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][1];
+ } else {
+ value = features[featureName][0];
+ }
+ }
+
this._setRollResult(ship, m, featureName, value);
}
this.setState({ modifications: this._setModifications(this.props) });
From ea3d57399cda0e5dc19842a3d153f9ee63ee36dd Mon Sep 17 00:00:00 2001
From: Cmdr McDonald
Date: Tue, 21 Feb 2017 16:27:09 +0000
Subject: [PATCH 10/24] Tidy up available modules layout
---
ChangeLog.md | 1 +
package.json | 2 +-
src/app/components/AvailableModulesMenu.jsx | 6 +++++-
src/app/i18n/en.js | 2 ++
src/less/select.less | 9 ---------
5 files changed, 9 insertions(+), 11 deletions(-)
diff --git a/ChangeLog.md b/ChangeLog.md
index a35d018b..de78613e 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -2,6 +2,7 @@
* Change methodology for calculating explorer role; can result in lighter builds
* Tidy up layout for module selection and lay everything out in a consistent best-to-worst for both class and grade
* Make integrity for module reinforcement packages visible
+ * Clean up breakpoints for modules in available modules list; stops 7- or 8- module long lines
#2.2.17
* Use in-game terminology for shield generator optmul and optmass items
diff --git a/package.json b/package.json
index 67ab2a88..12359301 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "coriolis_shipyard",
- "version": "2.2.17",
+ "version": "2.2.18b",
"repository": {
"type": "git",
"url": "https://github.com/EDCD/coriolis"
diff --git a/src/app/components/AvailableModulesMenu.jsx b/src/app/components/AvailableModulesMenu.jsx
index 9485eac3..a1e93235 100644
--- a/src/app/components/AvailableModulesMenu.jsx
+++ b/src/app/components/AvailableModulesMenu.jsx
@@ -207,6 +207,8 @@ export default class AvailableModulesMenu extends TranslatedComponent {
const tmp = sortedModules.map((v, i) => v['class']).reduce((count, cls) => { count[cls] = ++count[cls] || 1; return count; }, {});
const itemsPerClass = Math.max.apply(null, Object.keys(tmp).map(key => tmp[key]));
+ let itemsOnThisRow = 0;
+
for (let i = 0; i < sortedModules.length; i++) {
let m = sortedModules[i];
let mount = null;
@@ -240,8 +242,9 @@ export default class AvailableModulesMenu extends TranslatedComponent {
case 'T': mount = ; break;
}
- if (i > 0 && sortedModules.length > 3 && itemsPerClass > 2 && m.class != prevClass && (m.rating != prevRating || m.mount)) {
+ if (itemsOnThisRow == 6 || i > 0 && sortedModules.length > 3 && itemsPerClass > 2 && m.class != prevClass && (m.rating != prevRating || m.mount)) {
elems.push( );
+ itemsOnThisRow = 0;
}
elems.push(
@@ -250,6 +253,7 @@ export default class AvailableModulesMenu extends TranslatedComponent {
{(mount ? ' ' : '') + m.class + m.rating + (m.missile ? '/' + m.missile : '') + (m.name ? ' ' + translate(m.name) : '')}
);
+ itemsOnThisRow++;
prevClass = m.class;
prevRating = m.rating;
}
diff --git a/src/app/i18n/en.js b/src/app/i18n/en.js
index dc04c526..9e6d636b 100644
--- a/src/app/i18n/en.js
+++ b/src/app/i18n/en.js
@@ -212,6 +212,8 @@ Once you have a working companion API connection go to the 'Shipyard'
Note that Internet Explorer and Edge might not import correctly, due to their internal restrictions on URL length. If you find that this is the case then please change your default browser to Chrome.
+Also, the imported information does not provide any data on the power priority or enabled status of your cargo hatch. Coriolis sets this item to have a power priority of "5" and to be disabled by default. You can change this after import in the Power Management section.
+
Importing Your Ship From EDMC
To import your ship from EDMC once your connection to the Frontier servers' companion API is working go to 'Settings ->Configuration' and set the 'Preferred Shipyard' to 'Coriolis'. Once this is set up clicking on your ship in the main window will open your default web browser in Coriolis with the ship's build.
diff --git a/src/less/select.less b/src/less/select.less
index 8169a6a8..c32c55ca 100755
--- a/src/less/select.less
+++ b/src/less/select.less
@@ -158,15 +158,6 @@ select {
width: 4.5em;
padding: 0.1em 0.2em;
}
- ul {
- width: 17em;
- }
- }
-
- &.standard {
- ul {
- width: 16.25em;
- }
}
}
From d2d8f084d2692934bb2ec71cab5cf1f7124ffbf7 Mon Sep 17 00:00:00 2001
From: Cmdr McDonald
Date: Tue, 21 Feb 2017 19:22:14 +0000
Subject: [PATCH 11/24] Move to newer version of d3
---
package.json | 2 +-
src/app/components/BarChart.jsx | 20 +++++++++----------
src/app/components/DamageDealt.jsx | 6 ++++--
src/app/components/LineChart.jsx | 31 +++++++++++++++---------------
src/app/components/PowerBands.jsx | 10 +++++-----
src/app/i18n/Language.jsx | 30 +++++++++++++++--------------
src/less/charts.less | 5 +++--
7 files changed, 55 insertions(+), 49 deletions(-)
diff --git a/package.json b/package.json
index 267e1f16..6b38c301 100644
--- a/package.json
+++ b/package.json
@@ -87,7 +87,7 @@
"classnames": "^2.2.0",
"browserify-zlib": "ipfs/browserify-zlib",
"coriolis-data": "EDCD/coriolis-data",
- "d3": "3.5.16",
+ "d3": "4.6.0",
"fbemitter": "^2.0.0",
"lodash": "^4.15.0",
"lz-string": "^1.4.4",
diff --git a/src/app/components/BarChart.jsx b/src/app/components/BarChart.jsx
index 561921e2..8ab59851 100644
--- a/src/app/components/BarChart.jsx
+++ b/src/app/components/BarChart.jsx
@@ -1,5 +1,5 @@
import React from 'react';
-import d3 from 'd3';
+import * as d3 from 'd3';
import TranslatedComponent from './TranslatedComponent';
const MARGIN = { top: 15, right: 20, bottom: 40, left: 150 };
@@ -68,13 +68,13 @@ export default class BarChart extends TranslatedComponent {
this._updateDimensions = this._updateDimensions.bind(this);
this._hideTip = this._hideTip.bind(this);
- let scale = d3.scale.linear();
- let y0 = d3.scale.ordinal();
- let y1 = d3.scale.ordinal();
+ let scale = d3.scaleLinear();
+ let y0 = d3.scaleBand();
+ let y1 = d3.scaleBand();
- this.xAxis = d3.svg.axis().scale(scale).ticks(5).outerTickSize(0).orient('bottom').tickFormat(context.language.formats.s2);
- this.yAxis = d3.svg.axis().scale(y0).outerTickSize(0).orient('left');
- this.state = { scale, y0, y1, color: d3.scale.ordinal().range(props.colors) };
+ this.xAxis = d3.axisBottom(scale).ticks(5).tickSizeOuter(0).tickFormat(context.language.formats.s2);
+ this.yAxis = d3.axisLeft(y0).tickSizeOuter(0);
+ this.state = { scale, y0, y1, color: d3.scaleOrdinal().range(props.colors) };
}
/**
@@ -131,8 +131,8 @@ export default class BarChart extends TranslatedComponent {
let max = data.reduce((max, build) => (properties.reduce(((m, p) => (m > build[p] ? m : build[p])), max)), 0);
this.state.scale.range([0, innerWidth]).domain([0, max]);
- this.state.y0.domain(data.map(bName)).rangeRoundBands([0, innerHeight], 0.3);
- this.state.y1.domain(properties).rangeRoundBands([0, this.state.y0.rangeBand()]);
+ this.state.y0.domain(data.map(bName)).range([0, innerHeight], 0.3).padding(0.4);
+ this.state.y1.domain(properties).range([0, this.state.y0.bandwidth()]).padding(0.1);
this.setState({
barHeight,
@@ -192,7 +192,7 @@ export default class BarChart extends TranslatedComponent {
x={0}
y={y1(p)}
width={scale(build[p])}
- height={y1.rangeBand()}
+ height={y1.bandwidth()}
fill={color(p)}
onMouseOver={this._showTip.bind(this, build, p, propIndex)}
onMouseOut={this._hideTip}
diff --git a/src/app/components/DamageDealt.jsx b/src/app/components/DamageDealt.jsx
index 33ece310..c20e9391 100644
--- a/src/app/components/DamageDealt.jsx
+++ b/src/app/components/DamageDealt.jsx
@@ -162,7 +162,7 @@ export default class DamageDealt extends TranslatedComponent {
let names = [];
let num = 1;
for (let i =0; i < ship.hardpoints.length; i++) {
- if (ship.hardpoints[i].m && ship.hardpoints[i].enabled) {
+ if (ship.hardpoints[i].maxClass > 0 && ship.hardpoints[i].m && ship.hardpoints[i].enabled) {
const m = ship.hardpoints[i].m;
let name = '' + num++ + ': ' + m.class + m.rating + (m.missile ? '/' + m.missile : '') + ' ' + translate(m.name || m.grp);
let engineering;
@@ -242,7 +242,7 @@ export default class DamageDealt extends TranslatedComponent {
let weapons = [];
for (let i = 0; i < ship.hardpoints.length; i++) {
- if (ship.hardpoints[i].m && ship.hardpoints[i].enabled) {
+ if (ship.hardpoints[i].maxClass > 0 && ship.hardpoints[i].m && ship.hardpoints[i].enabled) {
const m = ship.hardpoints[i].m;
if (m.getDamage() && m.grp !== 'po') {
let dropoff = 1;
@@ -493,6 +493,7 @@ export default class DamageDealt extends TranslatedComponent {
series={this.state.weaponNames}
colors={DAMAGE_DEALT_COLORS}
func={this.state.calcDpsFunc}
+ points={200}
/>
The damage dealt panel provides information about the effectiveness of your build's weapons against opponents' shields and hull at different engagement distances.
@@ -281,7 +281,7 @@ Total effective DPS, SDPS and effectiveness against both shields and hull are pr
At the bottom of this panel you can change your engagement range. The engagement range is the distance between your ship and your target. Many weapons suffer from what is known as damage falloff, where their effectiveness decreases the further the distance between your ship and your target. This allows you to model the effect of engaging at different ranges.
-Note that this panel only shows enabled weapons, so if you want to see your overall effectiveness for a subset of your weapons you can disable the undesired weapons in the power management panel.
+Note that this panel only shows enabled weapons, so if you want to see your overall effectiveness for a subset of your weapons you can disable the undesired weapons in the power management panel.
Damage Received
The damage received panel provides information about the effectiveness of your build's defences against opponent's weapons at different engagement range. Features and functions are the same as the damage dealt panel, except that it does take in to account your build's resistances.
From 76027b8537b3273e47eca04bd5260bb697d3634f Mon Sep 17 00:00:00 2001
From: Cmdr McDonald
Date: Mon, 30 Jan 2017 13:34:41 +0000
Subject: [PATCH 13/24] Playing with damage dealt graph
---
src/app/components/DamageDealt.jsx | 127 +++++++++++++++++++++++++++--
src/app/pages/OutfittingPage.jsx | 2 +-
2 files changed, 120 insertions(+), 9 deletions(-)
diff --git a/src/app/components/DamageDealt.jsx b/src/app/components/DamageDealt.jsx
index 3fd7e826..24f21935 100644
--- a/src/app/components/DamageDealt.jsx
+++ b/src/app/components/DamageDealt.jsx
@@ -4,8 +4,11 @@ import { Ships } from 'coriolis-data/dist';
import ShipSelector from './ShipSelector';
import { nameComparator } from '../utils/SlotFunctions';
import { CollapseSection, ExpandSection, MountFixed, MountGimballed, MountTurret } from './SvgIcons';
+import LineChart from '../components/LineChart';
import Slider from '../components/Slider';
+const DAMAGE_DEALT_COLORS = ['#0088d2', '#ff8c0d', '#D26D00', '#c06400'];
+
/**
* Generates an internationalization friendly weapon comparator that will
* sort by specified property (if provided) then by name/group, class, rating
@@ -47,6 +50,7 @@ export function weaponComparator(translate, propComparator, desc) {
export default class DamageDealt extends TranslatedComponent {
static PropTypes = {
ship: React.PropTypes.object.isRequired,
+ chartWidth: React.PropTypes.number.isRequired,
code: React.PropTypes.string.isRequired
};
@@ -63,13 +67,23 @@ export default class DamageDealt extends TranslatedComponent {
this._onShipChange = this._onShipChange.bind(this);
this._onCollapseExpand = this._onCollapseExpand.bind(this);
+ const ship = this.props.ship;
+ const against = DamageDealt.DEFAULT_AGAINST;
+ const range = 0.1667;
+ const maxRange = 6000;
+ const maxDps = this._calcMaxDps(ship, against)
+ const weaponNames = this._weaponNames(ship);
+
this.state = {
predicate: 'n',
desc: true,
- against: DamageDealt.DEFAULT_AGAINST,
+ against,
expanded: false,
- range: 0.1667,
- maxRange: 6000
+ range,
+ maxRange,
+ maxDps,
+ weaponNames,
+ calcDpsFunc: this._calcDps.bind(this, ship, against)
};
}
@@ -89,12 +103,84 @@ export default class DamageDealt extends TranslatedComponent {
*/
componentWillReceiveProps(nextProps, nextContext) {
if (nextProps.code != this.props.code) {
- const data = this._calcWeapons(this.props.ship, this.state.against, this.state.range * this.state.maxRange);
- this.setState({ weapons: data.weapons, totals: data.totals });
+ const data = this._calcWeapons(nextProps.ship, this.state.against, this.state.range * this.state.maxRange);
+ const weaponNames = this._weaponNames(nextProps.ship);
+ this.setState({ weapons: data.weapons,
+ totals: data.totals,
+ weaponNames,
+ calcDpsFunc: this._calcDps.bind(this, nextProps.ship, this.state.against) });
}
return true;
}
+ /**
+ * Calculate the maximum single-weapon DPS for this ship against another ship
+ * @param {Object} ship The ship
+ * @param {Object} against The target
+ * @return {number} The maximum single-weapon DPS
+ */
+ _calcMaxDps(ship, against) {
+ let maxDps = 0;
+ for (let i =0; i < ship.hardpoints.length; i++) {
+ if (ship.hardpoints[i].m && ship.hardpoints[i].enabled) {
+ const m = ship.hardpoints[i].m;
+ const thisDps = m.getDps() * (m.getPiercing() >= against.properties.hardness ? 1 : m.getPiercing() / against.properties.hardness);
+ if (thisDps > maxDps) {
+ maxDps = thisDps;
+ }
+ }
+ }
+ return maxDps;
+ }
+
+ /**
+ * Calculate the per-weapon DPS for this ship against another ship at a given range
+ * @param {Object} ship The ship
+ * @param {Object} against The target
+ * @param {Object} range The engagement range
+ * @return {array} The array of weapon DPS
+ */
+ _calcDps(ship, against, range) {
+ let results = {}
+ for (let i =0; i < ship.hardpoints.length; i++) {
+ if (ship.hardpoints[i].m && ship.hardpoints[i].enabled) {
+ const m = ship.hardpoints[i].m;
+ const thisDps = m.getDps() * (m.getPiercing() >= against.properties.hardness ? 1 : m.getPiercing() / against.properties.hardness);
+ results[i] = thisDps;
+ }
+ }
+ return results;
+ }
+
+ /**
+ * Obtain the weapon names for this ship
+ * @param {Object} ship The ship
+ * @return {array} The weapon names
+ */
+ _weaponNames(ship) {
+ let names = [];
+ for (let i =0; i < ship.hardpoints.length; i++) {
+ if (ship.hardpoints[i].m && ship.hardpoints[i].enabled) {
+ const m = ship.hardpoints[i].m;
+ // TODO translate
+ let name = m.class + m.rating + (m.missile ? '/' + m.missile : '') + ' ' + (m.name || m.grp);
+ let engineering;
+ if (m.blueprint && m.blueprint.name) {
+ engineering = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade;
+ if (m.blueprint.special && m.blueprint.special.id) {
+ engineering += ', ' + translate(m.blueprint.special.name);
+ }
+ }
+ if (engineering) {
+ name = name + ' (' + engineering + ')';
+ }
+ names.push(name)
+ }
+ }
+ return names;
+ }
+
+
/**
* Calculate the damage dealt by a ship
* @param {Object} ship The ship which will deal the damage
@@ -193,7 +279,12 @@ export default class DamageDealt extends TranslatedComponent {
_onShipChange(s) {
const against = Ships[s];
const data = this._calcWeapons(this.props.ship, against, this.state.range * this.state.maxRange);
- this.setState({ against, weapons: data.weapons, totals: data.totals });
+ const maxDps = this._calcMaxDps(this.props.ship, against)
+ this.setState({ against,
+ weapons: data.weapons,
+ totals: data.totals,
+ maxDps,
+ calcDpsFunc: this.props.ship.calcDps.bind(this, this.props.ship, against) });
}
/**
@@ -278,7 +369,10 @@ export default class DamageDealt extends TranslatedComponent {
*/
_rangeChange(range) {
const data = this._calcWeapons(this.props.ship, this.state.against, this.state.range * this.state.maxRange);
- this.setState({ range, weapons: data.weapons, totals: data.totals });
+ this.setState({ range,
+ weapons: data.weapons,
+ totals: data.totals,
+ calcDpsFunc: this.props.ship.calcDps.bind(this, this.props.ship, against) });
}
/**
@@ -290,6 +384,7 @@ export default class DamageDealt extends TranslatedComponent {
const { formats, translate, units } = language;
const { expanded, maxRange, range, totals } = this.state;
+
const sortOrder = this._sortOrder;
const onCollapseExpand = this._onCollapseExpand;
@@ -349,7 +444,23 @@ export default class DamageDealt extends TranslatedComponent {
- : null }
+
+