diff --git a/package-lock.json b/package-lock.json
index 43c25f9b..fca17783 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2455,6 +2455,12 @@
"resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
"integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ=="
},
+ "common-tags": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz",
+ "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==",
+ "dev": true
+ },
"commondir": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
@@ -6984,6 +6990,12 @@
"minimalistic-crypto-utils": "^1.0.1"
}
},
+ "hoek": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz",
+ "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==",
+ "dev": true
+ },
"home-or-tmp": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
@@ -7830,6 +7842,23 @@
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
+ "isemail": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.1.3.tgz",
+ "integrity": "sha512-5xbsG5wYADIcB+mfLsd+nst1V/D+I7EU7LEZPo2GOIMu4JzfcRs5yQoypP4avA7QtUqgxYLKBYNv4IdzBmbhdw==",
+ "dev": true,
+ "requires": {
+ "punycode": "2.x.x"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "dev": true
+ }
+ }
+ },
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -8952,6 +8981,17 @@
}
}
},
+ "joi": {
+ "version": "11.4.0",
+ "resolved": "https://registry.npmjs.org/joi/-/joi-11.4.0.tgz",
+ "integrity": "sha512-O7Uw+w/zEWgbL6OcHbyACKSj0PkQeUgmehdoXVSxt92QFCq4+1390Rwh5moI2K/OgC7D8RHRZqHZxT2husMJHA==",
+ "dev": true,
+ "requires": {
+ "hoek": "4.x.x",
+ "isemail": "3.x.x",
+ "topo": "2.x.x"
+ }
+ },
"js-base64": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.3.2.tgz",
@@ -9469,6 +9509,12 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg=="
},
+ "lodash._reinterpolate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
+ "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=",
+ "dev": true
+ },
"lodash.assignin": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz",
@@ -9553,6 +9599,25 @@
"integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=",
"dev": true
},
+ "lodash.template": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz",
+ "integrity": "sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A=",
+ "dev": true,
+ "requires": {
+ "lodash._reinterpolate": "~3.0.0",
+ "lodash.templatesettings": "^4.0.0"
+ }
+ },
+ "lodash.templatesettings": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz",
+ "integrity": "sha1-K01OlbpEDZFf8IvImeRVNmZxMxY=",
+ "dev": true,
+ "requires": {
+ "lodash._reinterpolate": "~3.0.0"
+ }
+ },
"lodash.uniq": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
@@ -11104,6 +11169,12 @@
"integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
"dev": true
},
+ "pretty-bytes": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-4.0.2.tgz",
+ "integrity": "sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk=",
+ "dev": true
+ },
"pretty-error": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz",
@@ -12728,6 +12799,15 @@
"integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=",
"dev": true
},
+ "topo": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/topo/-/topo-2.0.2.tgz",
+ "integrity": "sha1-zVYVdSU5BXwNwEkaYhw7xvvh0YI=",
+ "dev": true,
+ "requires": {
+ "hoek": "4.x.x"
+ }
+ },
"toposort": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.6.tgz",
@@ -13403,6 +13483,171 @@
"integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
"dev": true
},
+ "workbox-background-sync": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-3.4.1.tgz",
+ "integrity": "sha512-Ksb2nCg/2wOyBMhSBqSbtCEwuKaf5sHgTY8HdCxbLIQSzDh9/qZqg+1P11CKlgJmHtje3EK3B8EsrzukZo10xA==",
+ "dev": true,
+ "requires": {
+ "workbox-core": "^3.4.1"
+ }
+ },
+ "workbox-broadcast-cache-update": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/workbox-broadcast-cache-update/-/workbox-broadcast-cache-update-3.4.1.tgz",
+ "integrity": "sha512-+WPqHFk4ER4RICAMOYrP88yBbiUQ9ZOFNruqwbl9YxGfbADV16OEGmYpIs+Az6HT6DNDCx8eQqtFiaG8N3O11Q==",
+ "dev": true,
+ "requires": {
+ "workbox-core": "^3.4.1"
+ }
+ },
+ "workbox-build": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-3.4.1.tgz",
+ "integrity": "sha512-Qi04XdHjkXbRN0CV5XO1oqDWbJSIm7VYhxmxjtnVcKK8PrMT6rOUFUi9ziDI+8UQgcXbLK4ZChWf2ptZS1/MbA==",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "^6.26.0",
+ "common-tags": "^1.4.0",
+ "fs-extra": "^4.0.2",
+ "glob": "^7.1.2",
+ "joi": "^11.1.1",
+ "lodash.template": "^4.4.0",
+ "pretty-bytes": "^4.0.2",
+ "workbox-background-sync": "^3.4.1",
+ "workbox-broadcast-cache-update": "^3.4.1",
+ "workbox-cache-expiration": "^3.4.1",
+ "workbox-cacheable-response": "^3.4.1",
+ "workbox-core": "^3.4.1",
+ "workbox-google-analytics": "^3.4.1",
+ "workbox-navigation-preload": "^3.4.1",
+ "workbox-precaching": "^3.4.1",
+ "workbox-range-requests": "^3.4.1",
+ "workbox-routing": "^3.4.1",
+ "workbox-strategies": "^3.4.1",
+ "workbox-streams": "^3.4.1",
+ "workbox-sw": "^3.4.1"
+ },
+ "dependencies": {
+ "fs-extra": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz",
+ "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ }
+ }
+ }
+ },
+ "workbox-cache-expiration": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/workbox-cache-expiration/-/workbox-cache-expiration-3.4.1.tgz",
+ "integrity": "sha512-AzOPB+dwfxg13v4+q5jWkxsw/oim9mPIzew1anu8ALA3vB8qySaJJToXp+ZlVh/Co+sDK0tgjlB76bvSFHgZ4g==",
+ "dev": true,
+ "requires": {
+ "workbox-core": "^3.4.1"
+ }
+ },
+ "workbox-cacheable-response": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-3.4.1.tgz",
+ "integrity": "sha512-SO2k830JT93GitPwc5tzJI49d9VwyVxXwiCbyvo+Sqo+dcvWSrmpsyuXdzy6zuasbPrWUF0vsFj1uGtZbOym8Q==",
+ "dev": true,
+ "requires": {
+ "workbox-core": "^3.4.1"
+ }
+ },
+ "workbox-core": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-3.4.1.tgz",
+ "integrity": "sha512-RqMV2so9/KLAu9aUxJ/85pvrZMUn835B8zoHmqRyGNetiDr8B1zSBeKXPZAjFlX/88KdhizNwiRlJtqlXtM4tA==",
+ "dev": true
+ },
+ "workbox-google-analytics": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-3.4.1.tgz",
+ "integrity": "sha512-w6Osz2Rr1/4+W0gram6Yzg6NNWLvHP51RwFCNAZSpEnipr0qSEtD+yvwrdaHfiJHWhcK2yH/V6E1MV8Hrczmvw==",
+ "dev": true,
+ "requires": {
+ "workbox-background-sync": "^3.4.1",
+ "workbox-core": "^3.4.1",
+ "workbox-routing": "^3.4.1",
+ "workbox-strategies": "^3.4.1"
+ }
+ },
+ "workbox-navigation-preload": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-3.4.1.tgz",
+ "integrity": "sha512-P3FHAcyZ8db2QiW/BpMkuosC1OkRsEoUaT7U3QOgg7JSjjsJoEbF7G5olNe+P+PQYdVhJA7TCuptI6dy2gLS/g==",
+ "dev": true,
+ "requires": {
+ "workbox-core": "^3.4.1"
+ }
+ },
+ "workbox-precaching": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-3.4.1.tgz",
+ "integrity": "sha512-ykU2mly9xmRrCW6iMeUWYydWiso/WSE16+7wponhI0WC53jiQSt2JvykWm0VpWFJSs6ZTSZZ1WK2gs/brRnPug==",
+ "dev": true,
+ "requires": {
+ "workbox-core": "^3.4.1"
+ }
+ },
+ "workbox-range-requests": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-3.4.1.tgz",
+ "integrity": "sha512-ktgjl6liZrRTmQjPw1pBblC5umHnTb8XcvFVitdGz17B23jj6cUV4EXzEU2ilGn6jO6+MLV1Vn9SWajtLSc2Gg==",
+ "dev": true,
+ "requires": {
+ "workbox-core": "^3.4.1"
+ }
+ },
+ "workbox-routing": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-3.4.1.tgz",
+ "integrity": "sha512-6j6cXMUYfMPYTycmElxVOfBTr6WV5zAn/JUFJ7GJ5pYFIE9cqztprnrcOsWJ42+AiNIeHPbKfyIWE/rZVviMxQ==",
+ "dev": true,
+ "requires": {
+ "workbox-core": "^3.4.1"
+ }
+ },
+ "workbox-strategies": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-3.4.1.tgz",
+ "integrity": "sha512-7mJuzFsgejflzjfnChXCFma1S0mi9WC6wlSU2wE50M7bJmEuf9A3j3MojpKcsTEM58hbhbnU6QF/u9iIV7+opw==",
+ "dev": true,
+ "requires": {
+ "workbox-core": "^3.4.1"
+ }
+ },
+ "workbox-streams": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-3.4.1.tgz",
+ "integrity": "sha512-krw+5bp+oe9Za5c6WlTWM3SgZGfExYcqRSn1gsyYgKeXmgzTwf+DOb5Lwult0KSWlJfq8B3Wk7sW8Sl7lRzSbA==",
+ "dev": true,
+ "requires": {
+ "workbox-core": "^3.4.1"
+ }
+ },
+ "workbox-sw": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-3.4.1.tgz",
+ "integrity": "sha512-nnm2by5oaQGXRH7x4M5/n2KqjUGVmP4P8azUmJITnYa3DWVYn/ghDg3LJ5+h4A28vYq9V6ePgATaEPfb6B5pug==",
+ "dev": true
+ },
+ "workbox-webpack-plugin": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-3.4.1.tgz",
+ "integrity": "sha512-dwIaEJK27xbGKMQv1sbSjywxhfX74nMW1zgUP9XUtpFeykH0e5Dm1j7wbQezXU3mFoaO7xuzqwGpAFxMKc0xMA==",
+ "dev": true,
+ "requires": {
+ "json-stable-stringify": "^1.0.1",
+ "workbox-build": "^3.4.1"
+ }
+ },
"worker-farm": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.5.1.tgz",
diff --git a/package.json b/package.json
index 9c30e406..785f0ff3 100644
--- a/package.json
+++ b/package.json
@@ -65,9 +65,16 @@
"babel-preset-react": "*",
"babel-preset-stage-0": "*",
"create-react-class": "^15.6.2",
- "css-loader": "^0.28.0",
"cross-env": "^5.1.4",
+ "css-loader": "^0.28.0",
"d3-selection": "1",
+ "esdoc": "^1.1.0",
+ "esdoc-custom-theme": "^1.4.2",
+ "esdoc-ecmascript-proposal-plugin": "^1.0.0",
+ "esdoc-jsx-plugin": "^1.0.0",
+ "esdoc-publish-html-plugin": "^1.1.2",
+ "esdoc-react-plugin": "^1.0.1",
+ "esdoc-standard-plugin": "^1.0.0",
"eslint": "3.19.0",
"eslint-plugin-react": "^6.10.3",
"expose-loader": "^0.7.3",
@@ -91,16 +98,10 @@
"uglify-js": "^2.4.11",
"url-loader": "^0.5.8",
"webpack": "^2.4.1",
+ "webpack-bugsnag-plugins": "^1.1.1",
"webpack-dev-server": "^2.4.4",
"webpack-notifier": "^1.6.0",
- "webpack-bugsnag-plugins": "^1.1.1",
- "esdoc": "^1.1.0",
- "esdoc-ecmascript-proposal-plugin": "^1.0.0",
- "esdoc-jsx-plugin": "^1.0.0",
- "esdoc-react-plugin": "^1.0.1",
- "esdoc-standard-plugin": "^1.0.0",
- "esdoc-publish-html-plugin": "^1.1.2",
- "esdoc-custom-theme": "^1.4.2"
+ "workbox-webpack-plugin": "^3.4.1"
},
"dependencies": {
"babel-polyfill": "*",
diff --git a/src/app/Coriolis.jsx b/src/app/Coriolis.jsx
index 75d65ab7..e7a84e8c 100644
--- a/src/app/Coriolis.jsx
+++ b/src/app/Coriolis.jsx
@@ -322,14 +322,48 @@ export default class Coriolis extends React.Component {
*/
componentWillMount() {
// Listen for appcache updated event, present refresh to update view
- if (window.applicationCache) {
- window.applicationCache.addEventListener('updateready', () => {
- if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
- this.setState({ appCacheUpdate: true }); // Browser downloaded a new app cache.
- }
+ // Check that service workers are registered
+ if ('serviceWorker' in navigator) {
+ // Your service-worker.js *must* be located at the top-level directory relative to your site.
+ // It won't be able to control pages unless it's located at the same level or higher than them.
+ // *Don't* register service worker file in, e.g., a scripts/ sub-directory!
+ // See https://github.com/slightlyoff/ServiceWorker/issues/468
+ const self = this;
+ navigator.serviceWorker.register('/service-worker.js').then(function(reg) {
+ // updatefound is fired if service-worker.js changes.
+ reg.onupdatefound = function() {
+ // The updatefound event implies that reg.installing is set; see
+ // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#service-worker-container-updatefound-event
+ var installingWorker = reg.installing;
+
+ installingWorker.onstatechange = function() {
+ switch (installingWorker.state) {
+ case 'installed':
+ if (navigator.serviceWorker.controller) {
+ // At this point, the old content will have been purged and the fresh content will
+ // have been added to the cache.
+ // It's the perfect time to display a "New content is available; please refresh."
+ // message in the page's interface.
+ console.log('New or updated content is available.');
+ self.setState({ appCacheUpdate: true }); // Browser downloaded a new app cache.
+ } else {
+ // At this point, everything has been precached.
+ // It's the perfect time to display a "Content is cached for offline use." message.
+ console.log('Content is now available offline!');
+ self.setState({ appCacheUpdate: true }); // Browser downloaded a new app cache.
+ }
+ break;
+
+ case 'redundant':
+ console.error('The installing service worker became redundant.');
+ break;
+ }
+ };
+ };
+ }).catch(function(e) {
+ console.error('Error during service worker registration:', e);
});
}
-
window.onerror = this._onError.bind(this);
window.addEventListener('resize', () => this.emitter.emit('windowResize'));
document.getElementById('coriolis').addEventListener('scroll', () => this._tooltip());
diff --git a/src/app/components/AvailableModulesMenu.jsx b/src/app/components/AvailableModulesMenu.jsx
index c2bab8d9..8e743165 100644
--- a/src/app/components/AvailableModulesMenu.jsx
+++ b/src/app/components/AvailableModulesMenu.jsx
@@ -45,7 +45,12 @@ const GRPCAT = {
'mr': 'ordnance',
'axmr': 'experimental',
'rcpl': 'experimental',
+ 'dtl': 'experimental',
'tbsc': 'experimental',
+ 'tbem': 'experimental',
+ 'tbrfl': 'experimental',
+ 'mahr': 'experimental',
+ 'rsl': 'experimental',
'tp': 'ordnance',
'nl': 'ordnance',
'sc': 'scanners',
@@ -93,7 +98,7 @@ const CATEGORIES = {
'defence': ['ch', 'po', 'ec'],
'scanners': ['sc', 'ss', 'cs', 'kw', 'ws'], // Overloaded with internal scanners
// Experimental
- 'experimental': ['axmc', 'axmr', 'rfl', 'xs', 'sfn', 'rcpl', 'tbsc'],
+ 'experimental': ['axmc', 'axmr', 'rfl', 'tbrfl', 'tbsc', 'tbem', 'xs', 'sfn', 'rcpl', 'dtl', 'rsl', 'mahr', ],
// Guardian
'guardian': ['gpp', 'gpd', 'gpc', 'ggc', 'gsrp', 'gfsb', 'ghrp', 'gmrp', 'gsc']
@@ -473,7 +478,7 @@ export default class AvailableModulesMenu extends TranslatedComponent {
}
/**
* Handle focus if the component updates
- *
+ *
*/
componentWillUnmount() {
if(this.props.slotDiv) {
diff --git a/src/app/components/Defence.jsx b/src/app/components/Defence.jsx
index 4dbf0dc1..0528c192 100644
--- a/src/app/components/Defence.jsx
+++ b/src/app/components/Defence.jsx
@@ -102,19 +102,19 @@ export default class Defence extends TranslatedComponent {
// Add effective shield from resistances
const rawMj = shield.generator + shield.boosters + shield.cells;
- const explosiveMj = rawMj / shield.explosive.total - rawMj;
+ const explosiveMj = rawMj / (shield.explosive.base) - rawMj;
if (explosiveMj != 0) effectiveShieldExplosiveTt.push(
{translate('resistance') + ' ' + formats.int(explosiveMj)}{units.MJ}
);
- const kineticMj = rawMj / shield.kinetic.total - rawMj;
+ const kineticMj = rawMj / (shield.kinetic.base) - rawMj;
if (kineticMj != 0) effectiveShieldKineticTt.push({translate('resistance') + ' ' + formats.int(kineticMj)}{units.MJ}
);
- const thermalMj = rawMj / shield.thermal.total - rawMj;
+ const thermalMj = rawMj / (shield.thermal.base) - rawMj;
if (thermalMj != 0) effectiveShieldThermalTt.push({translate('resistance') + ' ' + formats.int(thermalMj)}{units.MJ}
);
// Add effective shield from power distributor SYS pips
if (shield.absolute.sys != 1) {
- effectiveShieldAbsoluteTt.push({translate('power distributor') + ' ' + formats.int(rawMj / shield.absolute.sys - rawMj)}{units.MJ}
);
- effectiveShieldExplosiveTt.push({translate('power distributor') + ' ' + formats.int(rawMj / shield.explosive.sys - rawMj)}{units.MJ}
);
- effectiveShieldKineticTt.push({translate('power distributor') + ' ' + formats.int(rawMj / shield.kinetic.sys - rawMj)}{units.MJ}
);
- effectiveShieldThermalTt.push({translate('power distributor') + ' ' + formats.int(rawMj / shield.thermal.sys - rawMj)}{units.MJ}
);
+ effectiveShieldAbsoluteTt.push({translate('power distributor') + ' ' + formats.int(rawMj / shield.absolute.total - rawMj)}{units.MJ}
);
+ effectiveShieldExplosiveTt.push({translate('power distributor') + ' ' + formats.int(rawMj / shield.explosive.total - rawMj / shield.explosive.base)}{units.MJ}
);
+ effectiveShieldKineticTt.push({translate('power distributor') + ' ' + formats.int(rawMj / shield.kinetic.total - rawMj / shield.kinetic.base)}{units.MJ}
);
+ effectiveShieldThermalTt.push({translate('power distributor') + ' ' + formats.int(rawMj / shield.thermal.total - rawMj / shield.thermal.base)}{units.MJ}
);
}
}
diff --git a/src/app/components/Header.jsx b/src/app/components/Header.jsx
index 24b67b0c..900da5e7 100644
--- a/src/app/components/Header.jsx
+++ b/src/app/components/Header.jsx
@@ -237,6 +237,10 @@ export default class Header extends TranslatedComponent {
/>);
};
+ /**
+ * Uploads all ship-builds to orbis
+ * @param {e} e Event
+ */
_uploadAllBuildsToOrbis(e) {
e.preventDefault();
const data = Persist.getBuilds();
diff --git a/src/app/components/ModalBatchOrbis.jsx b/src/app/components/ModalBatchOrbis.jsx
index 11a19e97..3e1c9ad5 100644
--- a/src/app/components/ModalBatchOrbis.jsx
+++ b/src/app/components/ModalBatchOrbis.jsx
@@ -30,6 +30,7 @@ export default class ModalBatchOrbis extends TranslatedComponent {
/**
* Send ship to Orbis.zone
* @param {SyntheticEvent} e React Event
+ * @return {Promise} Promise sending post request to orbis
*/
sendToOrbis(e) {
let agent;
diff --git a/src/app/components/Offence.jsx b/src/app/components/Offence.jsx
index 0898a57f..83450bdf 100644
--- a/src/app/components/Offence.jsx
+++ b/src/app/components/Offence.jsx
@@ -42,6 +42,63 @@ export function weaponComparator(translate, propComparator, desc) {
};
}
+/**
+ * Creates a tooltip that shows damage by type.
+ * @param {function} translate Translation function
+ * @param {Object} formats Object that holds format functions
+ * @param {Calc.SDps} sdpsObject Object that holds sdps split up by type
+ * @returns {Array} Tooltip
+ */
+function getSDpsTooltip(translate, formats, sdpsObject) {
+ return Object.keys(sdpsObject).filter(key => sdpsObject[key])
+ .map(key => {
+ return (
+
+ {translate(key) + ' ' + formats.f1(sdpsObject[key])}
+
+ );
+ });
+}
+
+/**
+ * Returns a data object used by {@link PieChart} that shows damage by type.
+ * @param {function} translate Translation function
+ * @param {Calc.SDps} sdpsObject Object that holds sdps split up by type
+ * @returns {Object} Data object
+ */
+function getSDpsData(translate, sdpsObject) {
+ return Object.keys(sdpsObject).map(key => {
+ return {
+ value: Math.round(sdpsObject[key]),
+ label: translate(key)
+ };
+ });
+}
+
+/**
+ * Adds all damage of `add` onto `addOn`.
+ * @param {Calc.SDps} addOn Object that holds sdps split up by type (will be mutated)
+ * @param {Calc.SDps} add Object that holds sdps split up by type
+ */
+function addSDps(addOn, add) {
+ Object.keys(addOn).map(k => addOn[k] += (add[k] ? add[k] : 0));
+}
+
+/**
+ * Calculates the overall sdps of an sdps object.
+ * @param {Calc.SDps} sdpsObject Object that holds sdps spluit up by type
+ */
+function sumSDps(sdpsObject) {
+ if (sdpsObject.total) {
+ return sdpsObject.total;
+ }
+
+ return Object.keys(sdpsObject).reduce(
+ (acc, k) => acc + (sdpsObject[k] ? sdpsObject[k] : 0),
+ 0
+ );
+}
+
/**
* Offence information
* Offence information consists of four panels:
@@ -70,7 +127,7 @@ export default class Offence extends TranslatedComponent {
this._sort = this._sort.bind(this);
const damage = Calc.offenceMetrics(props.ship, props.opponent, props.wep, props.opponentSys, props.engagementrange);
- this.state = {
+ this.state = {
predicate: 'n',
desc: true,
damage
@@ -144,51 +201,36 @@ export default class Offence extends TranslatedComponent {
const timeToDrain = Calc.timeToDrainWep(ship, wep);
- let absoluteShieldsSDps = 0;
- let explosiveShieldsSDps = 0;
- let kineticShieldsSDps = 0;
- let thermalShieldsSDps = 0;
- let absoluteArmourSDps = 0;
- let explosiveArmourSDps = 0;
- let kineticArmourSDps = 0;
- let thermalArmourSDps = 0;
let totalSEps = 0;
+ let totalSDpsObject = {'absolute': 0, 'explosive': 0, 'kinetic': 0, 'thermal': 0};
+ let shieldsSDpsObject = {'absolute': 0, 'explosive': 0, 'kinetic': 0, 'thermal': 0};
+ let armourSDpsObject = {'absolute': 0, 'explosive': 0, 'kinetic': 0, 'thermal': 0};
const rows = [];
for (let i = 0; i < damage.length; i++) {
const weapon = damage[i];
totalSEps += weapon.seps;
- absoluteShieldsSDps += weapon.sdps.shields.absolute;
- explosiveShieldsSDps += weapon.sdps.shields.explosive;
- kineticShieldsSDps += weapon.sdps.shields.kinetic;
- thermalShieldsSDps += weapon.sdps.shields.thermal;
- absoluteArmourSDps += weapon.sdps.armour.absolute;
- explosiveArmourSDps += weapon.sdps.armour.explosive;
- kineticArmourSDps += weapon.sdps.armour.kinetic;
- thermalArmourSDps += weapon.sdps.armour.thermal;
+ addSDps(totalSDpsObject, weapon.sdps.base);
+ addSDps(shieldsSDpsObject, weapon.sdps.shields);
+ addSDps(armourSDpsObject, weapon.sdps.armour);
+
+ const baseSDpsTooltipDetails = getSDpsTooltip(translate, formats, weapon.sdps.base);
const effectivenessShieldsTooltipDetails = [];
effectivenessShieldsTooltipDetails.push({translate('range') + ' ' + formats.pct1(weapon.effectiveness.shields.range)}
);
effectivenessShieldsTooltipDetails.push({translate('resistance') + ' ' + formats.pct1(weapon.effectiveness.shields.resistance)}
);
effectivenessShieldsTooltipDetails.push({translate('power distributor') + ' ' + formats.pct1(weapon.effectiveness.shields.sys)}
);
- const effectiveShieldsSDpsTooltipDetails = [];
- if (weapon.sdps.shields.absolute) effectiveShieldsSDpsTooltipDetails.push({translate('absolute') + ' ' + formats.f1(weapon.sdps.shields.absolute)}
);
- if (weapon.sdps.shields.explosive) effectiveShieldsSDpsTooltipDetails.push({translate('explosive') + ' ' + formats.f1(weapon.sdps.shields.explosive)}
);
- if (weapon.sdps.shields.kinetic) effectiveShieldsSDpsTooltipDetails.push({translate('kinetic') + ' ' + formats.f1(weapon.sdps.shields.kinetic)}
);
- if (weapon.sdps.shields.thermal) effectiveShieldsSDpsTooltipDetails.push({translate('thermal') + ' ' + formats.f1(weapon.sdps.shields.thermal)}
);
+ const effectiveShieldsSDpsTooltipDetails = getSDpsTooltip(translate, formats, weapon.sdps.armour);
const effectivenessArmourTooltipDetails = [];
effectivenessArmourTooltipDetails.push({translate('range') + ' ' + formats.pct1(weapon.effectiveness.armour.range)}
);
effectivenessArmourTooltipDetails.push({translate('resistance') + ' ' + formats.pct1(weapon.effectiveness.armour.resistance)}
);
effectivenessArmourTooltipDetails.push({translate('hardness') + ' ' + formats.pct1(weapon.effectiveness.armour.hardness)}
);
- const effectiveArmourSDpsTooltipDetails = [];
- if (weapon.sdps.armour.absolute) effectiveArmourSDpsTooltipDetails.push({translate('absolute') + ' ' + formats.f1(weapon.sdps.armour.absolute)}
);
- if (weapon.sdps.armour.explosive) effectiveArmourSDpsTooltipDetails.push({translate('explosive') + ' ' + formats.f1(weapon.sdps.armour.explosive)}
);
- if (weapon.sdps.armour.kinetic) effectiveArmourSDpsTooltipDetails.push({translate('kinetic') + ' ' + formats.f1(weapon.sdps.armour.kinetic)}
);
- if (weapon.sdps.armour.thermal) effectiveArmourSDpsTooltipDetails.push({translate('thermal') + ' ' + formats.f1(weapon.sdps.armour.thermal)}
);
+
+ const effectiveArmourSDpsTooltipDetails = getSDpsTooltip(translate, formats, weapon.sdps.armour);
rows.push(
@@ -199,27 +241,25 @@ export default class Offence extends TranslatedComponent {
{weapon.classRating} {translate(weapon.name)}
{weapon.engineering ? ' (' + weapon.engineering + ')' : null }
+ | {formats.f1(weapon.sdps.base.total)} |
{formats.f1(weapon.sdps.shields.total)} |
{formats.pct1(weapon.effectiveness.shields.total)} |
{formats.f1(weapon.sdps.armour.total)} |
{formats.pct1(weapon.effectiveness.armour.total)} |
);
- }
+ }
- const totalShieldsSDps = absoluteShieldsSDps + explosiveShieldsSDps + kineticShieldsSDps + thermalShieldsSDps;
- const totalArmourSDps = absoluteArmourSDps + explosiveArmourSDps + kineticArmourSDps + thermalArmourSDps;
+ const totalSDps = sumSDps(totalSDpsObject);
+ const totalSDpsTooltipDetails = getSDpsTooltip(translate, formats, totalSDpsObject);
+ const totalSDpsData = getSDpsData(translate, totalSDpsObject);
- const shieldsSDpsData = [];
- shieldsSDpsData.push({ value: Math.round(absoluteShieldsSDps), label: translate('absolute') });
- shieldsSDpsData.push({ value: Math.round(explosiveShieldsSDps), label: translate('explosive') });
- shieldsSDpsData.push({ value: Math.round(kineticShieldsSDps), label: translate('kinetic') });
- shieldsSDpsData.push({ value: Math.round(thermalShieldsSDps), label: translate('thermal') });
+ const totalShieldsSDps = sumSDps(shieldsSDpsObject);
+ const totalShieldsSDpsTooltipDetails = getSDpsTooltip(translate, formats, shieldsSDpsObject);
+ const shieldsSDpsData = getSDpsData(translate, shieldsSDpsObject);
- const armourSDpsData = [];
- armourSDpsData.push({ value: Math.round(absoluteArmourSDps), label: translate('absolute') });
- armourSDpsData.push({ value: Math.round(explosiveArmourSDps), label: translate('explosive') });
- armourSDpsData.push({ value: Math.round(kineticArmourSDps), label: translate('kinetic') });
- armourSDpsData.push({ value: Math.round(thermalArmourSDps), label: translate('thermal') });
+ const totalArmourSDps = sumSDps(armourSDpsObject);
+ const totalArmourSDpsTooltipDetails = getSDpsTooltip(translate, formats, armourSDpsObject);
+ const armourSDpsData = getSDpsData(translate, armourSDpsObject);
const timeToDepleteShields = Calc.timeToDeplete(opponentShields.total, totalShieldsSDps, totalSEps, pd.getWeaponsCapacity(), pd.getWeaponsRechargeRate() * (wep / 4));
const timeToDepleteArmour = Calc.timeToDeplete(opponentArmour.total, totalArmourSDps, totalSEps, pd.getWeaponsCapacity(), pd.getWeaponsRechargeRate() * (wep / 4));
@@ -231,19 +271,31 @@ export default class Offence extends TranslatedComponent {
| {translate('weapon')} |
+ {translate('overall')} |
{translate('opponent\'s shields')} |
{translate('opponent\'s armour')} |
+ | {'sdps'} |
{'sdps'} |
{'eft'} |
{'sdps'} |
{'eft'} |
-
- {rows}
-
+
+ {rows}
+ {rows.length > 0 &&
+
+ |
+ ={formats.f1(totalSDps)} |
+ ={formats.f1(totalShieldsSDps)} |
+ |
+ ={formats.f1(totalArmourSDps)} |
+ |
+
+ }
+
@@ -254,6 +306,10 @@ export default class Offence extends TranslatedComponent {
{translate('PHRASE_EFFECTIVE_SDPS_ARMOUR')}
{formats.f1(totalArmourSDps)}
{translate('PHRASE_TIME_TO_REMOVE_ARMOUR')}
{timeToDepleteArmour === Infinity ? translate('never') : formats.time(timeToDepleteArmour)}
+
+
{translate('overall damage')}
+
+
{translate('shield damage sources')}
diff --git a/src/app/components/ShipSummaryTable.jsx b/src/app/components/ShipSummaryTable.jsx
index 450c760e..b0d8d016 100644
--- a/src/app/components/ShipSummaryTable.jsx
+++ b/src/app/components/ShipSummaryTable.jsx
@@ -50,7 +50,7 @@ export default class ShipSummaryTable extends TranslatedComponent {
const speedTooltip = canThrust ? 'TT_SUMMARY_SPEED' : 'TT_SUMMARY_SPEED_NONFUNCTIONAL';
const canBoost = ship.canBoost(cargo, ship.fuelCapacity);
const boostTooltip = canBoost ? 'TT_SUMMARY_BOOST' : canThrust ? 'TT_SUMMARY_BOOST_NONFUNCTIONAL' : 'TT_SUMMARY_SPEED_NONFUNCTIONAL';
- const sgMetrics = Calc.shieldMetrics(ship, pips.sys || 2);
+ const sgMetrics = Calc.shieldMetrics(ship, pips.sys);
const shipBoost = canBoost ? Calc.calcBoost(ship) : 'No Boost';
const armourMetrics = Calc.armourMetrics(ship);
let shieldColour = 'blue';
@@ -149,8 +149,8 @@ export default class ShipSummaryTable extends TranslatedComponent {
{int(ship && ship.shield > 0 ? ship.shield * ((1 / (1 - (ship.shieldExplRes)))) : 0)}{u.MJ} |
{int(ship && ship.shield > 0 ? ship.shield * ((1 / (1 - (ship.shieldKinRes)))) : 0)}{u.MJ} |
{int(ship && ship.shield > 0 ? ship.shield * ((1 / (1 - (ship.shieldThermRes)))) : 0)}{u.MJ} |
-
{sgMetrics && sgMetrics.recover ? formats.time(sgMetrics.recover) : 0} |
-
{sgMetrics && sgMetrics.recharge ? formats.time(sgMetrics.recharge) : 0} |
+
{sgMetrics && sgMetrics.recover === Math.Inf ? translate('Never') : formats.time(sgMetrics.recover)} |
+
{sgMetrics && sgMetrics.recharge === Math.Inf ? translate('Never') : formats.time(sgMetrics.recharge)} |
diff --git a/src/app/i18n/en.json b/src/app/i18n/en.json
index 99624a88..83f11835 100644
--- a/src/app/i18n/en.json
+++ b/src/app/i18n/en.json
@@ -39,6 +39,7 @@
"PHRASE_TIME_TO_LOSE_ARMOUR": "Armour will hold for",
"PHRASE_MODULE_PROTECTION_EXTERNAL": "Protection for hardpoints",
"PHRASE_MODULE_PROTECTION_INTERNAL": "Protection for all other modules",
+ "PHRASE_OVERALL_DAMAGE": "Breakdown of sources for sustained DPS",
"PHRASE_SHIELD_DAMAGE": "Breakdown of sources for sustained DPS against shields",
"PHRASE_ARMOUR_DAMAGE": "Breakdown of sources for sustained DPS against armour",
"PHRASE_TIME_TO_REMOVE_SHIELDS": "Will remove shields in",
@@ -135,6 +136,7 @@
"rf": "Refinery",
"rfl": "Remote Release Flak Launcher",
"rg": "Rail Gun",
+ "rsl": "Research Limpet Controller",
"s": "Sensors",
"sb": "Shield Booster",
"sc": "Stellar Scanners",
@@ -150,6 +152,10 @@
"rpl": "Repair Limpet Controller",
"rcpl": "Recon Limpet Controller",
"xs": "Xeno Scanner",
+ "tbem": "Enzyme Missile Rack",
+ "tbrfl": "Remote Release Flechette Launcher",
+ "dtl": "Decontamination Limpet Controller",
+ "mahr": "Meta Alloy Hull Reinforcement Package",
"emptyrestricted": "empty (restricted)",
"damage dealt to": "Damage dealt to",
"damage received from": "Damage received from",
@@ -297,6 +303,7 @@
"opponent": "opponent",
"opponent's shields": "opponent's shields",
"opponent's armour": "opponent's armour",
+ "overall damage": "overall damage",
"shield damage sources": "shield damage sources",
"armour damage sources": "armour damage sources",
"never": "never",
diff --git a/src/app/shipyard/Calculations.js b/src/app/shipyard/Calculations.js
index aa62b187..cf66dfee 100644
--- a/src/app/shipyard/Calculations.js
+++ b/src/app/shipyard/Calculations.js
@@ -480,37 +480,56 @@ export function shieldMetrics(ship, sys) {
max: 1 - maxSysResistance
};
+ /**
+ * An object that stores a selection of difference damage multipliers that
+ * deal with a ship's shield strength.
+ * @typedef {Object} ShieldDamageMults
+ * @property {number} generator Base damage multiplier of the shield
+ * contributing it's base resistance.
+ * @property {number} boosters Damage multiplier contributed by all
+ * boosters, i.e. `rawMj / (generator * boosters)` equals shield strength
+ * with 0 pips to sys.
+ * @property {number} sys Damage multiplier contributed by pips to sys.
+ * @property {number} base Damage multiplier with 0 pips to sys; just
+ * boosters and shield generator. Equals `generator * boosters`.
+ * @property {number} total Damage multiplier with current pip settings.
+ * @property {number} max Damage multiplier with 4 pips to sys.
+ */
+
let sgExplosiveDmg = 1 - shieldGenerator.getExplosiveResistance();
let sgSbExplosiveDmg = diminishDamageMult(sgExplosiveDmg * 0.7, (1 - shieldGenerator.getExplosiveResistance()) * boosterExplDmg);
+ /** @type {ShieldDamageMults} */
shield.explosive = {
generator: sgExplosiveDmg,
- boosters: sgSbExplosiveDmg - sgExplosiveDmg,
+ boosters: sgSbExplosiveDmg / sgExplosiveDmg,
sys: (1 - sysResistance),
+ base: sgSbExplosiveDmg,
total: sgSbExplosiveDmg * (1 - sysResistance),
max: sgSbExplosiveDmg * (1 - maxSysResistance),
- res: 1 - sgSbExplosiveDmg
};
let sgKineticDmg = 1 - shieldGenerator.getKineticResistance();
let sgSbKineticDmg = diminishDamageMult(sgKineticDmg * 0.7, (1 - shieldGenerator.getKineticResistance()) * boosterKinDmg);
+ /** @type {ShieldDamageMults} */
shield.kinetic = {
generator: sgKineticDmg,
- boosters: sgSbKineticDmg - sgKineticDmg,
+ boosters: sgSbKineticDmg / sgKineticDmg,
sys: (1 - sysResistance),
+ base: sgSbKineticDmg,
total: sgSbKineticDmg * (1 - sysResistance),
max: sgSbKineticDmg * (1 - maxSysResistance),
- res: 1 - sgSbKineticDmg
};
let sgThermalDmg = 1 - shieldGenerator.getThermalResistance();
let sgSbThermalDmg = diminishDamageMult(sgThermalDmg * 0.7, (1 - shieldGenerator.getThermalResistance()) * boosterThermDmg);
+ /** @type {ShieldDamageMults} */
shield.thermal = {
generator: sgThermalDmg,
- boosters: sgSbThermalDmg - sgThermalDmg,
+ boosters: sgSbThermalDmg / sgThermalDmg,
sys: (1 - sysResistance),
+ base: sgSbThermalDmg,
total: sgSbThermalDmg * (1 - sysResistance),
max: sgSbThermalDmg * (1 - maxSysResistance),
- res: 1 - sgSbThermalDmg
};
}
return shield;
@@ -553,7 +572,7 @@ export function armourMetrics(ship) {
// };
// Armour from HRPs and module armour from MRPs
for (let slot of ship.internal) {
- if (slot.m && (slot.m.grp === 'hr' || slot.m.grp === 'ghrp')) {
+ if (slot.m && (slot.m.grp === 'hr' || slot.m.grp === 'ghrp' || slot.m.grp == 'mahr')) {
armourReinforcement += slot.m.getHullReinforcement();
// Hull boost for HRPs is applied against the ship's base armour
armourReinforcement += ship.baseArmour * slot.m.getModValue('hullboost') / 10000;
@@ -612,7 +631,7 @@ export function armourMetrics(ship) {
let armourReinforcedExplDmg = diminishDamageMult(0.7, (1 - ship.bulkheads.m.getExplosiveResistance()) * hullExplDmg);
armour.explosive = {
bulkheads: armourExplDmg,
- reinforcement: armourReinforcedExplDmg - armourExplDmg,
+ reinforcement: armourReinforcedExplDmg / armourExplDmg,
total: armourReinforcedExplDmg,
res: 1 - armourReinforcedExplDmg
};
@@ -621,7 +640,7 @@ export function armourMetrics(ship) {
let armourReinforcedKinDmg = diminishDamageMult(0.7, (1 - ship.bulkheads.m.getKineticResistance()) * hullKinDmg);
armour.kinetic = {
bulkheads: armourKinDmg,
- reinforcement: armourReinforcedKinDmg - armourKinDmg,
+ reinforcement: armourReinforcedKinDmg / armourKinDmg,
total: armourReinforcedKinDmg,
res: 1 - armourReinforcedKinDmg
};
@@ -630,7 +649,7 @@ export function armourMetrics(ship) {
let armourReinforcedThermDmg = diminishDamageMult(0.7, (1 - ship.bulkheads.m.getThermalResistance()) * hullThermDmg);
armour.thermal = {
bulkheads: armourThermDmg,
- reinforcement: armourReinforcedThermDmg - armourThermDmg,
+ reinforcement: armourReinforcedThermDmg / armourThermDmg,
total: armourReinforcedThermDmg,
res: 1 - armourReinforcedThermDmg
};
@@ -805,20 +824,55 @@ export function _sustainedDps(ship, opponent, opponentShields, opponentArmour, e
return { shieldsdps, armoursdps, eps };
}
+/**
+ * Stores SDPS split up by type.
+ * @typedef {Object} SDps
+ * @property {number} absolute Damage of type absolute
+ * @property {number} explosive Damage of type explosive
+ * @property {number} kinetic Damage of type kinetic
+ * @property {number} thermal Damage of type thermal
+ * @property {number} [total] Sum of all damage types
+ */
+
+/**
+ * An object that holds information about SDPS for a given weapon and opponent.
+ * @typedef {Object} WeaponDamage
+ * @property {number} eps Energy per second
+ * @property {Object} damage An object that stores damage inflicted by
+ * the weapon.
+ * @property {Object} effectiveness An object that stores the effectiveness of
+ * the weapon against the opponent given.
+ */
+
+/**
+ * Stores overall SDPS and against a given opponent's shields and armour.
+ * @typedef {Object} WeaponDamage~damage
+ * @property {SDps} base Overall SDPS.
+ * @property {SDps} shields SDPS against the given opponent's shields.
+ * @property {SDps} armour SDPS against the given opponent's armour.
+ */
+
/**
* Calculate the sustained DPS for a weapon at a given range
* @param {Object} m The weapon
- * @param {Object} opponent The opponent ship
+ * @param {Object} opponent The opponent ship
* @param {Object} opponentShields The opponent's shield resistances
* @param {Object} opponentArmour The opponent's armour resistances
* @param {int} engagementrange The range between the ship and opponent
- * @returns {Object} Sustained DPS for shield and armour
+ * @returns {WeaponDamage} Sustained DPS for shield and armour
*/
export function _weaponSustainedDps(m, opponent, opponentShields, opponentArmour, engagementrange) {
const opponentHasShields = opponentShields.generator ? true : false;
const weapon = {
eps: 0,
damage: {
+ base: {
+ absolute: 0,
+ explosive: 0,
+ kinetic: 0,
+ thermal: 0,
+ total: 0,
+ },
shields: {
absolute: 0,
explosive: 0,
@@ -863,6 +917,12 @@ export function _weaponSustainedDps(m, opponent, opponentShields, opponentArmour
sDps *= dropoff;
}
+ weapon.damage.base.absolute = sDps * m.getDamageDist().A;
+ weapon.damage.base.explosive = sDps * m.getDamageDist().E;
+ weapon.damage.base.kinetic = sDps * m.getDamageDist().K;
+ weapon.damage.base.thermal = sDps * m.getDamageDist().T;
+ weapon.damage.base.total = sDps;
+
// Piercing/hardness modifier (for armour only)
const armourMultiple = m.getPiercing() >= opponent.hardness ? 1 : m.getPiercing() / opponent.hardness;
weapon.effectiveness.armour.hardness = armourMultiple;
@@ -963,7 +1023,7 @@ export function timeToDeplete(amount, dps, eps, capacity, recharge) {
/**
* Applies diminishing returns to resistances.
- * @param {number} baseDamageMult The base resistance up to which no diminishing returns are applied.
+ * @param {number} diminishFrom The base resistance up to which no diminishing returns are applied.
* @param {number} damageMult Resistance as damage multiplier
* @returns {number} Actual damage multiplier
*/
diff --git a/src/app/shipyard/Constants.js b/src/app/shipyard/Constants.js
index 852bab9a..71d8107f 100755
--- a/src/app/shipyard/Constants.js
+++ b/src/app/shipyard/Constants.js
@@ -56,6 +56,7 @@ export const ModuleGroupToName = {
gfsb: 'Guardian Frame Shift Drive Booster',
ghrp: 'Guardian Hull Reinforcement Package',
gmrp: 'Guardian Module Reinforcement Package',
+ mahr: 'Meta Alloy Hull Reinforcement Package',
// Hard Points
bl: 'Beam Laser',
@@ -85,10 +86,14 @@ export const ModuleGroupToName = {
sfn: 'Shutdown Field Neutraliser',
xs: 'Xeno Scanner',
rcpl: 'Recon Limpet Controller',
+ rsl: 'Research Limpet Controller',
+ dtl: 'Decontamination Limpet Controller',
gpc: 'Guardian Plasma Charger',
ggc: 'Guardian Gauss Cannon',
tbsc: 'Shock Cannon',
gsc: 'Guardian Shard Cannon',
+ tbem: 'Enzyme Missile Rack',
+ tbrfl: 'Remote Release Flechette Launcher',
};
let GrpNameToCodeMap = {};
diff --git a/src/app/shipyard/Ship.js b/src/app/shipyard/Ship.js
index 182fa342..df219a83 100755
--- a/src/app/shipyard/Ship.js
+++ b/src/app/shipyard/Ship.js
@@ -937,7 +937,7 @@ export default class Ship {
let epsChanged = n && n.getEps() || old && old.getEps();
let hpsChanged = n && n.getHps() || old && old.getHps();
- let armourChange = (slot === this.bulkheads) || (n && n.grp === 'hr') || (n && n.grp === 'ghrp') || (old && old.grp === 'hr') || (old && old.grp === 'ghrp') || (n && n.grp === 'mrp') || (old && old.grp === 'mrp');
+ let armourChange = (slot === this.bulkheads) || (n && n.grp === 'hr') || (n && n.grp === 'ghrp') || (old && old.grp === 'hr') || (old && old.grp === 'ghrp') || (n && n.grp === 'mrp') || (old && old.grp === 'mrp') || (n && n.grp == 'mahr') || (old && old.grp == 'mahr');
let shieldChange = (n && n.grp === 'bsg') || (old && old.grp === 'bsg') || (n && n.grp === 'psg') || (old && old.grp === 'psg') || (n && n.grp === 'sg') || (old && old.grp === 'sg') || (n && n.grp === 'sb') || (old && old.grp === 'sb') || (old && old.grp === 'gsrp') || (n && n.grp === 'gsrp');
diff --git a/src/index.ejs b/src/index.ejs
index 32bccb3d..b6954789 100644
--- a/src/index.ejs
+++ b/src/index.ejs
@@ -1,5 +1,5 @@
- >
+
Coriolis EDCD Edition
diff --git a/src/sw.js b/src/sw.js
new file mode 100644
index 00000000..a12b92a0
--- /dev/null
+++ b/src/sw.js
@@ -0,0 +1,44 @@
+console.log('Hello from sw.js');
+
+if (workbox) {
+ console.log('Yay! Workbox is loaded 🎉');
+ workbox.routing.registerRoute(
+ new RegExp('https://fonts.(?:googleapis|gstatic).com/(.*)'),
+ workbox.strategies.cacheFirst({
+ cacheName: 'google-fonts',
+ plugins: [
+ new workbox.expiration.Plugin({
+ maxEntries: 30
+ }),
+ new workbox.cacheableResponse.Plugin({
+ statuses: [0, 200]
+ })
+ ]
+ })
+ );
+ workbox.routing.registerRoute(
+ /\.(?:png|gif|jpg|jpeg|svg)$/,
+ workbox.strategies.cacheFirst({
+ cacheName: 'images',
+ plugins: [
+ new workbox.expiration.Plugin({
+ maxEntries: 60,
+ maxAgeSeconds: 30 * 24 * 60 * 60 // 30 Days
+ })
+ ]
+ })
+ );
+ workbox.routing.registerRoute(
+ /\.(?:js|css)$/,
+ workbox.strategies.staleWhileRevalidate({
+ cacheName: 'static-resources'
+ })
+ );
+ try {
+ workbox.googleAnalytics.initialize();
+ } catch (e) {
+ console.log('Probably an ad-blocker');
+ }
+} else {
+ console.log('Boo! Workbox didn\'t load 😬');
+}
diff --git a/webpack.config.prod.js b/webpack.config.prod.js
index c0c78bc1..f5d9fac0 100644
--- a/webpack.config.prod.js
+++ b/webpack.config.prod.js
@@ -3,7 +3,8 @@ const exec = require('child_process').exec;
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
-const AppCachePlugin = require('appcache-webpack-plugin');
+const { InjectManifest } = require('workbox-webpack-plugin');
+
const { BugsnagSourceMapUploaderPlugin } = require('webpack-bugsnag-plugins');
const pkgJson = require('./package');
const buildDate = new Date();
@@ -75,12 +76,11 @@ module.exports = {
new CopyDirPlugin(path.join(__dirname, 'src/schemas'), 'schemas'),
new CopyDirPlugin(path.join(__dirname, 'src/images/logo/*'), ''),
new CopyDirPlugin(path.join(__dirname, 'src/.htaccess'), ''),
- new AppCachePlugin({
- network: ['*'],
- settings: ['prefer-online'],
- exclude: ['index.html', /.*\.map$/],
- output: 'coriolis.appcache'
- })
+ new InjectManifest({
+ swSrc: './src/sw.js',
+ importWorkboxFrom: 'cdn',
+ swDest: 'service-worker.js'
+ }),
],
module: {
rules: [