mirror of
https://github.com/EDCD/coriolis.git
synced 2025-12-10 07:05:35 +00:00
Compare commits
123 Commits
45508ba2d4
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1dfd3cdc23 | ||
|
|
a3d7c8b7a7 | ||
|
|
60a05d93c8 | ||
|
|
7f3056560d | ||
|
|
43718e15cf | ||
|
|
8a1ad353e2 | ||
|
|
fbe29d8087 | ||
|
|
8583c6a811 | ||
|
|
620a82faf2 | ||
|
|
8296562640 | ||
|
|
505c6809a1 | ||
|
|
35a24a55e8 | ||
|
|
b365faed0a | ||
|
|
060b98cc89 | ||
|
|
6a1eae8e9e | ||
|
|
98126267e7 | ||
|
|
22b73b9b0c | ||
|
|
f769a0d40d | ||
|
|
4ae2140178 | ||
|
|
070beade85 | ||
|
|
9705a49c96 | ||
|
|
d575d97837 | ||
|
|
dd3aa5fd7b | ||
|
|
bb658e8b59 | ||
|
|
a40bd5344e | ||
|
|
16b341d0d0 | ||
|
|
e04a99222d | ||
|
|
c78bbd1db4 | ||
|
|
f48d1bae20 | ||
|
|
112463a9e8 | ||
|
|
b1fd7991b6 | ||
|
|
0f4eae7d4c | ||
|
|
e545397d12 | ||
|
|
d06388f7c5 | ||
|
|
9a41153868 | ||
|
|
b7e6e7ab8b | ||
|
|
480466ff2a | ||
|
|
d1cb0fdcb5 | ||
|
|
2362ded438 | ||
|
|
cb1612d828 | ||
|
|
4b5940e651 | ||
|
|
06552dd860 | ||
|
|
ca91401507 | ||
|
|
ed5ffbc9f8 | ||
|
|
45935b90e4 | ||
|
|
5d41575e66 | ||
|
|
b86e90de4b | ||
|
|
105fc60f43 | ||
|
|
7ccfa09ddd | ||
|
|
ab3c93d52d | ||
|
|
ee04416e2b | ||
|
|
4efc47dff0 | ||
|
|
bd2e6eaf51 | ||
|
|
42b2e39064 | ||
|
|
d1217439bd | ||
|
|
2a6ae0f2ff | ||
|
|
dedd2ddbba | ||
|
|
f86ecede9b | ||
|
|
436a50cb45 | ||
|
|
f7cf39a9ae | ||
|
|
680f3b10f3 | ||
|
|
b31de9c37a | ||
|
|
9ef054c271 | ||
|
|
aa620be113 | ||
|
|
27f19a72a6 | ||
|
|
634be1f197 | ||
|
|
f747b25f26 | ||
|
|
02bf133c98 | ||
|
|
6c34a26273 | ||
|
|
b0b5c82131 | ||
|
|
ee92f2f2e4 | ||
|
|
0d749202e2 | ||
|
|
4283b0b839 | ||
|
|
fbd9c3d282 | ||
|
|
cd68199a41 | ||
|
|
f885fde04f | ||
|
|
8f5375f732 | ||
|
|
5c8ff57d16 | ||
|
|
3156b6a533 | ||
|
|
14ffa26ef9 | ||
|
|
18d7ada65f | ||
|
|
8593e18de4 | ||
|
|
284b0b3ce2 | ||
|
|
c3cb2cfa3b | ||
|
|
5d54eb8862 | ||
|
|
9fc6508be4 | ||
|
|
ef82cf4a00 | ||
|
|
9766f78e21 | ||
|
|
6d8bd6ca44 | ||
|
|
875af31ffe | ||
|
|
93adcb3daf | ||
|
|
ec9a07b143 | ||
|
|
bb8eeb4d3f | ||
|
|
8b7a7192a4 | ||
|
|
6688a1fbe3 | ||
|
|
2ea5fe5d58 | ||
|
|
efd644c6f1 | ||
|
|
17c6ec1f97 | ||
|
|
9bc6e36f14 | ||
|
|
062815054c | ||
|
|
7bc40d24d8 | ||
|
|
d9da250f50 | ||
|
|
801969dc07 | ||
|
|
6bf820934f | ||
|
|
887dbc25f8 | ||
|
|
50de77d613 | ||
|
|
13561ee21a | ||
|
|
333feaa6bf | ||
|
|
1e37fd15eb | ||
|
|
f82b0212b5 | ||
|
|
32138f5546 | ||
|
|
85ddce14a5 | ||
|
|
7e44772f2e | ||
|
|
e90bfe9b68 | ||
|
|
64002e1ae0 | ||
|
|
873dfaa305 | ||
|
|
7050356bce | ||
|
|
88c9bb0254 | ||
|
|
45f1dd2da9 | ||
|
|
46bcc2313f | ||
|
|
9e012c1490 | ||
|
|
50f9c0faa1 | ||
|
|
74829a09c0 |
6
.babelrc
6
.babelrc
@@ -7,6 +7,8 @@
|
|||||||
"@babel/plugin-syntax-dynamic-import",
|
"@babel/plugin-syntax-dynamic-import",
|
||||||
"@babel/plugin-syntax-import-meta",
|
"@babel/plugin-syntax-import-meta",
|
||||||
["@babel/plugin-proposal-class-properties", { "loose": true }],
|
["@babel/plugin-proposal-class-properties", { "loose": true }],
|
||||||
|
"@babel/plugin-proposal-do-expressions",
|
||||||
|
"@babel/plugin-proposal-function-bind",
|
||||||
"@babel/plugin-proposal-json-strings",
|
"@babel/plugin-proposal-json-strings",
|
||||||
[
|
[
|
||||||
"@babel/plugin-proposal-decorators",
|
"@babel/plugin-proposal-decorators",
|
||||||
@@ -28,7 +30,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"@babel/plugin-proposal-nullish-coalescing-operator",
|
"@babel/plugin-proposal-nullish-coalescing-operator",
|
||||||
"@babel/plugin-proposal-do-expressions",
|
["@babel/plugin-proposal-private-methods", { "loose": true }],
|
||||||
"@babel/plugin-proposal-function-bind"
|
["@babel/plugin-proposal-private-property-in-object", { "loose": true }]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
7
.dockerignore
Normal file
7
.dockerignore
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Dockerfile
|
||||||
|
.dockerignore
|
||||||
|
.gitignore
|
||||||
|
README.md
|
||||||
|
|
||||||
|
build
|
||||||
|
node_modules
|
||||||
14
.gitattributes
vendored
Normal file
14
.gitattributes
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Set the default behavior, in case people don't have core.autocrlf set, in order to prevent line ending inconsistency.
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
# Explicitly declare text files you want to always be normalized and converted
|
||||||
|
# to native line endings on checkout.
|
||||||
|
*.jsx text
|
||||||
|
*.js text
|
||||||
|
|
||||||
|
# Declare files that will always have CRLF line endings on checkout.
|
||||||
|
# *.sln text eol=crlf
|
||||||
|
|
||||||
|
# Denote all files that are truly binary and should not be modified.
|
||||||
|
*.png binary
|
||||||
|
*.jpg binary
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -10,4 +10,3 @@ env
|
|||||||
.project
|
.project
|
||||||
.vscode/
|
.vscode/
|
||||||
docs/
|
docs/
|
||||||
package-lock.json
|
|
||||||
|
|||||||
25
Dockerfile
Normal file
25
Dockerfile
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#syntax=docker/dockerfile:1.4
|
||||||
|
# Run this from within this directory. Change the location of coriolis-data repo and image name/tag as needed.
|
||||||
|
# docker buildx build --build-context data=../coriolis-data --tag coriolis .
|
||||||
|
|
||||||
|
FROM node:18-alpine
|
||||||
|
|
||||||
|
# TODO: For a production build, we may want to just build the bundle and copy that in. No need for local copy of source.
|
||||||
|
WORKDIR /app
|
||||||
|
ADD . .
|
||||||
|
COPY --from=data . /coriolis-data/
|
||||||
|
|
||||||
|
# Git is required before install if any modules (like coriolis-data) are loaded from github
|
||||||
|
RUN apk update
|
||||||
|
RUN apk add git
|
||||||
|
|
||||||
|
WORKDIR /app/coriolis-data
|
||||||
|
RUN npm install
|
||||||
|
WORKDIR /app
|
||||||
|
RUN npm install
|
||||||
|
# Bundle for production config with webpack & log
|
||||||
|
RUN npm run build > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2)
|
||||||
|
|
||||||
|
# Optimally, this will start a static asset server like nginx/apache. Currently, this will start dev webpack server.
|
||||||
|
CMD ["npm", "start"]
|
||||||
|
EXPOSE 3300
|
||||||
23
Dockerfile-dev
Normal file
23
Dockerfile-dev
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#syntax=docker/dockerfile:1.4
|
||||||
|
# Run this from within this directory. Change the location of coriolis-data repo and image name/tag as needed.
|
||||||
|
# docker buildx build --build-context data=../coriolis-data --tag coriolis -f ./Dockerfile-dev .
|
||||||
|
|
||||||
|
FROM node:18-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
ADD . .
|
||||||
|
COPY --from=data . /coriolis-data/
|
||||||
|
|
||||||
|
# Install git & any other desired in-container dev tools
|
||||||
|
# Git is required before install if any modules (like coriolis-data) are loaded from github
|
||||||
|
RUN apk update
|
||||||
|
RUN apk add git
|
||||||
|
|
||||||
|
WORKDIR /app/coriolis-data
|
||||||
|
RUN npm install
|
||||||
|
WORKDIR /app
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
|
||||||
|
CMD ["npm", "start"]
|
||||||
|
EXPOSE 3300
|
||||||
32
Dockerfile-local-prod
Normal file
32
Dockerfile-local-prod
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#syntax=docker/dockerfile:1.4
|
||||||
|
# Run this from within this directory. Change the location of coriolis-data repo and image name/tag as needed.
|
||||||
|
# docker buildx build --build-context data=../coriolis-data --tag coriolis:0.0.7-local-prod -f Dockerfile-local-prod .
|
||||||
|
# docker run -d -p 80:8080 coriolis:0.0.7-local-prod
|
||||||
|
|
||||||
|
FROM node:18-alpine
|
||||||
|
|
||||||
|
# TODO: For a production build, we may want to just build the bundle and copy that in. No need for local copy of source.
|
||||||
|
WORKDIR /app
|
||||||
|
ADD . .
|
||||||
|
# COPY --from=data . /coriolis-data/
|
||||||
|
|
||||||
|
# Git is required before install if any modules (like coriolis-data is now referenced in the package.json) are loaded from github
|
||||||
|
RUN apk update
|
||||||
|
RUN apk add git
|
||||||
|
|
||||||
|
# WORKDIR /app/coriolis-data
|
||||||
|
# RUN npm install
|
||||||
|
# WORKDIR /app
|
||||||
|
# RUN npm install
|
||||||
|
# Bundle for production config with webpack & log
|
||||||
|
# In this version of the dockerfile, I'm deferring automated webpack build so I can monitor a manual build
|
||||||
|
# RUN npm run build > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2)
|
||||||
|
|
||||||
|
RUN npm install -g http-server
|
||||||
|
|
||||||
|
# Optimally, this will start a static asset server like nginx/apache. Currently, this will start dev webpack server.
|
||||||
|
# CMD ["http-server", "/app/build", "-c-1"]
|
||||||
|
CMD ["/bin/ash"]
|
||||||
|
# CMD [""]
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
15
README.md
15
README.md
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## About
|
## About
|
||||||
|
|
||||||
The Coriolis project was inspired by [E:D Shipyard](http://www.edshipyard.com/) and, of course, [Elite Dangerous](http://www.elitedangerous.com). The ultimate goal of Coriolis is to provide rich features to support in-game play and planning while engaging the E:D community to support its development.
|
The Coriolis project was inspired by E:D Shipyard and, of course, [Elite Dangerous](http://www.elitedangerous.com). The ultimate goal of Coriolis is to provide rich features to support in-game play and planning while engaging the E:D community to support its development.
|
||||||
|
|
||||||
Coriolis was created using assets and imagery from Elite: Dangerous, with the permission of Frontier Developments plc, for non-commercial purposes. It is not endorsed by nor reflects the views or opinions of Frontier Developments and no employee of Frontier Developments was involved in the making of it.
|
Coriolis was created using assets and imagery from Elite: Dangerous, with the permission of Frontier Developments plc, for non-commercial purposes. It is not endorsed by nor reflects the views or opinions of Frontier Developments and no employee of Frontier Developments was involved in the making of it.
|
||||||
|
|
||||||
@@ -14,7 +14,16 @@ Coriolis was created using assets and imagery from Elite: Dangerous, with the pe
|
|||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
To get a local instance of coriolis running, perform the following steps in a shell:
|
This release includes the ability to run the app as a Docker container.
|
||||||
|
```sh
|
||||||
|
> git clone https://github.com/EDCD/coriolis.git
|
||||||
|
> git clone https://github.com/EDCD/coriolis-data.git
|
||||||
|
> cd coriolis
|
||||||
|
> docker buildx build --build-context data=../coriolis-data --tag coriolis .
|
||||||
|
> docker run -d -p 3300:3300 coriolis
|
||||||
|
```
|
||||||
|
|
||||||
|
Or to run an instance of coriolis without Docker Desktop, perform the following steps in a shell:
|
||||||
```sh
|
```sh
|
||||||
> git clone https://github.com/EDCD/coriolis.git
|
> git clone https://github.com/EDCD/coriolis.git
|
||||||
> git clone https://github.com/EDCD/coriolis-data.git
|
> git clone https://github.com/EDCD/coriolis-data.git
|
||||||
@@ -29,7 +38,7 @@ You will then have a development server running on `localhost:3300`.
|
|||||||
|
|
||||||
### Ship and Module Database
|
### Ship and Module Database
|
||||||
|
|
||||||
See the [Data wiki](https://github.com/cmmcleod/coriolis-data/wiki) for details on structure, etc.
|
See the [Data wiki](https://github.com/EDCD/coriolis-data/wiki) for details on structure, etc.
|
||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
|
|||||||
11
devServer.js
11
devServer.js
@@ -3,24 +3,13 @@ var WebpackDevServer = require("webpack-dev-server");
|
|||||||
var config = require('./webpack.config.dev');
|
var config = require('./webpack.config.dev');
|
||||||
|
|
||||||
new WebpackDevServer(webpack(config), {
|
new WebpackDevServer(webpack(config), {
|
||||||
publicPath: config.output.publicPath,
|
|
||||||
hot: true,
|
hot: true,
|
||||||
disableHostCheck: true,
|
|
||||||
headers: { "Access-Control-Allow-Origin": "*" },
|
headers: { "Access-Control-Allow-Origin": "*" },
|
||||||
historyApiFallback: {
|
historyApiFallback: {
|
||||||
rewrites: [
|
rewrites: [
|
||||||
// For some reason connect-history-api-fallback does not allow '.' in the URL for history fallback...
|
// For some reason connect-history-api-fallback does not allow '.' in the URL for history fallback...
|
||||||
{ from: /\/outfit\//, to: '/index.html' }
|
{ from: /\/outfit\//, to: '/index.html' }
|
||||||
]
|
]
|
||||||
},
|
|
||||||
stats: {
|
|
||||||
assets: true,
|
|
||||||
colors: true,
|
|
||||||
version: false,
|
|
||||||
hash: false,
|
|
||||||
timings: true,
|
|
||||||
chunks: false,
|
|
||||||
chunkModules: false
|
|
||||||
}
|
}
|
||||||
}).listen(3300, "0.0.0.0", function (err, result) {
|
}).listen(3300, "0.0.0.0", function (err, result) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|||||||
12992
package-lock.json
generated
Normal file
12992
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
95
package.json
95
package.json
@@ -1,14 +1,19 @@
|
|||||||
{
|
{
|
||||||
"name": "coriolis_shipyard",
|
"name": "coriolis_shipyard",
|
||||||
"version": "3.0.0",
|
"version": "3.0.1",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/EDCD/coriolis"
|
"url": "https://github.com/EDCD/coriolis"
|
||||||
},
|
},
|
||||||
"homepage": "https://coriolis.io",
|
"homepage": "https://coriolis.io",
|
||||||
"bugs": "https://github.com/EDCD/coriolis/issues",
|
"bugs": "https://github.com/EDCD/coriolis/issues",
|
||||||
|
"contributors": [
|
||||||
|
{ "name": "cmdrmcdonald" },
|
||||||
|
{ "name": "willb321" },
|
||||||
|
{ "name": "felixlinker" }
|
||||||
|
],
|
||||||
"private": true,
|
"private": true,
|
||||||
"engine": "node >= 4.8.1",
|
"engine": "node >= 10.13.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"extract-translations": "grep -hroE \"(translate\\('[^']+'\\))|(tip.bind\\(null, '[^']+')\" src/* | grep -oE \"'[^']+'\" | grep -oE \"[^']+\" | sort -u -f",
|
"extract-translations": "grep -hroE \"(translate\\('[^']+'\\))|(tip.bind\\(null, '[^']+')\" src/* | grep -oE \"'[^']+'\" | grep -oE \"[^']+\" | sort -u -f",
|
||||||
@@ -18,7 +23,8 @@
|
|||||||
"test": "jest",
|
"test": "jest",
|
||||||
"prod-serve": "nginx -p $(pwd) -c nginx.conf",
|
"prod-serve": "nginx -p $(pwd) -c nginx.conf",
|
||||||
"prod-stop": "kill -QUIT $(cat nginx.pid)",
|
"prod-stop": "kill -QUIT $(cat nginx.pid)",
|
||||||
"build": "npm run clean && cross-env NODE_ENV=production webpack -p --config webpack.config.prod.js",
|
"buildfresh": "rimraf node_modules && rm package-lock.json && npm install && npm run build > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2)",
|
||||||
|
"build": "npm run clean && cross-env NODE_ENV=production webpack --config webpack.config.prod.js",
|
||||||
"rsync": "rsync -ae \"ssh -i $CORIOLIS_PEM\" --delete build/ $CORIOLIS_USER@$CORIOLIS_HOST:~/wwws",
|
"rsync": "rsync -ae \"ssh -i $CORIOLIS_PEM\" --delete build/ $CORIOLIS_USER@$CORIOLIS_HOST:~/wwws",
|
||||||
"deploy": "npm run lint && npm test && npm run build && npm run rsync"
|
"deploy": "npm run lint && npm test && npm run build && npm run rsync"
|
||||||
},
|
},
|
||||||
@@ -55,7 +61,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.0.0",
|
"@babel/core": "^7.20.12",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.0.0",
|
"@babel/plugin-proposal-class-properties": "^7.0.0",
|
||||||
"@babel/plugin-proposal-decorators": "^7.0.0",
|
"@babel/plugin-proposal-decorators": "^7.0.0",
|
||||||
"@babel/plugin-proposal-do-expressions": "^7.0.0",
|
"@babel/plugin-proposal-do-expressions": "^7.0.0",
|
||||||
@@ -74,15 +80,12 @@
|
|||||||
"@babel/plugin-syntax-import-meta": "^7.0.0",
|
"@babel/plugin-syntax-import-meta": "^7.0.0",
|
||||||
"@babel/preset-env": "^7.0.0",
|
"@babel/preset-env": "^7.0.0",
|
||||||
"@babel/preset-react": "^7.0.0",
|
"@babel/preset-react": "^7.0.0",
|
||||||
"appcache-webpack-plugin": "^1.4.0",
|
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||||
"babel-core": "^7.0.0-bridge.0",
|
|
||||||
"babel-eslint": "^10.0.1",
|
|
||||||
"babel-jest": "^23.6.0",
|
|
||||||
"babel-loader": "^8.0.0",
|
"babel-loader": "^8.0.0",
|
||||||
"copy-webpack-plugin": "^4.5.2",
|
"copy-webpack-plugin": "^10.2.4",
|
||||||
"create-react-class": "^15.6.3",
|
"create-react-class": "^15.6.3",
|
||||||
"cross-env": "^5.2.0",
|
"cross-env": "^5.2.0",
|
||||||
"css-loader": "^1.0.0",
|
"css-loader": "^6.7.3",
|
||||||
"d3-selection": "^1.3.2",
|
"d3-selection": "^1.3.2",
|
||||||
"esdoc": "^1.1.0",
|
"esdoc": "^1.1.0",
|
||||||
"esdoc-custom-theme": "^1.4.2",
|
"esdoc-custom-theme": "^1.4.2",
|
||||||
@@ -93,54 +96,66 @@
|
|||||||
"esdoc-standard-plugin": "^1.0.0",
|
"esdoc-standard-plugin": "^1.0.0",
|
||||||
"eslint": "^5.6.0",
|
"eslint": "^5.6.0",
|
||||||
"eslint-plugin-react": "^7.11.1",
|
"eslint-plugin-react": "^7.11.1",
|
||||||
"expose-loader": "^0.7.5",
|
"expose-loader": "^3.1.0",
|
||||||
"express": "^4.16.3",
|
"express": "^4.18.2",
|
||||||
"extract-text-webpack-plugin": "^4.0.0-beta.0",
|
"html-webpack-plugin": "^5.5.0",
|
||||||
"file-loader": "^2.0.0",
|
"jsen": "^0.6.6",
|
||||||
"html-webpack-plugin": "^3.0.7",
|
|
||||||
"jest-cli": "^23.6.0",
|
|
||||||
"jsen": "^0.6.4",
|
|
||||||
"json-loader": "^0.5.4",
|
"json-loader": "^0.5.4",
|
||||||
"less": "^3.8.1",
|
"less": "^3.8.1",
|
||||||
"less-loader": "^4.1.0",
|
"less-loader": "^11.1.0",
|
||||||
"react-addons-perf": "^15.4.2",
|
"mini-css-extract-plugin": "^2.7.2",
|
||||||
"react-container-dimensions": "^1.4.1",
|
"react-container-dimensions": "^1.4.1",
|
||||||
"react-testutils-additions": "^16.0.0",
|
"react-testutils-additions": "^15.0.0",
|
||||||
"react-transition-group": "^2.5.0",
|
"react-transition-group": "^2.5.0",
|
||||||
"rimraf": "^2.6.1",
|
"rimraf": "^4.1.2",
|
||||||
"rollup": "^0.66.2",
|
"rollup": "^3.17.2",
|
||||||
"rollup-plugin-node-resolve": "^3.4.0",
|
"style-loader": "^3.3.1",
|
||||||
"style-loader": "^0.23.0",
|
"uglify-js": "^3.17.4",
|
||||||
"uglify-js": "^3.4.9",
|
"webpack": "^5.75.0",
|
||||||
"url-loader": "^1.1.1",
|
"webpack-cli": "^5.0.1",
|
||||||
"webpack": "^4.20.2",
|
"webpack-dev-server": "^4.11.1",
|
||||||
"webpack-bugsnag-plugins": "^1.2.2",
|
"webpack-merge": "^5.8.0",
|
||||||
"webpack-cli": "^3.1.1",
|
"webpack-notifier": "^1.15.0",
|
||||||
"webpack-dev-server": "^3.1.9",
|
"workbox-cacheable-response": "^6.5.4",
|
||||||
"webpack-notifier": "^1.6.0",
|
"workbox-expiration": "^6.5.4",
|
||||||
"workbox-webpack-plugin": "^3.6.1"
|
"workbox-precaching": "^6.5.4",
|
||||||
|
"workbox-routing": "^6.5.4",
|
||||||
|
"workbox-strategies": "^6.5.4",
|
||||||
|
"workbox-webpack-plugin": "^6.5.4"
|
||||||
},
|
},
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/polyfill": "^7.0.0",
|
"assert": "^1.5.0",
|
||||||
|
"auto-bind": "^5.0.1",
|
||||||
|
"base64url": "^3.0.1",
|
||||||
"browserify-zlib-next": "^1.0.1",
|
"browserify-zlib-next": "^1.0.1",
|
||||||
|
"buffer": "^5.7.0",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
|
"constants-browserify": "^1.0.0",
|
||||||
|
"core-js": "^3.28.0",
|
||||||
"coriolis-data": "../coriolis-data",
|
"coriolis-data": "../coriolis-data",
|
||||||
|
"crypto-browserify": "^3.12.0",
|
||||||
"d3": "^5.7.0",
|
"d3": "^5.7.0",
|
||||||
"detect-browser": "^3.0.1",
|
"detect-browser": "^3.0.1",
|
||||||
"fbemitter": "^2.1.1",
|
"fbemitter": "^2.1.1",
|
||||||
|
"https-browserify": "^1.0.0",
|
||||||
"lodash": "^4.17.11",
|
"lodash": "^4.17.11",
|
||||||
"lz-string": "^1.4.4",
|
"lz-string": "^1.4.4",
|
||||||
"pako": "^1.0.6",
|
"os-browserify": "^0.3.0",
|
||||||
|
"pako": "^2.1.0",
|
||||||
|
"path-browserify": "^1.0.1",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"react": "^15.5.4",
|
"react": "^15.6.2",
|
||||||
"react-dom": "^15.5.4",
|
"react-dom": "^15.6.2",
|
||||||
"react-extras": "^0.7.1",
|
|
||||||
"react-fuzzy": "^0.5.2",
|
"react-fuzzy": "^0.5.2",
|
||||||
"react-ga": "^2.5.3",
|
"react-ga": "^2.5.3",
|
||||||
"react-number-editor": "Athanasius/react-number-editor.git#miggy",
|
"react-number-editor": "^4.0.3",
|
||||||
"recharts": "^1.2.0",
|
"recharts": "^1.2.0",
|
||||||
"register-service-worker": "^1.5.2",
|
"register-service-worker": "^1.7.2",
|
||||||
"superagent": "^3.8.3"
|
"stream-browserify": "^3.0.0",
|
||||||
|
"stream-http": "^3.2.0",
|
||||||
|
"superagent": "^3.8.3",
|
||||||
|
"url": "^0.11.0",
|
||||||
|
"vm-browserify": "^1.1.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import nodeResolve from "rollup-plugin-node-resolve";
|
import nodeResolve from "@rollup/plugin-node-resolve";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
entry: "d3-funcs.js",
|
entry: "d3-funcs.js",
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ Options -MultiViews
|
|||||||
# </Files>
|
# </Files>
|
||||||
|
|
||||||
AddType application/x-web-app-manifest+json webapp
|
AddType application/x-web-app-manifest+json webapp
|
||||||
AddType text/cache-manifest appcache manifest
|
# AddType text/cache-manifest appcache manifest
|
||||||
|
|
||||||
# Media files
|
# Media files
|
||||||
AddType audio/mp4 f4a f4b m4a
|
AddType audio/mp4 f4a f4b m4a
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ export default class Coriolis extends React.Component {
|
|||||||
this.state = {
|
this.state = {
|
||||||
noTouch: !('ontouchstart' in window || navigator.msMaxTouchPoints || navigator.maxTouchPoints),
|
noTouch: !('ontouchstart' in window || navigator.msMaxTouchPoints || navigator.maxTouchPoints),
|
||||||
page: null,
|
page: null,
|
||||||
announcements: [],
|
// Announcements must have an expiry date in format "YYYY-MM-DDTHH:MM:SSZ"
|
||||||
|
announcements: [{expiry: "2025-04-10T00:00:00Z", text: "Corsair added"}],
|
||||||
language: getLanguage(Persist.getLangCode()),
|
language: getLanguage(Persist.getLangCode()),
|
||||||
route: {},
|
route: {},
|
||||||
sizeRatio: Persist.getSizeRatio()
|
sizeRatio: Persist.getSizeRatio()
|
||||||
@@ -93,7 +94,7 @@ export default class Coriolis extends React.Component {
|
|||||||
_importBuild(r) {
|
_importBuild(r) {
|
||||||
try {
|
try {
|
||||||
// Need to decode and gunzip the data, then build the ship
|
// Need to decode and gunzip the data, then build the ship
|
||||||
const data = zlib.inflate(new Buffer(r.params.data, 'base64'), { to: 'string' });
|
const data = zlib.inflate(new Buffer.from(r.params.data, 'base64'), { to: 'string' });
|
||||||
const json = JSON.parse(data);
|
const json = JSON.parse(data);
|
||||||
console.info('Ship import data: ');
|
console.info('Ship import data: ');
|
||||||
console.info(json);
|
console.info(json);
|
||||||
@@ -122,7 +123,15 @@ export default class Coriolis extends React.Component {
|
|||||||
this._showModal(<ModalImport importString={data}/>);
|
this._showModal(<ModalImport importString={data}/>);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this._onError('Failed to import ship', r.path, 0, 0, err);
|
const fullUrl = window.location.href;
|
||||||
|
|
||||||
|
if (fullUrl.length >= 2083) {
|
||||||
|
err = 'URL Length = ' + fullUrl.length;
|
||||||
|
this._onError('Failed to import ship - Potential URL Length issue', r.path, 0, 0, err);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this._onError('Failed to import ship - Unknown Reason', r.path, 0, 0, err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,13 +158,6 @@ export default class Coriolis extends React.Component {
|
|||||||
*/
|
*/
|
||||||
_onError(msg, scriptUrl, line, col, errObj) {
|
_onError(msg, scriptUrl, line, col, errObj) {
|
||||||
console && console.error && console.error(arguments); // eslint-disable-line no-console
|
console && console.error && console.error(arguments); // eslint-disable-line no-console
|
||||||
if (errObj) {
|
|
||||||
if (errObj instanceof Error) {
|
|
||||||
bugsnagClient.notify(errObj); // eslint-disable-line
|
|
||||||
} else if (errObj instanceof String) {
|
|
||||||
bugsnagClient.notify(msg, errObj); // eslint-disable-line
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.setState({
|
this.setState({
|
||||||
error: <ErrorDetails error={{ message: msg, details: { scriptUrl, line, col, error: JSON.stringify(errObj) } }}/>,
|
error: <ErrorDetails error={{ message: msg, details: { scriptUrl, line, col, error: JSON.stringify(errObj) } }}/>,
|
||||||
page: null,
|
page: null,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { autoBind } from 'react-extras';
|
import autoBind from 'auto-bind';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Announcement component
|
* Announcement component
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import * as ModuleUtils from '../shipyard/ModuleUtils';
|
|||||||
import TranslatedComponent from './TranslatedComponent';
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
import { stopCtxPropagation } from '../utils/UtilityFunctions';
|
import { stopCtxPropagation } from '../utils/UtilityFunctions';
|
||||||
import cn from 'classnames';
|
import cn from 'classnames';
|
||||||
import { MountFixed, MountGimballed, MountTurret } from './SvgIcons';
|
import { CoriolisLogo, MountFixed, MountGimballed, MountTurret } from './SvgIcons';
|
||||||
import FuzzySearch from 'react-fuzzy';
|
import FuzzySearch from 'react-fuzzy';
|
||||||
|
|
||||||
const PRESS_THRESHOLD = 500; // mouse/touch down threshold
|
const PRESS_THRESHOLD = 500; // mouse/touch down threshold
|
||||||
@@ -20,6 +20,7 @@ const GRPCAT = {
|
|||||||
'cc': 'limpet controllers',
|
'cc': 'limpet controllers',
|
||||||
'fx': 'limpet controllers',
|
'fx': 'limpet controllers',
|
||||||
'hb': 'limpet controllers',
|
'hb': 'limpet controllers',
|
||||||
|
'mlc': 'limpet controllers',
|
||||||
'pc': 'limpet controllers',
|
'pc': 'limpet controllers',
|
||||||
'rpl': 'limpet controllers',
|
'rpl': 'limpet controllers',
|
||||||
'pce': 'passenger cabins',
|
'pce': 'passenger cabins',
|
||||||
@@ -38,13 +39,18 @@ const GRPCAT = {
|
|||||||
'ml': 'lasers',
|
'ml': 'lasers',
|
||||||
'c': 'projectiles',
|
'c': 'projectiles',
|
||||||
'mc': 'projectiles',
|
'mc': 'projectiles',
|
||||||
|
'advmc': 'projectiles',
|
||||||
'axmc': 'experimental',
|
'axmc': 'experimental',
|
||||||
|
'axmce': 'experimental',
|
||||||
|
'ntp': 'experimental',
|
||||||
'fc': 'projectiles',
|
'fc': 'projectiles',
|
||||||
'rfl': 'experimental',
|
'rfl': 'experimental',
|
||||||
'pa': 'projectiles',
|
'pa': 'projectiles',
|
||||||
'rg': 'projectiles',
|
'rg': 'projectiles',
|
||||||
'mr': 'ordnance',
|
'mr': 'ordnance',
|
||||||
|
'amr': 'ordnance',
|
||||||
'axmr': 'experimental',
|
'axmr': 'experimental',
|
||||||
|
'axmre': 'experimental',
|
||||||
'rcpl': 'experimental',
|
'rcpl': 'experimental',
|
||||||
'dtl': 'experimental',
|
'dtl': 'experimental',
|
||||||
'tbsc': 'experimental',
|
'tbsc': 'experimental',
|
||||||
@@ -83,6 +89,8 @@ const GRPCAT = {
|
|||||||
// Assists
|
// Assists
|
||||||
'dc': 'flight assists',
|
'dc': 'flight assists',
|
||||||
'sua': 'flight assists',
|
'sua': 'flight assists',
|
||||||
|
// Stabilizers
|
||||||
|
'ews': 'weapon stabilizers',
|
||||||
};
|
};
|
||||||
// Order here is the order in which items will be shown in the modules menu
|
// Order here is the order in which items will be shown in the modules menu
|
||||||
const CATEGORIES = {
|
const CATEGORIES = {
|
||||||
@@ -92,7 +100,7 @@ const CATEGORIES = {
|
|||||||
'fi': ['fi'],
|
'fi': ['fi'],
|
||||||
'fuel': ['ft', 'fs'],
|
'fuel': ['ft', 'fs'],
|
||||||
'hangars': ['fh', 'pv'],
|
'hangars': ['fh', 'pv'],
|
||||||
'limpet controllers': ['cc', 'fx', 'hb', 'pc', 'rpl'],
|
'limpet controllers': ['cc', 'fx', 'hb', 'pc', 'rpl', 'mlc'],
|
||||||
'passenger cabins': ['pce', 'pci', 'pcm', 'pcq'],
|
'passenger cabins': ['pce', 'pci', 'pcm', 'pcq'],
|
||||||
'rf': ['rf'],
|
'rf': ['rf'],
|
||||||
'shields': ['sg', 'bsg', 'psg', 'scb'],
|
'shields': ['sg', 'bsg', 'psg', 'scb'],
|
||||||
@@ -101,16 +109,17 @@ const CATEGORIES = {
|
|||||||
|
|
||||||
// Hardpoints
|
// Hardpoints
|
||||||
'lasers': ['pl', 'ul', 'bl'],
|
'lasers': ['pl', 'ul', 'bl'],
|
||||||
'projectiles': ['mc', 'c', 'fc', 'pa', 'rg'],
|
'projectiles': ['mc', 'advmc', 'c', 'fc', 'pa', 'rg'],
|
||||||
'ordnance': ['mr', 'tp', 'nl'],
|
'ordnance': ['mr', 'amr', 'tp', 'nl'],
|
||||||
// Utilities
|
// Utilities
|
||||||
'sb': ['sb'],
|
'sb': ['sb'],
|
||||||
'hs': ['hs'],
|
'hs': ['hs'],
|
||||||
|
'csl': ['csl'],
|
||||||
'defence': ['ch', 'po', 'ec'],
|
'defence': ['ch', 'po', 'ec'],
|
||||||
'scanners': ['sc', 'ss', 'cs', 'kw', 'ws'], // Overloaded with internal scanners
|
'scanners': ['sc', 'ss', 'cs', 'kw', 'ws'], // Overloaded with internal scanners
|
||||||
// Experimental
|
// Experimental
|
||||||
'experimental': ['axmc', 'axmr', 'rfl', 'tbrfl', 'tbsc', 'tbem', 'xs', 'sfn', 'rcpl', 'dtl', 'rsl', 'mahr',],
|
'experimental': ['axmc', 'axmce', 'axmr', 'axmre', 'ntp','rfl', 'tbrfl', 'tbsc', 'tbem', 'xs', 'sfn', 'rcpl', 'dtl', 'rsl', 'mahr',],
|
||||||
|
'weapon stabilizers': ['ews'],
|
||||||
// Guardian
|
// Guardian
|
||||||
'guardian': ['gpp', 'gpd', 'gpc', 'ggc', 'gsrp', 'gfsb', 'ghrp', 'gmrp', 'gsc'],
|
'guardian': ['gpp', 'gpd', 'gpc', 'ggc', 'gsrp', 'gfsb', 'ghrp', 'gmrp', 'gsc'],
|
||||||
|
|
||||||
@@ -209,16 +218,30 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
if (categories.length === 1) {
|
if (categories.length === 1) {
|
||||||
// Show category header instead of group header
|
// Show category header instead of group header
|
||||||
if (m && grp == m.grp) {
|
if (m && grp == m.grp) {
|
||||||
list.push(<div ref={(elem) => this.groupElem = elem} key={category}
|
// If this is a missing module/weapon, skip it
|
||||||
|
if (m.grp == "mh" || m.grp == "mm"){
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
list.push(<div ref={(elem) => this.groupElem = elem} key={category}
|
||||||
className={'select-category upp'}>{translate(category)}</div>);
|
className={'select-category upp'}>{translate(category)}</div>);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
list.push(<div key={category} className={'select-category upp'}>{translate(category)}</div>);
|
if (category == "mh" || category == "mm"){
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
list.push(<div key={category} className={'select-category upp'}>{translate(category)}</div>);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Show category header as well as group header
|
// Show category header as well as group header
|
||||||
if (!categoryHeader) {
|
if (!categoryHeader) {
|
||||||
list.push(<div key={category} className={'select-category upp'}>{translate(category)}</div>);
|
if (category == "mh" || category == "mm"){
|
||||||
categoryHeader = true;
|
continue;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
list.push(<div key={category} className={'select-category upp'}>{translate(category)}</div>);
|
||||||
|
categoryHeader = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (m && grp == m.grp) {
|
if (m && grp == m.grp) {
|
||||||
list.push(<div ref={(elem) => this.groupElem = elem} key={grp}
|
list.push(<div ref={(elem) => this.groupElem = elem} key={grp}
|
||||||
@@ -237,7 +260,11 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
} else if (i.mount === 'T') {
|
} else if (i.mount === 'T') {
|
||||||
mount = 'Turreted';
|
mount = 'Turreted';
|
||||||
}
|
}
|
||||||
const fuzz = { grp, m: i, name: `${i.class}${i.rating}${mount ? ' ' + mount : ''} ${translate(grp)}` };
|
let special = '';
|
||||||
|
if (typeof(i.special) !== 'undefined') {
|
||||||
|
special = `(${translate(i.special)})`;
|
||||||
|
}
|
||||||
|
const fuzz = { grp, m: i, name: `${i.class}${i.rating}${mount ? ' ' + mount : ''} ${translate(grp)} ${translate(special)}` };
|
||||||
fuzzy.push(fuzz);
|
fuzzy.push(fuzz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -249,6 +276,24 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
return { list, currentGroup, fuzzy, trackingFocus };
|
return { list, currentGroup, fuzzy, trackingFocus };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return Is expiremental capacity reached
|
||||||
|
* @return {boolean} Is experimental capacity reached
|
||||||
|
*/
|
||||||
|
_experimentalCapacityReached() {
|
||||||
|
const ship = this.props.ship;
|
||||||
|
const ews = ship.internal.filter(o => o.m && o.m.grp === 'ews');
|
||||||
|
let expCap;
|
||||||
|
|
||||||
|
if(ews.length < 1){
|
||||||
|
expCap = 4;
|
||||||
|
} else{
|
||||||
|
expCap = ews[0].m.class == 3 ? 5 : 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
return expCap <= this.props.ship.hardpoints.filter(o => o.m && o.m.experimental).length;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate React Components for Module Group
|
* Generate React Components for Module Group
|
||||||
* @param {Ship} ship Ship the selection is for
|
* @param {Ship} ship Ship the selection is for
|
||||||
@@ -276,6 +321,11 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
let itemsOnThisRow = 0;
|
let itemsOnThisRow = 0;
|
||||||
for (let i = 0; i < sortedModules.length; i++) {
|
for (let i = 0; i < sortedModules.length; i++) {
|
||||||
let m = sortedModules[i];
|
let m = sortedModules[i];
|
||||||
|
// If m.grp is mh or mm, or m.symbol contains 'Missing' skip it
|
||||||
|
if (m.grp == 'mh' || m.grp == 'mm' || (typeof(m.symbol) !== 'undefined' && m.symbol.includes("Missing"))) {
|
||||||
|
// If this is a missing module, skip it
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let mount = null;
|
let mount = null;
|
||||||
let disabled = false;
|
let disabled = false;
|
||||||
prevName = m.name;
|
prevName = m.name;
|
||||||
@@ -285,7 +335,9 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
// If the mounted module is experimental as well, we can replace it so
|
// If the mounted module is experimental as well, we can replace it so
|
||||||
// the maximum does not apply
|
// the maximum does not apply
|
||||||
} else if (m.experimental && (!mountedModule || !mountedModule.experimental)) {
|
} else if (m.experimental && (!mountedModule || !mountedModule.experimental)) {
|
||||||
disabled = 4 <= ship.hardpoints.filter(o => o.m && o.m.experimental).length;
|
disabled = this._experimentalCapacityReached();
|
||||||
|
} else if (m.grp === 'mlc' && (!mountedModule || mountedModule.grp !== 'mlc')) {
|
||||||
|
disabled = 1 <= ship.internal.filter(o => o.m && o.m.grp === 'mlc').length;
|
||||||
}
|
}
|
||||||
let active = mountedModule && mountedModule.id === m.id;
|
let active = mountedModule && mountedModule.id === m.id;
|
||||||
let classes = cn(m.name ? 'lc' : 'c', {
|
let classes = cn(m.name ? 'lc' : 'c', {
|
||||||
@@ -382,6 +434,7 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
if (this.props.modules instanceof Array) {
|
if (this.props.modules instanceof Array) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const mountedModule = this.props.m;
|
||||||
return (
|
return (
|
||||||
<FuzzySearch
|
<FuzzySearch
|
||||||
list={this.state.fuzzy}
|
list={this.state.fuzzy}
|
||||||
@@ -393,11 +446,20 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
onSelect={e => this.props.onSelect.bind(null, e.m)()}
|
onSelect={e => this.props.onSelect.bind(null, e.m)()}
|
||||||
resultsTemplate={(props, state, styles, clickHandler) => {
|
resultsTemplate={(props, state, styles, clickHandler) => {
|
||||||
return state.results.map((val, i) => {
|
return state.results.map((val, i) => {
|
||||||
|
let disabled;
|
||||||
|
|
||||||
|
if(val.m.experimental && (!mountedModule || !mountedModule.experimental)) {
|
||||||
|
disabled = this._experimentalCapacityReached();
|
||||||
|
} else{
|
||||||
|
disabled = false;
|
||||||
|
}
|
||||||
|
const handler = disabled ? null : () => clickHandler(i);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={i}
|
key={i}
|
||||||
className={'lc'}
|
className={cn('lc', {disabled})}
|
||||||
onClick={() => clickHandler(i)}
|
onClick={handler}
|
||||||
>
|
>
|
||||||
{val.name}
|
{val.name}
|
||||||
</div>
|
</div>
|
||||||
@@ -516,6 +578,15 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Sort multi limpet controllers by name
|
||||||
|
if (a.grp === 'mlc') {
|
||||||
|
if (a.name[0] <= b.name[0]) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (a.name[0] > b.name[0]) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
// Rating ordered from highest (A) to lowest (E)
|
// Rating ordered from highest (A) to lowest (E)
|
||||||
if (a.rating < b.rating) {
|
if (a.rating < b.rating) {
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export default class CostSection extends TranslatedComponent {
|
|||||||
this._buildRetrofitShip = this._buildRetrofitShip.bind(this);
|
this._buildRetrofitShip = this._buildRetrofitShip.bind(this);
|
||||||
this._onBaseRetrofitChange = this._onBaseRetrofitChange.bind(this);
|
this._onBaseRetrofitChange = this._onBaseRetrofitChange.bind(this);
|
||||||
this._defaultRetrofitName = this._defaultRetrofitName.bind(this);
|
this._defaultRetrofitName = this._defaultRetrofitName.bind(this);
|
||||||
this._eddbShoppingList = this._eddbShoppingList.bind(this);
|
this._eddbShoppingList = this._inaraShoppingList.bind(this);
|
||||||
|
|
||||||
let data = Ships[props.ship.id]; // Retrieve the basic ship properties, slots and defaults
|
let data = Ships[props.ship.id]; // Retrieve the basic ship properties, slots and defaults
|
||||||
let retrofitName = this._defaultRetrofitName(props.ship.id, props.buildName);
|
let retrofitName = this._defaultRetrofitName(props.ship.id, props.buildName);
|
||||||
@@ -328,9 +328,9 @@ export default class CostSection extends TranslatedComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open up a window for EDDB with a shopping list of our retrofit components
|
* Open up a window for inara with a shopping list of our retrofit components
|
||||||
*/
|
*/
|
||||||
_eddbShoppingList() {
|
_inaraShoppingList() {
|
||||||
const { retrofitCosts } = this.state;
|
const { retrofitCosts } = this.state;
|
||||||
const { ship } = this.props;
|
const { ship } = this.props;
|
||||||
|
|
||||||
@@ -338,7 +338,7 @@ export default class CostSection extends TranslatedComponent {
|
|||||||
const modIds = retrofitCosts.filter(item => item.retroItem.incCost && item.buyId && !item.buyPp).map(item => item.buyId).filter((v, i, a) => a.indexOf(v) === i);
|
const modIds = retrofitCosts.filter(item => item.retroItem.incCost && item.buyId && !item.buyPp).map(item => item.buyId).filter((v, i, a) => a.indexOf(v) === i);
|
||||||
|
|
||||||
// Open up the relevant URL
|
// Open up the relevant URL
|
||||||
window.open('https://eddb.io/station?m=' + modIds.join(','));
|
window.open('https://inara.cz/inapi/corisearch.php?m=' + modIds.join(','));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -387,7 +387,7 @@ export default class CostSection extends TranslatedComponent {
|
|||||||
<tbody>
|
<tbody>
|
||||||
{rows}
|
{rows}
|
||||||
<tr className='ri'>
|
<tr className='ri'>
|
||||||
<td className='lbl' ><button onClick={this._eddbShoppingList} onMouseOver={termtip.bind(null, 'PHRASE_REFIT_SHOPPING_LIST')} onMouseOut={tooltip.bind(null, null)}><ShoppingIcon className='lg' style={{ fill: 'black' }}/></button></td>
|
<td className='lbl' ><button onClick={this._inaraShoppingList} onMouseOver={termtip.bind(null, 'PHRASE_REFIT_SHOPPING_LIST')} onMouseOut={tooltip.bind(null, null)}><ShoppingIcon className='lg' style={{ fill: 'black' }}/></button></td>
|
||||||
<td colSpan='3' className='lbl' >{translate('cost')}</td>
|
<td colSpan='3' className='lbl' >{translate('cost')}</td>
|
||||||
<td colSpan='2' className={cn('val', retrofitTotal > 0 ? 'warning' : 'secondary-disabled')} style={{ borderBottom:'none' }}>
|
<td colSpan='2' className={cn('val', retrofitTotal > 0 ? 'warning' : 'secondary-disabled')} style={{ borderBottom:'none' }}>
|
||||||
{int(retrofitTotal)}{units.CR}
|
{int(retrofitTotal)}{units.CR}
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ export default class HardpointSlot extends Slot {
|
|||||||
{showModuleResistances && m.getThermalResistance() ? <div
|
{showModuleResistances && m.getThermalResistance() ? <div
|
||||||
className='l'>{translate('thermres')}: {formats.pct(m.getThermalResistance())}</div> : null}
|
className='l'>{translate('thermres')}: {formats.pct(m.getThermalResistance())}</div> : null}
|
||||||
{m.getIntegrity() ? <div className='l'>{translate('integrity')}: {formats.int(m.getIntegrity())}</div> : null}
|
{m.getIntegrity() ? <div className='l'>{translate('integrity')}: {formats.int(m.getIntegrity())}</div> : null}
|
||||||
|
{m.getInfo() ? <div className='l'>{translate(m.getInfo())}</div> : null}
|
||||||
{m && validMods.length > 0 ? <div className='r' tabIndex="0" ref={modButton => this.modButton = modButton}>
|
{m && validMods.length > 0 ? <div className='r' tabIndex="0" ref={modButton => this.modButton = modButton}>
|
||||||
<button tabIndex="-1" onClick={this._toggleModifications.bind(this)} onContextMenu={stopCtxPropagation}
|
<button tabIndex="-1" onClick={this._toggleModifications.bind(this)} onContextMenu={stopCtxPropagation}
|
||||||
onMouseOver={termtip.bind(null, 'modifications')} onMouseOut={tooltip.bind(null, null)}>
|
onMouseOver={termtip.bind(null, 'modifications')} onMouseOut={tooltip.bind(null, null)}>
|
||||||
|
|||||||
@@ -388,9 +388,11 @@ export default class Header extends TranslatedComponent {
|
|||||||
if (this.props.announcements) {
|
if (this.props.announcements) {
|
||||||
announcements = [];
|
announcements = [];
|
||||||
for (let announce of this.props.announcements) {
|
for (let announce of this.props.announcements) {
|
||||||
if (announce.expiry < Date.now()) {
|
// Announcement has expired, skip it
|
||||||
|
if (Date.now() > Date.parse(announce.expiry)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// Add announcements which have not expired to the menu
|
||||||
announcements.push(<Announcement text={announce.text} />);
|
announcements.push(<Announcement text={announce.text} />);
|
||||||
announcements.push(<hr/>);
|
announcements.push(<hr/>);
|
||||||
}
|
}
|
||||||
@@ -398,7 +400,6 @@ export default class Header extends TranslatedComponent {
|
|||||||
return (
|
return (
|
||||||
<div className='menu-list' onClick={ (e) => e.stopPropagation() } style={{ whiteSpace: 'nowrap' }}>
|
<div className='menu-list' onClick={ (e) => e.stopPropagation() } style={{ whiteSpace: 'nowrap' }}>
|
||||||
{announcements}
|
{announcements}
|
||||||
<hr />
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ export default class InternalSlot extends Slot {
|
|||||||
{ m.getHullReinforcement() ? <div className='l'>{translate('armour')}: {formats.int(m.getHullReinforcement() + ship.baseArmour * m.getModValue('hullboost') / 10000)}</div> : null }
|
{ m.getHullReinforcement() ? <div className='l'>{translate('armour')}: {formats.int(m.getHullReinforcement() + ship.baseArmour * m.getModValue('hullboost') / 10000)}</div> : null }
|
||||||
{ m.getProtection() ? <div className='l'>{translate('protection')}: {formats.rPct(m.getProtection())}</div> : null }
|
{ m.getProtection() ? <div className='l'>{translate('protection')}: {formats.rPct(m.getProtection())}</div> : null }
|
||||||
{ m.getIntegrity() ? <div className='l'>{translate('integrity')}: {formats.int(m.getIntegrity())}</div> : null }
|
{ m.getIntegrity() ? <div className='l'>{translate('integrity')}: {formats.int(m.getIntegrity())}</div> : null }
|
||||||
|
{ m.getInfo() ? <div className='l'>{translate(m.getInfo())}</div> : null }
|
||||||
{ m && validMods.length > 0 ? <div className='r' tabIndex="0" ref={ modButton => this.modButton = modButton }><button tabIndex="-1" onClick={this._toggleModifications.bind(this)} onContextMenu={stopCtxPropagation} onMouseOver={termtip.bind(null, 'modifications')} onMouseOut={tooltip.bind(null, null)}><ListModifications /></button></div> : null }
|
{ m && validMods.length > 0 ? <div className='r' tabIndex="0" ref={ modButton => this.modButton = modButton }><button tabIndex="-1" onClick={this._toggleModifications.bind(this)} onContextMenu={stopCtxPropagation} onMouseOver={termtip.bind(null, 'modifications')} onMouseOut={tooltip.bind(null, null)}><ListModifications /></button></div> : null }
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export default class JumpRange extends TranslatedComponent {
|
|||||||
const fuel = this.state.fuelLevel * ship.fuelCapacity;
|
const fuel = this.state.fuelLevel * ship.fuelCapacity;
|
||||||
|
|
||||||
// Obtain the jump range
|
// Obtain the jump range
|
||||||
return Calc.jumpRange(ship.unladenMass + fuel + cargo, fsd, fuel, ship);
|
return Calc.jumpRange(ship.unladenMass + cargo, fsd, fuel, ship);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,281 +1,281 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import ContainerDimensions from 'react-container-dimensions';
|
import ContainerDimensions from 'react-container-dimensions';
|
||||||
import * as d3 from 'd3';
|
import * as d3 from 'd3';
|
||||||
import TranslatedComponent from './TranslatedComponent';
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
|
|
||||||
const MARGIN = { top: 15, right: 20, bottom: 35, left: 60 };
|
const MARGIN = { top: 15, right: 20, bottom: 35, left: 60 };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Line Chart
|
* Line Chart
|
||||||
*/
|
*/
|
||||||
export default class LineChart extends TranslatedComponent {
|
export default class LineChart extends TranslatedComponent {
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
code: '',
|
code: '',
|
||||||
xMin: 0,
|
xMin: 0,
|
||||||
yMin: 0,
|
yMin: 0,
|
||||||
points: 20,
|
points: 20,
|
||||||
colors: ['#ff8c0d'],
|
colors: ['#ff8c0d'],
|
||||||
aspect: 0.5
|
aspect: 0.5
|
||||||
};
|
};
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
func: PropTypes.func.isRequired,
|
func: PropTypes.func.isRequired,
|
||||||
xLabel: PropTypes.string.isRequired,
|
xLabel: PropTypes.string.isRequired,
|
||||||
xMin: PropTypes.number,
|
xMin: PropTypes.number,
|
||||||
xMax: PropTypes.number.isRequired,
|
xMax: PropTypes.number.isRequired,
|
||||||
xUnit: PropTypes.string.isRequired,
|
xUnit: PropTypes.string.isRequired,
|
||||||
xMark: PropTypes.number,
|
xMark: PropTypes.number,
|
||||||
yLabel: PropTypes.string.isRequired,
|
yLabel: PropTypes.string.isRequired,
|
||||||
yMin: PropTypes.number,
|
yMin: PropTypes.number,
|
||||||
yMax: PropTypes.number.isRequired,
|
yMax: PropTypes.number.isRequired,
|
||||||
yUnit: PropTypes.string,
|
yUnit: PropTypes.string,
|
||||||
series: PropTypes.array,
|
series: PropTypes.array,
|
||||||
colors: PropTypes.array,
|
colors: PropTypes.array,
|
||||||
points: PropTypes.number,
|
points: PropTypes.number,
|
||||||
aspect: PropTypes.number,
|
aspect: PropTypes.number,
|
||||||
code: PropTypes.string,
|
code: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
* @param {Object} context React Component context
|
* @param {Object} context React Component context
|
||||||
*/
|
*/
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this._updateDimensions = this._updateDimensions.bind(this);
|
this._updateDimensions = this._updateDimensions.bind(this);
|
||||||
this._updateSeries = this._updateSeries.bind(this);
|
this._updateSeries = this._updateSeries.bind(this);
|
||||||
this._tooltip = this._tooltip.bind(this);
|
this._tooltip = this._tooltip.bind(this);
|
||||||
this._showTip = this._showTip.bind(this);
|
this._showTip = this._showTip.bind(this);
|
||||||
this._hideTip = this._hideTip.bind(this);
|
this._hideTip = this._hideTip.bind(this);
|
||||||
this._moveTip = this._moveTip.bind(this);
|
this._moveTip = this._moveTip.bind(this);
|
||||||
|
|
||||||
const series = props.series;
|
const series = props.series;
|
||||||
|
|
||||||
let xScale = d3.scaleLinear();
|
let xScale = d3.scaleLinear();
|
||||||
let yScale = d3.scaleLinear();
|
let yScale = d3.scaleLinear();
|
||||||
let xAxisScale = d3.scaleLinear();
|
let xAxisScale = d3.scaleLinear();
|
||||||
|
|
||||||
this.xAxis = d3.axisBottom(xAxisScale).tickSizeOuter(0);
|
this.xAxis = d3.axisBottom(xAxisScale).tickSizeOuter(0);
|
||||||
this.yAxis = d3.axisLeft(yScale).ticks(6).tickSizeOuter(0);
|
this.yAxis = d3.axisLeft(yScale).ticks(6).tickSizeOuter(0);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
xScale,
|
xScale,
|
||||||
xAxisScale,
|
xAxisScale,
|
||||||
yScale,
|
yScale,
|
||||||
tipHeight: 2 + (1.2 * (series ? series.length : 0.8)),
|
tipHeight: 2 + (1.2 * (series ? series.length : 0.8)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update tooltip content
|
* Update tooltip content
|
||||||
* @param {number} xPos x coordinate
|
* @param {number} xPos x coordinate
|
||||||
* @param {number} width current container width
|
* @param {number} width current container width
|
||||||
*/
|
*/
|
||||||
_tooltip(xPos, width) {
|
_tooltip(xPos, width) {
|
||||||
let { xLabel, yLabel, xUnit, yUnit, func, series } = this.props;
|
let { xLabel, yLabel, xUnit, yUnit, func, series } = this.props;
|
||||||
let { xScale, yScale } = this.state;
|
let { xScale, yScale } = this.state;
|
||||||
let { formats, translate } = this.context.language;
|
let { formats, translate } = this.context.language;
|
||||||
let x0 = xScale.invert(xPos),
|
let x0 = xScale.invert(xPos),
|
||||||
y0 = func(x0),
|
y0 = func(x0),
|
||||||
tips = this.tipContainer,
|
tips = this.tipContainer,
|
||||||
yTotal = 0,
|
yTotal = 0,
|
||||||
flip = (xPos / width > 0.50),
|
flip = (xPos / width > 0.50),
|
||||||
tipWidth = 0,
|
tipWidth = 0,
|
||||||
tipHeightPx = tips.selectAll('rect').node().getBoundingClientRect().height;
|
tipHeightPx = tips.selectAll('rect').node().getBoundingClientRect().height;
|
||||||
|
|
||||||
|
|
||||||
xPos = xScale(x0); // Clamp xPos
|
xPos = xScale(x0); // Clamp xPos
|
||||||
|
|
||||||
tips.selectAll('text.text-tip.y').text(function(d, i) {
|
tips.selectAll('text.text-tip.y').text(function(d, i) {
|
||||||
let yVal = series ? y0[series[i]] : y0;
|
let yVal = series ? y0[series[i]] : y0;
|
||||||
yTotal += yVal;
|
yTotal += yVal;
|
||||||
return (series ? translate(series[i]) : '') + ' ' + formats.f2(yVal);
|
return (series ? translate(series[i]) : '') + ' ' + formats.f2(yVal);
|
||||||
}).append('tspan').attr('class', 'metric').text(yUnit ? ' ' + yUnit : '');
|
}).append('tspan').attr('class', 'metric').text(yUnit ? ' ' + yUnit : '');
|
||||||
|
|
||||||
tips.selectAll('text').each(function() {
|
tips.selectAll('text').each(function() {
|
||||||
if (this.getBBox().width > tipWidth) {
|
if (this.getBBox().width > tipWidth) {
|
||||||
tipWidth = Math.ceil(this.getBBox().width);
|
tipWidth = Math.ceil(this.getBBox().width);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let tipY = Math.floor(yScale(yTotal / (series ? series.length : 1)) - (tipHeightPx / 2));
|
let tipY = Math.floor(yScale(yTotal / (series ? series.length : 1)) - (tipHeightPx / 2));
|
||||||
|
|
||||||
tipWidth += 8;
|
tipWidth += 8;
|
||||||
tips.attr('transform', 'translate(' + xPos + ',' + tipY + ')');
|
tips.attr('transform', 'translate(' + xPos + ',' + tipY + ')');
|
||||||
tips.selectAll('text.text-tip').attr('x', flip ? -12 : 12).style('text-anchor', flip ? 'end' : 'start');
|
tips.selectAll('text.text-tip').attr('x', flip ? -12 : 12).style('text-anchor', flip ? 'end' : 'start');
|
||||||
tips.selectAll('text.text-tip.x').text(formats.f2(x0)).append('tspan').attr('class', 'metric').text(' ' + xUnit);
|
tips.selectAll('text.text-tip.x').text(formats.f2(x0)).append('tspan').attr('class', 'metric').text(' ' + xUnit);
|
||||||
tips.selectAll('rect').attr('width', tipWidth + 4).attr('x', flip ? -tipWidth - 12 : 8).attr('y', 0).style('text-anchor', flip ? 'end' : 'start');
|
tips.selectAll('rect').attr('width', tipWidth + 4).attr('x', flip ? -tipWidth - 12 : 8).attr('y', 0).style('text-anchor', flip ? 'end' : 'start');
|
||||||
this.markersContainer.selectAll('circle').attr('cx', xPos).attr('cy', (d, i) => yScale(series ? y0[series[i]] : y0));
|
this.markersContainer.selectAll('circle').attr('cx', xPos).attr('cy', (d, i) => yScale(series ? y0[series[i]] : y0));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update dimensions based on properties and scale
|
* Update dimensions based on properties and scale
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
* @param {number} scale size ratio / scale
|
* @param {number} scale size ratio / scale
|
||||||
* @param {number} width current width of the container
|
* @param {number} width current width of the container
|
||||||
* @returns {Object} calculated dimensions
|
* @returns {Object} calculated dimensions
|
||||||
*/
|
*/
|
||||||
_updateDimensions(props, scale, width) {
|
_updateDimensions(props, scale, width) {
|
||||||
const { xMax, xMin, yMin, yMax } = props;
|
const { xMax, xMin, yMin, yMax } = props;
|
||||||
const innerWidth = width - MARGIN.left - MARGIN.right;
|
const innerWidth = width - MARGIN.left - MARGIN.right;
|
||||||
const outerHeight = Math.round(width * props.aspect);
|
const outerHeight = Math.round(width * props.aspect);
|
||||||
const innerHeight = outerHeight - MARGIN.top - MARGIN.bottom;
|
const innerHeight = outerHeight - MARGIN.top - MARGIN.bottom;
|
||||||
|
|
||||||
this.state.xScale.range([0, innerWidth]).domain([xMin, xMax || 1]).clamp(true);
|
this.state.xScale.range([0, innerWidth]).domain([xMin, xMax || 1]).clamp(true);
|
||||||
this.state.xAxisScale.range([0, innerWidth]).domain([xMin, xMax]).clamp(true);
|
this.state.xAxisScale.range([0, innerWidth]).domain([xMin, xMax]).clamp(true);
|
||||||
this.state.yScale.range([innerHeight, 0]).domain([yMin, yMax + (yMax - yMin) * 0.1]); // 10% higher than maximum value for tooltip visibility
|
this.state.yScale.range([innerHeight, 0]).domain([yMin, yMax + (yMax - yMin) * 0.1]); // 10% higher than maximum value for tooltip visibility
|
||||||
return { innerWidth, outerHeight, innerHeight };
|
return { innerWidth, outerHeight, innerHeight };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show tooltip
|
* Show tooltip
|
||||||
* @param {SyntheticEvent} e Event
|
* @param {SyntheticEvent} e Event
|
||||||
*/
|
*/
|
||||||
_showTip(e) {
|
_showTip(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.tipContainer.style('display', null);
|
this.tipContainer.style('display', null);
|
||||||
this.markersContainer.style('display', null);
|
this.markersContainer.style('display', null);
|
||||||
this._moveTip(e);
|
this._moveTip(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move and update tooltip
|
* Move and update tooltip
|
||||||
* @param {SyntheticEvent} e Event
|
* @param {SyntheticEvent} e Event
|
||||||
* @param {number} width current container width
|
* @param {number} width current container width
|
||||||
*/
|
*/
|
||||||
_moveTip(e, width) {
|
_moveTip(e, width) {
|
||||||
let clientX = e.touches ? e.touches[0].clientX : e.clientX;
|
let clientX = e.touches ? e.touches[0].clientX : e.clientX;
|
||||||
this._tooltip(Math.round(clientX - e.currentTarget.getBoundingClientRect().left), width);
|
this._tooltip(Math.round(clientX - e.currentTarget.getBoundingClientRect().left), width);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hide tooltip
|
* Hide tooltip
|
||||||
* @param {SyntheticEvent} e Event
|
* @param {SyntheticEvent} e Event
|
||||||
*/
|
*/
|
||||||
_hideTip(e) {
|
_hideTip(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.tipContainer.style('display', 'none');
|
this.tipContainer.style('display', 'none');
|
||||||
this.markersContainer.style('display', 'none');
|
this.markersContainer.style('display', 'none');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update series generated from props
|
* Update series generated from props
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
* @param {Object} state React Component state
|
* @param {Object} state React Component state
|
||||||
*/
|
*/
|
||||||
_updateSeries(props, state) {
|
_updateSeries(props, state) {
|
||||||
let { func, xMin, xMax, series, points } = props;
|
let { func, xMin, xMax, series, points } = props;
|
||||||
let delta = (xMax - xMin) / points;
|
let delta = (xMax - xMin) / points;
|
||||||
let seriesData = new Array(points);
|
let seriesData = new Array(points);
|
||||||
|
|
||||||
if (delta) {
|
if (delta) {
|
||||||
seriesData = new Array(points);
|
seriesData = new Array(points);
|
||||||
for (let i = 0, x = xMin; i < points; i++) {
|
for (let i = 0, x = xMin; i < points; i++) {
|
||||||
seriesData[i] = [x, func(x)];
|
seriesData[i] = [x, func(x)];
|
||||||
x += delta;
|
x += delta;
|
||||||
}
|
}
|
||||||
seriesData[points - 1] = [xMax, func(xMax)];
|
seriesData[points - 1] = [xMax, func(xMax)];
|
||||||
} else {
|
} else {
|
||||||
let yVal = func(xMin);
|
let yVal = func(xMin);
|
||||||
seriesData = [[0, yVal], [1, yVal]];
|
seriesData = [[0, yVal], [1, yVal]];
|
||||||
}
|
}
|
||||||
|
|
||||||
const markerElems = [];
|
const markerElems = [];
|
||||||
const detailElems = [<text key='lbl' className='text-tip x' y='1.25em'/>];
|
const detailElems = [<text key='lbl' className='text-tip x' y='1.25em'/>];
|
||||||
const seriesLines = [];
|
const seriesLines = [];
|
||||||
for (let i = 0, l = series ? series.length : 1; i < l; i++) {
|
for (let i = 0, l = series ? series.length : 1; i < l; i++) {
|
||||||
const yAccessor = series ? function(d) { return state.yScale(d[1][this]); }.bind(series[i]) : (d) => state.yScale(d[1]);
|
const yAccessor = series ? function(d) { return state.yScale(d[1][this]); }.bind(series[i]) : (d) => state.yScale(d[1]);
|
||||||
seriesLines.push(d3.line().x((d, i) => this.state.xScale(d[0])).y(yAccessor));
|
seriesLines.push(d3.line().x((d, i) => this.state.xScale(d[0])).y(yAccessor));
|
||||||
detailElems.push(<text key={i} className='text-tip y' strokeWidth={0} fill={props.colors[i]} y={1.25 * (i + 2) + 'em'}/>);
|
detailElems.push(<text key={i} className='text-tip y' strokeWidth={0} fill={props.colors[i]} y={1.25 * (i + 2) + 'em'}/>);
|
||||||
markerElems.push(<circle key={i} className='marker' r='4' />);
|
markerElems.push(<circle key={i} className='marker' r='4' />);
|
||||||
}
|
}
|
||||||
|
|
||||||
const tipHeight = 2 + (1.2 * (seriesLines ? seriesLines.length : 0.8));
|
const tipHeight = 2 + (1.2 * (seriesLines ? seriesLines.length : 0.8));
|
||||||
|
|
||||||
this.setState({ markerElems, detailElems, seriesLines, seriesData, tipHeight });
|
this.setState({ markerElems, detailElems, seriesLines, seriesData, tipHeight });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update dimensions and series data based on props and context.
|
* Update dimensions and series data based on props and context.
|
||||||
*/
|
*/
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
this._updateSeries(this.props, this.state);
|
this._updateSeries(this.props, this.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update state based on property and context changes
|
* Update state based on property and context changes
|
||||||
* @param {Object} nextProps Incoming/Next properties
|
* @param {Object} nextProps Incoming/Next properties
|
||||||
* @param {Object} nextContext Incoming/Next conext
|
* @param {Object} nextContext Incoming/Next conext
|
||||||
*/
|
*/
|
||||||
componentWillReceiveProps(nextProps, nextContext) {
|
componentWillReceiveProps(nextProps, nextContext) {
|
||||||
const props = this.props;
|
const props = this.props;
|
||||||
|
|
||||||
if (props.code != nextProps.code) {
|
if (props.code != nextProps.code) {
|
||||||
this._updateSeries(nextProps, this.state);
|
this._updateSeries(nextProps, this.state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the chart
|
* Render the chart
|
||||||
* @return {React.Component} Chart SVG
|
* @return {React.Component} Chart SVG
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<ContainerDimensions>
|
<ContainerDimensions>
|
||||||
{ ({ width, height }) => {
|
{ ({ width, height }) => {
|
||||||
const { innerWidth, outerHeight, innerHeight } = this._updateDimensions(this.props, this.context.sizeRatio, width, height);
|
const { innerWidth, outerHeight, innerHeight } = this._updateDimensions(this.props, this.context.sizeRatio, width, height);
|
||||||
const { xMin, xMax, xLabel, yLabel, xUnit, yUnit, xMark, colors } = this.props;
|
const { xMin, xMax, xLabel, yLabel, xUnit, yUnit, xMark, colors } = this.props;
|
||||||
const { tipHeight, detailElems, markerElems, seriesData, seriesLines } = this.state;
|
const { tipHeight, detailElems, markerElems, seriesData, seriesLines } = this.state;
|
||||||
const lines = seriesLines.map((line, i) => <path key={i} className='line' fill='none' stroke={colors[i]} strokeWidth='1' d={line(seriesData)} />).reverse();
|
const lines = seriesLines.map((line, i) => <path key={i} className='line' fill='none' stroke={colors[i]} strokeWidth='1' d={line(seriesData)} />).reverse();
|
||||||
|
|
||||||
const markX = xMark ? innerWidth * (xMark - xMin) / (xMax - xMin) : 0;
|
const markX = xMark ? innerWidth * (xMark - xMin) / (xMax - xMin) : 0;
|
||||||
const xmark = xMark ? <path key={'mark'} className='line' fill='none' strokeDasharray='5,5' stroke={'#ff8c0d'} strokeWidth='1' d={'M ' + markX + ' ' + innerHeight + ' L ' + markX + ' 0'} /> : '';
|
const xmark = xMark ? <path key={'mark'} className='line' fill='none' strokeDasharray='5,5' stroke={'#ff8c0d'} strokeWidth='1' d={'M ' + markX + ' ' + innerHeight + ' L ' + markX + ' 0'} /> : '';
|
||||||
return (
|
return (
|
||||||
<div width={width} height={height}>
|
<div width={width} height={height}>
|
||||||
<svg style={{ width: '100%', height: outerHeight }}>
|
<svg style={{ width: '100%', height: outerHeight }}>
|
||||||
<g transform={`translate(${MARGIN.left},${MARGIN.top})`}>
|
<g transform={`translate(${MARGIN.left},${MARGIN.top})`}>
|
||||||
<g>{xmark}</g>
|
<g>{xmark}</g>
|
||||||
<g>{lines}</g>
|
<g>{lines}</g>
|
||||||
<g className='x axis' ref={(elem) => d3.select(elem).call(this.xAxis)} transform={`translate(0,${innerHeight})`}>
|
<g className='x axis' ref={(elem) => d3.select(elem).call(this.xAxis)} transform={`translate(0,${innerHeight})`}>
|
||||||
<text className='cap' y='30' dy='.1em' x={innerWidth / 2} style={{ textAnchor: 'middle' }}>
|
<text className='cap' y='30' dy='.1em' x={innerWidth / 2} style={{ textAnchor: 'middle' }}>
|
||||||
<tspan>{xLabel}</tspan>
|
<tspan>{xLabel}</tspan>
|
||||||
<tspan className='metric'> ({xUnit})</tspan>
|
<tspan className='metric'> ({xUnit})</tspan>
|
||||||
</text>
|
</text>
|
||||||
</g>
|
</g>
|
||||||
<g className='y axis' ref={(elem) => d3.select(elem).call(this.yAxis)}>
|
<g className='y axis' ref={(elem) => d3.select(elem).call(this.yAxis)}>
|
||||||
<text className='cap' transform='rotate(-90)' y='-50' dy='.1em' x={innerHeight / -2} style={{ textAnchor: 'middle' }}>
|
<text className='cap' transform='rotate(-90)' y='-50' dy='.1em' x={innerHeight / -2} style={{ textAnchor: 'middle' }}>
|
||||||
<tspan>{yLabel}</tspan>
|
<tspan>{yLabel}</tspan>
|
||||||
{ yUnit && <tspan className='metric'> ({yUnit})</tspan> }
|
{ yUnit && <tspan className='metric'> ({yUnit})</tspan> }
|
||||||
</text>
|
</text>
|
||||||
</g>
|
</g>
|
||||||
<g ref={(g) => this.tipContainer = d3.select(g)} style={{ display: 'none' }}>
|
<g ref={(g) => this.tipContainer = d3.select(g)} style={{ display: 'none' }}>
|
||||||
<rect className='tooltip' height={tipHeight + 'em'}></rect>
|
<rect className='tooltip' height={tipHeight + 'em'}></rect>
|
||||||
{detailElems}
|
{detailElems}
|
||||||
</g>
|
</g>
|
||||||
<g ref={(g) => this.markersContainer = d3.select(g)} style={{ display: 'none' }}>
|
<g ref={(g) => this.markersContainer = d3.select(g)} style={{ display: 'none' }}>
|
||||||
{markerElems}
|
{markerElems}
|
||||||
</g>
|
</g>
|
||||||
<rect
|
<rect
|
||||||
fillOpacity='0'
|
fillOpacity='0'
|
||||||
height={innerHeight}
|
height={innerHeight}
|
||||||
width={innerWidth + 1}
|
width={innerWidth + 1}
|
||||||
onMouseEnter={this._showTip}
|
onMouseEnter={this._showTip}
|
||||||
onTouchStart={this._showTip}
|
onTouchStart={this._showTip}
|
||||||
onMouseLeave={this._hideTip}
|
onMouseLeave={this._hideTip}
|
||||||
onTouchEnd={this._hideTip}
|
onTouchEnd={this._hideTip}
|
||||||
onMouseMove={e => this._moveTip(e, width)}
|
onMouseMove={e => this._moveTip(e, width)}
|
||||||
onTouchMove={e => this._moveTip(e, width)}
|
onTouchMove={e => this._moveTip(e, width)}
|
||||||
/>
|
/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</ContainerDimensions>
|
</ContainerDimensions>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,18 @@ export default class ModalPermalink extends TranslatedComponent {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy the shortened URL to the clipboard
|
||||||
|
* @param {Event} e Click event
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
copyShortLink() {
|
||||||
|
let copyText = document.getElementById("shortenedUrl");
|
||||||
|
// Copy the text inside the shortendUrl input to the clipboard
|
||||||
|
copyText.select();
|
||||||
|
document.execCommand("copy");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the modal
|
* Render the modal
|
||||||
* @return {React.Component} Modal Content
|
* @return {React.Component} Modal Content
|
||||||
@@ -42,15 +54,17 @@ export default class ModalPermalink extends TranslatedComponent {
|
|||||||
let translate = this.context.language.translate;
|
let translate = this.context.language.translate;
|
||||||
|
|
||||||
return <div className='modal' onClick={ (e) => e.stopPropagation() }>
|
return <div className='modal' onClick={ (e) => e.stopPropagation() }>
|
||||||
<h2>{translate('permalink')}</h2>
|
<h3>{translate('permalink')}</h3>
|
||||||
<br/>
|
<br/>
|
||||||
<h3>{translate('URL')}</h3>
|
<h3>{translate('URL')}</h3>
|
||||||
<input value={this.props.url} size={40} readOnly onFocus={ (e) => e.target.select() }/>
|
<input value={this.props.url} size={40} readOnly onFocus={ (e) => e.target.select() }/>
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
<h3 >{translate('shortened')}</h3>
|
<h3 >{translate('shortened')}</h3>
|
||||||
<input value={this.state.shortenedUrl} readOnly size={25} onFocus={ (e) => e.target.select() }/>
|
<input id={'shortenedUrl'} value={this.state.shortenedUrl} readOnly size={25} onFocus={ (e) => e.target.select() }/><button className={'cb dismiss cap'} onClick={this.copyShortLink}>{translate('copy to clipboard')}</button>
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
<p>s.orbis.zone is the new URL shortener domain, old eddp.co urls are considered end of life and could go down at any moment. Sorry for any inconvenience.</p>
|
<hr />
|
||||||
|
<p>s.orbis.zone is the URL shortener domain. These links should persist indefinitely going forward. If for some reason there is a problem with the link shortening process, please report it in the EDCD Discord Server.</p>
|
||||||
|
<hr />
|
||||||
<button className={'r dismiss cap'} onClick={this.context.hideModal}>{translate('close')}</button>
|
<button className={'r dismiss cap'} onClick={this.context.hideModal}>{translate('close')}</button>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import PropTypes from 'prop-types';
|
|||||||
import TranslatedComponent from './TranslatedComponent';
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
import request from 'superagent';
|
import request from 'superagent';
|
||||||
import Persist from '../stores/Persist';
|
import Persist from '../stores/Persist';
|
||||||
|
const zlib = require('zlib');
|
||||||
|
const base64url = require('base64url');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Permalink modal
|
* Permalink modal
|
||||||
@@ -10,7 +12,8 @@ import Persist from '../stores/Persist';
|
|||||||
export default class ModalShoppingList extends TranslatedComponent {
|
export default class ModalShoppingList extends TranslatedComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
ship: PropTypes.object.isRequired
|
ship: PropTypes.object.isRequired,
|
||||||
|
buildName: PropTypes.string
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -56,7 +59,6 @@ export default class ModalShoppingList extends TranslatedComponent {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (module.m.blueprint.special) {
|
if (module.m.blueprint.special) {
|
||||||
console.log(module.m.blueprint.special);
|
|
||||||
blueprints.push({ uuid: module.m.blueprint.special.uuid, number: 1 });
|
blueprints.push({ uuid: module.m.blueprint.special.uuid, number: 1 });
|
||||||
}
|
}
|
||||||
for (const g in module.m.blueprint.grades) {
|
for (const g in module.m.blueprint.grades) {
|
||||||
@@ -89,8 +91,10 @@ export default class ModalShoppingList extends TranslatedComponent {
|
|||||||
request
|
request
|
||||||
.get('http://localhost:44405/commanders')
|
.get('http://localhost:44405/commanders')
|
||||||
.end((err, res) => {
|
.end((err, res) => {
|
||||||
|
this.display = 'block';
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
|
this.display = 'none';
|
||||||
return this.setState({ failed: true });
|
return this.setState({ failed: true });
|
||||||
}
|
}
|
||||||
const cmdrs = JSON.parse(res.text);
|
const cmdrs = JSON.parse(res.text);
|
||||||
@@ -146,6 +150,113 @@ export default class ModalShoppingList extends TranslatedComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fix issues with the item name for bulkheads when sending to EDOMH
|
||||||
|
* @param {*} ship Ship object
|
||||||
|
* @param {*} item Item name
|
||||||
|
* @returns updated item name
|
||||||
|
*/
|
||||||
|
fixArmourItemNameForEDOMH(ship, item) {
|
||||||
|
// The module blueprint fdname contains "Armour_" it's a bulkhead and we need to pre-populate the item field with the correct name from the ship object
|
||||||
|
switch (ship.bulkheads.m.name){
|
||||||
|
case "Lightweight Alloy":
|
||||||
|
item = ship.id + "_Armour_Grade1";
|
||||||
|
break;
|
||||||
|
case "Reinforced Alloy":
|
||||||
|
item = ship.id + "_Armour_Grade2";
|
||||||
|
break;
|
||||||
|
case "Military Grade Composite":
|
||||||
|
item = ship.id + "_Armour_Grade3";
|
||||||
|
break;
|
||||||
|
case "Mirrored Surface Composite":
|
||||||
|
item = ship.id + "_Armour_Mirrored";
|
||||||
|
break;
|
||||||
|
case "Reactive Surface Composite":
|
||||||
|
item = ship.id + "_Armour_Reactive";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send all blueprints to EDOMH. This is a modified copy of registerBPs because this.state.blueprints was empty when I tried to modify sendToEDEng and I couldn't figure out why
|
||||||
|
* @param {Event} event React event
|
||||||
|
*/
|
||||||
|
sendToEDOMH(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const ship = this.props.ship;
|
||||||
|
const buildName = this.props.buildName;
|
||||||
|
let blueprints = [];
|
||||||
|
|
||||||
|
//create the json
|
||||||
|
for (const module of ship.costList) {
|
||||||
|
if (module.type === 'SHIP') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (module.m && module.m.blueprint) {
|
||||||
|
if (!module.m.blueprint.grade || !module.m.blueprint.grades) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (module.m.blueprint.special) {
|
||||||
|
let item = "";
|
||||||
|
// If the module blueprint fdname contains "Armour_" it's a bulkhead and we need to pre-populate the item field with the correct name from the ship object
|
||||||
|
if (module.m.blueprint.fdname.includes("Armour_")) {
|
||||||
|
item = this.fixArmourItemNameForEDOMH(ship, item)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item = module.m.symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
blueprints.push({
|
||||||
|
"item": item,
|
||||||
|
"blueprint": module.m.blueprint.special.edname
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (let g in module.m.blueprint.grades) {
|
||||||
|
if (!module.m.blueprint.grades.hasOwnProperty(g)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// We only want the grade that the module is currently at, not every grade up to that point
|
||||||
|
if (Number(g) !== module.m.blueprint.grade) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let item = "";
|
||||||
|
// If the module blueprint fdname contains "Armour_" it's a bulkhead and we need to pre-populate the item field with the correct name from the ship object
|
||||||
|
if (module.m.blueprint.fdname.includes("Armour_")) {
|
||||||
|
item = this.fixArmourItemNameForEDOMH(ship, item)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item = module.m.symbol;
|
||||||
|
}
|
||||||
|
blueprints.push({
|
||||||
|
"item": item,
|
||||||
|
"blueprint": module.m.blueprint.fdname,
|
||||||
|
"grade": module.m.blueprint.grade,
|
||||||
|
"highestGradePercentage":1.0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let shipName = buildName + " - " + ship.name;
|
||||||
|
|
||||||
|
//create JSON to encode
|
||||||
|
let baseJson = {
|
||||||
|
"version":1,
|
||||||
|
"name": shipName, // TO-DO: Import build name and put that here correctly
|
||||||
|
"items": blueprints
|
||||||
|
}
|
||||||
|
|
||||||
|
let JSONString = JSON.stringify(baseJson)
|
||||||
|
let deflated = zlib.deflateSync(JSONString)
|
||||||
|
|
||||||
|
//actually encode
|
||||||
|
let link = base64url.encode(deflated)
|
||||||
|
link = "edomh://coriolis/?" + link;
|
||||||
|
|
||||||
|
window.open(link, "_self")
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert mats object to string
|
* Convert mats object to string
|
||||||
*/
|
*/
|
||||||
@@ -160,14 +271,15 @@ export default class ModalShoppingList extends TranslatedComponent {
|
|||||||
if (!module.m.blueprint.grade || !module.m.blueprint.grades) {
|
if (!module.m.blueprint.grade || !module.m.blueprint.grades) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (const g in module.m.blueprint.grades) {
|
for (let g in module.m.blueprint.grades) {
|
||||||
if (!module.m.blueprint.grades.hasOwnProperty(g)) {
|
if (!module.m.blueprint.grades.hasOwnProperty(g)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (g > module.m.blueprint.grade) {
|
// Ignore grades higher than the grade selected
|
||||||
|
if (Number(g) > module.m.blueprint.grade) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (const i in module.m.blueprint.grades[g].components) {
|
for (let i in module.m.blueprint.grades[g].components) {
|
||||||
if (!module.m.blueprint.grades[g].components.hasOwnProperty(i)) {
|
if (!module.m.blueprint.grades[g].components.hasOwnProperty(i)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -178,6 +290,18 @@ export default class ModalShoppingList extends TranslatedComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (module.m.blueprint.special) {
|
||||||
|
for (const j in module.m.blueprint.special.components) {
|
||||||
|
if (!module.m.blueprint.special.components.hasOwnProperty(j)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (mats[j]) {
|
||||||
|
mats[j] += module.m.blueprint.special.components[j];
|
||||||
|
} else {
|
||||||
|
mats[j] = module.m.blueprint.special.components[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let matsString = '';
|
let matsString = '';
|
||||||
@@ -229,34 +353,48 @@ export default class ModalShoppingList extends TranslatedComponent {
|
|||||||
const compatible = this.checkBrowserIsCompatible();
|
const compatible = this.checkBrowserIsCompatible();
|
||||||
this.cmdrChangeHandler = this.cmdrChangeHandler.bind(this);
|
this.cmdrChangeHandler = this.cmdrChangeHandler.bind(this);
|
||||||
this.sendToEDEng = this.sendToEDEng.bind(this);
|
this.sendToEDEng = this.sendToEDEng.bind(this);
|
||||||
|
this.sendToEDOMH = this.sendToEDOMH.bind(this);
|
||||||
return <div className='modal' onClick={ (e) => e.stopPropagation() }>
|
return <div className='modal' onClick={ (e) => e.stopPropagation() }>
|
||||||
<h2>{translate('PHRASE_SHOPPING_MATS')}</h2>
|
<h3>{translate('PHRASE_SHOPPING_MATS')}</h3>
|
||||||
<label>{translate('Grade 1 rolls ')}</label>
|
|
||||||
<input id={1} type={'number'} min={0} defaultValue={this.state.matsPerGrade[1]} onChange={this.changeHandler} />
|
|
||||||
<br/>
|
|
||||||
<label>{translate('Grade 2 rolls ')}</label>
|
|
||||||
<input id={2} type={'number'} min={0} defaultValue={this.state.matsPerGrade[2]} onChange={this.changeHandler} />
|
|
||||||
<br/>
|
|
||||||
<label>{translate('Grade 3 rolls ')}</label>
|
|
||||||
<input id={3} type={'number'} min={0} value={this.state.matsPerGrade[3]} onChange={this.changeHandler} />
|
|
||||||
<br/>
|
|
||||||
<label>{translate('Grade 4 rolls ')}</label>
|
|
||||||
<input id={4} type={'number'} min={0} value={this.state.matsPerGrade[4]} onChange={this.changeHandler} />
|
|
||||||
<br/>
|
|
||||||
<label>{translate('Grade 5 rolls ')}</label>
|
|
||||||
<input id={5} type={'number'} min={0} value={this.state.matsPerGrade[5]} onChange={this.changeHandler} />
|
|
||||||
<div>
|
<div>
|
||||||
<textarea className='cb json' readOnly value={this.state.matsList} />
|
<p>{translate('PHRASE_DIFFERENT_ROLLS')}</p>
|
||||||
|
<label>{translate('G1')}</label>
|
||||||
|
<input className={'groll'} id={1} type={'number'} min={0} defaultValue={this.state.matsPerGrade[1]} onChange={this.changeHandler} />
|
||||||
|
| <label>{translate('G2')}</label>
|
||||||
|
<input className={'groll'} id={2} type={'number'} min={0} defaultValue={this.state.matsPerGrade[2]} onChange={this.changeHandler} />
|
||||||
|
| <label>{translate('G3')}</label>
|
||||||
|
<input className={'groll'} id={3} type={'number'} min={0} value={this.state.matsPerGrade[3]} onChange={this.changeHandler} />
|
||||||
|
| <label>{translate('G4')}</label>
|
||||||
|
<input className={'groll'} id={4} type={'number'} min={0} value={this.state.matsPerGrade[4]} onChange={this.changeHandler} />
|
||||||
|
| <label>{translate('G5')}</label>
|
||||||
|
<input className={'groll'} id={5} type={'number'} min={0} value={this.state.matsPerGrade[5]} onChange={this.changeHandler} />
|
||||||
</div>
|
</div>
|
||||||
<label hidden={!compatible} className={'l cap'}>{translate('CMDR Name')}</label>
|
|
||||||
<br/>
|
<div>
|
||||||
<select hidden={!compatible} className={'cmdr-select l cap'} onChange={this.cmdrChangeHandler} defaultValue={this.state.cmdrName}>
|
<p>{translate('PHRASE_ALL_MODULES_ALL_ROLLS')}</p>
|
||||||
{this.state.cmdrs.map(e => <option key={e}>{e}</option>)}
|
<textarea className='cb json' readOnly value={this.state.matsList} />
|
||||||
</select>
|
<p>{translate('PHRASE_FOR_FINER_CONTROL')}</p>
|
||||||
<br/>
|
</div>
|
||||||
<p hidden={!this.state.failed} id={'failed'} className={'l'}>{translate('PHRASE_FAIL_EDENGINEER')}</p>
|
|
||||||
<p hidden={compatible} id={'browserbad'} className={'l'}>{translate('PHRASE_FIREFOX_EDENGINEER')}</p>
|
<div id='edengineer' display={this.display} hidden={!!this.state.failed && !compatible}>
|
||||||
<button className={'l cb dismiss cap'} disabled={!!this.state.failed || !compatible} onClick={this.sendToEDEng}>{translate('Send to EDEngineer')}</button>
|
<hr />
|
||||||
|
<h3>ED Engineer</h3>
|
||||||
|
<h4 hidden={compatible} id={'browserbad'} className={'l'}>{translate('PHRASE_FIREFOX_EDENGINEER')}</h4>
|
||||||
|
<h4 hidden={!this.state.failed} id={'failed'} className={'l'}>{translate('PHRASE_FAILED_TO_FIND_EDENGINEER')}</h4>
|
||||||
|
<label for='cmdr-select' hidden={!!this.state.failed || !compatible} className={'l cap'}>{translate('CMDR Name:')}</label>
|
||||||
|
<select id='cmdr-select' hidden={!!this.state.failed || !compatible} className={'cmdr-select l cap'} onChange={this.cmdrChangeHandler} defaultValue={this.state.cmdrName}>
|
||||||
|
{this.state.cmdrs.map(e => <option key={e}>{e}</option>)}
|
||||||
|
</select>
|
||||||
|
<br/>
|
||||||
|
<button className={'l cb dismiss cap'} disabled={!!this.state.failed || !compatible} onClick={this.sendToEDEng}>{translate('Send to EDEngineer')}</button>
|
||||||
|
</div>
|
||||||
|
<div id='edomh'>
|
||||||
|
<hr />
|
||||||
|
<h3>ED Odyssey Materials Helper</h3>
|
||||||
|
<p>{translate('PHRASE_ENSURE_EDOMH')}</p>
|
||||||
|
<button className={'l cb dismiss cap'} onClick={this.sendToEDOMH}>{translate('Send to EDOMH')}</button>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
<button className={'r dismiss cap'} onClick={this.context.hideModal}>{translate('close')}</button>
|
<button className={'r dismiss cap'} onClick={this.context.hideModal}>{translate('close')}</button>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export default class Modification extends TranslatedComponent {
|
|||||||
if (reCast.endsWith(value) || reCast.startsWith(value)) {
|
if (reCast.endsWith(value) || reCast.startsWith(value)) {
|
||||||
let { m, name, ship } = this.props;
|
let { m, name, ship } = this.props;
|
||||||
value = Math.max(Math.min(value, 50000), -50000);
|
value = Math.max(Math.min(value, 50000), -50000);
|
||||||
ship.setModification(m, name, value, true, true);
|
ship.setModification(m, name, value, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ export default class ModificationsMenu extends TranslatedComponent {
|
|||||||
this.modValDidChange = false; // used to determine if component update was caused by change in modification value.
|
this.modValDidChange = false; // used to determine if component update was caused by change in modification value.
|
||||||
this._handleModChange = this._handleModChange.bind(this);
|
this._handleModChange = this._handleModChange.bind(this);
|
||||||
|
|
||||||
|
// console.log(props.m.blueprint)
|
||||||
this.state = {
|
this.state = {
|
||||||
blueprintMenuOpened: !(props.m.blueprint && props.m.blueprint.name),
|
blueprintMenuOpened: !(props.m.blueprint && props.m.blueprint.name),
|
||||||
specialMenuOpened: false
|
specialMenuOpened: false
|
||||||
@@ -421,15 +422,31 @@ export default class ModificationsMenu extends TranslatedComponent {
|
|||||||
let haveBlueprint = false;
|
let haveBlueprint = false;
|
||||||
let blueprintTt;
|
let blueprintTt;
|
||||||
let blueprintCv;
|
let blueprintCv;
|
||||||
|
let bprintSearchName;
|
||||||
|
|
||||||
|
// If the fdname is Weapon_Overcharged, we need to check if it's an MC
|
||||||
|
if (m.blueprint && m.blueprint.fdname) {
|
||||||
|
// Set the bprintSearchName value to the fdname of the blueprint for this module
|
||||||
|
bprintSearchName = m.blueprint.fdname;
|
||||||
|
if (m.blueprint.fdname === 'Weapon_Overcharged') {
|
||||||
|
// If the module is a MultiCannon, we need to fix the blueprint search name, else it will find the Laser Weapon_Overcharged Blueprint and not the MC Weapon_Overcharged Blueprint
|
||||||
|
if (m.symbol.match(/MultiCannon/i)) {
|
||||||
|
// console.log(Modifications.modules[m.grp].blueprints['MC_Overcharged']);
|
||||||
|
// console.log(m.blueprint.fdname);
|
||||||
|
bprintSearchName = 'MC_Overcharged';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// TODO: Fix this to actually find the correct blueprint.
|
// TODO: Fix this to actually find the correct blueprint.
|
||||||
if (!m.blueprint || !m.blueprint.name || !m.blueprint.fdname || !Modifications.modules[m.grp].blueprints || !Modifications.modules[m.grp].blueprints[m.blueprint.fdname]) {
|
if (!m.blueprint || !m.blueprint.name || !m.blueprint.fdname || !Modifications.modules[m.grp].blueprints || !Modifications.modules[m.grp].blueprints[bprintSearchName]) {
|
||||||
this.props.ship.clearModuleBlueprint(m);
|
this.props.ship.clearModuleBlueprint(m);
|
||||||
this.props.ship.clearModuleSpecial(m);
|
this.props.ship.clearModuleSpecial(m);
|
||||||
}
|
}
|
||||||
if (m.blueprint && m.blueprint.name && Modifications.modules[m.grp].blueprints[m.blueprint.fdname].grades[m.blueprint.grade]) {
|
if (m.blueprint && m.blueprint.name && Modifications.modules[m.grp].blueprints[bprintSearchName].grades[m.blueprint.grade]) {
|
||||||
blueprintLabel = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade;
|
blueprintLabel = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade;
|
||||||
haveBlueprint = true;
|
haveBlueprint = true;
|
||||||
blueprintTt = blueprintTooltip(translate, m.blueprint.grades[m.blueprint.grade], Modifications.modules[m.grp].blueprints[m.blueprint.fdname].grades[m.blueprint.grade].engineers, m.grp);
|
// console.log(haveBlueprint);
|
||||||
|
blueprintTt = blueprintTooltip(translate, m.blueprint.grades[m.blueprint.grade], Modifications.modules[m.grp].blueprints[bprintSearchName].grades[m.blueprint.grade].engineers, m.grp);
|
||||||
blueprintCv = getPercent(m);
|
blueprintCv = getPercent(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,92 +1,92 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import ContainerDimensions from 'react-container-dimensions';
|
import ContainerDimensions from 'react-container-dimensions';
|
||||||
import * as d3 from 'd3';
|
import * as d3 from 'd3';
|
||||||
|
|
||||||
const CORIOLIS_COLOURS = ['#FF8C0D', '#1FB0FF', '#71A052', '#D5D54D'];
|
const CORIOLIS_COLOURS = ['#FF8C0D', '#1FB0FF', '#71A052', '#D5D54D'];
|
||||||
const LABEL_COLOUR = '#000000';
|
const LABEL_COLOUR = '#000000';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A pie chart
|
* A pie chart
|
||||||
*/
|
*/
|
||||||
export default class PieChart extends Component {
|
export default class PieChart extends Component {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
data : PropTypes.array.isRequired
|
data : PropTypes.array.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
* @param {Object} context React Component context
|
* @param {Object} context React Component context
|
||||||
*/
|
*/
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.pie = d3.pie().value((d) => d.value);
|
this.pie = d3.pie().value((d) => d.value);
|
||||||
this.colors = CORIOLIS_COLOURS;
|
this.colors = CORIOLIS_COLOURS;
|
||||||
this.arc = d3.arc();
|
this.arc = d3.arc();
|
||||||
this.arc.innerRadius(0);
|
this.arc.innerRadius(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a slice of the pie chart
|
* Generate a slice of the pie chart
|
||||||
* @param {Object} d the data for this slice
|
* @param {Object} d the data for this slice
|
||||||
* @param {number} i the index of this slice
|
* @param {number} i the index of this slice
|
||||||
* @param {number} width the current width of the parent container
|
* @param {number} width the current width of the parent container
|
||||||
* @returns {Object} the SVG for the slice
|
* @returns {Object} the SVG for the slice
|
||||||
*/
|
*/
|
||||||
sliceGenerator(d, i, width) {
|
sliceGenerator(d, i, width) {
|
||||||
if (!d || d.value == 0) {
|
if (!d || d.value == 0) {
|
||||||
// Ignore 0 values
|
// Ignore 0 values
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data } = this.props;
|
const { data } = this.props;
|
||||||
|
|
||||||
// Push the labels further out from the centre of the slice
|
// Push the labels further out from the centre of the slice
|
||||||
let [labelX, labelY] = this.arc.centroid(d);
|
let [labelX, labelY] = this.arc.centroid(d);
|
||||||
const labelTranslate = `translate(${labelX * 1.5}, ${labelY * 1.5})`;
|
const labelTranslate = `translate(${labelX * 1.5}, ${labelY * 1.5})`;
|
||||||
|
|
||||||
// Put the keys in a line with equal spacing
|
// Put the keys in a line with equal spacing
|
||||||
const nonZeroItems = data.filter(d => d.value != 0).length;
|
const nonZeroItems = data.filter(d => d.value != 0).length;
|
||||||
const thisItemIndex = data.slice(0, i + 1).filter(d => d.value != 0).length - 1;
|
const thisItemIndex = data.slice(0, i + 1).filter(d => d.value != 0).length - 1;
|
||||||
const keyX = -width / 2 + (width / nonZeroItems) * (thisItemIndex + 0.5);
|
const keyX = -width / 2 + (width / nonZeroItems) * (thisItemIndex + 0.5);
|
||||||
const keyTranslate = `translate(${keyX}, ${width * 0.45})`;
|
const keyTranslate = `translate(${keyX}, ${width * 0.45})`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g key={`group-${i}`}>
|
<g key={`group-${i}`}>
|
||||||
<path key={`arc-${i}`} d={this.arc(d)} style={{ fill: this.colors[i] }} />
|
<path key={`arc-${i}`} d={this.arc(d)} style={{ fill: this.colors[i] }} />
|
||||||
<text key={`label-${i}`} transform={labelTranslate} style={{ strokeWidth: '0px', fill: LABEL_COLOUR }} textAnchor='middle'>{d.value}</text>
|
<text key={`label-${i}`} transform={labelTranslate} style={{ strokeWidth: '0px', fill: LABEL_COLOUR }} textAnchor='middle'>{d.value}</text>
|
||||||
<text key={`key-${i}`} transform={keyTranslate} style={{ strokeWidth:'0px', fill: this.colors[i] }} textAnchor='middle'>{d.data.label}</text>
|
<text key={`key-${i}`} transform={keyTranslate} style={{ strokeWidth:'0px', fill: this.colors[i] }} textAnchor='middle'>{d.data.label}</text>
|
||||||
</g>
|
</g>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the component
|
* Render the component
|
||||||
* @returns {object} Markup
|
* @returns {object} Markup
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<ContainerDimensions>
|
<ContainerDimensions>
|
||||||
{ ({ width }) => {
|
{ ({ width }) => {
|
||||||
const pie = this.pie(this.props.data),
|
const pie = this.pie(this.props.data),
|
||||||
translate = `translate(${width / 2}, ${width * 0.4})`;
|
translate = `translate(${width / 2}, ${width * 0.4})`;
|
||||||
|
|
||||||
this.arc.outerRadius(width * 0.4);
|
this.arc.outerRadius(width * 0.4);
|
||||||
return (
|
return (
|
||||||
<div width={width} height={width}>
|
<div width={width} height={width}>
|
||||||
<svg style={{ stroke: 'None' }} width={width} height={width * 0.9}>
|
<svg style={{ stroke: 'None' }} width={width} height={width * 0.9}>
|
||||||
<g transform={translate}>
|
<g transform={translate}>
|
||||||
{pie.map((d, i) => this.sliceGenerator(d, i, width))}
|
{pie.map((d, i) => this.sliceGenerator(d, i, width))}
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</ContainerDimensions>
|
</ContainerDimensions>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import TranslatedComponent from './TranslatedComponent';
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
import { Pip } from './SvgIcons';
|
import { Pip } from './SvgIcons';
|
||||||
import { autoBind } from 'react-extras';
|
import autoBind from 'auto-bind';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pips displays SYS/ENG/WEP pips and allows users to change them with key presses by clicking on the relevant area.
|
* Pips displays SYS/ENG/WEP pips and allows users to change them with key presses by clicking on the relevant area.
|
||||||
|
|||||||
@@ -125,15 +125,31 @@ export default class PowerManagement extends TranslatedComponent {
|
|||||||
retractedElem = <td className='ptr disabled upp' colSpan='2' onClick={toggleEnabled}>{translate('disabled')}</td>;
|
retractedElem = <td className='ptr disabled upp' colSpan='2' onClick={toggleEnabled}>{translate('disabled')}</td>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this is a Guardian Shield Reinforcement Package or Guardian Hull Reinforcement Package, or Guardian Module Reinforcement Package, it cannot change priority
|
||||||
|
let priorityField;
|
||||||
|
if (m.symbol) {
|
||||||
|
if (m.symbol.match(/GuardianShield/i) || m.symbol.match(/GuardianHull/i) || m.symbol.match(/GuardianModule/i)) {
|
||||||
|
priorityField = <td>1</td>;
|
||||||
|
} else {
|
||||||
|
priorityField = <td>
|
||||||
|
<span className='flip ptr btn' onClick={this._priority.bind(this, slot, -1)}>►</span>
|
||||||
|
{' ' + (slot.priority + 1) + ' '}
|
||||||
|
<span className='ptr btn' onClick={this._priority.bind(this, slot, 1)}>►</span>
|
||||||
|
</td>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
priorityField = <td>
|
||||||
|
<span className='flip ptr btn' onClick={this._priority.bind(this, slot, -1)}>►</span>
|
||||||
|
{' ' + (slot.priority + 1) + ' '}
|
||||||
|
<span className='ptr btn' onClick={this._priority.bind(this, slot, 1)}>►</span>
|
||||||
|
</td>;
|
||||||
|
}
|
||||||
powerRows.push(<tr key={i} className={cn('highlight', { disabled: !slot.enabled })}>
|
powerRows.push(<tr key={i} className={cn('highlight', { disabled: !slot.enabled })}>
|
||||||
<td className='ptr' style={{ width: '1em' }} onClick={toggleEnabled}>{m.class + m.rating}</td>
|
<td className='ptr' style={{ width: '1em' }} onClick={toggleEnabled}>{m.class + m.rating}</td>
|
||||||
<td className='ptr le shorten cap' onClick={toggleEnabled}>{slotName(translate, slot)}</td>
|
<td className='ptr le shorten cap' onClick={toggleEnabled}>{slotName(translate, slot)}</td>
|
||||||
<td className='ptr' onClick={toggleEnabled}><u>{translate(slot.type)}</u></td>
|
<td className='ptr' onClick={toggleEnabled}><u>{translate(slot.type)}</u></td>
|
||||||
<td>
|
{priorityField}
|
||||||
<span className='flip ptr btn' onClick={this._priority.bind(this, slot, -1)}>►</span>
|
|
||||||
{' ' + (slot.priority + 1) + ' '}
|
|
||||||
<span className='ptr btn' onClick={this._priority.bind(this, slot, 1)}>►</span>
|
|
||||||
</td>
|
|
||||||
<td className='ri ptr' style={{ width: '3.25em' }} onClick={toggleEnabled}>{pwr(m.getPowerUsage())}</td>
|
<td className='ri ptr' style={{ width: '3.25em' }} onClick={toggleEnabled}>{pwr(m.getPowerUsage())}</td>
|
||||||
<td className='ri ptr' style={{ width: '3em' }} onClick={toggleEnabled}><u>{pct(m.getPowerUsage() / ship.powerAvailable)}</u></td>
|
<td className='ri ptr' style={{ width: '3em' }} onClick={toggleEnabled}><u>{pct(m.getPowerUsage() / ship.powerAvailable)}</u></td>
|
||||||
{retractedElem}
|
{retractedElem}
|
||||||
|
|||||||
@@ -52,7 +52,8 @@ export default class ShipSummaryTable extends TranslatedComponent {
|
|||||||
const boostTooltip = canBoost ? 'TT_SUMMARY_BOOST' : canThrust ? 'TT_SUMMARY_BOOST_NONFUNCTIONAL' : 'TT_SUMMARY_SPEED_NONFUNCTIONAL';
|
const boostTooltip = canBoost ? 'TT_SUMMARY_BOOST' : canThrust ? 'TT_SUMMARY_BOOST_NONFUNCTIONAL' : 'TT_SUMMARY_SPEED_NONFUNCTIONAL';
|
||||||
const canJump = ship.getSlotStatus(ship.standard[2]) == 3;
|
const canJump = ship.getSlotStatus(ship.standard[2]) == 3;
|
||||||
const sgMetrics = Calc.shieldMetrics(ship, pips.sys);
|
const sgMetrics = Calc.shieldMetrics(ship, pips.sys);
|
||||||
const shipBoost = canBoost ? Calc.calcBoost(ship) : 'No Boost';
|
const distBoost = canBoost ? Calc.calcBoost(ship) : 'No Boost';
|
||||||
|
//const shipBoost = ship.boostInterval(ship)
|
||||||
const restingHeat = Math.sqrt(((ship.standard[0].m.pgen * ship.standard[0].m.eff) / ship.heatCapacity) / 0.2);
|
const restingHeat = Math.sqrt(((ship.standard[0].m.pgen * ship.standard[0].m.eff) / ship.heatCapacity) / 0.2);
|
||||||
const armourMetrics = Calc.armourMetrics(ship);
|
const armourMetrics = Calc.armourMetrics(ship);
|
||||||
let shieldColour = 'blue';
|
let shieldColour = 'blue';
|
||||||
@@ -72,6 +73,7 @@ export default class ShipSummaryTable extends TranslatedComponent {
|
|||||||
<tr className='main'>
|
<tr className='main'>
|
||||||
<th rowSpan={2} className={ cn({ 'bg-warning-disabled': !canThrust }) }>{translate('speed')}</th>
|
<th rowSpan={2} className={ cn({ 'bg-warning-disabled': !canThrust }) }>{translate('speed')}</th>
|
||||||
<th rowSpan={2} className={ cn({ 'bg-warning-disabled': !canBoost }) }>{translate('boost')}</th>
|
<th rowSpan={2} className={ cn({ 'bg-warning-disabled': !canBoost }) }>{translate('boost')}</th>
|
||||||
|
<th onMouseEnter={termtip.bind(null, 'TT_SUMMARY_BOOST_INTERVALS', { cap: 0 })}colSpan={2} className={ cn({ 'bg-warning-disabled': !canBoost }) }>{translate('boost int')}</th>
|
||||||
<th colSpan={5} className={ cn({ 'bg-warning-disabled': !canJump }) }>{translate('jump range')}</th>
|
<th colSpan={5} className={ cn({ 'bg-warning-disabled': !canJump }) }>{translate('jump range')}</th>
|
||||||
<th rowSpan={2}>{translate('shield')}</th>
|
<th rowSpan={2}>{translate('shield')}</th>
|
||||||
<th rowSpan={2}>{translate('integrity')}</th>
|
<th rowSpan={2}>{translate('integrity')}</th>
|
||||||
@@ -86,10 +88,11 @@ export default class ShipSummaryTable extends TranslatedComponent {
|
|||||||
<th onMouseEnter={termtip.bind(null, 'hull hardness', { cap: 0 })} onMouseLeave={hide} rowSpan={2}>{translate('hrd')}</th>
|
<th onMouseEnter={termtip.bind(null, 'hull hardness', { cap: 0 })} onMouseLeave={hide} rowSpan={2}>{translate('hrd')}</th>
|
||||||
<th rowSpan={2}>{translate('crew')}</th>
|
<th rowSpan={2}>{translate('crew')}</th>
|
||||||
<th onMouseEnter={termtip.bind(null, 'mass lock factor', { cap: 0 })} onMouseLeave={hide} rowSpan={2}>{translate('MLF')}</th>
|
<th onMouseEnter={termtip.bind(null, 'mass lock factor', { cap: 0 })} onMouseLeave={hide} rowSpan={2}>{translate('MLF')}</th>
|
||||||
<th onMouseEnter={termtip.bind(null, 'TT_SUMMARY_BOOST_INTERVAL', { cap: 0 })} onMouseLeave={hide} rowSpan={2}>{translate('boost interval')}</th>
|
|
||||||
<th rowSpan={2}>{translate('resting heat (Beta)')}</th>
|
<th rowSpan={2}>{translate('resting heat (Beta)')}</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th onMouseEnter={termtip.bind(null, 'TT_SUMMARY_BOOST_INTERVAL', { cap: 0 })} onMouseLeave={hide}>{translate('distro')}</th>
|
||||||
|
<th onMouseEnter={termtip.bind(null, 'TT_SUMMARY_SHIP_BOOST_INTERVAL', { cap: 0 })} onMouseLeave={hide}>{translate('ship')}</th>
|
||||||
<th className={ cn({ 'lft': true, 'bg-warning-disabled': !canJump }) }>{translate('max')}</th>
|
<th className={ cn({ 'lft': true, 'bg-warning-disabled': !canJump }) }>{translate('max')}</th>
|
||||||
<th className={ cn({ 'bg-warning-disabled': !canJump }) }>{translate('unladen')}</th>
|
<th className={ cn({ 'bg-warning-disabled': !canJump }) }>{translate('unladen')}</th>
|
||||||
<th className={ cn({ 'bg-warning-disabled': !canJump }) }>{translate('laden')}</th>
|
<th className={ cn({ 'bg-warning-disabled': !canJump }) }>{translate('laden')}</th>
|
||||||
@@ -104,11 +107,13 @@ export default class ShipSummaryTable extends TranslatedComponent {
|
|||||||
<tr>
|
<tr>
|
||||||
<td onMouseEnter={termtip.bind(null, speedTooltip, { cap: 0 })} onMouseLeave={hide}>{ canThrust ? <span>{int(ship.calcSpeed(4, ship.fuelCapacity, 0, false))}{u['m/s']}</span> : <span className='warning'>0 <Warning/></span> }</td>
|
<td onMouseEnter={termtip.bind(null, speedTooltip, { cap: 0 })} onMouseLeave={hide}>{ canThrust ? <span>{int(ship.calcSpeed(4, ship.fuelCapacity, 0, false))}{u['m/s']}</span> : <span className='warning'>0 <Warning/></span> }</td>
|
||||||
<td onMouseEnter={termtip.bind(null, boostTooltip, { cap: 0 })} onMouseLeave={hide}>{ canBoost ? <span>{int(ship.calcSpeed(4, ship.fuelCapacity, 0, true))}{u['m/s']}</span> : <span className='warning'>0 <Warning/></span> }</td>
|
<td onMouseEnter={termtip.bind(null, boostTooltip, { cap: 0 })} onMouseLeave={hide}>{ canBoost ? <span>{int(ship.calcSpeed(4, ship.fuelCapacity, 0, true))}{u['m/s']}</span> : <span className='warning'>0 <Warning/></span> }</td>
|
||||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_MAX_SINGLE_JUMP', { cap: 0 })} onMouseLeave={hide}>{ canJump ? <span>{ f2(Calc.jumpRange(ship.unladenMass + ship.standard[2].m.getMaxFuelPerJump(), ship.standard[2].m, ship.standard[2].m.getMaxFuelPerJump(), ship))}{u.LY}</span> : <span className='warning'>0 <Warning/></span> }</td>
|
<td>{distBoost !== 'No Boost' ? formats.time(distBoost) : 'No Boost'}</td>
|
||||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_UNLADEN_SINGLE_JUMP', { cap: 0 })} onMouseLeave={hide}>{ canJump ? <span>{f2(Calc.jumpRange(ship.unladenMass + ship.fuelCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}</span> : <span className='warning'>0 <Warning/></span> }</td>
|
<td>{ship.boostInt && ship.boostInt !== 'undefined' ? formats.time(ship.boostInt) : 0 }</td>
|
||||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_LADEN_SINGLE_JUMP', { cap: 0 })} onMouseLeave={hide}>{ canJump ? <span>{f2(Calc.jumpRange(ship.unladenMass + ship.fuelCapacity + ship.cargoCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}</span> : <span className='warning'>0 <Warning/></span> }</td>
|
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_MAX_SINGLE_JUMP', { cap: 0 })} onMouseLeave={hide}>{ canJump ? <span>{ f2(Calc.jumpRange(ship.unladenMass - ship.fuelCapacity + ship.standard[2].m.getMaxFuelPerJump(), ship.standard[2].m, ship.standard[2].m.getMaxFuelPerJump(), ship))}{u.LY}</span> : <span className='warning'>0 <Warning/></span> }</td>
|
||||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_UNLADEN_TOTAL_JUMP', { cap: 0 })} onMouseLeave={hide}>{ canJump ? <span>{f2(Calc.totalJumpRange(ship.unladenMass + ship.fuelCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}</span> : <span className='warning'>0 <Warning/></span> }</td>
|
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_UNLADEN_SINGLE_JUMP', { cap: 0 })} onMouseLeave={hide}>{ canJump ? <span>{f2(Calc.jumpRange(ship.unladenMass, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}</span> : <span className='warning'>0 <Warning/></span> }</td>
|
||||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_LADEN_TOTAL_JUMP', { cap: 0 })} onMouseLeave={hide}>{ canJump ? <span>{f2(Calc.totalJumpRange(ship.unladenMass + ship.fuelCapacity + ship.cargoCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}</span> : <span className='warning'>0 <Warning/></span> }</td>
|
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_LADEN_SINGLE_JUMP', { cap: 0 })} onMouseLeave={hide}>{ canJump ? <span>{f2(Calc.jumpRange(ship.unladenMass + ship.cargoCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}</span> : <span className='warning'>0 <Warning/></span> }</td>
|
||||||
|
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_UNLADEN_TOTAL_JUMP', { cap: 0 })} onMouseLeave={hide}>{ canJump ? <span>{f2(Calc.totalJumpRange(ship.unladenMass, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}</span> : <span className='warning'>0 <Warning/></span> }</td>
|
||||||
|
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_LADEN_TOTAL_JUMP', { cap: 0 })} onMouseLeave={hide}>{ canJump ? <span>{f2(Calc.totalJumpRange(ship.unladenMass + ship.cargoCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}</span> : <span className='warning'>0 <Warning/></span> }</td>
|
||||||
<td className={sgClassNames} onMouseEnter={termtip.bind(null, sgTooltip, { cap: 0 })} onMouseLeave={hide}>{int(ship.shield)}{u.MJ}</td>
|
<td className={sgClassNames} onMouseEnter={termtip.bind(null, sgTooltip, { cap: 0 })} onMouseLeave={hide}>{int(ship.shield)}{u.MJ}</td>
|
||||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_INTEGRITY', { cap: 0 })} onMouseLeave={hide}>{int(ship.armour)}</td>
|
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_INTEGRITY', { cap: 0 })} onMouseLeave={hide}>{int(ship.armour)}</td>
|
||||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_DPS', { cap: 0 })} onMouseLeave={hide}>{f1(ship.totalDps)}</td>
|
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_DPS', { cap: 0 })} onMouseLeave={hide}>{f1(ship.totalDps)}</td>
|
||||||
@@ -124,7 +129,6 @@ export default class ShipSummaryTable extends TranslatedComponent {
|
|||||||
<td>{int(ship.hardness)}</td>
|
<td>{int(ship.hardness)}</td>
|
||||||
<td>{ship.crew}</td>
|
<td>{ship.crew}</td>
|
||||||
<td>{ship.masslock}</td>
|
<td>{ship.masslock}</td>
|
||||||
<td>{shipBoost !== 'No Boost' ? formats.time(shipBoost) : 'No Boost'}</td>
|
|
||||||
<td>{formats.pct(restingHeat)}</td>
|
<td>{formats.pct(restingHeat)}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -1,386 +1,386 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
const MARGIN_LR = 8; // Left/ Right margin
|
const MARGIN_LR = 8; // Left/ Right margin
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Horizontal Slider
|
* Horizontal Slider
|
||||||
*/
|
*/
|
||||||
export default class Slider extends React.Component {
|
export default class Slider extends React.Component {
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
axis: false,
|
axis: false,
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 1,
|
max: 1,
|
||||||
scale: 1 // SVG render scale
|
scale: 1 // SVG render scale
|
||||||
};
|
};
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
axis: PropTypes.bool,
|
axis: PropTypes.bool,
|
||||||
axisUnit: PropTypes.string,// units (T, M, etc.)
|
axisUnit: PropTypes.string,// units (T, M, etc.)
|
||||||
max: PropTypes.number,
|
max: PropTypes.number,
|
||||||
min: PropTypes.number,
|
min: PropTypes.number,
|
||||||
onChange: PropTypes.func.isRequired,// function which determins percent value
|
onChange: PropTypes.func.isRequired,// function which determins percent value
|
||||||
onResize: PropTypes.func,
|
onResize: PropTypes.func,
|
||||||
percent: PropTypes.number.isRequired,// value of slider
|
percent: PropTypes.number.isRequired,// value of slider
|
||||||
scale: PropTypes.number
|
scale: PropTypes.number
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
*/
|
*/
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this._down = this._down.bind(this);
|
this._down = this._down.bind(this);
|
||||||
this._move = this._move.bind(this);
|
this._move = this._move.bind(this);
|
||||||
this._up = this._up.bind(this);
|
this._up = this._up.bind(this);
|
||||||
this._keyup = this._keyup.bind(this);
|
this._keyup = this._keyup.bind(this);
|
||||||
this._keydown = this._keydown.bind(this);
|
this._keydown = this._keydown.bind(this);
|
||||||
this._touchstart = this._touchstart.bind(this);
|
this._touchstart = this._touchstart.bind(this);
|
||||||
this._touchend = this._touchend.bind(this);
|
this._touchend = this._touchend.bind(this);
|
||||||
|
|
||||||
this._updatePercent = this._updatePercent.bind(this);
|
this._updatePercent = this._updatePercent.bind(this);
|
||||||
this._updateDimensions = this._updateDimensions.bind(this);
|
this._updateDimensions = this._updateDimensions.bind(this);
|
||||||
|
|
||||||
this.state = { width: 0 };
|
this.state = { width: 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On Mouse/Touch down handler
|
* On Mouse/Touch down handler
|
||||||
* @param {SyntheticEvent} event Event
|
* @param {SyntheticEvent} event Event
|
||||||
*/
|
*/
|
||||||
_down(event) {
|
_down(event) {
|
||||||
let rect = event.currentTarget.getBoundingClientRect();
|
let rect = event.currentTarget.getBoundingClientRect();
|
||||||
this.left = rect.left;
|
this.left = rect.left;
|
||||||
this.width = rect.width;
|
this.width = rect.width;
|
||||||
this._move(event);
|
this._move(event);
|
||||||
this.touchStartTimer = setTimeout(() => this.sliderInputBox._setDisplay('block'), 1500);
|
this.touchStartTimer = setTimeout(() => this.sliderInputBox._setDisplay('block'), 1500);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the slider percentage on move
|
* Update the slider percentage on move
|
||||||
* @param {SyntheticEvent} event Event
|
* @param {SyntheticEvent} event Event
|
||||||
*/
|
*/
|
||||||
_move(event) {
|
_move(event) {
|
||||||
if(this.width !== null && this.left != null) {
|
if(this.width !== null && this.left != null) {
|
||||||
let clientX = event.touches ? event.touches[0].clientX : event.clientX;
|
let clientX = event.touches ? event.touches[0].clientX : event.clientX;
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this._updatePercent(clientX - this.left, this.width);
|
this._updatePercent(clientX - this.left, this.width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On Mouse/Touch up handler
|
* On Mouse/Touch up handler
|
||||||
* @param {Event} event DOM Event
|
* @param {Event} event DOM Event
|
||||||
*/
|
*/
|
||||||
_up(event) {
|
_up(event) {
|
||||||
this.sliderInputBox.sliderVal.focus();
|
this.sliderInputBox.sliderVal.focus();
|
||||||
clearTimeout(this.touchStartTimer);
|
clearTimeout(this.touchStartTimer);
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.left = null;
|
this.left = null;
|
||||||
this.width = null;
|
this.width = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Key up handler for keyboard.
|
* Key up handler for keyboard.
|
||||||
* display the number field then set focus to it
|
* display the number field then set focus to it
|
||||||
* when "Enter" key is pressed
|
* when "Enter" key is pressed
|
||||||
* @param {Event} event Keyboard event
|
* @param {Event} event Keyboard event
|
||||||
*/
|
*/
|
||||||
_keyup(event) {
|
_keyup(event) {
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case 'Enter':
|
case 'Enter':
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.sliderInputBox._setDisplay('block');
|
this.sliderInputBox._setDisplay('block');
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Key down handler
|
* Key down handler
|
||||||
* increment slider position by +/- 1 when right/left arrow key is pressed or held
|
* increment slider position by +/- 1 when right/left arrow key is pressed or held
|
||||||
* @param {Event} event Keyboard even
|
* @param {Event} event Keyboard even
|
||||||
*/
|
*/
|
||||||
_keydown(event) {
|
_keydown(event) {
|
||||||
let newVal = this.props.percent * this.props.max;
|
let newVal = this.props.percent * this.props.max;
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case 'ArrowRight':
|
case 'ArrowRight':
|
||||||
newVal += 1;
|
newVal += 1;
|
||||||
if (newVal <= this.props.max) this.props.onChange(newVal / this.props.max);
|
if (newVal <= this.props.max) this.props.onChange(newVal / this.props.max);
|
||||||
return;
|
return;
|
||||||
case 'ArrowLeft':
|
case 'ArrowLeft':
|
||||||
newVal -= 1;
|
newVal -= 1;
|
||||||
if (newVal >= 0) this.props.onChange(newVal / this.props.max);
|
if (newVal >= 0) this.props.onChange(newVal / this.props.max);
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Touch start handler
|
* Touch start handler
|
||||||
* @param {Event} event DOM Event
|
* @param {Event} event DOM Event
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
_touchstart(event) {
|
_touchstart(event) {
|
||||||
this.touchStartTimer = setTimeout(() => this.sliderInputBox._setDisplay('block'), 1500);
|
this.touchStartTimer = setTimeout(() => this.sliderInputBox._setDisplay('block'), 1500);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Touch end handler
|
* Touch end handler
|
||||||
* @param {Event} event DOM Event
|
* @param {Event} event DOM Event
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
_touchend(event) {
|
_touchend(event) {
|
||||||
this.sliderInputBox.sliderVal.focus();
|
this.sliderInputBox.sliderVal.focus();
|
||||||
clearTimeout(this.touchStartTimer);
|
clearTimeout(this.touchStartTimer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if the user is still dragging
|
* Determine if the user is still dragging
|
||||||
* @param {SyntheticEvent} event Event
|
* @param {SyntheticEvent} event Event
|
||||||
*/
|
*/
|
||||||
_enter(event) {
|
_enter(event) {
|
||||||
if(event.buttons !== 1) {
|
if(event.buttons !== 1) {
|
||||||
this.left = null;
|
this.left = null;
|
||||||
this.width = null;
|
this.width = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the slider percentage
|
* Update the slider percentage
|
||||||
* @param {number} pos Slider drag position
|
* @param {number} pos Slider drag position
|
||||||
* @param {number} width Slider width
|
* @param {number} width Slider width
|
||||||
* @param {Event} event DOM Event
|
* @param {Event} event DOM Event
|
||||||
*/
|
*/
|
||||||
_updatePercent(pos, width) {
|
_updatePercent(pos, width) {
|
||||||
this.props.onChange(Math.min(Math.max(pos / width, 0), 1));
|
this.props.onChange(Math.min(Math.max(pos / width, 0), 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update dimenions from rendered DOM
|
* Update dimenions from rendered DOM
|
||||||
*/
|
*/
|
||||||
_updateDimensions() {
|
_updateDimensions() {
|
||||||
this.setState({
|
this.setState({
|
||||||
outerWidth: this.node.getBoundingClientRect().width
|
outerWidth: this.node.getBoundingClientRect().width
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add listeners when about to mount
|
* Add listeners when about to mount
|
||||||
*/
|
*/
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
if (this.props.onResize) {
|
if (this.props.onResize) {
|
||||||
this.resizeListener = this.props.onResize(this._updateDimensions);
|
this.resizeListener = this.props.onResize(this._updateDimensions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trigger DOM updates on mount
|
* Trigger DOM updates on mount
|
||||||
*/
|
*/
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this._updateDimensions();
|
this._updateDimensions();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove listeners on unmount
|
* Remove listeners on unmount
|
||||||
*/
|
*/
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
if (this.resizeListener) {
|
if (this.resizeListener) {
|
||||||
this.resizeListener.remove();
|
this.resizeListener.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the slider
|
* Render the slider
|
||||||
* @return {React.Component} The slider
|
* @return {React.Component} The slider
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
let outerWidth = this.state.outerWidth;
|
let outerWidth = this.state.outerWidth;
|
||||||
let { axis, axisUnit, min, max, scale } = this.props;
|
let { axis, axisUnit, min, max, scale } = this.props;
|
||||||
let style = {
|
let style = {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: axis ? '2.5em' : '1.5em',
|
height: axis ? '2.5em' : '1.5em',
|
||||||
boxSizing: 'border-box'
|
boxSizing: 'border-box'
|
||||||
};
|
};
|
||||||
if (!outerWidth) {
|
if (!outerWidth) {
|
||||||
return <svg style={style} ref={node => this.node = node} />;
|
return <svg style={style} ref={node => this.node = node} />;
|
||||||
}
|
}
|
||||||
let margin = MARGIN_LR * scale;
|
let margin = MARGIN_LR * scale;
|
||||||
let width = outerWidth - (margin * 2);
|
let width = outerWidth - (margin * 2);
|
||||||
let pctPos = width * this.props.percent;
|
let pctPos = width * this.props.percent;
|
||||||
return <div><svg
|
return <div><svg
|
||||||
onMouseUp={this._up} onMouseEnter={this._enter.bind(this)} onMouseMove={this._move} onKeyUp={this._keyup} onKeyDown={this._keydown} style={style} ref={node => this.node = node} tabIndex="0">
|
onMouseUp={this._up} onMouseEnter={this._enter.bind(this)} onMouseMove={this._move} onKeyUp={this._keyup} onKeyDown={this._keydown} style={style} ref={node => this.node = node} tabIndex="0">
|
||||||
<rect className='primary' style={{ opacity: 0.3 }} x={margin} y='0.25em' rx='0.3em' ry='0.3em' width={width} height='0.7em' />
|
<rect className='primary' style={{ opacity: 0.3 }} x={margin} y='0.25em' rx='0.3em' ry='0.3em' width={width} height='0.7em' />
|
||||||
<rect className='primary-disabled' x={margin} y='0.45em' rx='0.15em' ry='0.15em' width={pctPos} height='0.3em' />
|
<rect className='primary-disabled' x={margin} y='0.45em' rx='0.15em' ry='0.15em' width={pctPos} height='0.3em' />
|
||||||
<circle className='primary' r={margin} cy='0.6em' cx={pctPos + margin} />
|
<circle className='primary' r={margin} cy='0.6em' cx={pctPos + margin} />
|
||||||
<rect x={margin} width={width} height='100%' fillOpacity='0' style={{ cursor: 'col-resize' }} onMouseDown={this._down} onTouchMove={this._move} onTouchStart={this._down} onTouchEnd={this._touchend} />
|
<rect x={margin} width={width} height='100%' fillOpacity='0' style={{ cursor: 'col-resize' }} onMouseDown={this._down} onTouchMove={this._move} onTouchStart={this._down} onTouchEnd={this._touchend} />
|
||||||
{axis && <g style={{ fontSize: '.7em' }}>
|
{axis && <g style={{ fontSize: '.7em' }}>
|
||||||
<text className='primary-disabled' y='3em' x={margin} style={{ textAnchor: 'middle' }}>{min + axisUnit}</text>
|
<text className='primary-disabled' y='3em' x={margin} style={{ textAnchor: 'middle' }}>{min + axisUnit}</text>
|
||||||
<text className='primary-disabled' y='3em' x='50%' style={{ textAnchor: 'middle' }}>{(min + max / 2) + axisUnit}</text>
|
<text className='primary-disabled' y='3em' x='50%' style={{ textAnchor: 'middle' }}>{(min + max / 2) + axisUnit}</text>
|
||||||
<text className='primary-disabled' y='3em' x='100%' style={{ textAnchor: 'end' }}>{max + axisUnit}</text>
|
<text className='primary-disabled' y='3em' x='100%' style={{ textAnchor: 'end' }}>{max + axisUnit}</text>
|
||||||
</g>}
|
</g>}
|
||||||
</svg>
|
</svg>
|
||||||
<TextInputBox ref={(tb) => this.sliderInputBox = tb}
|
<TextInputBox ref={(tb) => this.sliderInputBox = tb}
|
||||||
onChange={this.props.onChange}
|
onChange={this.props.onChange}
|
||||||
percent={this.props.percent}
|
percent={this.props.percent}
|
||||||
axisUnit={this.props.axisUnit}
|
axisUnit={this.props.axisUnit}
|
||||||
scale={this.props.scale}
|
scale={this.props.scale}
|
||||||
max={this.props.max}
|
max={this.props.max}
|
||||||
/>
|
/>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* New component to add keyboard support for sliders - works on all devices (desktop, iOS, Android)
|
* New component to add keyboard support for sliders - works on all devices (desktop, iOS, Android)
|
||||||
**/
|
**/
|
||||||
class TextInputBox extends React.Component {
|
class TextInputBox extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
axisUnit: PropTypes.string,// units (T, M, etc.)
|
axisUnit: PropTypes.string,// units (T, M, etc.)
|
||||||
max: PropTypes.number,
|
max: PropTypes.number,
|
||||||
onChange: PropTypes.func.isRequired,// function which determins percent value
|
onChange: PropTypes.func.isRequired,// function which determins percent value
|
||||||
percent: PropTypes.number.isRequired,// value of slider
|
percent: PropTypes.number.isRequired,// value of slider
|
||||||
scale: PropTypes.number
|
scale: PropTypes.number
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Determine if the user is still dragging
|
* Determine if the user is still dragging
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
*/
|
*/
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this._handleFocus = this._handleFocus.bind(this);
|
this._handleFocus = this._handleFocus.bind(this);
|
||||||
this._handleBlur = this._handleBlur.bind(this);
|
this._handleBlur = this._handleBlur.bind(this);
|
||||||
this._handleChange = this._handleChange.bind(this);
|
this._handleChange = this._handleChange.bind(this);
|
||||||
this._keyup = this._keyup.bind(this);
|
this._keyup = this._keyup.bind(this);
|
||||||
this.state = this._getInitialState();
|
this.state = this._getInitialState();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Update input value if slider changes will change props/state
|
* Update input value if slider changes will change props/state
|
||||||
* @param {Object} nextProps React Component properites
|
* @param {Object} nextProps React Component properites
|
||||||
* @param {Object} nextState React Component state values
|
* @param {Object} nextState React Component state values
|
||||||
*/
|
*/
|
||||||
componentWillReceiveProps(nextProps, nextState) {
|
componentWillReceiveProps(nextProps, nextState) {
|
||||||
let nextValue = nextProps.percent * nextProps.max;
|
let nextValue = nextProps.percent * nextProps.max;
|
||||||
// See https://stackoverflow.com/questions/32414308/updating-state-on-props-change-in-react-form
|
// See https://stackoverflow.com/questions/32414308/updating-state-on-props-change-in-react-form
|
||||||
if (nextValue !== this.state.inputValue && nextValue <= nextProps.max) {
|
if (nextValue !== this.state.inputValue && nextValue <= nextProps.max) {
|
||||||
this.setState({ inputValue: nextValue });
|
this.setState({ inputValue: nextValue });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Update slider textbox visibility/values if changes are made to slider
|
* Update slider textbox visibility/values if changes are made to slider
|
||||||
* @param {Object} prevProps React Component properites
|
* @param {Object} prevProps React Component properites
|
||||||
* @param {Object} prevState React Component state values
|
* @param {Object} prevState React Component state values
|
||||||
*/
|
*/
|
||||||
componentDidUpdate(prevProps, prevState) {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
if (prevState.divStyle.display == 'none' && this.state.divStyle.display == 'block') {
|
if (prevState.divStyle.display == 'none' && this.state.divStyle.display == 'block') {
|
||||||
this.enterTimer = setTimeout(() => this.sliderVal.focus(), 10);
|
this.enterTimer = setTimeout(() => this.sliderVal.focus(), 10);
|
||||||
}
|
}
|
||||||
if (prevProps.max !== this.props.max && this.state.inputValue > this.props.max) {
|
if (prevProps.max !== this.props.max && this.state.inputValue > this.props.max) {
|
||||||
// they chose a different module
|
// they chose a different module
|
||||||
this.setState({ inputValue: this.props.max });
|
this.setState({ inputValue: this.props.max });
|
||||||
}
|
}
|
||||||
if (this.state.inputValue != prevState.inputValue && prevProps.max == this.props.max) {
|
if (this.state.inputValue != prevState.inputValue && prevProps.max == this.props.max) {
|
||||||
this.props.onChange(this.state.inputValue / this.props.max);
|
this.props.onChange(this.state.inputValue / this.props.max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Set initial state for the textbox.
|
* Set initial state for the textbox.
|
||||||
* We may want to rethink this to
|
* We may want to rethink this to
|
||||||
* try and make it a stateless component
|
* try and make it a stateless component
|
||||||
* @returns {object} React state object with initial values set
|
* @returns {object} React state object with initial values set
|
||||||
*/
|
*/
|
||||||
_getInitialState() {
|
_getInitialState() {
|
||||||
return {
|
return {
|
||||||
divStyle: { display:'none' },
|
divStyle: { display:'none' },
|
||||||
inputStyle: { width:'4em' },
|
inputStyle: { width:'4em' },
|
||||||
labelStyle: { marginLeft: '.1em' },
|
labelStyle: { marginLeft: '.1em' },
|
||||||
maxLength:5,
|
maxLength:5,
|
||||||
size:5,
|
size:5,
|
||||||
min:0,
|
min:0,
|
||||||
tabIndex:-1,
|
tabIndex:-1,
|
||||||
type:'number',
|
type:'number',
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
inputValue: this.props.percent * this.props.max
|
inputValue: this.props.percent * this.props.max
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {string} val block or none
|
* @param {string} val block or none
|
||||||
*/
|
*/
|
||||||
_setDisplay(val) {
|
_setDisplay(val) {
|
||||||
this.setState({
|
this.setState({
|
||||||
divStyle: { display:val }
|
divStyle: { display:val }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Update the input value
|
* Update the input value
|
||||||
* when textbox gets focus
|
* when textbox gets focus
|
||||||
*/
|
*/
|
||||||
_handleFocus() {
|
_handleFocus() {
|
||||||
this.setState({
|
this.setState({
|
||||||
inputValue:this._getValue()
|
inputValue:this._getValue()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Update inputValue when textbox loses focus
|
* Update inputValue when textbox loses focus
|
||||||
*/
|
*/
|
||||||
_handleBlur() {
|
_handleBlur() {
|
||||||
this._setDisplay('none');
|
this._setDisplay('none');
|
||||||
if (this.state.inputValue !== '') {
|
if (this.state.inputValue !== '') {
|
||||||
this.props.onChange(this.state.inputValue / this.props.max);
|
this.props.onChange(this.state.inputValue / this.props.max);
|
||||||
} else {
|
} else {
|
||||||
this.setState({
|
this.setState({
|
||||||
inputValue: this.props.percent * this.props.max
|
inputValue: this.props.percent * this.props.max
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Get the value in the text box
|
* Get the value in the text box
|
||||||
* @returns {number} inputValue Value of the input box
|
* @returns {number} inputValue Value of the input box
|
||||||
*/
|
*/
|
||||||
_getValue() {
|
_getValue() {
|
||||||
return this.state.inputValue;
|
return this.state.inputValue;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Update and set limits on input box
|
* Update and set limits on input box
|
||||||
* values depending on what user
|
* values depending on what user
|
||||||
* has selected
|
* has selected
|
||||||
*
|
*
|
||||||
* @param {SyntheticEvent} event ReactJs onChange event
|
* @param {SyntheticEvent} event ReactJs onChange event
|
||||||
*/
|
*/
|
||||||
_handleChange(event) {
|
_handleChange(event) {
|
||||||
if (event.target.value < 0) {
|
if (event.target.value < 0) {
|
||||||
this.setState({ inputValue: 0 });
|
this.setState({ inputValue: 0 });
|
||||||
} else if (event.target.value <= this.props.max) {
|
} else if (event.target.value <= this.props.max) {
|
||||||
this.setState({ inputValue: event.target.value });
|
this.setState({ inputValue: event.target.value });
|
||||||
} else {
|
} else {
|
||||||
this.setState({ inputValue: this.props.max });
|
this.setState({ inputValue: this.props.max });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Key up handler for input field.
|
* Key up handler for input field.
|
||||||
* If user hits Enter key, blur/close the input field
|
* If user hits Enter key, blur/close the input field
|
||||||
* @param {Event} event Keyboard event
|
* @param {Event} event Keyboard event
|
||||||
*/
|
*/
|
||||||
_keyup(event) {
|
_keyup(event) {
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case 'Enter':
|
case 'Enter':
|
||||||
this.sliderVal.blur();
|
this.sliderVal.blur();
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Get the value in the text box
|
* Get the value in the text box
|
||||||
* @return {React.Component} Text Input component for Slider
|
* @return {React.Component} Text Input component for Slider
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
let { axisUnit, onChange, percent, scale } = this.props;
|
let { axisUnit, onChange, percent, scale } = this.props;
|
||||||
return <div style={this.state.divStyle}><input style={this.state.inputStyle} value={this._getValue()} min={this.state.min} max={this.props.max} onChange={this._handleChange} onKeyUp={this._keyup} tabIndex={this.state.tabIndex} maxLength={this.state.maxLength} size={this.state.size} onBlur={() => {this._handleBlur();}} onFocus={() => {this._handleFocus();}} type={this.state.type} ref={(ip) => this.sliderVal = ip}/><text className="primary upp" style={this.state.labelStyle}>{this.props.axisUnit}</text></div>;
|
return <div style={this.state.divStyle}><input style={this.state.inputStyle} value={this._getValue()} min={this.state.min} max={this.props.max} onChange={this._handleChange} onKeyUp={this._keyup} tabIndex={this.state.tabIndex} maxLength={this.state.maxLength} size={this.state.size} onBlur={() => {this._handleBlur();}} onFocus={() => {this._handleFocus();}} type={this.state.type} ref={(ip) => this.sliderVal = ip}/><text className="primary upp" style={this.state.labelStyle}>{this.props.axisUnit}</text></div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ export default class Slot extends TranslatedComponent {
|
|||||||
let translate = language.translate;
|
let translate = language.translate;
|
||||||
let { ship, m, enabled, dropClass, dragOver, onOpen, onChange, selected, eligible, onSelect, warning, availableModules } = this.props;
|
let { ship, m, enabled, dropClass, dragOver, onOpen, onChange, selected, eligible, onSelect, warning, availableModules } = this.props;
|
||||||
let slotDetails, modificationsMarker, menu;
|
let slotDetails, modificationsMarker, menu;
|
||||||
|
let missing = false;
|
||||||
|
|
||||||
if (!selected) {
|
if (!selected) {
|
||||||
// If not selected then sure that modifications flag is unset
|
// If not selected then sure that modifications flag is unset
|
||||||
@@ -108,6 +109,11 @@ export default class Slot extends TranslatedComponent {
|
|||||||
if (m) {
|
if (m) {
|
||||||
slotDetails = this._getSlotDetails(m, enabled, translate, language.formats, language.units); // Must be implemented by sub classes
|
slotDetails = this._getSlotDetails(m, enabled, translate, language.formats, language.units); // Must be implemented by sub classes
|
||||||
modificationsMarker = JSON.stringify(m);
|
modificationsMarker = JSON.stringify(m);
|
||||||
|
if(typeof m.grp !== 'undefined' || m.grp !== null) {
|
||||||
|
if(m.grp == "mh" || m.grp == "mm") {
|
||||||
|
missing = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
slotDetails = <div className={'empty'}>{translate(eligible ? 'emptyrestricted' : 'empty')}</div>;
|
slotDetails = <div className={'empty'}>{translate(eligible ? 'emptyrestricted' : 'empty')}</div>;
|
||||||
modificationsMarker = '';
|
modificationsMarker = '';
|
||||||
@@ -138,13 +144,16 @@ export default class Slot extends TranslatedComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement touch dragging
|
// TODO: implement touch dragging
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn('slot', dropClass, { selected })} onClick={onOpen} onKeyDown={this._keyDown} onContextMenu={this._contextMenu} onDragOver={dragOver} tabIndex="0" ref={slotDiv => this.slotDiv = slotDiv}>
|
<div className={cn('slot', dropClass, { selected })} onClick={onOpen} onKeyDown={this._keyDown} onContextMenu={this._contextMenu} onDragOver={dragOver} tabIndex="0" ref={slotDiv => this.slotDiv = slotDiv}>
|
||||||
<div className='details-container'>
|
{
|
||||||
|
// If missing module/hardpoint, set the div container to warning status.
|
||||||
|
}
|
||||||
|
<div className={ missing === true ? 'details-container warning' : 'details-container'}>
|
||||||
<div className='sz'>{this._getMaxClassLabel(translate)}</div>
|
<div className='sz'>{this._getMaxClassLabel(translate)}</div>
|
||||||
{slotDetails}
|
{slotDetails}
|
||||||
</div>
|
</div>
|
||||||
{menu}
|
{menu}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -93,6 +93,11 @@ export default class StandardSlot extends TranslatedComponent {
|
|||||||
this._modificationsSelected = false;
|
this._modificationsSelected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this is a missing module, therefore has the 'info' field, set the warning value on the module to be true when loaded.
|
||||||
|
if (m.info) {
|
||||||
|
warning = () => true;
|
||||||
|
}
|
||||||
|
|
||||||
const modificationsMarker = JSON.stringify(m);
|
const modificationsMarker = JSON.stringify(m);
|
||||||
|
|
||||||
if (selected) {
|
if (selected) {
|
||||||
@@ -124,14 +129,14 @@ export default class StandardSlot extends TranslatedComponent {
|
|||||||
<div className={cn('details-container', { warning: warning && warning(slot.m), disabled: m.grp !== 'bh' && !slot.enabled })}>
|
<div className={cn('details-container', { warning: warning && warning(slot.m), disabled: m.grp !== 'bh' && !slot.enabled })}>
|
||||||
<div className={'sz'}>{m.grp == 'bh' ? m.name.charAt(0) : slot.maxClass}</div>
|
<div className={'sz'}>{m.grp == 'bh' ? m.name.charAt(0) : slot.maxClass}</div>
|
||||||
<div>
|
<div>
|
||||||
<div className={'l'}>{classRating} {translate(m.name || m.grp)}{m.mods && Object.keys(m.mods).length > 0 ? <span className='r' onMouseOver={termtip.bind(null, modTT)} onMouseOut={tooltip.bind(null, null)}><Modified /></span> : null }</div>
|
<div className={'l'}>{classRating} {m.getInfo() ? translate(m.ukName) : translate(m.name || m.grp)}{m.mods && Object.keys(m.mods).length > 0 ? <span className='r' onMouseOver={termtip.bind(null, modTT)} onMouseOut={tooltip.bind(null, null)}><Modified /></span> : null }</div>
|
||||||
<div className={'r'}>{formats.round(mass)}{units.T}</div>
|
<div className={'r'}>{formats.round(mass)}{units.T}</div>
|
||||||
<div/>
|
<div/>
|
||||||
<div className={'cb'}>
|
<div className={'cb'}>
|
||||||
{ m.getMinMass() ? <div className='l'>{translate('minimum mass')}: {formats.int(m.getMinMass())}{units.T}</div> : null }
|
{ m.getMinMass() ? <div className='l'>{translate('minmass')}: {formats.int(m.getMinMass())}{units.T}</div> : null }
|
||||||
{ m.getOptMass() ? <div className='l'>{translate('optimal mass')}: {formats.int(m.getOptMass())}{units.T}</div> : null }
|
{ m.getOptMass() ? <div className='l'>{translate('optmass')}: {formats.int(m.getOptMass())}{units.T}</div> : null }
|
||||||
{ m.getMaxMass() ? <div className='l'>{translate('max mass')}: {formats.int(m.getMaxMass())}{units.T}</div> : null }
|
{ m.getMaxMass() ? <div className='l'>{translate('maxmass')}: {formats.int(m.getMaxMass())}{units.T}</div> : null }
|
||||||
{ m.getOptMul() ? <div className='l'>{translate('optimal multiplier')}: {formats.rPct(m.getOptMul())}</div> : null }
|
{ m.getOptMul() ? <div className='l'>{translate('optmul')}: {formats.rPct(m.getOptMul())}</div> : null }
|
||||||
{ m.getRange() ? <div className='l'>{translate('range', m.grp)}: {formats.f2(m.getRange())}{units.km}</div> : null }
|
{ m.getRange() ? <div className='l'>{translate('range', m.grp)}: {formats.f2(m.getRange())}{units.km}</div> : null }
|
||||||
{ m.time ? <div className='l'>{translate('time')}: {formats.time(m.time)}</div> : null }
|
{ m.time ? <div className='l'>{translate('time')}: {formats.time(m.time)}</div> : null }
|
||||||
{ m.getThermalEfficiency() ? <div className='l'>{translate('efficiency')}: {formats.f2(m.getThermalEfficiency())}</div> : null }
|
{ m.getThermalEfficiency() ? <div className='l'>{translate('efficiency')}: {formats.f2(m.getThermalEfficiency())}</div> : null }
|
||||||
@@ -144,7 +149,8 @@ export default class StandardSlot extends TranslatedComponent {
|
|||||||
{ showModuleResistances && m.getKineticResistance() ? <div className='l'>{translate('kinres')}: {formats.pct(m.getKineticResistance())}</div> : null }
|
{ showModuleResistances && m.getKineticResistance() ? <div className='l'>{translate('kinres')}: {formats.pct(m.getKineticResistance())}</div> : null }
|
||||||
{ showModuleResistances && m.getThermalResistance() ? <div className='l'>{translate('thermres')}: {formats.pct(m.getThermalResistance())}</div> : null }
|
{ showModuleResistances && m.getThermalResistance() ? <div className='l'>{translate('thermres')}: {formats.pct(m.getThermalResistance())}</div> : null }
|
||||||
{ m.getIntegrity() ? <div className='l'>{translate('integrity')}: {formats.int(m.getIntegrity())}</div> : null }
|
{ m.getIntegrity() ? <div className='l'>{translate('integrity')}: {formats.int(m.getIntegrity())}</div> : null }
|
||||||
{ validMods.length > 0 ? <div className='r' tabIndex="0" ref={ modButton => this.modButton = modButton }><button tabIndex="-1" onClick={this._toggleModifications.bind(this)} onContextMenu={stopCtxPropagation} onMouseOver={termtip.bind(null, 'modifications')} onMouseOut={tooltip.bind(null, null)}><ListModifications /></button></div> : null }
|
{ m.getInfo() ? <div className='l'>{translate(m.getInfo())}</div> : null }
|
||||||
|
{ m.getInfo() ? <div className='r'></div> : validMods.length > 0 ? <div className='r' tabIndex="0" ref={ modButton => this.modButton = modButton }><button tabIndex="-1" onClick={this._toggleModifications.bind(this)} onContextMenu={stopCtxPropagation} onMouseOver={termtip.bind(null, 'modifications')} onMouseOut={tooltip.bind(null, null)}><ListModifications /></button></div> : null }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ export default class StandardSlotSection extends SlotSection {
|
|||||||
selected={currentMenu == st[4]}
|
selected={currentMenu == st[4]}
|
||||||
onChange={this.props.onChange}
|
onChange={this.props.onChange}
|
||||||
ship={ship}
|
ship={ship}
|
||||||
warning={m => m instanceof Module ? m.getEnginesCapacity() <= ship.boostEnergy : m.engcap <= ship.boostEnergy}
|
warning={m => m instanceof Module ? m.getEnginesCapacity() < ship.boostEnergy : m.engcap < ship.boostEnergy}
|
||||||
/>;
|
/>;
|
||||||
|
|
||||||
slots[6] = <StandardSlot
|
slots[6] = <StandardSlot
|
||||||
|
|||||||
@@ -1,80 +1,80 @@
|
|||||||
import TranslatedComponent from './TranslatedComponent';
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import ContainerDimensions from 'react-container-dimensions';
|
import ContainerDimensions from 'react-container-dimensions';
|
||||||
import { BarChart, Bar, XAxis, YAxis, LabelList } from 'recharts';
|
import { BarChart, Bar, XAxis, YAxis, LabelList } from 'recharts';
|
||||||
|
|
||||||
const CORIOLIS_COLOURS = ['#FF8C0D', '#1FB0FF', '#71A052', '#D5D54D'];
|
const CORIOLIS_COLOURS = ['#FF8C0D', '#1FB0FF', '#71A052', '#D5D54D'];
|
||||||
const LABEL_COLOUR = '#000000';
|
const LABEL_COLOUR = '#000000';
|
||||||
const AXIS_COLOUR = '#C06400';
|
const AXIS_COLOUR = '#C06400';
|
||||||
|
|
||||||
const ASPECT = 1;
|
const ASPECT = 1;
|
||||||
|
|
||||||
const merge = function(one, two) {
|
const merge = function(one, two) {
|
||||||
return Object.assign({}, one, two);
|
return Object.assign({}, one, two);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A vertical bar chart
|
* A vertical bar chart
|
||||||
*/
|
*/
|
||||||
export default class VerticalBarChart extends TranslatedComponent {
|
export default class VerticalBarChart extends TranslatedComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
data : PropTypes.array.isRequired,
|
data : PropTypes.array.isRequired,
|
||||||
yMax : PropTypes.number
|
yMax : PropTypes.number
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
* @param {Object} context React Component context
|
* @param {Object} context React Component context
|
||||||
*/
|
*/
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this._termtip = this._termtip.bind(this);
|
this._termtip = this._termtip.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the bar chart
|
* Render the bar chart
|
||||||
* @returns {Object} the markup
|
* @returns {Object} the markup
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
const { tooltip, termtip } = this.context;
|
const { tooltip, termtip } = this.context;
|
||||||
|
|
||||||
// Calculate maximum for Y
|
// Calculate maximum for Y
|
||||||
let dataMax = Math.max(...this.props.data.map(d => d.value));
|
let dataMax = Math.max(...this.props.data.map(d => d.value));
|
||||||
if (dataMax == -Infinity) dataMax = 0;
|
if (dataMax == -Infinity) dataMax = 0;
|
||||||
let yMax = this.props.yMax ? Math.round(this.props.yMax) : 0;
|
let yMax = this.props.yMax ? Math.round(this.props.yMax) : 0;
|
||||||
const localMax = Math.max(dataMax, yMax);
|
const localMax = Math.max(dataMax, yMax);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ContainerDimensions>
|
<ContainerDimensions>
|
||||||
{ ({ width }) => (
|
{ ({ width }) => (
|
||||||
<div width='100%'>
|
<div width='100%'>
|
||||||
<BarChart width={width} height={width * ASPECT} data={this.props.data} margin={{ top: 5, right: 5, left: 5, bottom: 5 }}>
|
<BarChart width={width} height={width * ASPECT} data={this.props.data} margin={{ top: 5, right: 5, left: 5, bottom: 5 }}>
|
||||||
<XAxis interval={0} fontSize='0.8em' stroke={AXIS_COLOUR} dataKey='label' />
|
<XAxis interval={0} fontSize='0.8em' stroke={AXIS_COLOUR} dataKey='label' />
|
||||||
<YAxis interval={'preserveStart'} tickCount={11} fontSize='0.8em' stroke={AXIS_COLOUR} type='number' domain={[0, localMax]}/>
|
<YAxis interval={'preserveStart'} tickCount={11} fontSize='0.8em' stroke={AXIS_COLOUR} type='number' domain={[0, localMax]}/>
|
||||||
<Bar dataKey='value' fill={CORIOLIS_COLOURS[0]} isAnimationActive={false} onMouseOver={this._termtip} onMouseOut={tooltip.bind(null, null)}>
|
<Bar dataKey='value' fill={CORIOLIS_COLOURS[0]} isAnimationActive={false} onMouseOver={this._termtip} onMouseOut={tooltip.bind(null, null)}>
|
||||||
<LabelList dataKey='value' position='insideTop'/>
|
<LabelList dataKey='value' position='insideTop'/>
|
||||||
</Bar>
|
</Bar>
|
||||||
</BarChart>
|
</BarChart>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</ContainerDimensions>
|
</ContainerDimensions>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a term tip
|
* Generate a term tip
|
||||||
* @param {Object} d the data
|
* @param {Object} d the data
|
||||||
* @param {number} i the index
|
* @param {number} i the index
|
||||||
* @param {Object} e the event
|
* @param {Object} e the event
|
||||||
* @returns {Object} termtip markup
|
* @returns {Object} termtip markup
|
||||||
*/
|
*/
|
||||||
_termtip(d, i, e) {
|
_termtip(d, i, e) {
|
||||||
if (this.props.data[i].tooltip) {
|
if (this.props.data[i].tooltip) {
|
||||||
return this.context.termtip(this.props.data[i].tooltip, e);
|
return this.context.termtip(this.props.data[i].tooltip, e);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import * as RU from './ru';
|
|||||||
import * as PL from './pl';
|
import * as PL from './pl';
|
||||||
import * as PT from './pt';
|
import * as PT from './pt';
|
||||||
import * as CN from './cn';
|
import * as CN from './cn';
|
||||||
|
import * as KO from './ko';
|
||||||
import * as d3 from 'd3';
|
import * as d3 from 'd3';
|
||||||
|
|
||||||
let fallbackTerms = EN.terms;
|
let fallbackTerms = EN.terms;
|
||||||
@@ -29,6 +30,7 @@ export function getLanguage(langCode) {
|
|||||||
case 'pl': lang = PL; break;
|
case 'pl': lang = PL; break;
|
||||||
case 'pt': lang = PT; break;
|
case 'pt': lang = PT; break;
|
||||||
case 'cn': lang = CN; break;
|
case 'cn': lang = CN; break;
|
||||||
|
case 'ko': lang = KO; break;
|
||||||
default:
|
default:
|
||||||
lang = EN;
|
lang = EN;
|
||||||
}
|
}
|
||||||
@@ -97,5 +99,6 @@ export const Languages = {
|
|||||||
ru: 'ру́сский',
|
ru: 'ру́сский',
|
||||||
pl: 'polski',
|
pl: 'polski',
|
||||||
pt: 'português',
|
pt: 'português',
|
||||||
cn: '中文'
|
cn: '中文',
|
||||||
|
ko: '한국어'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -398,6 +398,7 @@
|
|||||||
"No modded components.": "没有改装的部件",
|
"No modded components.": "没有改装的部件",
|
||||||
"Sending...": "发送中...",
|
"Sending...": "发送中...",
|
||||||
"Send to EDEngineer": "发送至EDEngineer",
|
"Send to EDEngineer": "发送至EDEngineer",
|
||||||
|
"Send to EDOMH": "发送至EDOMH",
|
||||||
"PHASE_UPLOAD_ORBIS": "上传到orbis.zone(测试阶段)",
|
"PHASE_UPLOAD_ORBIS": "上传到orbis.zone(测试阶段)",
|
||||||
"orbis username": "orbis.zone的Email或用户名",
|
"orbis username": "orbis.zone的Email或用户名",
|
||||||
"orbis password": "orbis.zone的密码",
|
"orbis password": "orbis.zone的密码",
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
export const formats = {
|
export const formats = {
|
||||||
decimal: ',',
|
decimal: ',',
|
||||||
thousands: '.',
|
thousands: '.',
|
||||||
grouping: [3],
|
grouping: [3],
|
||||||
currency: ['', ' €'],
|
currency: ['', ' €'],
|
||||||
dateTime: '%A, der %e. %B %Y, %X',
|
dateTime: '%A, der %e. %B %Y, %X',
|
||||||
date: '%d.%m.%Y',
|
date: '%d.%m.%Y',
|
||||||
time: '%H:%M:%S',
|
time: '%H:%M:%S',
|
||||||
periods: ['AM', 'PM'], // unused
|
periods: ['AM', 'PM'], // unused
|
||||||
days: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
|
days: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
|
||||||
shortDays: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'],
|
shortDays: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'],
|
||||||
months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
|
months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
|
||||||
shortMonths: ['Jan', 'Feb', 'Mrz', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez']
|
shortMonths: ['Jan', 'Feb', 'Mrz', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez']
|
||||||
};
|
};
|
||||||
|
|
||||||
export { default as terms } from './de.json';
|
export { default as terms } from './de.json';
|
||||||
|
|||||||
@@ -26,6 +26,9 @@
|
|||||||
"PHRASE_NO_SPECIAL": "No experimental effect",
|
"PHRASE_NO_SPECIAL": "No experimental effect",
|
||||||
"PHRASE_SHOPPING_LIST": "Stations that sell this build",
|
"PHRASE_SHOPPING_LIST": "Stations that sell this build",
|
||||||
"PHRASE_SHOPPING_MATS": "Materials needed for this build",
|
"PHRASE_SHOPPING_MATS": "Materials needed for this build",
|
||||||
|
"PHRASE_DIFFERENT_ROLLS": "Material requirements will differ, based on the number of rolls per grade, per module.",
|
||||||
|
"PHRASE_FOR_FINER_CONTROL": "For finer control over rolls per grade/module, a more accurate list of required mats and help in finding those mats, please consider using the export options below to ED Odyssey Materials Helper, or ED Engineer, or use the Crafting Lists feature on inara.cz.",
|
||||||
|
"PHRASE_ALL_MODULES_ALL_ROLLS": "The list below, assumes standard to G5 Engineered (approx 80% - 90%) with the rolls above, for ALL engineered modules in the build. You can adjust the number of rolls above for each grade, however it will still apply to all engineered modules in the build.",
|
||||||
"PHRASE_REFIT_SHOPPING_LIST": "Stations that sell required modules",
|
"PHRASE_REFIT_SHOPPING_LIST": "Stations that sell required modules",
|
||||||
"PHRASE_TOTAL_EFFECTIVE_SHIELD": "Total amount of damage that can be taken from each damage type, if using all shield cells",
|
"PHRASE_TOTAL_EFFECTIVE_SHIELD": "Total amount of damage that can be taken from each damage type, if using all shield cells",
|
||||||
"PHRASE_TIME_TO_LOSE_SHIELDS": "Shields will hold for",
|
"PHRASE_TIME_TO_LOSE_SHIELDS": "Shields will hold for",
|
||||||
@@ -63,15 +66,17 @@
|
|||||||
"TT_SUMMARY_SPEED": "With full fuel tank and 4 pips to ENG",
|
"TT_SUMMARY_SPEED": "With full fuel tank and 4 pips to ENG",
|
||||||
"TT_SUMMARY_SPEED_NONFUNCTIONAL": "Thrusters powered off or over maximum mass with full fuel and cargo loads",
|
"TT_SUMMARY_SPEED_NONFUNCTIONAL": "Thrusters powered off or over maximum mass with full fuel and cargo loads",
|
||||||
"TT_SUMMARY_BOOST": "With full fuel tank and 4 pips to ENG",
|
"TT_SUMMARY_BOOST": "With full fuel tank and 4 pips to ENG",
|
||||||
"TT_SUMMARY_BOOST_INTERVAL": "Time between each boost with 4 pips to ENG",
|
"TT_SUMMARY_SHIP_BOOST_INTERVAL": "Time each boost lasts on this ship",
|
||||||
|
"TT_SUMMARY_BOOST_INTERVAL": "Time between boosts with 4 pips to ENG",
|
||||||
|
"TT_SUMMARY_BOOST_INTERVALS": "If DISTRO is less than or equal to SHIP, the ship can boost continuously",
|
||||||
"TT_SUMMARY_BOOST_NONFUNCTIONAL": "Power distributor not able to supply enough power to boost",
|
"TT_SUMMARY_BOOST_NONFUNCTIONAL": "Power distributor not able to supply enough power to boost",
|
||||||
"TT_SUMMARY_SHIELDS": "Raw shield strength, including boosters",
|
"TT_SUMMARY_SHIELDS": "Raw shield strength, including boosters",
|
||||||
"TT_SUMMARY_SHIELDS_SCB": "Raw shield strength, including boosters and SCBs",
|
"TT_SUMMARY_SHIELDS_SCB": "Raw shield strength, including boosters and SCBs",
|
||||||
"TT_SUMMARY_SHIELDS_NONFUNCTIONAL": "No shield generator or shield generator powered off",
|
"TT_SUMMARY_SHIELDS_NONFUNCTIONAL": "No shield generator or shield generator powered off",
|
||||||
"TT_SUMMARY_INTEGRITY": "Ship integrity, including bulkheads and hull reinforcement packages",
|
"TT_SUMMARY_INTEGRITY": "Ship integrity, including bulkheads and hull reinforcement packages",
|
||||||
"TT_SUMMARY_HULL_MASS": "Mass of the hull prior to any modules being installed",
|
"TT_SUMMARY_HULL_MASS": "Mass of the hull prior to any modules being installed",
|
||||||
"TT_SUMMARY_UNLADEN_MASS": "Mass of the hull and modules prior to any fuel or cargo",
|
"TT_SUMMARY_UNLADEN_MASS": "Mass of the hull and modules prior to any cargo or passengers",
|
||||||
"TT_SUMMARY_LADEN_MASS": "Mass of the hull and modules with full fuel and cargo",
|
"TT_SUMMARY_LADEN_MASS": "Mass of the hull and modules with full fuel, cargo, passengers, etc.",
|
||||||
"TT_SUMMARY_DPS": "Damage per second with all weapons firing",
|
"TT_SUMMARY_DPS": "Damage per second with all weapons firing",
|
||||||
"TT_SUMMARY_EPS": "WEP capacitor consumed per second with all weapons firing",
|
"TT_SUMMARY_EPS": "WEP capacitor consumed per second with all weapons firing",
|
||||||
"TT_SUMMARY_TTD": "Time to drain WEP capacitor with all weapons firing and 4 pips to WEP",
|
"TT_SUMMARY_TTD": "Time to drain WEP capacitor with all weapons firing and 4 pips to WEP",
|
||||||
@@ -81,8 +86,10 @@
|
|||||||
"TT_SUMMARY_UNLADEN_TOTAL_JUMP": "Farthest possible range with no cargo, a full fuel tank, and jumping as far as possible each time",
|
"TT_SUMMARY_UNLADEN_TOTAL_JUMP": "Farthest possible range with no cargo, a full fuel tank, and jumping as far as possible each time",
|
||||||
"TT_SUMMARY_LADEN_TOTAL_JUMP": "Farthest possible range with full cargo, a full fuel tank, and jumping as far as possible each time",
|
"TT_SUMMARY_LADEN_TOTAL_JUMP": "Farthest possible range with full cargo, a full fuel tank, and jumping as far as possible each time",
|
||||||
"HELP_MODIFICATIONS_MENU": "Click on a number to enter a new value, or drag along the bar for small changes",
|
"HELP_MODIFICATIONS_MENU": "Click on a number to enter a new value, or drag along the bar for small changes",
|
||||||
"PHRASE_FAIL_EDENGINEER": "Failed to send to EDEngineer (Launch EDEngineer and make sure the API is started then refresh the page.)",
|
"PHRASE_ENSURE_EDOMH": "Ensure ED Odyssey Material Helper is installed and registered to handle edomh:// urls, else this button will do nothing!",
|
||||||
"PHRASE_FIREFOX_EDENGINEER": "Sending to EDEngineer is not compatible with Firefox's security settings. Please try again with Chrome.",
|
"PHRASE_FIREFOX_EDENGINEER": "Sending to EDEngineer is not compatible with Firefox's security settings. Please try again with Chrome.",
|
||||||
|
"PHRASE_FAILED_TO_FIND_EDENGINEER": "Failed to find ED Engineer API. Please ensure it is running and try again.",
|
||||||
|
"MISSING_MODULES": "Missing Modules",
|
||||||
"am": "Auto Field-Maintenance Unit",
|
"am": "Auto Field-Maintenance Unit",
|
||||||
"bh": "Bulkheads",
|
"bh": "Bulkheads",
|
||||||
"bl": "Beam Laser",
|
"bl": "Beam Laser",
|
||||||
@@ -93,6 +100,7 @@
|
|||||||
"ch": "Chaff Launcher",
|
"ch": "Chaff Launcher",
|
||||||
"cr": "Cargo Rack",
|
"cr": "Cargo Rack",
|
||||||
"cs": "Manifest Scanner",
|
"cs": "Manifest Scanner",
|
||||||
|
"csl": "Caustic Sink Launcher",
|
||||||
"dc": "Docking Computer",
|
"dc": "Docking Computer",
|
||||||
"ec": "Electronic Countermeasure",
|
"ec": "Electronic Countermeasure",
|
||||||
"fc": "Fragment Cannon",
|
"fc": "Fragment Cannon",
|
||||||
@@ -108,10 +116,18 @@
|
|||||||
"kw": "Kill Warrant Scanner",
|
"kw": "Kill Warrant Scanner",
|
||||||
"ls": "Life Support",
|
"ls": "Life Support",
|
||||||
"mc": "Multi-cannon",
|
"mc": "Multi-cannon",
|
||||||
|
"mh": "Missing Weapon/Utility",
|
||||||
|
"mm": "Missing Module",
|
||||||
|
"advmc": "Multi-cannon (Advanced)",
|
||||||
"axmc": "AX Multi-cannon",
|
"axmc": "AX Multi-cannon",
|
||||||
|
"axmce": "AX Multi-cannon (Enhanced)",
|
||||||
"ml": "Mining Laser",
|
"ml": "Mining Laser",
|
||||||
|
"mlc": "Multi Limpet Controller",
|
||||||
"mr": "Missile Rack",
|
"mr": "Missile Rack",
|
||||||
|
"amr": "Missile Rack (Advanced)",
|
||||||
"axmr": "AX Missile Rack",
|
"axmr": "AX Missile Rack",
|
||||||
|
"axmre": "AX Missile Rack (Enhanced)",
|
||||||
|
"ews": "Experimental Weapon Stabilizer",
|
||||||
"mrp": "Module Reinforcement Package",
|
"mrp": "Module Reinforcement Package",
|
||||||
"nl": "Mine Launcher",
|
"nl": "Mine Launcher",
|
||||||
"pa": "Plasma Accelerator",
|
"pa": "Plasma Accelerator",
|
||||||
@@ -156,8 +172,10 @@
|
|||||||
"sua": "Supercruise Assist",
|
"sua": "Supercruise Assist",
|
||||||
"t": "thrusters",
|
"t": "thrusters",
|
||||||
"tp": "Torpedo Pylon",
|
"tp": "Torpedo Pylon",
|
||||||
|
"ntp": "Nanite Torpedo Pylon",
|
||||||
"ul": "Burst Laser",
|
"ul": "Burst Laser",
|
||||||
"Send To EDEngineer": "Send To EDEngineer",
|
"Send To EDEngineer": "Send To EDEngineer",
|
||||||
|
"Send To EDOMH": "Send To EDOMH",
|
||||||
"ws": "Frame Shift Wake Scanner",
|
"ws": "Frame Shift Wake Scanner",
|
||||||
"rpl": "Repair Limpet Controller",
|
"rpl": "Repair Limpet Controller",
|
||||||
"rcpl": "Recon Limpet Controller",
|
"rcpl": "Recon Limpet Controller",
|
||||||
@@ -208,6 +226,7 @@
|
|||||||
"boost interval": "Boost interval",
|
"boost interval": "Boost interval",
|
||||||
"total": "Total",
|
"total": "Total",
|
||||||
"ammo": "Ammunition maximum",
|
"ammo": "Ammunition maximum",
|
||||||
|
"info": "Info",
|
||||||
"boot": "Boot time",
|
"boot": "Boot time",
|
||||||
"hacktime": "Hack time",
|
"hacktime": "Hack time",
|
||||||
"brokenregen": "Broken regeneration rate",
|
"brokenregen": "Broken regeneration rate",
|
||||||
@@ -257,8 +276,10 @@
|
|||||||
"thermres": "Thermal resistance",
|
"thermres": "Thermal resistance",
|
||||||
"wepcap": "Weapons capacity",
|
"wepcap": "Weapons capacity",
|
||||||
"weprate": "Weapons recharge rate",
|
"weprate": "Weapons recharge rate",
|
||||||
|
"minmass": "Minimum mass",
|
||||||
"minmass_sg": "Minimum hull mass",
|
"minmass_sg": "Minimum hull mass",
|
||||||
"optmass_sg": "Optimal hull mass",
|
"optmass_sg": "Optimal hull mass",
|
||||||
|
"maxmass": "Maximum mass",
|
||||||
"maxmass_sg": "Maximum hull mass",
|
"maxmass_sg": "Maximum hull mass",
|
||||||
"minmul_sg": "Minimum strength",
|
"minmul_sg": "Minimum strength",
|
||||||
"optmul_sg": "Optimal strength",
|
"optmul_sg": "Optimal strength",
|
||||||
|
|||||||
16
src/app/i18n/ko.js
Normal file
16
src/app/i18n/ko.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
export const formats = {
|
||||||
|
decimal: '.',
|
||||||
|
thousands: ',',
|
||||||
|
grouping: [3],
|
||||||
|
currency: ['₩', ''],
|
||||||
|
dateTime: '%a %b %e %X %Y',
|
||||||
|
date: '%Y/%m/%d',
|
||||||
|
time: '%H:%M:%S',
|
||||||
|
periods: ['오전', '오후'],
|
||||||
|
days: ['일요일', '월요일', '화요일', '수요일', '목요일', '금요일', '토요일'],
|
||||||
|
shortDays: ['일', '월', '화', '수', '목', '금', '토'],
|
||||||
|
months: ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'],
|
||||||
|
shortMonths: ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월']
|
||||||
|
};
|
||||||
|
|
||||||
|
export { default as terms } from './ko.json';
|
||||||
369
src/app/i18n/ko.json
Normal file
369
src/app/i18n/ko.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -13,7 +13,7 @@
|
|||||||
"PHRASE_SG_RECOVER": "Восстановление с 0% до 50% объема щита, учитывая полный аккумулятор СИС в начале",
|
"PHRASE_SG_RECOVER": "Восстановление с 0% до 50% объема щита, учитывая полный аккумулятор СИС в начале",
|
||||||
"PHRASE_UNLADEN": "Масса корабля без учета топлива и грузов",
|
"PHRASE_UNLADEN": "Масса корабля без учета топлива и грузов",
|
||||||
"PHRASE_UPDATE_RDY": "Доступна новая версия. Нажмите для обновления.",
|
"PHRASE_UPDATE_RDY": "Доступна новая версия. Нажмите для обновления.",
|
||||||
"PHRASE_ENGAGEMENT_RANGE": "Дистанция между кораблем и целью",
|
"PHRASE_ENGAGEMENT_RANGE": "Дистанция между кораблём и целью",
|
||||||
"PHRASE_SELECT_BLUEPRINT": "Нажмите чтобы выбрать чертеж",
|
"PHRASE_SELECT_BLUEPRINT": "Нажмите чтобы выбрать чертеж",
|
||||||
"PHRASE_BLUEPRINT_WORST": "Худшие основные значения для чертежа",
|
"PHRASE_BLUEPRINT_WORST": "Худшие основные значения для чертежа",
|
||||||
"PHRASE_BLUEPRINT_FIFTY": "50% значения для чертежа",
|
"PHRASE_BLUEPRINT_FIFTY": "50% значения для чертежа",
|
||||||
@@ -24,9 +24,9 @@
|
|||||||
"PHRASE_BLUEPRINT_RESET": "Сбросить все модификаторы и чертеж",
|
"PHRASE_BLUEPRINT_RESET": "Сбросить все модификаторы и чертеж",
|
||||||
"PHRASE_SELECT_SPECIAL": "Нажмите, чтобы выбрать экспериментальный эффект",
|
"PHRASE_SELECT_SPECIAL": "Нажмите, чтобы выбрать экспериментальный эффект",
|
||||||
"PHRASE_NO_SPECIAL": "Без экспериментального эффекта",
|
"PHRASE_NO_SPECIAL": "Без экспериментального эффекта",
|
||||||
"PHRASE_SHOPPING_LIST": "Станции, что продают эту сборку",
|
"PHRASE_SHOPPING_LIST": "Станции, на которых продают эту сборку",
|
||||||
"PHRASE_SHOPPING_MATS": "Материалы которые нужны для сборки",
|
"PHRASE_SHOPPING_MATS": "Материалы которые нужны для сборки",
|
||||||
"PHRASE_REFIT_SHOPPING_LIST": "Станции, что продают необходимые модули",
|
"PHRASE_REFIT_SHOPPING_LIST": "Станции, на которых продают необходимые модули",
|
||||||
"PHRASE_TOTAL_EFFECTIVE_SHIELD": "Общий урон, что может быть нанесен в каждым типе, если используются все щитонакопители",
|
"PHRASE_TOTAL_EFFECTIVE_SHIELD": "Общий урон, что может быть нанесен в каждым типе, если используются все щитонакопители",
|
||||||
"PHRASE_TIME_TO_LOSE_SHIELDS": "Щиты продержатся",
|
"PHRASE_TIME_TO_LOSE_SHIELDS": "Щиты продержатся",
|
||||||
"PHRASE_TIME_TO_RECOVER_SHIELDS": "Щиты восстановятся за",
|
"PHRASE_TIME_TO_RECOVER_SHIELDS": "Щиты восстановятся за",
|
||||||
@@ -37,36 +37,36 @@
|
|||||||
"PHRASE_EFFECTIVE_ARMOUR": "Эффективная сила брони против разных типов урона",
|
"PHRASE_EFFECTIVE_ARMOUR": "Эффективная сила брони против разных типов урона",
|
||||||
"PHRASE_DAMAGE_TAKEN": "% общих повреждений полученных в разных типах урона",
|
"PHRASE_DAMAGE_TAKEN": "% общих повреждений полученных в разных типах урона",
|
||||||
"PHRASE_TIME_TO_LOSE_ARMOUR": "Броня продержится",
|
"PHRASE_TIME_TO_LOSE_ARMOUR": "Броня продержится",
|
||||||
"PHRASE_MODULE_PROTECTION_EXTERNAL": "Защита гнезд",
|
"PHRASE_MODULE_PROTECTION_EXTERNAL": "Защита гнёзд",
|
||||||
"PHRASE_MODULE_PROTECTION_INTERNAL": "Защита всех остальных модулей",
|
"PHRASE_MODULE_PROTECTION_INTERNAL": "Защита всех остальных модулей",
|
||||||
"PHRASE_OVERALL_DAMAGE": "Разбивка источников устойчивого ДПС",
|
"PHRASE_OVERALL_DAMAGE": "Разбивка источников устойчивого УвС",
|
||||||
"PHRASE_SHIELD_DAMAGE": "Подробности источников поддерживаемого ДПС против щитов",
|
"PHRASE_SHIELD_DAMAGE": "Подробности источников поддерживаемого УвС против щитов",
|
||||||
"PHRASE_ARMOUR_DAMAGE": "Подробности источников поддерживаемого ДПС против брони",
|
"PHRASE_ARMOUR_DAMAGE": "Подробности источников поддерживаемого УвС против брони",
|
||||||
"PHRASE_TIME_TO_REMOVE_SHIELDS": "Снимет щиты за",
|
"PHRASE_TIME_TO_REMOVE_SHIELDS": "Снимет щиты за",
|
||||||
"PHRASE_MULTI_CREW_CAPACITOR_POINTS": "Щелкните правой кновкой мыши чтобы объединить в группу.",
|
"PHRASE_MULTI_CREW_CAPACITOR_POINTS": "Щелкните правой кновкой мыши чтобы объединить в группу.",
|
||||||
"TT_TIME_TO_REMOVE_SHIELDS": "Непрерывным огнем из всех орудий",
|
"TT_TIME_TO_REMOVE_SHIELDS": "Непрерывным огнём из всех орудий",
|
||||||
"PHRASE_TIME_TO_REMOVE_ARMOUR": "Снимет броню за",
|
"PHRASE_TIME_TO_REMOVE_ARMOUR": "Снимет броню за",
|
||||||
"TT_TIME_TO_REMOVE_ARMOUR": "Непрерывным огнем из всех орудий",
|
"TT_TIME_TO_REMOVE_ARMOUR": "Непрерывным огнём из всех орудий",
|
||||||
"PHRASE_TIME_TO_DRAIN_WEP": "Опустошит ОРУ за",
|
"PHRASE_TIME_TO_DRAIN_WEP": "Опустошит ОРУ за",
|
||||||
"TT_TIME_TO_DRAIN_WEP": "Время, за которое опустошится аккумулятор ОРУ при стрельбе из всех орудий",
|
"TT_TIME_TO_DRAIN_WEP": "Время, за которое опустошится аккумулятор ОРУ при стрельбе из всех орудий",
|
||||||
"TT_TIME_TO_LOSE_SHIELDS": "Против поддерживаемой стрельбы из всех орудий противника",
|
"TT_TIME_TO_LOSE_SHIELDS": "Против поддерживаемой стрельбы из всех орудий противника",
|
||||||
"TT_TIME_TO_LOSE_ARMOUR": "Против поддерживаемой стрельбы из всех орудий противника",
|
"TT_TIME_TO_LOSE_ARMOUR": "Против поддерживаемой стрельбы из всех орудий противника",
|
||||||
"TT_MODULE_ARMOUR": "Броня, защищающая модули от урона",
|
"TT_MODULE_ARMOUR": "Броня, защищающая модули от урона",
|
||||||
"TT_MODULE_PROTECTION_EXTERNAL": "Процент урона, перенаправленного от гнезд на наборы для усиления модулей",
|
"TT_MODULE_PROTECTION_EXTERNAL": "Процент урона, перенаправленного от гнезд на наборы для усиления модулей",
|
||||||
"TT_MODULE_PROTECTION_INTERNAL": "Процент урона, перенаправленного от модулей вне гнезд на наборы для усиления модулей",
|
"TT_MODULE_PROTECTION_INTERNAL": "Процент урона, перенаправленного от модулей вне гнёзд на наборы для усиления модулей",
|
||||||
"TT_EFFECTIVE_SDPS_SHIELDS": "Реальный поддерживаемый ДПС пока аккумулятор ОРУ не пуст",
|
"TT_EFFECTIVE_SDPS_SHIELDS": "Реальный поддерживаемый УвС пока ёмкость ОРУ не пуста",
|
||||||
"TT_EFFECTIVENESS_SHIELDS": "Эффективность в сравнении с попаданием по цели с 0-сопротивляемостью без пунктов в СИС на 0 метрах",
|
"TT_EFFECTIVENESS_SHIELDS": "Эффективность в сравнении с попаданием по цели с 0-сопротивляемостью без пунктов в СИС на 0 метрах",
|
||||||
"TT_EFFECTIVE_SDPS_ARMOUR": "Реальный поддерживаемый ДПС пока аккумулятор ОРУ не пуст",
|
"TT_EFFECTIVE_SDPS_ARMOUR": "Реальный поддерживаемый УвС пока аккумулятор ОРУ не пуст",
|
||||||
"TT_EFFECTIVENESS_ARMOUR": "Эффективность в сравнении с попаданием по цели с 0-сопротивляемостью на 0 метрах",
|
"TT_EFFECTIVENESS_ARMOUR": "Эффективность в сравнении с попаданием по цели с 0-сопротивляемостью на 0 метрах",
|
||||||
"PHRASE_EFFECTIVE_SDPS_SHIELDS": "ПДПС против щитов",
|
"PHRASE_EFFECTIVE_SDPS_SHIELDS": "ПУвС против щитов",
|
||||||
"PHRASE_EFFECTIVE_SDPS_ARMOUR": "ПДПС против брони",
|
"PHRASE_EFFECTIVE_SDPS_ARMOUR": "ПУвС против брони",
|
||||||
"TT_SUMMARY_SPEED": "С полным топливным баком и 4 пунктами в ДВГ",
|
"TT_SUMMARY_SPEED": "С полным топливным баком и 4 пунктами в ДВГ",
|
||||||
"TT_SUMMARY_SPEED_NONFUNCTIONAL": "Маневровые двигатели выключены или превышена максимальная масса с топливом и грузом",
|
"TT_SUMMARY_SPEED_NONFUNCTIONAL": "Маневровые двигатели выключены или превышена максимальная масса с топливом и грузом",
|
||||||
"TT_SUMMARY_BOOST": "С полным топливным баком и 4 пунктами в ДВГ",
|
"TT_SUMMARY_BOOST": "С полным топливным баком и 4 пунктами в ДВГ",
|
||||||
"TT_SUMMARY_BOOST_INTERVAL": "Время заполнения с 4 пунктами в СИС",
|
"TT_SUMMARY_BOOST_INTERVAL": "Время заполнения с 4 пунктами в СИС",
|
||||||
"TT_SUMMARY_BOOST_NONFUNCTIONAL": "Распределитель питания не может обеспечить достаточно энергии для форсажа",
|
"TT_SUMMARY_BOOST_NONFUNCTIONAL": "Распределитель питания не может обеспечить достаточно энергии для форсажа",
|
||||||
"TT_SUMMARY_SHIELDS": "Чистая сила щита, включая усилители",
|
"TT_SUMMARY_SHIELDS": "Чистая сила щита, включая усилители",
|
||||||
"TT_SUMMARY_SHIELDS_SCB": "Прочность щита, включая бустеры и SCB",
|
"TT_SUMMARY_SHIELDS_SCB": "Прочность щита, включая бустеры и щитонакопители",
|
||||||
"TT_SUMMARY_SHIELDS_NONFUNCTIONAL": "Шитогенератор отсутствует или выключен",
|
"TT_SUMMARY_SHIELDS_NONFUNCTIONAL": "Шитогенератор отсутствует или выключен",
|
||||||
"TT_SUMMARY_INTEGRITY": "Целостность корабля, включая переборки и наборы для усиления корпуса",
|
"TT_SUMMARY_INTEGRITY": "Целостность корабля, включая переборки и наборы для усиления корпуса",
|
||||||
"TT_SUMMARY_HULL_MASS": "Масса корпуса без каких-либо модулей",
|
"TT_SUMMARY_HULL_MASS": "Масса корпуса без каких-либо модулей",
|
||||||
@@ -88,22 +88,23 @@
|
|||||||
"bl": "Пучковый лазер",
|
"bl": "Пучковый лазер",
|
||||||
"bsg": "Двухпоточный щитогенератор",
|
"bsg": "Двухпоточный щитогенератор",
|
||||||
"c": "Пушка",
|
"c": "Пушка",
|
||||||
"causres": "Каустическое сопротивление",
|
"causres": "Сопротивление едк.урону",
|
||||||
"Caustic resistance": "Каустическое сопротивление",
|
"Caustic resistance": "Сопротивление едк.урону",
|
||||||
"cc": "Контроллер магнитного снаряда для сбора",
|
"cc": "Контроллер дронов-сборщиков",
|
||||||
"ch": "Разбрасыватель дипольных отражателей",
|
"ch": "Разбрасыватель дипольных отражателей",
|
||||||
"cr": "Грузовой стеллаж",
|
"cr": "Грузовой стеллаж",
|
||||||
"cs": "Сканер содержимого",
|
"cs": "Сканер содержимого",
|
||||||
|
"csl": "Антикор катапульта",
|
||||||
"dc": "Стыковочный компьютер",
|
"dc": "Стыковочный компьютер",
|
||||||
"ec": "Электр. противодействие",
|
"ec": "Радиоэлектронное подавление",
|
||||||
"fc": "Залповое орудие",
|
"fc": "Залповое орудие",
|
||||||
"fh": "Ангар для истребителя",
|
"fh": "Ангар для истребителя",
|
||||||
"fi": "FSD-перехватчик",
|
"fi": "FSD-перехватчик",
|
||||||
"fs": "Топливозаборник",
|
"fs": "Топливозаборник",
|
||||||
"fsd": "Рамочно-сместительный двигатель",
|
"fsd": "Рамочно-сместительный двигатель",
|
||||||
"ft": "Топливный бак",
|
"ft": "Топливный бак",
|
||||||
"fx": "Контроллер магнитного снаряда для топлива",
|
"fx": "Контроллер дронов-заправщиков",
|
||||||
"hb": "Контроллер магнитного снаряда для взлома трюма",
|
"hb": "Контроллер дронов-взломщиков трюмов",
|
||||||
"hr": "Набор для усиления корпуса",
|
"hr": "Набор для усиления корпуса",
|
||||||
"hs": "Теплоотводная катапульта",
|
"hs": "Теплоотводная катапульта",
|
||||||
"kw": "Сканер преступников",
|
"kw": "Сканер преступников",
|
||||||
@@ -111,13 +112,14 @@
|
|||||||
"mc": "Многоствольное орудие",
|
"mc": "Многоствольное орудие",
|
||||||
"axmc": "Многоствольное орудие АИ",
|
"axmc": "Многоствольное орудие АИ",
|
||||||
"ml": "Проходочный лазер",
|
"ml": "Проходочный лазер",
|
||||||
"mr": "Ракетный лоток",
|
"mr": "Блок ракет",
|
||||||
"axmr": "Блок ракет АИ",
|
"axmr": "Блок ракет АИ",
|
||||||
|
"ews": "Стабилизатор экспериментального вооружения",
|
||||||
"mrp": "Набор для усиления модуля",
|
"mrp": "Набор для усиления модуля",
|
||||||
"nl": "Мины",
|
"nl": "Мины",
|
||||||
"pa": "Ускоритель плазмы",
|
"pa": "Ускоритель плазмы",
|
||||||
"pas": "Комплект для сближения с планетой",
|
"pas": "Комплект для сближения с планетой",
|
||||||
"pc": "Контроллер магнитного снаряда для геологоразведки",
|
"pc": "Контроллер дронов-геологоразведчиков",
|
||||||
"pce": "Каюта пассажира эконом-класса",
|
"pce": "Каюта пассажира эконом-класса",
|
||||||
"passenger capacity": "Количество пассажиров",
|
"passenger capacity": "Количество пассажиров",
|
||||||
"pci": "Каюта пассажира бизнес-класса",
|
"pci": "Каюта пассажира бизнес-класса",
|
||||||
@@ -143,36 +145,38 @@
|
|||||||
"gsc": "Осколочное орудие Стражей",
|
"gsc": "Осколочное орудие Стражей",
|
||||||
"psg": "Призматический щитогенератор",
|
"psg": "Призматический щитогенератор",
|
||||||
"pv": "Гараж для планетарного транспорта",
|
"pv": "Гараж для планетарного транспорта",
|
||||||
"rf": "Устройство переработки",
|
"rf": "Очиститель",
|
||||||
"rfl": "Зенитная установка (снаряды с дистанционным подрывом)",
|
"rfl": "Зенитная установка (снаряды с дистанционным подрывом)",
|
||||||
"rg": "Электромагнитная пушка",
|
"rg": "Рельсотрон",
|
||||||
"rsl": "Дроны-исследователи",
|
"rsl": "Контроллер дронов-исследователей",
|
||||||
"s": "Сенсоры",
|
"s": "Сенсоры",
|
||||||
"sb": "Усилитель щита",
|
"sb": "Усилитель щита",
|
||||||
"sc": "Сканер обнаружения",
|
"sc": "Сканер обнаружения",
|
||||||
"scb": "Щитонакопитель",
|
"scb": "Щитонакопитель",
|
||||||
"sfn": "Нейтрализатор глушащего поля",
|
"sfn": "Нейтрализатор отключающего поля",
|
||||||
"sg": "Щитогенератор",
|
"sg": "Щитогенератор",
|
||||||
"ss": "Сканер поверхностей",
|
"ss": "Сканер поверхностей",
|
||||||
"sua": "Помощь в гиперкрейсерском режиме",
|
"sua": "Помощь в гиперкрейсерском режиме",
|
||||||
"t": "Маневровые двигатели",
|
"t": "Маневровые двигатели",
|
||||||
"tp": "Торпедная стойка",
|
"tp": "Торпедная установка",
|
||||||
"ul": "Пульсирующие лазеры",
|
"ul": "Пульсирующий лазер",
|
||||||
"Send To EDEngineer": "Отправить в EDEngineer",
|
"Send To EDEngineer": "Отправить в EDEngineer",
|
||||||
|
"Send To EDOMH": "Отправить в EDOMH",
|
||||||
"ws": "Сканер следа FSD",
|
"ws": "Сканер следа FSD",
|
||||||
"rpl": "Дроны-ремонтники",
|
"rpl": "Контроллер дронов-ремонтников",
|
||||||
"rcpl": "Дроны-разведчики",
|
"rcpl": "Контроллер дронов-разведчиков",
|
||||||
"xs": "Сканер «инопланетянин»",
|
"xs": "Ксено-сканер",
|
||||||
"tbem": "Блок энзимных ракет",
|
"tbem": "Блок энзимных ракет",
|
||||||
"tbrfl": "Установка для стрельбы стреловидными снарядами с дистанционным подрывом",
|
"tbrfl": "Установка для стрельбы стреловидными снарядами с дистанционным подрывом",
|
||||||
"dtl": "Дроны-очистители",
|
"dtl": "Контроллер дронов-очистителей",
|
||||||
"mahr": "Набор для усиления корпуса из Метасплава",
|
"mlc": "Мультиконтроллер",
|
||||||
|
"mahr": "Метасплавное усиление корпуса",
|
||||||
"emptyrestricted": "пусто (ограниченно)",
|
"emptyrestricted": "пусто (ограниченно)",
|
||||||
"damage dealt to": "Урон нанесен",
|
"damage dealt to": "Урон нанесён",
|
||||||
"damage received from": "Урон получен от",
|
"damage received from": "Урон получен от",
|
||||||
"against shields": "Против щитов",
|
"against shields": "Против щитов",
|
||||||
"against hull": "Против корпуса",
|
"against hull": "Против корпуса",
|
||||||
"total effective shield": "Общие эффективные щиты",
|
"total effective shield": "Общая эффективность щита",
|
||||||
"ammunition": "Припасы",
|
"ammunition": "Припасы",
|
||||||
"secs": "с",
|
"secs": "с",
|
||||||
"bays": "Ячейки",
|
"bays": "Ячейки",
|
||||||
@@ -201,7 +205,7 @@
|
|||||||
"shield cells": "Щитонакопители",
|
"shield cells": "Щитонакопители",
|
||||||
"recovery": "включение",
|
"recovery": "включение",
|
||||||
"recharge": "перезарядка",
|
"recharge": "перезарядка",
|
||||||
"engine pips": "Пункты в двигателе",
|
"engine pips": "Ячейки питания на ДВГ",
|
||||||
"4b": "4 пункта и Форсаж",
|
"4b": "4 пункта и Форсаж",
|
||||||
"speed": "скорость",
|
"speed": "скорость",
|
||||||
"pitch": "Тангаж",
|
"pitch": "Тангаж",
|
||||||
@@ -287,12 +291,12 @@
|
|||||||
"explosive": "Взрывч.",
|
"explosive": "Взрывч.",
|
||||||
"kinetic": "Механич.",
|
"kinetic": "Механич.",
|
||||||
"thermal": "Тепл.",
|
"thermal": "Тепл.",
|
||||||
"caustic": "Каустич.",
|
"caustic": "Едкий",
|
||||||
"generator": "Генератор",
|
"generator": "Генератор",
|
||||||
"boosters": "Усилители",
|
"boosters": "Усилители",
|
||||||
"cells": "Ячейки",
|
"cells": "Ячейки",
|
||||||
"shield addition": "ДОбавления к щиту",
|
"shield addition": "Добавления к щиту",
|
||||||
"jump addition": "ДОбавления к прыжку",
|
"jump addition": "Добавления к прыжку",
|
||||||
"bulkheads": "Переборки",
|
"bulkheads": "Переборки",
|
||||||
"reinforcement": "Усилители",
|
"reinforcement": "Усилители",
|
||||||
"power and costs": "Энергия и стоимость",
|
"power and costs": "Энергия и стоимость",
|
||||||
@@ -374,9 +378,9 @@
|
|||||||
"/s": "/с",
|
"/s": "/с",
|
||||||
"/min": "/мин",
|
"/min": "/мин",
|
||||||
"m/s": "м/с",
|
"m/s": "м/с",
|
||||||
"Ls": "Св.сек",
|
"Ls": "Св.с",
|
||||||
"LY": "Св.лет",
|
"LY": "Св.лет",
|
||||||
"CR": "кр.",
|
"CR": "КР.",
|
||||||
"S": "М",
|
"S": "М",
|
||||||
"M": "С",
|
"M": "С",
|
||||||
"L": "Б",
|
"L": "Б",
|
||||||
@@ -435,7 +439,7 @@
|
|||||||
"deployed": "Открыты",
|
"deployed": "Открыты",
|
||||||
"disabled": "Отключено",
|
"disabled": "Отключено",
|
||||||
"discount": "Скидка",
|
"discount": "Скидка",
|
||||||
"DPS": "УВС",
|
"DPS": "УвС",
|
||||||
"efficiency": "Эффективность",
|
"efficiency": "Эффективность",
|
||||||
"empty": "пусто",
|
"empty": "пусто",
|
||||||
"ENG": "ДВГ",
|
"ENG": "ДВГ",
|
||||||
@@ -449,7 +453,7 @@
|
|||||||
"jumps": "Прыжков",
|
"jumps": "Прыжков",
|
||||||
"laden": "Груж",
|
"laden": "Груж",
|
||||||
"language": "Язык",
|
"language": "Язык",
|
||||||
"maneuverability": "Маневренность",
|
"maneuverability": "Манёвренность",
|
||||||
"max": "Макс",
|
"max": "Макс",
|
||||||
"no": "Нет",
|
"no": "Нет",
|
||||||
"pen": "ПБ",
|
"pen": "ПБ",
|
||||||
@@ -462,7 +466,7 @@
|
|||||||
"repair": "Починка",
|
"repair": "Починка",
|
||||||
"ret": "Убр",
|
"ret": "Убр",
|
||||||
"retracted": "Убрано",
|
"retracted": "Убрано",
|
||||||
"ROF": "В\/сек",
|
"ROF": "В\/с",
|
||||||
"save": "Сохранить",
|
"save": "Сохранить",
|
||||||
"sell": "Продать",
|
"sell": "Продать",
|
||||||
"settings": "Настройки",
|
"settings": "Настройки",
|
||||||
@@ -492,7 +496,7 @@
|
|||||||
"module": "модуль",
|
"module": "модуль",
|
||||||
"announcements": "объявления",
|
"announcements": "объявления",
|
||||||
"resistance": "сопротивление",
|
"resistance": "сопротивление",
|
||||||
"Lightweight Alloy": "Легкие сплавы",
|
"Lightweight Alloy": "Лёгкие сплавы",
|
||||||
"base": "базовые",
|
"base": "базовые",
|
||||||
"core module classes": "основные модули",
|
"core module classes": "основные модули",
|
||||||
"Group highlighted ships": "Сгруппировать выделенные корабли",
|
"Group highlighted ships": "Сгруппировать выделенные корабли",
|
||||||
@@ -511,7 +515,7 @@
|
|||||||
"maximum speed": "максимальная скорость",
|
"maximum speed": "максимальная скорость",
|
||||||
"maximum range": "максимальная дальность",
|
"maximum range": "максимальная дальность",
|
||||||
"shortlink": "короткая ссылка",
|
"shortlink": "короткая ссылка",
|
||||||
"guardian": "стражи",
|
"guardian": "Стражи",
|
||||||
"engineers": "инженеры",
|
"engineers": "инженеры",
|
||||||
"component": "компонент",
|
"component": "компонент",
|
||||||
"amount": "кол-во",
|
"amount": "кол-во",
|
||||||
@@ -520,35 +524,35 @@
|
|||||||
"Heat Sink Launcher": "Теплоотводная катапульта",
|
"Heat Sink Launcher": "Теплоотводная катапульта",
|
||||||
"scanners": "сканеры",
|
"scanners": "сканеры",
|
||||||
"experimental": "экспериментальное",
|
"experimental": "экспериментальное",
|
||||||
"mining": "шахтерство",
|
"mining": "добыча ресурсов",
|
||||||
"lasers": "лазеры",
|
"lasers": "лазеры",
|
||||||
"ordnance": "артиллерия",
|
"ordnance": "артиллерия",
|
||||||
"projectiles": "с боеприпасами",
|
"projectiles": "с боеприпасами",
|
||||||
"hangars": "ангары",
|
"hangars": "ангары",
|
||||||
"limpet controllers": "контроллеры снарядов",
|
"limpet controllers": "контроллеры дронов",
|
||||||
"passenger cabins": "каюты пассажиров",
|
"passenger cabins": "каюты пассажиров",
|
||||||
"structural reinforcement": "структурные усиления",
|
"structural reinforcement": "усиление конструктива",
|
||||||
"flight assists": "помощники в полете",
|
"flight assists": "помощь в полёте",
|
||||||
"modifications": "модификации",
|
"modifications": "модификации",
|
||||||
"wep_reload": "перезарядка",
|
"wep_reload": "перезарядка",
|
||||||
"optimal multiplier": "оптимальный усилитель",
|
"optimal multiplier": "оптимальный усилитель",
|
||||||
"Cargo Hatch": "Грузовой люк",
|
"Cargo Hatch": "Грузовой люк",
|
||||||
"Chaff Launcher": "Разбрасыватель дипольных отражателей",
|
"Chaff Launcher": "Разбрасыватель дипольных отражателей",
|
||||||
"Point Defence": "Точечная оборона",
|
"Point Defence": "Точечная оборона",
|
||||||
"Electronic Countermeasure": "Электронное противодействие",
|
"Electronic Countermeasure": "Радиоэлектронное подавление",
|
||||||
"Xeno Scanner": "Сканер «инопланетянин»",
|
"Xeno Scanner": "Ксено-сканер",
|
||||||
"Shutdown Field Neutraliser": "Нейтрализатор глушащего поля",
|
"Shutdown Field Neutraliser": "Нейтрализатор отключающего поля",
|
||||||
"Disruptor": "Диверсант",
|
"Disruptor": "«Диверсант»",
|
||||||
"Pacifier": "Миротворец",
|
"Pacifier": "«Миротворец»",
|
||||||
"Advanced Plasma Accelerator": "Улучшенный ускоритель плазмы",
|
"Advanced Plasma Accelerator": "Улучшенный ускоритель плазмы",
|
||||||
"Cytoscrambler": "Дезинтегратор",
|
"Cytoscrambler": "«Дезинтегратор»",
|
||||||
"Retributor": "Каратель",
|
"Retributor": "«Каратель»",
|
||||||
"Enforcer": "Убийца",
|
"Enforcer": "«Убийца»",
|
||||||
"Imperial Hammer": "Имперский молот",
|
"Imperial Hammer": "«Имперский молот»",
|
||||||
"Rocket Propelled FSD Disruptor": "Ракетный FSD-разрушитель",
|
"Rocket Propelled FSD Disruptor": "Ракетный FSD-разрушитель",
|
||||||
"Pack-Hound": "Гончие",
|
"Pack-Hound": "«Гончие»",
|
||||||
"Shock Mine Launcher": "Установщик шоковых мин",
|
"Shock Mine Launcher": "Установщик шоковых мин",
|
||||||
"Mining Lance": "Копье шахтера",
|
"Mining Lance": "«Копьё шахтера»",
|
||||||
"Corrosion Resistant": "Коррозийно-устойчивый стеллаж",
|
"Corrosion Resistant": "Коррозийно-устойчивый стеллаж",
|
||||||
"Standard Docking Computer": "Стандартный стыковочный компьютер",
|
"Standard Docking Computer": "Стандартный стыковочный компьютер",
|
||||||
"Advanced Docking Computer": "Улучшенный стыковочный компьютер",
|
"Advanced Docking Computer": "Улучшенный стыковочный компьютер",
|
||||||
@@ -557,20 +561,20 @@
|
|||||||
"Guardian Power Distributor": "Рапределитель питания Стражей",
|
"Guardian Power Distributor": "Рапределитель питания Стражей",
|
||||||
"Enhanced Performance": "Усиленные маневровые двигатели",
|
"Enhanced Performance": "Усиленные маневровые двигатели",
|
||||||
"Guardian Hybrid Power Plant": "Гибридная силовая установка Стражей",
|
"Guardian Hybrid Power Plant": "Гибридная силовая установка Стражей",
|
||||||
"Reinforced Alloy": "Укрепленные сплавы",
|
"Reinforced Alloy": "Укреплённые сплавы",
|
||||||
"Military Grade Composite": "Композит военного класса",
|
"Military Grade Composite": "Композит военного класса",
|
||||||
"Mirrored Surface Composite": "Композит с зеркальной поверхностью",
|
"Mirrored Surface Composite": "Композит с зеркальной поверхностью",
|
||||||
"Reactive Surface Composite": "Композит с реактивной поверхностью",
|
"Reactive Surface Composite": "Композит с реактивной поверхностью",
|
||||||
"Proto Light Alloys": "Опытные легкие сплавы",
|
"Proto Light Alloys": "Опытные лёгкие сплавы",
|
||||||
"Ammo capacity": "Вместимость магазина",
|
"Ammo capacity": "Вместимость магазина",
|
||||||
"Lightweight": "Облегченный",
|
"Lightweight": "Облегчённый",
|
||||||
"Reinforced": "Усиленный",
|
"Reinforced": "Усиленный",
|
||||||
"Shielded": "Защищенный",
|
"Shielded": "Защищённый",
|
||||||
"Fast scan": "Быстрое сканирование",
|
"Fast scan": "Быстрое сканирование",
|
||||||
"Long range": "Дальнего действия",
|
"Long range": "Дальнего действия",
|
||||||
"Wide angle": "Широкоугольный",
|
"Wide angle": "Широкоугольный",
|
||||||
"Blast resistant": "Взрывостойкий",
|
"Blast resistant": "Взрывостойкий",
|
||||||
"Heavy duty": "Надежный",
|
"Heavy duty": "Надёжный",
|
||||||
"Kinetic resistant": "Противокинетический",
|
"Kinetic resistant": "Противокинетический",
|
||||||
"Resistance augmented": "С универсальной защитой",
|
"Resistance augmented": "С универсальной защитой",
|
||||||
"Thermal resistant": "Термостойкий",
|
"Thermal resistant": "Термостойкий",
|
||||||
@@ -622,7 +626,7 @@
|
|||||||
"Penetrator Munitions": "Бронебойные боеголовки",
|
"Penetrator Munitions": "Бронебойные боеголовки",
|
||||||
"Mass lock munition": "Боеприпасы с гравитационным захватом",
|
"Mass lock munition": "Боеприпасы с гравитационным захватом",
|
||||||
"Mass Lock Munition": "Боеприпасы с гравитационным захватом",
|
"Mass Lock Munition": "Боеприпасы с гравитационным захватом",
|
||||||
"Reverberating cascade": "Отраженный залп",
|
"Reverberating cascade": "Отражённый залп",
|
||||||
"Shift-lock canister": "Рамоблокирующая кассета",
|
"Shift-lock canister": "Рамоблокирующая кассета",
|
||||||
"Ion disruptor": "Ионный дестабилизатор",
|
"Ion disruptor": "Ионный дестабилизатор",
|
||||||
"Radiant Canister": "Светящаяся кассета",
|
"Radiant Canister": "Светящаяся кассета",
|
||||||
@@ -639,7 +643,7 @@
|
|||||||
"Reflective Plating": "Отражающая броня",
|
"Reflective Plating": "Отражающая броня",
|
||||||
"Angled Plating": "Угловая броня",
|
"Angled Plating": "Угловая броня",
|
||||||
"Layered Plating": "Многослойная броня",
|
"Layered Plating": "Многослойная броня",
|
||||||
"Deep Plating": "Утолщенная броня",
|
"Deep Plating": "Утолщённая броня",
|
||||||
"Expanded Probe Scanning Radius": "Увеличение радиуса сканирования зондов",
|
"Expanded Probe Scanning Radius": "Увеличение радиуса сканирования зондов",
|
||||||
"High charge capacity": "Высокоёмкий",
|
"High charge capacity": "Высокоёмкий",
|
||||||
"Charge enhanced": "Быстрозаряжающийся",
|
"Charge enhanced": "Быстрозаряжающийся",
|
||||||
@@ -666,8 +670,8 @@
|
|||||||
"Combat": "Боец",
|
"Combat": "Боец",
|
||||||
"Trader": "Торговец",
|
"Trader": "Торговец",
|
||||||
"Explorer": "Исследователь",
|
"Explorer": "Исследователь",
|
||||||
"Planetary Explorer": "Планетарный исследователь",
|
"Planetary Explorer": "Исследователь планет",
|
||||||
"Miner": "Шахтер",
|
"Miner": "Старатель",
|
||||||
"Racer": "Гонщик",
|
"Racer": "Гонщик",
|
||||||
|
|
||||||
"Aberrant Shield Pattern Analysis": "Анализ аномального поведения щита",
|
"Aberrant Shield Pattern Analysis": "Анализ аномального поведения щита",
|
||||||
@@ -691,7 +695,7 @@
|
|||||||
"Chemical Manipulators": "Манипуляторы для работы с химикатами",
|
"Chemical Manipulators": "Манипуляторы для работы с химикатами",
|
||||||
"Chemical Processors": "Оборудование для химобработки",
|
"Chemical Processors": "Оборудование для химобработки",
|
||||||
"Chromium": "Хром",
|
"Chromium": "Хром",
|
||||||
"Classified Scan Databanks": "Засекреченные базы данных сканированоя",
|
"Classified Scan Databanks": "Засекреченные базы данных сканирования",
|
||||||
"Classified Scan Fragment": "Засекреченные фрагменты данных сканирования",
|
"Classified Scan Fragment": "Засекреченные фрагменты данных сканирования",
|
||||||
"Compound Shielding": "Многоступенчатая защита",
|
"Compound Shielding": "Многоступенчатая защита",
|
||||||
"Conductive Ceramics": "Проводящая керамика",
|
"Conductive Ceramics": "Проводящая керамика",
|
||||||
@@ -702,7 +706,7 @@
|
|||||||
"Cracked Industrial Firmware": "Взломанные промышленные микропрограммы",
|
"Cracked Industrial Firmware": "Взломанные промышленные микропрограммы",
|
||||||
"Datamined Wake Exceptions": "Исключения из глубинного анализа данных следа",
|
"Datamined Wake Exceptions": "Исключения из глубинного анализа данных следа",
|
||||||
"Decoded Emission Data": "Расшифрованные данные об излучении",
|
"Decoded Emission Data": "Расшифрованные данные об излучении",
|
||||||
"Distorted Shield Cycle Recordings": "Поврежденные цикличные записи щита",
|
"Distorted Shield Cycle Recordings": "Повреждённые цикличные записи щита",
|
||||||
"Divergent Scan Data": "Неформатные данные сканирования",
|
"Divergent Scan Data": "Неформатные данные сканирования",
|
||||||
"Eccentric Hyperspace Trajectories": "Аномальные траектории в гиперпространстве",
|
"Eccentric Hyperspace Trajectories": "Аномальные траектории в гиперпространстве",
|
||||||
"Electrochemical Arrays": "Электрохимические массивы",
|
"Electrochemical Arrays": "Электрохимические массивы",
|
||||||
@@ -717,7 +721,7 @@
|
|||||||
"Heat Dispersion Plate": "Теплорассеивающая пластина",
|
"Heat Dispersion Plate": "Теплорассеивающая пластина",
|
||||||
"Heat Exchangers": "Теплообменные агрегаты",
|
"Heat Exchangers": "Теплообменные агрегаты",
|
||||||
"Heat Vanes": "Тепловые заслонки",
|
"Heat Vanes": "Тепловые заслонки",
|
||||||
"High Density Composites": "Высокоплотные композиты",
|
"High Density Composites": "Высокоплотностные композиты",
|
||||||
"Hybrid Capacitors": "Гибридные конденсаторы",
|
"Hybrid Capacitors": "Гибридные конденсаторы",
|
||||||
"Imperial Shielding": "Имперская защита",
|
"Imperial Shielding": "Имперская защита",
|
||||||
"Improvised Components": "Кустарные компоненты",
|
"Improvised Components": "Кустарные компоненты",
|
||||||
@@ -731,8 +735,8 @@
|
|||||||
"Mercury": "Ртуть",
|
"Mercury": "Ртуть",
|
||||||
"Military Grade Alloys": "Сплавы военного назначения",
|
"Military Grade Alloys": "Сплавы военного назначения",
|
||||||
"Military Supercapacitors": "Военные суперконденсаторы",
|
"Military Supercapacitors": "Военные суперконденсаторы",
|
||||||
"Modified Consumer Firmware": "Измененные пользовательские микропрограммы",
|
"Modified Consumer Firmware": "Изменённые пользовательские микропрограммы",
|
||||||
"Modified Embedded Firmware": "Измененные встроенные микропрограммы",
|
"Modified Embedded Firmware": "Изменённые встроенные микропрограммы",
|
||||||
"Molybdenum": "Молибден",
|
"Molybdenum": "Молибден",
|
||||||
"Nickel": "Никель",
|
"Nickel": "Никель",
|
||||||
"Niobium": "Ниобий",
|
"Niobium": "Ниобий",
|
||||||
@@ -741,7 +745,7 @@
|
|||||||
"Phase Alloys": "Фазовые сплавы",
|
"Phase Alloys": "Фазовые сплавы",
|
||||||
"Phosphorus": "Фосфор",
|
"Phosphorus": "Фосфор",
|
||||||
"Polymer Capacitors": "Полимерные конденсаторы",
|
"Polymer Capacitors": "Полимерные конденсаторы",
|
||||||
"Precipitated Alloys": "Осажденные сплавы",
|
"Precipitated Alloys": "Осаждённые сплавы",
|
||||||
"Proprietary Composites": "Патентованные композиты",
|
"Proprietary Composites": "Патентованные композиты",
|
||||||
"Proto Heat Radiators": "Прототипы теплоизлучателей",
|
"Proto Heat Radiators": "Прототипы теплоизлучателей",
|
||||||
"Proto Radiolic Alloys": "Сплавы для изготовления зондов",
|
"Proto Radiolic Alloys": "Сплавы для изготовления зондов",
|
||||||
@@ -749,15 +753,15 @@
|
|||||||
"Ruthenium": "Рутений",
|
"Ruthenium": "Рутений",
|
||||||
"Salvaged Alloys": "Захваченные сплавы",
|
"Salvaged Alloys": "Захваченные сплавы",
|
||||||
"Security Firmware Patch": "Обновление для защитной микропрограммы",
|
"Security Firmware Patch": "Обновление для защитной микропрограммы",
|
||||||
"Selenium": "Селениум",
|
"Selenium": "Селен",
|
||||||
"Shield Emitters": "Щитоизлучатели",
|
"Shield Emitters": "Щитоизлучатели",
|
||||||
"Shielding Sensors": "Сенсоры системы экранирования",
|
"Shielding Sensors": "Сенсоры системы экранирования",
|
||||||
"Specialised Legacy Firmware": "Специальные микропрограммы предыдущего поколения",
|
"Specialised Legacy Firmware": "Специальные микропрограммы предыдущего поколения",
|
||||||
"Strange Wake Solutions": "Странные расчеты следа",
|
"Strange Wake Solutions": "Странные расчёты следа",
|
||||||
"Sulphur": "Сера",
|
"Sulphur": "Сера",
|
||||||
"Tagged Encryption Codes": "Меченные шифровальные коды",
|
"Tagged Encryption Codes": "Меченные шифровальные коды",
|
||||||
"Technetium": "Технеций",
|
"Technetium": "Технеций",
|
||||||
"Tellurium": "Теллурий",
|
"Tellurium": "Теллур",
|
||||||
"Thermic Alloys": "Термические сплавы",
|
"Thermic Alloys": "Термические сплавы",
|
||||||
"Tin": "Олово",
|
"Tin": "Олово",
|
||||||
"Tungsten": "Вольфрам",
|
"Tungsten": "Вольфрам",
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
import '@babel/polyfill';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { render } from 'react-dom';
|
import { render } from 'react-dom';
|
||||||
import '../less/app.less';
|
import '../less/app.less';
|
||||||
import Coriolis from './Coriolis';
|
import Coriolis from './Coriolis';
|
||||||
// import TapEventPlugin from 'react/lib/TapEventPlugin';
|
|
||||||
// import EventPluginHub from 'react/lib/EventPluginHub';
|
|
||||||
|
|
||||||
// onTouchTap not ready for primetime yet, too many issues with preventing default
|
|
||||||
// EventPluginHub.injection.injectEventPluginsByName({ TapEventPlugin });
|
|
||||||
|
|
||||||
render(<Coriolis />, document.getElementById('coriolis'));
|
render(<Coriolis />, document.getElementById('coriolis'));
|
||||||
|
|||||||
@@ -33,24 +33,27 @@ export default class AboutPage extends Page {
|
|||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
This is a clone of the Coriolis project, whose original author is
|
This is now the only active version of the Coriolis project. The original author has handed over the maintenance of the project to the {' '}
|
||||||
currently unable to maintain it. This clone is maintained by the{' '}
|
|
||||||
<a href="http://edcd.github.io/">EDCD community</a>.
|
<a href="http://edcd.github.io/">EDCD community</a>.
|
||||||
</p>
|
</p>
|
||||||
|
<h3>Expectations</h3>
|
||||||
<p>
|
<p>
|
||||||
To recover your builds, go to{' '}
|
Although every attempt is made to update the data as soon as possible, following the release of new modules and ships, there may be a delay, of up-to a few days, before the data is available. Wherever possible, the current maintainers aim to keep this delay to a minimum. Please be aware that the project maintainers are volunteers and have real lives to attend to, so please be patient. If you would like to help with the maintenance of the project, please see the link to the EDCD Discord Server below, where you can get involved.
|
||||||
<a href="https://coriolis.io/" target="_blank">
|
|
||||||
https://coriolis.io/
|
|
||||||
</a>
|
|
||||||
, backup your builds (Settings / Backup), copy the text, return here
|
|
||||||
and import (Settings / Import).
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
The Coriolis project was inspired by{' '}
|
There are, some missing modules from the time where the project was essentially not being maintained. These modules are gradually being added to the Coriolis database as and when the maintainers have the time to do so.
|
||||||
<a href="http://www.edshipyard.com/" target="_blank">
|
</p>
|
||||||
E:D Shipyard
|
<p>
|
||||||
</a>{' '}
|
Please check the {' '} <a href="https://github.com/EDCD/coriolis/issues/" target="_blank" >Github Issues List</a> for any specific modules you cannot find and see if there is an open request for them. If not, please feel free to open a new issue, however, please note that there is an existing issue open for the addition of pre-engineered modules, so please do not open a new issue for these.
|
||||||
and, of course,{' '}
|
</p>
|
||||||
|
<h3>Donations</h3>
|
||||||
|
<p>
|
||||||
|
If you would like to donate to the project, in order to help with the costs of hosting and maintainence, please see the link to the {' '}
|
||||||
|
<a href="https://github.com/Brighter-Applications/coriolis" target="_blank">Current Maintainers version of the Git Repository</a> and use the 'Sponsor' button at the top of the page.
|
||||||
|
</p>
|
||||||
|
<h3>History</h3>
|
||||||
|
<p>
|
||||||
|
The Coriolis project was inspired by 'E:D Shipyard' (Now Defunct) and, of course,{' '}
|
||||||
<a href="http://www.elitedangerous.com" target="_blank">
|
<a href="http://www.elitedangerous.com" target="_blank">
|
||||||
Elite Dangerous
|
Elite Dangerous
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export default class ErrorDetails extends React.Component {
|
|||||||
<div style={{ marginTop: '2em' }}>
|
<div style={{ marginTop: '2em' }}>
|
||||||
<div><span className='warning'>Browser:</span> {window.navigator.userAgent}</div>
|
<div><span className='warning'>Browser:</span> {window.navigator.userAgent}</div>
|
||||||
<div><span className='warning'>Path:</span> {this.context.route.canonicalPath}</div>
|
<div><span className='warning'>Path:</span> {this.context.route.canonicalPath}</div>
|
||||||
<div><span className='warning'>Error:</span> {error.type || 'Unknown'}</div>
|
<div><span className='warning'>Error:</span> {ed["error"] || 'Unknown'}</div>
|
||||||
<div className='warning'>Details:</div>
|
<div className='warning'>Details:</div>
|
||||||
<div><pre>{typeof ed == 'object' ? Object.keys(ed).map((e) => `${e}: ${ed[e]}\n`) : ed}</pre></div>
|
<div><pre>{typeof ed == 'object' ? Object.keys(ed).map((e) => `${e}: ${ed[e]}\n`) : ed}</pre></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -42,15 +42,67 @@ export default class ErrorDetails extends React.Component {
|
|||||||
|
|
||||||
const importerror = ed && ed.scriptUrl && ed.scriptUrl.indexOf('/import') != -1;
|
const importerror = ed && ed.scriptUrl && ed.scriptUrl.indexOf('/import') != -1;
|
||||||
|
|
||||||
return <div className='error'>
|
if (ed['error'].match(/URL Length/i)) {
|
||||||
<h1>Jameson, we have a problem..</h1>
|
return <div className='error'>
|
||||||
<h1><small>{error.message}</small></h1>
|
<h1>Jameson, we have a problem..</h1>
|
||||||
<br/>
|
<h1><small>{error.message}</small></h1>
|
||||||
{importerror ? <div>If you are attempting to import a ship from EDDI or EDMC and are seeing a 'Z_BUF_ERROR' it means that the URL has not been provided correctly. This is a common problem when using Microsoft Internet Explorer or Microsoft Edge, and you should use another browser instead.</div> : null }
|
It looks as though you've encountered a URL Length issue for your browser.
|
||||||
<br/>
|
|
||||||
<div>Please note that this site uses Google Analytics to track performance and usage. If you are blocking cookies, for example using Ghostery, please disable blocking for this site and try again.</div>
|
<br /><br />
|
||||||
<br/>
|
|
||||||
{content}
|
This is a known issue with Internet Explorer and Edge, as well as Google Chrome, all of which only support 2083 characters and your URL is:
|
||||||
</div>;
|
|
||||||
|
<br /><br />
|
||||||
|
|
||||||
|
{ed["error"]} characters.
|
||||||
|
|
||||||
|
<br /><br />
|
||||||
|
|
||||||
|
Please try using another browser first, before reporting an issue, such as Firefox which supports 65,536 characters or Safari, which supports 80,000 characters.
|
||||||
|
|
||||||
|
<br /><br />
|
||||||
|
|
||||||
|
Don't copy the URL from Explorer, Edge or Chrome, as they will have truncated it and the data string will be incorrect. You'll need to change your default browser settings, so that when you click the link, it opens in the browser you want to use.
|
||||||
|
<br /><br />
|
||||||
|
If you're already using Firefox, which supports up to 65,536 characters or Safari, which supports up to 80,000 characters, please see the data output below.
|
||||||
|
<br/><br />
|
||||||
|
<h3>Data Output</h3>
|
||||||
|
{content}
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return <div className='error'>
|
||||||
|
<h1>Jameson, we have a problem..</h1>
|
||||||
|
<h1><small>{error.message}</small></h1>
|
||||||
|
Import Error handling has been improved, but still isn't perfect.
|
||||||
|
|
||||||
|
<br /><br />
|
||||||
|
|
||||||
|
If you're seeing this page, we may have failed to handle the errors in your import correctly. Please check the common import failures list and then the data output below, specifically the 'scriptUrl:' section if it's there and then if you feel confident enough, please check the github issues page linked below and see if there is a similar issue already logged. If not, please create a new issue with the data below. If you're not confident, please ask for help on the Coriolis Channel of the EDCD Discord server.
|
||||||
|
|
||||||
|
<br /><br />
|
||||||
|
<h3>Common Import Failures</h3>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Previously, most failures were a result of missing modules in Coriolis, although this is rarer now since the import system was improved. If you're using a module in game and you know it isn't in Coriolis, this could be the problem, please check the data output section below.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Incorrect import strings generated by third party apps do still occur, please check the data output below and if the import was from something like EDMC, please check you're using the latest version.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
You've hit a 'maximum URL Length' for your browser. This is a known issue with Internet Explorer and Edge, as well as Google Chrome, all of which only support 2083 characters. Please try using another browser first, before reporting an issue, such as Firefox which supports 65,536 characters or Safari, which supports 80,000 characters. Don't copy the URL from Explorer, Edge or Chrome, as they will have truncated it and the data string will be incorrect. You'll need to change your default browser settings, so that when you click the link, it opens in the browser you want to use.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{importerror ? <div>If you are attempting to import a ship from EDDI or EDMC and are seeing a 'Z_BUF_ERROR' it means that the URL has not been understood correctly by the browser. This is a common problem when using Microsoft Internet Explorer or Microsoft Edge, and you should use another browser instead.</div> : null }
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<br/>
|
||||||
|
<div>Please note that this site uses Google Analytics to track performance and usage. If you are blocking cookies, for example using Ghostery, please disable blocking for this site and try again.</div>
|
||||||
|
<br/>
|
||||||
|
<h3>Data Output</h3>
|
||||||
|
{content}
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
// import Perf from 'react-addons-perf';
|
|
||||||
import { Ships } from 'coriolis-data/dist';
|
import { Ships } from 'coriolis-data/dist';
|
||||||
import cn from 'classnames';
|
import cn from 'classnames';
|
||||||
import Page from './Page';
|
import Page from './Page';
|
||||||
@@ -58,7 +57,6 @@ export default class OutfittingPage extends Page {
|
|||||||
*/
|
*/
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
// window.Perf = Perf;
|
|
||||||
this.state = this._initState(props, context);
|
this.state = this._initState(props, context);
|
||||||
this._keyDown = this._keyDown.bind(this);
|
this._keyDown = this._keyDown.bind(this);
|
||||||
this._exportBuild = this._exportBuild.bind(this);
|
this._exportBuild = this._exportBuild.bind(this);
|
||||||
@@ -679,9 +677,9 @@ export default class OutfittingPage extends Page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open up a window for EDDB with a shopping list of our components
|
* Open up a window for inara with a shopping list of our components
|
||||||
*/
|
*/
|
||||||
_eddbShoppingList() {
|
_inaraShoppingList() {
|
||||||
const ship = this.state.ship;
|
const ship = this.state.ship;
|
||||||
|
|
||||||
const shipId = Ships[ship.id].eddbID;
|
const shipId = Ships[ship.id].eddbID;
|
||||||
@@ -694,7 +692,7 @@ export default class OutfittingPage extends Page {
|
|||||||
|
|
||||||
// Open up the relevant URL
|
// Open up the relevant URL
|
||||||
window.open(
|
window.open(
|
||||||
'https://eddb.io/station?s=' + shipId + '&m=' + modIds.join(',')
|
'https://inara.cz/inapi/corisearch.php?s=' + shipId + '&m=' + modIds.join(',')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -702,7 +700,9 @@ export default class OutfittingPage extends Page {
|
|||||||
* Generates the shopping list
|
* Generates the shopping list
|
||||||
*/
|
*/
|
||||||
_genShoppingList() {
|
_genShoppingList() {
|
||||||
this.context.showModal(<ModalShoppingList ship={this.state.ship} />);
|
this.context.showModal(<ModalShoppingList
|
||||||
|
ship={this.state.ship}
|
||||||
|
buildName={this.state.buildName} />);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -914,7 +914,7 @@ export default class OutfittingPage extends Page {
|
|||||||
<Download className="lg" />
|
<Download className="lg" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={this._eddbShoppingList}
|
onClick={this._inaraShoppingList}
|
||||||
onMouseOver={termtip.bind(null, 'PHRASE_SHOPPING_LIST')}
|
onMouseOver={termtip.bind(null, 'PHRASE_SHOPPING_LIST')}
|
||||||
onMouseOut={hide}
|
onMouseOut={hide}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -383,7 +383,8 @@ export function shieldMetrics(ship, sys) {
|
|||||||
|
|
||||||
// Our initial regeneration comes from the SYS capacitor store, which is replenished as it goes
|
// Our initial regeneration comes from the SYS capacitor store, which is replenished as it goes
|
||||||
// 0.6 is a magic number from FD: each 0.6 MW of energy from the power distributor recharges 1 MJ/s of regeneration
|
// 0.6 is a magic number from FD: each 0.6 MW of energy from the power distributor recharges 1 MJ/s of regeneration
|
||||||
let capacitorDrain = (shieldGenerator.getBrokenRegenerationRate() * 0.6) - sysRechargeRate;
|
let capacitorDrain = (shieldGenerator.getBrokenRegenerationRate() * shieldGenerator.getDistDraw()) - sysRechargeRate;
|
||||||
|
|
||||||
let capacitorLifetime = powerDistributor.getSystemsCapacity() / capacitorDrain;
|
let capacitorLifetime = powerDistributor.getSystemsCapacity() / capacitorDrain;
|
||||||
|
|
||||||
let recover = 16;
|
let recover = 16;
|
||||||
@@ -399,7 +400,7 @@ export function shieldMetrics(ship, sys) {
|
|||||||
recover = Math.Infinity;
|
recover = Math.Infinity;
|
||||||
} else {
|
} else {
|
||||||
// Recover remaining shields at the rate of the power distributor's recharge
|
// Recover remaining shields at the rate of the power distributor's recharge
|
||||||
recover += remainingShieldToRecover / (sysRechargeRate / 0.6);
|
recover += remainingShieldToRecover / (sysRechargeRate / shieldGenerator.getDistDraw());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,7 +409,7 @@ export function shieldMetrics(ship, sys) {
|
|||||||
|
|
||||||
// Our initial regeneration comes from the SYS capacitor store, which is replenished as it goes
|
// Our initial regeneration comes from the SYS capacitor store, which is replenished as it goes
|
||||||
// 0.6 is a magic number from FD: each 0.6 MW of energy from the power distributor recharges 1 MJ/s of regeneration
|
// 0.6 is a magic number from FD: each 0.6 MW of energy from the power distributor recharges 1 MJ/s of regeneration
|
||||||
capacitorDrain = (shieldGenerator.getRegenerationRate() * 0.6) - sysRechargeRate;
|
capacitorDrain = (shieldGenerator.getRegenerationRate() * shieldGenerator.getDistDraw()) - sysRechargeRate;
|
||||||
capacitorLifetime = powerDistributor.getSystemsCapacity() / capacitorDrain;
|
capacitorLifetime = powerDistributor.getSystemsCapacity() / capacitorDrain;
|
||||||
|
|
||||||
let recharge = 0;
|
let recharge = 0;
|
||||||
@@ -424,7 +425,7 @@ export function shieldMetrics(ship, sys) {
|
|||||||
recharge = Math.Inf;
|
recharge = Math.Inf;
|
||||||
} else {
|
} else {
|
||||||
// Recharge remaining shields at the rate of the power distributor's recharge
|
// Recharge remaining shields at the rate of the power distributor's recharge
|
||||||
recharge += remainingShieldToRecharge / (sysRechargeRate / 0.6);
|
recharge += remainingShieldToRecharge / (sysRechargeRate / shieldGenerator.getDistDraw());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -918,8 +919,8 @@ export function _weaponSustainedDps(m, opponent, opponentShields, opponentArmour
|
|||||||
weapon.effectiveness.shields.total = weapon.effectiveness.shields.range * weapon.effectiveness.shields.sys * weapon.effectiveness.shields.resistance;
|
weapon.effectiveness.shields.total = weapon.effectiveness.shields.range * weapon.effectiveness.shields.sys * weapon.effectiveness.shields.resistance;
|
||||||
weapon.effectiveness.armour.total = weapon.effectiveness.armour.range * weapon.effectiveness.armour.resistance * weapon.effectiveness.armour.hardness;
|
weapon.effectiveness.armour.total = weapon.effectiveness.armour.range * weapon.effectiveness.armour.resistance * weapon.effectiveness.armour.hardness;
|
||||||
|
|
||||||
weapon.effectiveness.shields.dpe = weapon.damage.shields.total / m.getEps();
|
weapon.effectiveness.shields.dpe = weapon.damage.shields.total / m.getEps() / m.getSustainedFactor();
|
||||||
weapon.effectiveness.armour.dpe = weapon.damage.armour.total / m.getEps();
|
weapon.effectiveness.armour.dpe = weapon.damage.armour.total / m.getEps() / m.getSustainedFactor();
|
||||||
|
|
||||||
|
|
||||||
return weapon;
|
return weapon;
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ export const ModuleGroupToName = {
|
|||||||
pd: 'Power Distributor',
|
pd: 'Power Distributor',
|
||||||
s: 'Sensors',
|
s: 'Sensors',
|
||||||
ft: 'Fuel Tank',
|
ft: 'Fuel Tank',
|
||||||
pas: 'Planetary Approach Suite',
|
|
||||||
|
|
||||||
// Internal
|
// Internal
|
||||||
fs: 'Fuel Scoop',
|
fs: 'Fuel Scoop',
|
||||||
@@ -58,6 +57,9 @@ export const ModuleGroupToName = {
|
|||||||
gmrp: 'Guardian Module Reinforcement Package',
|
gmrp: 'Guardian Module Reinforcement Package',
|
||||||
mahr: 'Meta Alloy Hull Reinforcement Package',
|
mahr: 'Meta Alloy Hull Reinforcement Package',
|
||||||
sua: 'Supercruise Assist',
|
sua: 'Supercruise Assist',
|
||||||
|
mlc: "Multi Limpet Controller",
|
||||||
|
rpl: "Repair Limpet Controller",
|
||||||
|
pas: 'Planetary Approach Suite',
|
||||||
|
|
||||||
// Hard Points
|
// Hard Points
|
||||||
bl: 'Beam Laser',
|
bl: 'Beam Laser',
|
||||||
@@ -75,11 +77,15 @@ export const ModuleGroupToName = {
|
|||||||
nl: 'Mine Launcher',
|
nl: 'Mine Launcher',
|
||||||
ml: 'Mining Laser',
|
ml: 'Mining Laser',
|
||||||
mr: 'Missile Rack',
|
mr: 'Missile Rack',
|
||||||
|
amr: 'Missile Rack (Advanced)',
|
||||||
axmr: 'AX Missile Rack',
|
axmr: 'AX Missile Rack',
|
||||||
|
axmre: 'AX Missile Rack (Enhanced)',
|
||||||
pa: 'Plasma Accelerator',
|
pa: 'Plasma Accelerator',
|
||||||
po: 'Point Defence',
|
po: 'Point Defence',
|
||||||
mc: 'Multi-cannon',
|
mc: 'Multi-cannon',
|
||||||
|
advmc: 'Multi-cannon (Advanced)',
|
||||||
axmc: 'AX Multi-cannon',
|
axmc: 'AX Multi-cannon',
|
||||||
|
axmce: 'AX Multi-cannon (Enhanced)',
|
||||||
pl: 'Pulse Laser',
|
pl: 'Pulse Laser',
|
||||||
rg: 'Rail Gun',
|
rg: 'Rail Gun',
|
||||||
sb: 'Shield Booster',
|
sb: 'Shield Booster',
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ export default class Module {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a value for a given modification ID
|
* Set a value for a given modification ID
|
||||||
* @param {Number} name The name of the modification
|
* @param {String} name The name of the modification
|
||||||
* @param {object} value The value of the modification. If it is a numeric value then it should be an integer scaled so that -2.34% == -234
|
* @param {object} value The value of the modification. If it is a numeric value then it should be an integer scaled so that -2.34% == -234
|
||||||
* @param {Boolean} valueiswithspecial true if the value includes the special effect (when coming from a UI component)
|
* @param {Boolean} valueiswithspecial true if the value includes the special effect (when coming from a UI component)
|
||||||
*/
|
*/
|
||||||
@@ -81,7 +81,13 @@ export default class Module {
|
|||||||
if (!this.origVals) {
|
if (!this.origVals) {
|
||||||
this.origVals = {};
|
this.origVals = {};
|
||||||
}
|
}
|
||||||
if (valueiswithspecial && this.blueprint && this.blueprint.special) {
|
if (!valueiswithspecial) {
|
||||||
|
// Resistance modifiers scale with the base value.
|
||||||
|
if (name === 'kinres' || name === 'thermres' || name === 'causres' || name === 'explres') {
|
||||||
|
let baseValue = this.get(name, false);
|
||||||
|
value = (1 - baseValue) * value;
|
||||||
|
}
|
||||||
|
} else if (valueiswithspecial && this.blueprint && this.blueprint.special) {
|
||||||
// This module has a special effect, see if we need to alter the stored value
|
// This module has a special effect, see if we need to alter the stored value
|
||||||
const modifierActions = Modifications.modifierActions[this.blueprint.special.edname];
|
const modifierActions = Modifications.modifierActions[this.blueprint.special.edname];
|
||||||
if (modifierActions && modifierActions[name]) {
|
if (modifierActions && modifierActions[name]) {
|
||||||
@@ -113,7 +119,7 @@ export default class Module {
|
|||||||
/**
|
/**
|
||||||
* Helper to obtain a module's value.
|
* Helper to obtain a module's value.
|
||||||
* @param {String} name The name of the modifier to obtain
|
* @param {String} name The name of the modifier to obtain
|
||||||
* @param {Number} modified Whether to return the raw or modified value
|
* @param {Boolean} modified Whether to return the raw or modified value
|
||||||
* @return {Number} The value queried
|
* @return {Number} The value queried
|
||||||
*/
|
*/
|
||||||
get(name, modified = true) {
|
get(name, modified = true) {
|
||||||
@@ -433,6 +439,15 @@ export default class Module {
|
|||||||
return this.get('integrity', modified);
|
return this.get('integrity', modified);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the info of this module
|
||||||
|
* @param {Boolean} [modified=false] Whether to take modifications into account
|
||||||
|
* @return {String} the info of this module
|
||||||
|
*/
|
||||||
|
getInfo(modified = false) {
|
||||||
|
return (modified && this.getModValue('info')) || this.info;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the mass of this module
|
* Get the mass of this module
|
||||||
* @param {Boolean} [modified=true] Whether to take modifications into account
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
||||||
@@ -912,8 +927,9 @@ export default class Module {
|
|||||||
const burst = this.get('burst', modified) || 1;
|
const burst = this.get('burst', modified) || 1;
|
||||||
const burstRoF = this.get('burstrof', modified) || 1;
|
const burstRoF = this.get('burstrof', modified) || 1;
|
||||||
const intRoF = this.get('rof', modified);
|
const intRoF = this.get('rof', modified);
|
||||||
|
const charge = this.get('charge', modified) || 0;
|
||||||
|
|
||||||
return burst / (((burst - 1) / burstRoF) + 1 / intRoF);
|
return burst / (((burst - 1) / burstRoF) + 1 / intRoF + charge);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -13,6 +13,19 @@ function filter(arr, maxClass, minClass, mass) {
|
|||||||
return arr.filter(m => m.class <= maxClass && m.class >= minClass && (m.maxmass === undefined || mass <= m.maxmass));
|
return arr.filter(m => m.class <= maxClass && m.class >= minClass && (m.maxmass === undefined || mass <= m.maxmass));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter SCO Modules to only return legal size.
|
||||||
|
* @param {Array} arr Array of available FSD modules.
|
||||||
|
* @param {number} maxSize Maximum allowable size for SCO modules.
|
||||||
|
* @return {Array} Subset of modules filtered based on legal size amd type.
|
||||||
|
*/
|
||||||
|
function sco_filter(arr, maxSize) {
|
||||||
|
return arr.filter(module => {
|
||||||
|
return !(module.hasOwnProperty('name') && module['name'] === "Frame Shift Drive (SCO)" && module['class'] < maxSize);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The available module set for a specific ship
|
* The available module set for a specific ship
|
||||||
*/
|
*/
|
||||||
@@ -41,6 +54,7 @@ export default class ModuleSet {
|
|||||||
|
|
||||||
this.standard[0] = filter(stnd.pp, maxStandardArr[0], 0, mass); // Power Plant
|
this.standard[0] = filter(stnd.pp, maxStandardArr[0], 0, mass); // Power Plant
|
||||||
this.standard[2] = filter(stnd.fsd, maxStandardArr[2], 0, mass); // FSD
|
this.standard[2] = filter(stnd.fsd, maxStandardArr[2], 0, mass); // FSD
|
||||||
|
this.standard[2] = sco_filter(this.standard[2], maxStandardArr[2]) // FSD - Filter SCO Modules
|
||||||
this.standard[4] = filter(stnd.pd, maxStandardArr[4], 0, mass); // Power Distributor
|
this.standard[4] = filter(stnd.pd, maxStandardArr[4], 0, mass); // Power Distributor
|
||||||
this.standard[6] = filter(stnd.ft, maxStandardArr[6], 0, mass); // Fuel Tank
|
this.standard[6] = filter(stnd.ft, maxStandardArr[6], 0, mass); // Fuel Tank
|
||||||
// Thrusters, filter modules by class only (to show full list of ratings for that class)
|
// Thrusters, filter modules by class only (to show full list of ratings for that class)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { Ships, Modifications } from 'coriolis-data/dist';
|
|||||||
import { chain } from 'lodash';
|
import { chain } from 'lodash';
|
||||||
const zlib = require('zlib');
|
const zlib = require('zlib');
|
||||||
|
|
||||||
const UNIQUE_MODULES = ['psg', 'sg', 'bsg', 'rf', 'fs', 'fh', 'gfsb', 'dc'];
|
const UNIQUE_MODULES = ['psg', 'sg', 'bsg', 'rf', 'fs', 'fh', 'gfsb', 'dc', 'ews'];
|
||||||
|
|
||||||
// Constants for modifications struct
|
// Constants for modifications struct
|
||||||
const SLOT_ID_DONE = -1;
|
const SLOT_ID_DONE = -1;
|
||||||
@@ -140,7 +140,7 @@ export default class Ship {
|
|||||||
*/
|
*/
|
||||||
canBoost(cargo, fuel) {
|
canBoost(cargo, fuel) {
|
||||||
return this.canThrust(cargo, fuel) && // Thrusters operational
|
return this.canThrust(cargo, fuel) && // Thrusters operational
|
||||||
this.standard[4].m.getEnginesCapacity() > this.boostEnergy; // PD capacitor is sufficient for boost
|
this.standard[4].m.getEnginesCapacity() >= this.boostEnergy; // PD capacitor is sufficient for boost
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -492,25 +492,18 @@ export default class Ship {
|
|||||||
* @param {Object} m The module to change
|
* @param {Object} m The module to change
|
||||||
* @param {Object} name The name of the modification to change
|
* @param {Object} name The name of the modification to change
|
||||||
* @param {Number} value The new value of the modification. The value of the modification is scaled to provide two decimal places of precision in an integer. For example 1.23% is stored as 123
|
* @param {Number} value The new value of the modification. The value of the modification is scaled to provide two decimal places of precision in an integer. For example 1.23% is stored as 123
|
||||||
* @param {bool} sentfromui True if this update was sent from the UI
|
* @param {boolean} isAbsolute True if value is an absolute value and not a modification value
|
||||||
* @param {bool} isAbsolute True if value is an absolute value and not a
|
|
||||||
* modification value
|
|
||||||
*/
|
*/
|
||||||
setModification(m, name, value, sentfromui, isAbsolute) {
|
setModification(m, name, value, isAbsolute = false) {
|
||||||
if (isNaN(value)) {
|
if (isNaN(value)) {
|
||||||
// Value passed is invalid; reset it to 0
|
// Value passed is invalid; reset it to 0
|
||||||
value = 0;
|
value = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isAbsolute) {
|
if (isAbsolute) {
|
||||||
m.setPretty(name, value, sentfromui);
|
m.setPretty(name, value, isAbsolute);
|
||||||
} else {
|
} else {
|
||||||
// Resistance modifiers scale with the base value
|
m.setModValue(name, value, false);
|
||||||
if (name == 'kinres' || name == 'thermres' || name == 'causres' || name == 'explres') {
|
|
||||||
let baseValue = m.get(name, false);
|
|
||||||
value = (1 - baseValue) * value;
|
|
||||||
}
|
|
||||||
m.setModValue(name, value, sentfromui);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle special cases
|
// Handle special cases
|
||||||
@@ -543,7 +536,7 @@ export default class Ship {
|
|||||||
this.recalculateArmour();
|
this.recalculateArmour();
|
||||||
} else if (name === 'shieldreinforcement') {
|
} else if (name === 'shieldreinforcement') {
|
||||||
this.recalculateShieldCells();
|
this.recalculateShieldCells();
|
||||||
} else if (name === 'burst' || name == 'burstrof' || name === 'clip' || name === 'damage' || name === 'distdraw' || name === 'jitter' || name === 'piercing' || name === 'range' || name === 'reload' || name === 'rof' || name === 'thermload') {
|
} else if (name === 'burst' || name === 'burstrof' || name === 'clip' || name === 'damage' || name === 'distdraw' || name === 'jitter' || name === 'piercing' || name === 'range' || name === 'reload' || name === 'rof' || name === 'thermload') {
|
||||||
this.recalculateDps();
|
this.recalculateDps();
|
||||||
this.recalculateHps();
|
this.recalculateHps();
|
||||||
this.recalculateEps();
|
this.recalculateEps();
|
||||||
@@ -1217,12 +1210,11 @@ export default class Ship {
|
|||||||
.value();
|
.value();
|
||||||
|
|
||||||
// Update global stats
|
// Update global stats
|
||||||
this.unladenMass = unladenMass;
|
this.unladenMass = unladenMass + fuelCapacity;
|
||||||
this.cargoCapacity = cargoCapacity;
|
this.cargoCapacity = cargoCapacity;
|
||||||
this.fuelCapacity = fuelCapacity;
|
this.fuelCapacity = fuelCapacity;
|
||||||
this.passengerCapacity = passengerCapacity;
|
this.passengerCapacity = passengerCapacity;
|
||||||
this.ladenMass = unladenMass + fuelCapacity + cargoCapacity;
|
this.ladenMass = unladenMass + fuelCapacity + cargoCapacity;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -108,9 +108,9 @@ export class Persist extends EventEmitter {
|
|||||||
this.matsPerGrade = matsPerGrade || {
|
this.matsPerGrade = matsPerGrade || {
|
||||||
1: 2,
|
1: 2,
|
||||||
2: 2,
|
2: 2,
|
||||||
3: 4,
|
3: 3,
|
||||||
4: 4,
|
4: 4,
|
||||||
5: 10
|
5: 5
|
||||||
};
|
};
|
||||||
this.cmdrName = cmdrName || { selected: '', cmdrs: [] };
|
this.cmdrName = cmdrName || { selected: '', cmdrs: [] };
|
||||||
this.tooltipsEnabled = tips === null ? true : tips;
|
this.tooltipsEnabled = tips === null ? true : tips;
|
||||||
|
|||||||
@@ -1,435 +1,458 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Modifications } from 'coriolis-data/dist';
|
import { Modifications } from 'coriolis-data/dist';
|
||||||
import { STATS_FORMATTING } from '../shipyard/StatsFormatting';
|
import { STATS_FORMATTING } from '../shipyard/StatsFormatting';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a tooltip with details of a blueprint's specials
|
* Generate a tooltip with details of a blueprint's specials
|
||||||
* @param {Object} translate The translate object
|
* @param {Object} translate The translate object
|
||||||
* @param {Object} blueprint The blueprint at the required grade
|
* @param {Object} blueprint The blueprint at the required grade
|
||||||
* @param {string} grp The group of the module
|
* @param {string} grp The group of the module
|
||||||
* @param {Object} m The module to compare with
|
* @param {Object} m The module to compare with
|
||||||
* @param {string} specialName The name of the special
|
* @param {string} specialName The name of the special
|
||||||
* @returns {Object} The react components
|
* @returns {Object} The react components
|
||||||
*/
|
*/
|
||||||
export function specialToolTip(translate, blueprint, grp, m, specialName) {
|
export function specialToolTip(translate, blueprint, grp, m, specialName) {
|
||||||
const effects = [];
|
const description = [];
|
||||||
if (!blueprint || !blueprint.features) {
|
const effects = [];
|
||||||
return undefined;
|
if (!blueprint || !blueprint.features) {
|
||||||
}
|
return undefined;
|
||||||
if (m) {
|
}
|
||||||
// We also add in any benefits from specials that aren't covered above
|
if (m) {
|
||||||
if (m.blueprint) {
|
// We also add in any benefits from specials that aren't covered above
|
||||||
for (const feature in Modifications.modifierActions[specialName]) {
|
if (m.blueprint) {
|
||||||
// if (!blueprint.features[feature] && !m.mods.feature) {
|
if (specialName) {
|
||||||
const featureDef = Modifications.modifications[feature];
|
if (Modifications.specials[specialName].description) {
|
||||||
if (featureDef && !featureDef.hidden) {
|
description.push(
|
||||||
let symbol = '';
|
<div className={'success'} style={{ maxWidth: 350, padding: 5, marginBottom: 10 }}>
|
||||||
if (feature === 'jitter') {
|
{Modifications.specials[specialName].description}
|
||||||
symbol = '°';
|
</div>
|
||||||
} else if (featureDef.type === 'percentage') {
|
);
|
||||||
symbol = '%';
|
}
|
||||||
}
|
}
|
||||||
let current = m.getModValue(feature) - m.getModValue(feature, true);
|
for (const feature in Modifications.modifierActions[specialName]) {
|
||||||
if (featureDef.type === 'percentage') {
|
// if (!blueprint.features[feature] && !m.mods.feature) {
|
||||||
current = Math.round(current / 10) / 10;
|
const featureDef = Modifications.modifications[feature];
|
||||||
} else if (featureDef.type === 'numeric') {
|
if (featureDef && !featureDef.hidden) {
|
||||||
current /= 100;
|
let symbol = '';
|
||||||
}
|
if (feature === 'jitter') {
|
||||||
const currentIsBeneficial = isValueBeneficial(feature, current);
|
symbol = '°';
|
||||||
|
} else if (featureDef.type === 'percentage') {
|
||||||
effects.push(
|
symbol = '%';
|
||||||
<tr key={feature + '_specialTT'}>
|
}
|
||||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
let current = m.getModValue(feature) - m.getModValue(feature, true);
|
||||||
<td> </td>
|
if (featureDef.type === 'percentage') {
|
||||||
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'}
|
current = Math.round(current / 10) / 10;
|
||||||
style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
} else if (featureDef.type === 'numeric') {
|
||||||
<td> </td>
|
current /= 100;
|
||||||
</tr>
|
}
|
||||||
);
|
const currentIsBeneficial = isValueBeneficial(feature, current);
|
||||||
}
|
|
||||||
}
|
effects.push(
|
||||||
}
|
<tr key={feature + '_specialTT'}>
|
||||||
}
|
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
||||||
|
<td> </td>
|
||||||
return (
|
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'}
|
||||||
<div>
|
style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
||||||
<table width='100%'>
|
<td> </td>
|
||||||
<tbody>
|
</tr>
|
||||||
{effects}
|
);
|
||||||
</tbody>
|
}
|
||||||
</table>
|
}
|
||||||
</div>
|
}
|
||||||
);
|
}
|
||||||
}
|
|
||||||
|
return (
|
||||||
/**
|
<div>
|
||||||
* Generate a tooltip with details of a blueprint's effects
|
{description}
|
||||||
* @param {Object} translate The translate object
|
<table width='100%'>
|
||||||
* @param {Object} blueprint The blueprint at the required grade
|
<tbody>
|
||||||
* @param {Array} engineers The engineers supplying this blueprint
|
{effects}
|
||||||
* @param {string} grp The group of the module
|
</tbody>
|
||||||
* @param {Object} m The module to compare with
|
</table>
|
||||||
* @returns {Object} The react components
|
</div>
|
||||||
*/
|
);
|
||||||
export function blueprintTooltip(translate, blueprint, engineers, grp, m) {
|
}
|
||||||
const effects = [];
|
|
||||||
if (!blueprint || !blueprint.features) {
|
/**
|
||||||
return undefined;
|
* Generate a tooltip with details of a blueprint's effects
|
||||||
}
|
* @param {Object} translate The translate object
|
||||||
for (const feature in blueprint.features) {
|
* @param {Object} blueprint The blueprint at the required grade
|
||||||
const featureIsBeneficial = isBeneficial(feature, blueprint.features[feature]);
|
* @param {Array} engineers The engineers supplying this blueprint
|
||||||
const featureDef = Modifications.modifications[feature];
|
* @param {string} grp The group of the module
|
||||||
if (!featureDef.hidden) {
|
* @param {Object} m The module to compare with
|
||||||
let symbol = '';
|
* @returns {Object} The react components
|
||||||
if (feature === 'jitter') {
|
*/
|
||||||
symbol = '°';
|
export function blueprintTooltip(translate, blueprint, engineers, grp, m) {
|
||||||
} else if (featureDef.type === 'percentage') {
|
const effects = [];
|
||||||
symbol = '%';
|
if (!blueprint || !blueprint.features) {
|
||||||
}
|
return undefined;
|
||||||
let lowerBound = blueprint.features[feature][0];
|
}
|
||||||
let upperBound = blueprint.features[feature][1];
|
for (const feature in blueprint.features) {
|
||||||
if (featureDef.type === 'percentage') {
|
const featureIsBeneficial = isBeneficial(feature, blueprint.features[feature]);
|
||||||
lowerBound = Math.round(lowerBound * 1000) / 10;
|
const featureDef = Modifications.modifications[feature];
|
||||||
upperBound = Math.round(upperBound * 1000) / 10;
|
if (!featureDef.hidden) {
|
||||||
}
|
let symbol = '';
|
||||||
const lowerIsBeneficial = isValueBeneficial(feature, lowerBound);
|
if (feature === 'jitter') {
|
||||||
const upperIsBeneficial = isValueBeneficial(feature, upperBound);
|
symbol = '°';
|
||||||
if (m) {
|
} else if (featureDef.type === 'percentage') {
|
||||||
// We have a module - add in the current value
|
symbol = '%';
|
||||||
let current = m.getModValue(feature);
|
}
|
||||||
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
|
let lowerBound = blueprint.features[feature][0];
|
||||||
current = Math.round(current / 10) / 10;
|
let upperBound = blueprint.features[feature][1];
|
||||||
} else if (featureDef.type === 'numeric') {
|
if (featureDef.type === 'percentage') {
|
||||||
current /= 100;
|
lowerBound = Math.round(lowerBound * 1000) / 10;
|
||||||
}
|
upperBound = Math.round(upperBound * 1000) / 10;
|
||||||
const currentIsBeneficial = isValueBeneficial(feature, current);
|
}
|
||||||
effects.push(
|
const lowerIsBeneficial = isValueBeneficial(feature, lowerBound);
|
||||||
<tr key={feature}>
|
const upperIsBeneficial = isValueBeneficial(feature, upperBound);
|
||||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
if (m) {
|
||||||
<td className={lowerBound === 0 ? '' : lowerIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{lowerBound}{symbol}</td>
|
// We have a module - add in the current value
|
||||||
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
let current = m.getModValue(feature);
|
||||||
<td className={upperBound === 0 ? '' : upperIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{upperBound}{symbol}</td>
|
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
|
||||||
</tr>
|
current = Math.round(current / 10) / 10;
|
||||||
);
|
} else if (featureDef.type === 'numeric') {
|
||||||
} else {
|
current /= 100;
|
||||||
// We do not have a module, no value
|
}
|
||||||
effects.push(
|
const currentIsBeneficial = isValueBeneficial(feature, current);
|
||||||
<tr key={feature}>
|
effects.push(
|
||||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
<tr key={feature}>
|
||||||
<td className={lowerBound === 0 ? '' : lowerIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{lowerBound}{symbol}</td>
|
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
||||||
<td className={upperBound === 0 ? '' : upperIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{upperBound}{symbol}</td>
|
<td className={lowerBound === 0 ? '' : lowerIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{lowerBound}{symbol}</td>
|
||||||
</tr>
|
<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 {
|
||||||
if (m) {
|
// We do not have a module, no value
|
||||||
// Because we have a module add in any benefits that aren't part of the primary blueprint
|
effects.push(
|
||||||
for (const feature in m.mods) {
|
<tr key={feature}>
|
||||||
if (!blueprint.features[feature]) {
|
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
||||||
const featureDef = Modifications.modifications[feature];
|
<td className={lowerBound === 0 ? '' : lowerIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{lowerBound}{symbol}</td>
|
||||||
if (featureDef && !featureDef.hidden) {
|
<td className={upperBound === 0 ? '' : upperIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{upperBound}{symbol}</td>
|
||||||
let symbol = '';
|
</tr>
|
||||||
if (feature === 'jitter') {
|
);
|
||||||
symbol = '°';
|
}
|
||||||
} else if (featureDef.type === 'percentage') {
|
}
|
||||||
symbol = '%';
|
}
|
||||||
}
|
if (m) {
|
||||||
let current = m.getModValue(feature);
|
// Because we have a module add in any benefits that aren't part of the primary blueprint
|
||||||
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
|
for (const feature in m.mods) {
|
||||||
current = Math.round(current / 10) / 10;
|
if (!blueprint.features[feature]) {
|
||||||
} else if (featureDef.type === 'numeric') {
|
const featureDef = Modifications.modifications[feature];
|
||||||
current /= 100;
|
if (featureDef && !featureDef.hidden) {
|
||||||
}
|
let symbol = '';
|
||||||
const currentIsBeneficial = isValueBeneficial(feature, current);
|
if (feature === 'jitter') {
|
||||||
effects.push(
|
symbol = '°';
|
||||||
<tr key={feature}>
|
} else if (featureDef.type === 'percentage') {
|
||||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
symbol = '%';
|
||||||
<td> </td>
|
}
|
||||||
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
let current = m.getModValue(feature);
|
||||||
<td> </td>
|
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
|
||||||
</tr>
|
current = Math.round(current / 10) / 10;
|
||||||
);
|
} else if (featureDef.type === 'numeric') {
|
||||||
}
|
current /= 100;
|
||||||
}
|
}
|
||||||
}
|
const currentIsBeneficial = isValueBeneficial(feature, current);
|
||||||
|
effects.push(
|
||||||
// We also add in any benefits from specials that aren't covered above
|
<tr key={feature}>
|
||||||
if (m.blueprint && m.blueprint.special) {
|
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
||||||
for (const feature in Modifications.modifierActions[m.blueprint.special.edname]) {
|
<td> </td>
|
||||||
if (!blueprint.features[feature] && !m.mods.feature) {
|
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
||||||
const featureDef = Modifications.modifications[feature];
|
<td> </td>
|
||||||
if (featureDef && !featureDef.hidden) {
|
</tr>
|
||||||
let symbol = '';
|
);
|
||||||
if (feature === 'jitter') {
|
}
|
||||||
symbol = '°';
|
}
|
||||||
} else if (featureDef.type === 'percentage') {
|
}
|
||||||
symbol = '%';
|
|
||||||
}
|
// We also add in any benefits from specials that aren't covered above
|
||||||
let current = m.getModValue(feature);
|
if (m.blueprint && m.blueprint.special) {
|
||||||
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
|
for (const feature in Modifications.modifierActions[m.blueprint.special.edname]) {
|
||||||
current = Math.round(current / 10) / 10;
|
if (!blueprint.features[feature] && !m.mods.feature) {
|
||||||
} else if (featureDef.type === 'numeric') {
|
const featureDef = Modifications.modifications[feature];
|
||||||
current /= 100;
|
if (featureDef && !featureDef.hidden) {
|
||||||
}
|
let symbol = '';
|
||||||
const currentIsBeneficial = isValueBeneficial(feature, current);
|
if (feature === 'jitter') {
|
||||||
effects.push(
|
symbol = '°';
|
||||||
<tr key={feature}>
|
} else if (featureDef.type === 'percentage') {
|
||||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
symbol = '%';
|
||||||
<td> </td>
|
}
|
||||||
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
let current = m.getModValue(feature);
|
||||||
<td> </td>
|
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
|
||||||
</tr>
|
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>
|
||||||
let components;
|
<td> </td>
|
||||||
if (!m) {
|
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
||||||
components = [];
|
<td> </td>
|
||||||
for (const component in blueprint.components) {
|
</tr>
|
||||||
components.push(
|
);
|
||||||
<tr key={component}>
|
}
|
||||||
<td style={{ textAlign: 'left' }}>{translate(component)}</td>
|
}
|
||||||
<td style={{ textAlign: 'right' }}>{blueprint.components[component]}</td>
|
}
|
||||||
</tr>
|
}
|
||||||
);
|
}
|
||||||
}
|
|
||||||
}
|
let components;
|
||||||
|
if (!m) {
|
||||||
let engineersList;
|
components = [];
|
||||||
if (engineers) {
|
for (const component in blueprint.components) {
|
||||||
engineersList = [];
|
components.push(
|
||||||
for (const engineer of engineers) {
|
<tr key={component}>
|
||||||
engineersList.push(
|
<td style={{ textAlign: 'left' }}>{translate(component)}</td>
|
||||||
<tr key={engineer}>
|
<td style={{ textAlign: 'right' }}>{blueprint.components[component]}</td>
|
||||||
<td style={{ textAlign: 'left' }}>{engineer}</td>
|
</tr>
|
||||||
</tr>
|
);
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
let engineersList;
|
||||||
return (
|
if (engineers) {
|
||||||
<div>
|
engineersList = [];
|
||||||
<table width='100%'>
|
for (const engineer of engineers) {
|
||||||
<thead>
|
engineersList.push(
|
||||||
<tr>
|
<tr key={engineer}>
|
||||||
<td>{translate('feature')}</td>
|
<td style={{ textAlign: 'left' }}>{engineer}</td>
|
||||||
<td>{translate('worst')}</td>
|
</tr>
|
||||||
{m ? <td>{translate('current')}</td> : null }
|
);
|
||||||
<td>{translate('best')}</td>
|
}
|
||||||
</tr>
|
}
|
||||||
</thead>
|
|
||||||
<tbody>
|
return (
|
||||||
{effects}
|
<div>
|
||||||
</tbody>
|
<table width='100%'>
|
||||||
</table>
|
<thead>
|
||||||
{ components ? <table width='100%'>
|
<tr>
|
||||||
<thead>
|
<td>{translate('feature')}</td>
|
||||||
<tr>
|
<td>{translate('worst')}</td>
|
||||||
<td>{translate('component')}</td>
|
{m ? <td>{translate('current')}</td> : null }
|
||||||
<td>{translate('amount')}</td>
|
<td>{translate('best')}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{components}
|
{effects}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table> : null }
|
</table>
|
||||||
{ engineersList ? <table width='100%'>
|
{ components ? <table width='100%'>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{translate('engineers')}</td>
|
<td>{translate('component')}</td>
|
||||||
</tr>
|
<td>{translate('amount')}</td>
|
||||||
</thead>
|
</tr>
|
||||||
<tbody>
|
</thead>
|
||||||
{engineersList}
|
<tbody>
|
||||||
</tbody>
|
{components}
|
||||||
</table> : null }
|
</tbody>
|
||||||
</div>
|
</table> : null }
|
||||||
);
|
{ engineersList ? <table width='100%'>
|
||||||
}
|
<thead>
|
||||||
|
<tr>
|
||||||
/**
|
<td>{translate('engineers')}</td>
|
||||||
* Is this blueprint feature beneficial?
|
</tr>
|
||||||
* @param {string} feature The name of the feature
|
</thead>
|
||||||
* @param {array} values The value of the feature
|
<tbody>
|
||||||
* @returns {boolean} True if this feature is beneficial
|
{engineersList}
|
||||||
*/
|
</tbody>
|
||||||
export function isBeneficial(feature, values) {
|
</table> : null }
|
||||||
const fact = (values[0] < 0 || (values[0] === 0 && values[1] < 0));
|
</div>
|
||||||
if (Modifications.modifications[feature].higherbetter) {
|
);
|
||||||
return !fact;
|
}
|
||||||
} else {
|
|
||||||
return fact;
|
/**
|
||||||
}
|
* 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
|
||||||
* Is this feature value beneficial?
|
*/
|
||||||
* @param {string} feature The name of the feature
|
export function isBeneficial(feature, values) {
|
||||||
* @param {number} value The value of the feature
|
const fact = (values[0] < 0 || (values[0] === 0 && values[1] < 0));
|
||||||
* @returns {boolean} True if this value is beneficial
|
if (Modifications.modifications[feature].higherbetter) {
|
||||||
*/
|
return !fact;
|
||||||
export function isValueBeneficial(feature, value) {
|
} else {
|
||||||
if (Modifications.modifications[feature].higherbetter) {
|
return fact;
|
||||||
return value > 0;
|
}
|
||||||
} else {
|
}
|
||||||
return value < 0;
|
|
||||||
}
|
/**
|
||||||
}
|
* Is this feature value beneficial?
|
||||||
|
* @param {string} feature The name of the feature
|
||||||
/**
|
* @param {number} value The value of the feature
|
||||||
* Is the change as shown beneficial?
|
* @returns {boolean} True if this value is beneficial
|
||||||
* @param {string} feature The name of the feature
|
*/
|
||||||
* @param {number} value The value of the feature as percentage change
|
export function isValueBeneficial(feature, value) {
|
||||||
* @returns True if the value is beneficial
|
if (Modifications.modifications[feature].higherbetter) {
|
||||||
*/
|
return value > 0;
|
||||||
export function isChangeValueBeneficial(feature, value) {
|
} else {
|
||||||
let changeHigherBetter = STATS_FORMATTING[feature].higherbetter;
|
return value < 0;
|
||||||
if (changeHigherBetter === undefined) {
|
}
|
||||||
return isValueBeneficial(feature, value);
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
if (changeHigherBetter) {
|
* Is the change as shown beneficial?
|
||||||
return value > 0;
|
* @param {string} feature The name of the feature
|
||||||
} else {
|
* @param {number} value The value of the feature as percentage change
|
||||||
return value < 0;
|
* @returns True if the value is beneficial
|
||||||
}
|
*/
|
||||||
}
|
export function isChangeValueBeneficial(feature, value) {
|
||||||
|
let changeHigherBetter = STATS_FORMATTING[feature].higherbetter;
|
||||||
/**
|
if (changeHigherBetter === undefined) {
|
||||||
* Get a blueprint with a given name and an optional module
|
return isValueBeneficial(feature, value);
|
||||||
* @param {string} name The name of the blueprint
|
}
|
||||||
* @param {Object} module The module for which to obtain this blueprint
|
|
||||||
* @returns {Object} The matching blueprint
|
if (changeHigherBetter) {
|
||||||
*/
|
return value > 0;
|
||||||
export function getBlueprint(name, module) {
|
} else {
|
||||||
// Start with a copy of the blueprint
|
return value < 0;
|
||||||
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 {};
|
/**
|
||||||
}
|
* Get a blueprint with a given name and an optional module
|
||||||
const blueprint = JSON.parse(JSON.stringify(found));
|
* @param {string} name The name of the blueprint
|
||||||
return blueprint;
|
* @param {Object} module The module for which to obtain this blueprint
|
||||||
}
|
* @returns {Object} The matching blueprint
|
||||||
|
*/
|
||||||
/**
|
export function getBlueprint(name, module) {
|
||||||
* Provide 'percent' primary modifications
|
// Special case for multi-cannons. Conflicting 'Weapon_Overcharged' Blueprints exist due to FD's naming conventions. If this blueprint is for a multi-cannon, we need to use the correct blueprint.
|
||||||
* @param {Object} ship The ship for which to perform the modifications
|
if (name === 'weapon_overcharged') {
|
||||||
* @param {Object} m The module for which to perform the modifications
|
if (module.symbol.match(/MultiCannon/i)) {
|
||||||
* @param {Number} percent The percent to set values to of full.
|
name = 'mc_overcharged';
|
||||||
*/
|
}
|
||||||
export function setPercent(ship, m, percent) {
|
}
|
||||||
ship.clearModifications(m);
|
else if (name === 'Weapon_Overcharged') {
|
||||||
// Pick given value as multiplier
|
if (module.symbol.match(/MultiCannon/i)) {
|
||||||
const mult = percent / 100;
|
name = 'MC_Overcharged';
|
||||||
const features = m.blueprint.grades[m.blueprint.grade].features;
|
}
|
||||||
for (const featureName in features) {
|
}
|
||||||
let value;
|
// Start with a copy of the blueprint
|
||||||
if (Modifications.modifications[featureName].higherbetter) {
|
const findMod = val => Object.keys(Modifications.blueprints).find(elem => elem.toString().toLowerCase().search(val.toString().toLowerCase().replace(/(OutfittingFieldType_|persecond)/igm, '')) >= 0);
|
||||||
// Higher is better, but is this making it better or worse?
|
const found = Modifications.blueprints[findMod(name)];
|
||||||
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
if (!found || !found.fdname) {
|
||||||
value = features[featureName][1] + ((features[featureName][0] - features[featureName][1]) * mult);
|
console.error('Blueprint not found:', name);
|
||||||
} else {
|
return {};
|
||||||
value = features[featureName][0] + ((features[featureName][1] - features[featureName][0]) * mult);
|
}
|
||||||
}
|
const blueprint = JSON.parse(JSON.stringify(found));
|
||||||
} else {
|
return blueprint;
|
||||||
// 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 {
|
* Provide 'percent' primary modifications
|
||||||
value = features[featureName][1] + ((features[featureName][0] - features[featureName][1]) * mult);
|
* @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.
|
||||||
|
*/
|
||||||
_setValue(ship, m, featureName, value);
|
export function setPercent(ship, m, percent) {
|
||||||
}
|
ship.clearModifications(m);
|
||||||
}
|
// Pick given value as multiplier
|
||||||
|
const mult = percent / 100;
|
||||||
/**
|
setQualityCB(m.blueprint, mult, (featureName, value) => ship.setModification(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
|
/**
|
||||||
*/
|
* Sets the blueprint quality and fires a callback for each property affected.
|
||||||
export function setRandom(ship, m) {
|
* @param {Object} blueprint The ship for which to perform the modifications
|
||||||
// Pick a single value for our randomness
|
* @param {Number} quality The quality to apply - float number 0 to 1.
|
||||||
setPercent(ship, m, Math.random() * 100);
|
* @param {Function} cb The Callback to run for each property. Function (featureName, value)
|
||||||
}
|
*/
|
||||||
|
export function setQualityCB(blueprint, quality, cb) {
|
||||||
/**
|
// Pick given value as multiplier
|
||||||
* Set a modification feature value
|
const features = blueprint.grades[blueprint.grade].features;
|
||||||
* @param {Object} ship The ship for which to perform the modifications
|
for (const featureName in features) {
|
||||||
* @param {Object} m The module for which to perform the modifications
|
let value;
|
||||||
* @param {string} featureName The feature being set
|
if (Modifications.modifications[featureName].higherbetter) {
|
||||||
* @param {number} value The value being set for the feature
|
// Higher is better, but is this making it better or worse?
|
||||||
*/
|
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
||||||
function _setValue(ship, m, featureName, value) {
|
value = features[featureName][1] + ((features[featureName][0] - features[featureName][1]) * quality);
|
||||||
if (Modifications.modifications[featureName].type == 'percentage') {
|
} else {
|
||||||
ship.setModification(m, featureName, value * 10000);
|
value = features[featureName][0] + ((features[featureName][1] - features[featureName][0]) * quality);
|
||||||
} else if (Modifications.modifications[featureName].type == 'numeric') {
|
}
|
||||||
ship.setModification(m, featureName, value * 100);
|
} else {
|
||||||
} else {
|
// Higher is worse, but is this making it better or worse?
|
||||||
ship.setModification(m, featureName, value);
|
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
||||||
}
|
value = features[featureName][0] + ((features[featureName][1] - features[featureName][0]) * quality);
|
||||||
}
|
} else {
|
||||||
|
value = features[featureName][1] + ((features[featureName][0] - features[featureName][1]) * quality);
|
||||||
/**
|
}
|
||||||
* 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.
|
if (Modifications.modifications[featureName].type == 'percentage') {
|
||||||
*/
|
value = value * 10000;
|
||||||
export function getPercent(m) {
|
} else if (Modifications.modifications[featureName].type == 'numeric') {
|
||||||
let result = null;
|
value = value * 100;
|
||||||
const features = m.blueprint.grades[m.blueprint.grade].features;
|
}
|
||||||
for (const featureName in features) {
|
|
||||||
if (features[featureName][0] === features[featureName][1]) {
|
cb(featureName, value);
|
||||||
continue;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let value = _getValue(m, featureName);
|
/**
|
||||||
let mult;
|
* Provide 'random' primary modifications
|
||||||
if (Modifications.modifications[featureName].higherbetter) {
|
* @param {Object} ship The ship for which to perform the modifications
|
||||||
// Higher is better, but is this making it better or worse?
|
* @param {Object} m The module for which to perform the modifications
|
||||||
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);
|
export function setRandom(ship, m) {
|
||||||
} else {
|
// Pick a single value for our randomness
|
||||||
mult = Math.round((value - features[featureName][0]) / (features[featureName][1] - features[featureName][0]) * 100);
|
setPercent(ship, m, Math.random() * 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)) {
|
* Provide 'percent' primary query
|
||||||
mult = Math.round((value - features[featureName][0]) / (features[featureName][1] - features[featureName][0]) * 100);
|
* @param {Object} m The module for which to perform the query
|
||||||
} else {
|
* @returns {Number} percent The percentage indicator of current applied values.
|
||||||
mult = Math.round((value - features[featureName][1]) / (features[featureName][0] - features[featureName][1]) * 100);
|
*/
|
||||||
}
|
export function getPercent(m) {
|
||||||
}
|
let result = null;
|
||||||
|
const features = m.blueprint.grades[m.blueprint.grade].features;
|
||||||
if (result && result != mult) {
|
for (const featureName in features) {
|
||||||
return null;
|
if (features[featureName][0] === features[featureName][1]) {
|
||||||
} else if (result != mult) {
|
continue;
|
||||||
result = mult;
|
}
|
||||||
}
|
|
||||||
}
|
let value = _getValue(m, featureName);
|
||||||
|
let mult;
|
||||||
return result;
|
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);
|
||||||
* Query a feature value
|
} else {
|
||||||
* @param {Object} m The module for which to perform the query
|
mult = Math.round((value - features[featureName][0]) / (features[featureName][1] - features[featureName][0]) * 100);
|
||||||
* @param {string} featureName The feature being queried
|
}
|
||||||
* @returns {number} The value of the modification as a %
|
} else {
|
||||||
*/
|
// Higher is worse, but is this making it better or worse?
|
||||||
function _getValue(m, featureName) {
|
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
||||||
if (Modifications.modifications[featureName].type == 'percentage') {
|
mult = Math.round((value - features[featureName][0]) / (features[featureName][1] - features[featureName][0]) * 100);
|
||||||
return m.getModValue(featureName, true) / 10000;
|
} else {
|
||||||
} else if (Modifications.modifications[featureName].type == 'numeric') {
|
mult = Math.round((value - features[featureName][1]) / (features[featureName][0] - features[featureName][1]) * 100);
|
||||||
return m.getModValue(featureName, true) / 100;
|
}
|
||||||
} else {
|
}
|
||||||
return m.getModValue(featureName, true);
|
|
||||||
}
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ export const SHIP_FD_NAME_TO_CORIOLIS_NAME = {
|
|||||||
'BelugaLiner': 'beluga',
|
'BelugaLiner': 'beluga',
|
||||||
'CobraMkIII': 'cobra_mk_iii',
|
'CobraMkIII': 'cobra_mk_iii',
|
||||||
'CobraMkIV': 'cobra_mk_iv',
|
'CobraMkIV': 'cobra_mk_iv',
|
||||||
|
'CobraMkV': 'cobramkv',
|
||||||
|
'Corsair': 'imperial_corsair',
|
||||||
'Cutter': 'imperial_cutter',
|
'Cutter': 'imperial_cutter',
|
||||||
'DiamondBackXL': 'diamondback_explorer',
|
'DiamondBackXL': 'diamondback_explorer',
|
||||||
'DiamondBack': 'diamondback',
|
'DiamondBack': 'diamondback',
|
||||||
@@ -31,12 +33,15 @@ export const SHIP_FD_NAME_TO_CORIOLIS_NAME = {
|
|||||||
'Independant_Trader': 'keelback',
|
'Independant_Trader': 'keelback',
|
||||||
'Krait_MkII': 'krait_mkii',
|
'Krait_MkII': 'krait_mkii',
|
||||||
'Mamba': 'mamba',
|
'Mamba': 'mamba',
|
||||||
|
'Mandalay': 'mandalay',
|
||||||
'Krait_Light': 'krait_phantom',
|
'Krait_Light': 'krait_phantom',
|
||||||
'Orca': 'orca',
|
'Orca': 'orca',
|
||||||
'Python': 'python',
|
'Python': 'python',
|
||||||
|
'Python_nx': 'python_nx',
|
||||||
'SideWinder': 'sidewinder',
|
'SideWinder': 'sidewinder',
|
||||||
'Type6': 'type_6_transporter',
|
'Type6': 'type_6_transporter',
|
||||||
'Type7': 'type_7_transport',
|
'Type7': 'type_7_transport',
|
||||||
|
'Type8': 'type_8_transport',
|
||||||
'Type9': 'type_9_heavy',
|
'Type9': 'type_9_heavy',
|
||||||
'Type9_Military': 'type_10_defender',
|
'Type9_Military': 'type_10_defender',
|
||||||
'TypeX': 'alliance_chieftain',
|
'TypeX': 'alliance_chieftain',
|
||||||
|
|||||||
@@ -1,322 +1,396 @@
|
|||||||
import Ship from '../shipyard/Ship';
|
import Ship from '../shipyard/Ship';
|
||||||
import { HARDPOINT_NUM_TO_CLASS, shipModelFromJson } from './CompanionApiUtils';
|
import { HARDPOINT_NUM_TO_CLASS, shipModelFromJson } from './CompanionApiUtils';
|
||||||
import { Ships } from 'coriolis-data/dist';
|
import { Ships } from 'coriolis-data/dist';
|
||||||
import Module from '../shipyard/Module';
|
import Module from '../shipyard/Module';
|
||||||
import { Modules } from 'coriolis-data/dist';
|
import { Modules } from 'coriolis-data/dist';
|
||||||
import { Modifications } from 'coriolis-data/dist';
|
import { Modifications } from 'coriolis-data/dist';
|
||||||
import { getBlueprint } from './BlueprintFunctions';
|
import { getBlueprint, setQualityCB } from './BlueprintFunctions';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain a module given its FD Name
|
* Check if an imported module is valid
|
||||||
* @param {string} fdname the FD Name of the module
|
* @param {Object} module the module to check
|
||||||
* @return {Module} the module
|
* @param {Object} moduleType the type of module to check
|
||||||
*/
|
* @return {boolean} true if the module is valid
|
||||||
function _moduleFromFdName(fdname) {
|
*/
|
||||||
if (!fdname) return null;
|
function _isValidImportedModule(module, moduleType) {
|
||||||
fdname = fdname.toLowerCase();
|
// First of all, has the _moduleFromFdName function returned 'null'?
|
||||||
// Check standard modules
|
if (!module){
|
||||||
for (const grp in Modules.standard) {
|
return false
|
||||||
if (Modules.standard.hasOwnProperty(grp)) {
|
}
|
||||||
for (const i in Modules.standard[grp]) {
|
else {
|
||||||
if (Modules.standard[grp][i].symbol && Modules.standard[grp][i].symbol.toLowerCase() === fdname) {
|
return true
|
||||||
// Found it
|
}
|
||||||
return new Module({ template: Modules.standard[grp][i] });
|
}
|
||||||
}
|
|
||||||
}
|
/**
|
||||||
}
|
* Obtain a module given its FD Name
|
||||||
}
|
* @param {string} fdname the FD Name of the module
|
||||||
|
* @return {Module} the module
|
||||||
// Check hardpoint modules
|
*/
|
||||||
for (const grp in Modules.hardpoints) {
|
function _moduleFromFdName(fdname) {
|
||||||
if (Modules.hardpoints.hasOwnProperty(grp)) {
|
if (!fdname) return null;
|
||||||
for (const i in Modules.hardpoints[grp]) {
|
fdname = fdname.toLowerCase();
|
||||||
if (Modules.hardpoints[grp][i].symbol && Modules.hardpoints[grp][i].symbol.toLowerCase() === fdname) {
|
// Check standard modules
|
||||||
// Found it
|
for (const grp in Modules.standard) {
|
||||||
return new Module({ template: Modules.hardpoints[grp][i] });
|
if (Modules.standard.hasOwnProperty(grp)) {
|
||||||
}
|
for (const i in Modules.standard[grp]) {
|
||||||
}
|
if (Modules.standard[grp][i].symbol && Modules.standard[grp][i].symbol.toLowerCase() === fdname) {
|
||||||
}
|
// Found it
|
||||||
}
|
return new Module({ template: Modules.standard[grp][i] });
|
||||||
|
}
|
||||||
// Check internal modules
|
}
|
||||||
for (const grp in Modules.internal) {
|
}
|
||||||
if (Modules.internal.hasOwnProperty(grp)) {
|
}
|
||||||
for (const i in Modules.internal[grp]) {
|
|
||||||
if (Modules.internal[grp][i].symbol && Modules.internal[grp][i].symbol.toLowerCase() === fdname) {
|
// Check hardpoint modules
|
||||||
// Found it
|
for (const grp in Modules.hardpoints) {
|
||||||
return new Module({ template: Modules.internal[grp][i] });
|
if (Modules.hardpoints.hasOwnProperty(grp)) {
|
||||||
}
|
for (const i in Modules.hardpoints[grp]) {
|
||||||
}
|
if (Modules.hardpoints[grp][i].symbol && Modules.hardpoints[grp][i].symbol.toLowerCase() === fdname) {
|
||||||
}
|
// Found it
|
||||||
}
|
return new Module({ template: Modules.hardpoints[grp][i] });
|
||||||
|
}
|
||||||
// Not found
|
}
|
||||||
return null;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Check internal modules
|
||||||
* Build a ship from the journal Loadout event JSON
|
for (const grp in Modules.internal) {
|
||||||
* @param {object} json the Loadout event JSON
|
if (Modules.internal.hasOwnProperty(grp)) {
|
||||||
* @return {Ship} the built ship
|
for (const i in Modules.internal[grp]) {
|
||||||
*/
|
if (Modules.internal[grp][i].symbol && Modules.internal[grp][i].symbol.toLowerCase() === fdname) {
|
||||||
export function shipFromLoadoutJSON(json) {
|
// Found it
|
||||||
// Start off building a basic ship
|
return new Module({ template: Modules.internal[grp][i] });
|
||||||
const shipModel = shipModelFromJson(json);
|
}
|
||||||
if (!shipModel) {
|
}
|
||||||
throw 'No such ship found: "' + json.Ship + '"';
|
}
|
||||||
}
|
}
|
||||||
const shipTemplate = Ships[shipModel];
|
|
||||||
|
// Not found
|
||||||
let ship = new Ship(shipModel, shipTemplate.properties, shipTemplate.slots);
|
return null;
|
||||||
ship.buildWith(null);
|
}
|
||||||
// Initial Ship building, don't do engineering yet.
|
|
||||||
let modsToAdd = [];
|
/**
|
||||||
|
* Build a ship from the journal Loadout event JSON
|
||||||
for (const module of json.Modules) {
|
* @param {object} json the Loadout event JSON
|
||||||
switch (module.Slot.toLowerCase()) {
|
* @return {Ship} the built ship
|
||||||
// Cargo Hatch.
|
*/
|
||||||
case 'cargohatch':
|
export function shipFromLoadoutJSON(json) {
|
||||||
ship.cargoHatch.enabled = module.On;
|
// Start off building a basic ship
|
||||||
ship.cargoHatch.priority = module.Priority;
|
const shipModel = shipModelFromJson(json);
|
||||||
break;
|
if (!shipModel) {
|
||||||
// Add the bulkheads
|
throw 'No such ship found: "' + json.Ship + '"';
|
||||||
case 'armour':
|
}
|
||||||
if (module.Item.toLowerCase().endsWith('_armour_grade1')) {
|
const shipTemplate = Ships[shipModel];
|
||||||
ship.useBulkhead(0, true);
|
|
||||||
} else if (module.Item.toLowerCase().endsWith('_armour_grade2')) {
|
let ship = new Ship(shipModel, shipTemplate.properties, shipTemplate.slots);
|
||||||
ship.useBulkhead(1, true);
|
ship.buildWith(null);
|
||||||
} else if (module.Item.toLowerCase().endsWith('_armour_grade3')) {
|
// Initial Ship building, don't do engineering yet.
|
||||||
ship.useBulkhead(2, true);
|
let modsToAdd = [];
|
||||||
} else if (module.Item.toLowerCase().endsWith('_armour_mirrored')) {
|
|
||||||
ship.useBulkhead(3, true);
|
for (const module of json.Modules) {
|
||||||
} else if (module.Item.toLowerCase().endsWith('_armour_reactive')) {
|
switch (module.Slot.toLowerCase()) {
|
||||||
ship.useBulkhead(4, true);
|
// Cargo Hatch.
|
||||||
} else {
|
case 'cargohatch':
|
||||||
throw 'Unknown bulkheads "' + module.Item + '"';
|
ship.cargoHatch.enabled = module.On;
|
||||||
}
|
ship.cargoHatch.priority = module.Priority;
|
||||||
ship.bulkheads.enabled = true;
|
break;
|
||||||
if (module.Engineering) _addModifications(ship.bulkheads.m, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
// Add the bulkheads
|
||||||
break;
|
case 'armour':
|
||||||
case 'powerplant':
|
if (module.Item.toLowerCase().endsWith('_armour_grade1')) {
|
||||||
const powerplant = _moduleFromFdName(module.Item);
|
ship.useBulkhead(0, true);
|
||||||
ship.use(ship.standard[0], powerplant, true);
|
} else if (module.Item.toLowerCase().endsWith('_armour_grade2')) {
|
||||||
ship.standard[0].enabled = module.On;
|
ship.useBulkhead(1, true);
|
||||||
ship.standard[0].priority = module.Priority;
|
} else if (module.Item.toLowerCase().endsWith('_armour_grade3')) {
|
||||||
if (module.Engineering) _addModifications(powerplant, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
ship.useBulkhead(2, true);
|
||||||
break;
|
} else if (module.Item.toLowerCase().endsWith('_armour_mirrored')) {
|
||||||
case 'mainengines':
|
ship.useBulkhead(3, true);
|
||||||
const thrusters = _moduleFromFdName(module.Item);
|
} else if (module.Item.toLowerCase().endsWith('_armour_reactive')) {
|
||||||
ship.use(ship.standard[1], thrusters, true);
|
ship.useBulkhead(4, true);
|
||||||
ship.standard[1].enabled = module.On;
|
} else {
|
||||||
ship.standard[1].priority = module.Priority;
|
throw 'Unknown bulkheads "' + module.Item + '"';
|
||||||
if (module.Engineering) _addModifications(thrusters, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
}
|
||||||
break;
|
ship.bulkheads.enabled = true;
|
||||||
case 'frameshiftdrive':
|
if (module.Engineering) _addModifications(ship.bulkheads.m, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
||||||
const frameshiftdrive = _moduleFromFdName(module.Item);
|
break;
|
||||||
ship.use(ship.standard[2], frameshiftdrive, true);
|
case 'powerplant':
|
||||||
ship.standard[2].enabled = module.On;
|
let powerplant = _moduleFromFdName(module.Item);
|
||||||
ship.standard[2].priority = module.Priority;
|
// Check the powerplant returned is valid
|
||||||
if (module.Engineering) _addModifications(frameshiftdrive, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
if (!_isValidImportedModule(powerplant, 'powerplant'))
|
||||||
break;
|
{
|
||||||
case 'lifesupport':
|
powerplant = _moduleFromFdName('Int_Missing_Powerplant');
|
||||||
const lifesupport = _moduleFromFdName(module.Item);
|
module.Engineering = null;
|
||||||
ship.use(ship.standard[3], lifesupport, true);
|
}
|
||||||
ship.standard[3].enabled = module.On === true;
|
ship.use(ship.standard[0], powerplant, true);
|
||||||
ship.standard[3].priority = module.Priority;
|
ship.standard[0].enabled = module.On;
|
||||||
if (module.Engineering) _addModifications(lifesupport, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
ship.standard[0].priority = module.Priority;
|
||||||
break;
|
if (module.Engineering) _addModifications(powerplant, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
||||||
case 'powerdistributor':
|
break;
|
||||||
const powerdistributor = _moduleFromFdName(module.Item);
|
case 'mainengines':
|
||||||
ship.use(ship.standard[4], powerdistributor, true);
|
let thrusters = _moduleFromFdName(module.Item);
|
||||||
ship.standard[4].enabled = module.On;
|
// Check the thrusters returned is valid
|
||||||
ship.standard[4].priority = module.Priority;
|
if (!_isValidImportedModule(thrusters, 'thrusters'))
|
||||||
if (module.Engineering) _addModifications(powerdistributor, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
{
|
||||||
break;
|
thrusters = _moduleFromFdName('Int_Missing_Engine');
|
||||||
case 'radar':
|
module.Engineering = null;
|
||||||
const sensors = _moduleFromFdName(module.Item);
|
}
|
||||||
ship.use(ship.standard[5], sensors, true);
|
ship.use(ship.standard[1], thrusters, true);
|
||||||
ship.standard[5].enabled = module.On;
|
ship.standard[1].enabled = module.On;
|
||||||
ship.standard[5].priority = module.Priority;
|
ship.standard[1].priority = module.Priority;
|
||||||
if (module.Engineering) _addModifications(sensors, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
if (module.Engineering) _addModifications(thrusters, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
||||||
break;
|
break;
|
||||||
case 'fueltank':
|
case 'frameshiftdrive':
|
||||||
const fueltank = _moduleFromFdName(module.Item);
|
let frameshiftdrive = _moduleFromFdName(module.Item);
|
||||||
ship.use(ship.standard[6], fueltank, true);
|
// Check the frameshiftdrive returned is valid
|
||||||
ship.standard[6].enabled = true;
|
if (!_isValidImportedModule(frameshiftdrive, 'frameshiftdrive'))
|
||||||
ship.standard[6].priority = 0;
|
{
|
||||||
break;
|
frameshiftdrive = _moduleFromFdName('Int_Missing_Hyperdrive');
|
||||||
default:
|
module.Engineering = null;
|
||||||
}
|
}
|
||||||
if (module.Slot.toLowerCase().search(/hardpoint/) !== -1) {
|
ship.use(ship.standard[2], frameshiftdrive, true);
|
||||||
// Add hardpoints
|
ship.standard[2].enabled = module.On;
|
||||||
let hardpoint;
|
ship.standard[2].priority = module.Priority;
|
||||||
let hardpointClassNum = -1;
|
if (module.Engineering) _addModifications(frameshiftdrive, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
||||||
let hardpointSlotNum = -1;
|
break;
|
||||||
let hardpointArrayNum = 0;
|
case 'lifesupport':
|
||||||
for (let i in shipTemplate.slots.hardpoints) {
|
let lifesupport = _moduleFromFdName(module.Item);
|
||||||
if (shipTemplate.slots.hardpoints[i] === hardpointClassNum) {
|
// Check the lifesupport returned is valid
|
||||||
// Another slot of the same class
|
if (!_isValidImportedModule(lifesupport, 'lifesupport'))
|
||||||
hardpointSlotNum++;
|
{
|
||||||
} else {
|
lifesupport = _moduleFromFdName('Int_Missing_LifeSupport');
|
||||||
// The first slot of a new class
|
module.Engineering = null;
|
||||||
hardpointClassNum = shipTemplate.slots.hardpoints[i];
|
}
|
||||||
hardpointSlotNum = 1;
|
ship.use(ship.standard[3], lifesupport, true);
|
||||||
}
|
ship.standard[3].enabled = module.On === true;
|
||||||
|
ship.standard[3].priority = module.Priority;
|
||||||
// Now that we know what we're looking for, find it
|
if (module.Engineering) _addModifications(lifesupport, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
||||||
const hardpointName = HARDPOINT_NUM_TO_CLASS[hardpointClassNum] + 'Hardpoint' + hardpointSlotNum;
|
break;
|
||||||
const hardpointSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === hardpointName.toLowerCase());
|
case 'powerdistributor':
|
||||||
if (!hardpointSlot) {
|
let powerdistributor = _moduleFromFdName(module.Item);
|
||||||
// This can happen with old imports that don't contain new hardpoints
|
// Check the powerdistributor returned is valid
|
||||||
} else if (!hardpointSlot) {
|
if (!_isValidImportedModule(powerdistributor, 'powerdistributor'))
|
||||||
// No module
|
{
|
||||||
} else {
|
powerdistributor = _moduleFromFdName('Int_Missing_PowerDistributor');
|
||||||
hardpoint = _moduleFromFdName(hardpointSlot.Item);
|
module.Engineering = null;
|
||||||
ship.use(ship.hardpoints[hardpointArrayNum], hardpoint, true);
|
}
|
||||||
ship.hardpoints[hardpointArrayNum].enabled = hardpointSlot.On;
|
ship.use(ship.standard[4], powerdistributor, true);
|
||||||
ship.hardpoints[hardpointArrayNum].priority = hardpointSlot.Priority;
|
ship.standard[4].enabled = module.On;
|
||||||
modsToAdd.push({ coriolisMod: hardpoint, json: hardpointSlot });
|
ship.standard[4].priority = module.Priority;
|
||||||
}
|
if (module.Engineering) _addModifications(powerdistributor, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
||||||
hardpointArrayNum++;
|
break;
|
||||||
}
|
case 'radar':
|
||||||
}
|
let sensors = _moduleFromFdName(module.Item);
|
||||||
}
|
// Check the sensors returned is valid
|
||||||
|
if (!_isValidImportedModule(sensors, 'sensors'))
|
||||||
let internalSlotNum = 0;
|
{
|
||||||
let militarySlotNum = 1;
|
sensors = _moduleFromFdName('Int_Missing_Sensors');
|
||||||
for (let i in shipTemplate.slots.internal) {
|
module.Engineering = null;
|
||||||
if (!shipTemplate.slots.internal.hasOwnProperty(i)) {
|
}
|
||||||
continue;
|
ship.use(ship.standard[5], sensors, true);
|
||||||
}
|
ship.standard[5].enabled = module.On;
|
||||||
const isMilitary = isNaN(shipTemplate.slots.internal[i]) ? shipTemplate.slots.internal[i].name == 'Military' : false;
|
ship.standard[5].priority = module.Priority;
|
||||||
|
if (module.Engineering) _addModifications(sensors, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
||||||
// The internal slot might be a standard or a military slot. Military slots have a different naming system
|
break;
|
||||||
let internalSlot = null;
|
case 'fueltank':
|
||||||
if (isMilitary) {
|
let fueltank = _moduleFromFdName(module.Item);
|
||||||
const internalName = 'Military0' + militarySlotNum;
|
// Check the fueltank returned is valid
|
||||||
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase());
|
if (!_isValidImportedModule(fueltank, 'fueltank'))
|
||||||
militarySlotNum++;
|
{
|
||||||
} else {
|
fueltank = _moduleFromFdName('Int_Missing_FuelTank');
|
||||||
// Slot numbers are not contiguous so handle skips.
|
}
|
||||||
for (; internalSlot === null && internalSlotNum < 99; internalSlotNum++) {
|
ship.use(ship.standard[6], fueltank, true);
|
||||||
// Slot sizes have no relationship to the actual size, either, so check all possibilities
|
ship.standard[6].enabled = true;
|
||||||
for (let slotsize = 0; slotsize < 9; slotsize++) {
|
ship.standard[6].priority = 0;
|
||||||
const internalName = 'Slot' + (internalSlotNum <= 9 ? '0' : '') + internalSlotNum + '_Size' + slotsize;
|
break;
|
||||||
if (json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase())) {
|
default:
|
||||||
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase());
|
}
|
||||||
break;
|
if (module.Slot.toLowerCase().search(/hardpoint/) !== -1) {
|
||||||
}
|
// Add hardpoints
|
||||||
}
|
let hardpoint;
|
||||||
}
|
let hardpointClassNum = -1;
|
||||||
}
|
let hardpointSlotNum = -1;
|
||||||
|
let hardpointArrayNum = 0;
|
||||||
if (!internalSlot) {
|
for (let i in shipTemplate.slots.hardpoints) {
|
||||||
// This can happen with old imports that don't contain new slots
|
if (shipTemplate.slots.hardpoints[i] === hardpointClassNum) {
|
||||||
} else {
|
// Another slot of the same class
|
||||||
const internalJson = internalSlot;
|
hardpointSlotNum++;
|
||||||
const internal = _moduleFromFdName(internalJson.Item);
|
} else {
|
||||||
ship.use(ship.internal[i], internal, true);
|
// The first slot of a new class
|
||||||
ship.internal[i].enabled = internalJson.On === true;
|
hardpointClassNum = shipTemplate.slots.hardpoints[i];
|
||||||
ship.internal[i].priority = internalJson.Priority;
|
hardpointSlotNum = 1;
|
||||||
modsToAdd.push({ coriolisMod: internal, json: internalSlot });
|
}
|
||||||
}
|
|
||||||
}
|
// Now that we know what we're looking for, find it
|
||||||
|
const hardpointName = HARDPOINT_NUM_TO_CLASS[hardpointClassNum] + 'Hardpoint' + hardpointSlotNum;
|
||||||
for (const i of modsToAdd) {
|
const hardpointSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === hardpointName.toLowerCase());
|
||||||
if (i.json.Engineering) {
|
if (!hardpointSlot) {
|
||||||
_addModifications(i.coriolisMod, i.json.Engineering.Modifiers, i.json.Engineering.Quality, i.json.Engineering.BlueprintName, i.json.Engineering.Level, i.json.Engineering.ExperimentalEffect);
|
// This can happen with old imports that don't contain new hardpoints
|
||||||
}
|
} else {
|
||||||
}
|
hardpoint = _moduleFromFdName(hardpointSlot.Item);
|
||||||
// We don't have any information on it so guess it's priority 5 and disabled
|
// Check the hardpoint module returned is valid
|
||||||
if (!ship.cargoHatch) {
|
if (!_isValidImportedModule(hardpoint, 'hardpoint')){
|
||||||
ship.cargoHatch.enabled = false;
|
// Check if it's a Utility or Hardpoint
|
||||||
ship.cargoHatch.priority = 4;
|
if (hardpointSlot.Slot.toLowerCase().search(/tiny/))
|
||||||
}
|
{
|
||||||
|
// Use the missing_hardpoint module 'Missing Hardpoint' which will inform the user that the module is missing
|
||||||
// Now update the ship's codes before returning it
|
hardpoint = _moduleFromFdName('Hpt_Missing_Hardpoint');
|
||||||
return ship.updatePowerPrioritesString().updatePowerEnabledString().updateModificationsString();
|
}
|
||||||
}
|
else {
|
||||||
|
// Use the missing_hardpoint module 'Missing Utility' which will inform the user that the module is missing
|
||||||
/**
|
hardpoint = _moduleFromFdName('Hpt_Missing_Utility');
|
||||||
* Add the modifications for a module
|
}
|
||||||
* @param {Module} module the module
|
ship.use(ship.hardpoints[hardpointArrayNum], hardpoint, true);
|
||||||
* @param {Object} modifiers the modifiers
|
ship.hardpoints[hardpointArrayNum].enabled = hardpointSlot.On;
|
||||||
* @param {float} quality quality of the modifiers 0 to 1
|
ship.hardpoints[hardpointArrayNum].priority = hardpointSlot.Priority;
|
||||||
* @param {Object} blueprint the blueprint of the modification
|
} else {
|
||||||
* @param {Object} grade the grade of the modification
|
ship.use(ship.hardpoints[hardpointArrayNum], hardpoint, true);
|
||||||
* @param {Object} specialModifications special modification
|
ship.hardpoints[hardpointArrayNum].enabled = hardpointSlot.On;
|
||||||
*/
|
ship.hardpoints[hardpointArrayNum].priority = hardpointSlot.Priority;
|
||||||
function _addModifications(module, modifiers, quality, blueprint, grade, specialModifications) {
|
modsToAdd.push({ coriolisMod: hardpoint, json: hardpointSlot });
|
||||||
if (!modifiers && !quality) return;
|
}
|
||||||
let special;
|
}
|
||||||
if (specialModifications) {
|
hardpointArrayNum++;
|
||||||
if (specialModifications == 'special_plasma_slug') {
|
}
|
||||||
if (module.symbol.match(/PlasmaAccelerator/i)) {
|
}
|
||||||
specialModifications = 'special_plasma_slug_pa';
|
}
|
||||||
} else {
|
|
||||||
specialModifications = 'special_plasma_slug_cooled';
|
let internalSlotNum = 0;
|
||||||
}
|
let militarySlotNum = 1;
|
||||||
}
|
for (let i in shipTemplate.slots.internal) {
|
||||||
special = Modifications.specials[specialModifications];
|
if (!shipTemplate.slots.internal.hasOwnProperty(i)) {
|
||||||
}
|
continue;
|
||||||
// Add the blueprint definition, grade and special
|
}
|
||||||
if (blueprint) {
|
const isMilitary = isNaN(shipTemplate.slots.internal[i]) ? shipTemplate.slots.internal[i].name == 'Military' : false;
|
||||||
module.blueprint = getBlueprint(blueprint, module);
|
const isPlanetary = isNaN(shipTemplate.slots.internal[i]) ? shipTemplate.slots.internal[i].name == 'PlanetaryApproachSuite' : false;
|
||||||
if (grade) {
|
|
||||||
module.blueprint.grade = Number(grade);
|
// The internal slot might be a standard or a military slot, or a planetary slot. Military and Planetary slots have a different naming system
|
||||||
}
|
let internalSlot = null;
|
||||||
if (special) {
|
if (isMilitary) {
|
||||||
module.blueprint.special = special;
|
const internalName = 'Military0' + militarySlotNum;
|
||||||
}
|
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase());
|
||||||
}
|
militarySlotNum++;
|
||||||
if (modifiers) {
|
} else if (isPlanetary) {
|
||||||
for (const i in modifiers) {
|
const internalName = 'PlanetaryApproachSuite';
|
||||||
// Some special modifications
|
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase());
|
||||||
// Look up the modifiers to find what we need to do
|
} else {
|
||||||
const findMod = val => Object.keys(Modifications.modifierActions).find(elem => elem.toString().toLowerCase().replace(/(outfittingfieldtype_|persecond)/igm, '') === val.toString().toLowerCase().replace(/(outfittingfieldtype_|persecond)/igm, ''));
|
// Slot numbers are not contiguous so handle skips.
|
||||||
const modifierActions = Modifications.modifierActions[findMod(modifiers[i].Label)];
|
for (; internalSlot === null && internalSlotNum < 99; internalSlotNum++) {
|
||||||
// TODO: Figure out how to scale this value.
|
// Slot sizes have no relationship to the actual size, either, so check all possibilities
|
||||||
if (!!modifiers[i].LessIsGood) {
|
for (let slotsize = 0; slotsize < 9; slotsize++) {
|
||||||
|
const internalName = 'Slot' + (internalSlotNum <= 9 ? '0' : '') + internalSlotNum + '_Size' + slotsize;
|
||||||
}
|
if (json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase())) {
|
||||||
let value = (modifiers[i].Value / modifiers[i].OriginalValue * 100 - 100) * 100;
|
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase());
|
||||||
if (value === Infinity) {
|
break;
|
||||||
value = modifiers[i].Value * 100;
|
}
|
||||||
}
|
}
|
||||||
if (modifiers[i].Label.search('DamageFalloffRange') >= 0) {
|
}
|
||||||
value = (modifiers[i].Value / module.range - 1) * 100;
|
}
|
||||||
}
|
|
||||||
if (modifiers[i].Label.search('Resistance') >= 0) {
|
if (!internalSlot) {
|
||||||
value = (modifiers[i].Value * 100) - (modifiers[i].OriginalValue * 100);
|
// This can happen with old imports that don't contain new slots
|
||||||
}
|
} else {
|
||||||
if (modifiers[i].Label.search('ShieldMultiplier') >= 0 || modifiers[i].Label.search('DefenceModifierHealthMultiplier') >= 0) {
|
const internalJson = internalSlot;
|
||||||
value = ((100 + modifiers[i].Value) / (100 + modifiers[i].OriginalValue) * 100 - 100) * 100;
|
let internal = _moduleFromFdName(internalJson.Item);
|
||||||
}
|
// Check the internal module returned is valid
|
||||||
|
if (!_isValidImportedModule(internal, 'internal'))
|
||||||
// Carry out the required changes
|
{
|
||||||
for (const action in modifierActions) {
|
internal = _moduleFromFdName('Int_Missing_Module');
|
||||||
if (isNaN(modifierActions[action])) {
|
ship.use(ship.internal[i], internal, true);
|
||||||
module.setModValue(action, modifierActions[action]);
|
ship.internal[i].enabled = internalJson.On === true;
|
||||||
} else {
|
ship.internal[i].priority = internalJson.Priority;
|
||||||
module.setModValue(action, value, true);
|
//throw 'Unknown internal module: "' + module.Item + '"';
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
}
|
ship.use(ship.internal[i], internal, true);
|
||||||
} else if (quality) {
|
ship.internal[i].enabled = internalJson.On === true;
|
||||||
if (module.blueprint.grades) {
|
ship.internal[i].priority = internalJson.Priority;
|
||||||
const features = module.blueprint.grades[Number(grade)].features;
|
modsToAdd.push({ coriolisMod: internal, json: internalSlot });
|
||||||
Object.keys(features).map(featureKey => {
|
}
|
||||||
/*
|
}
|
||||||
Here we compute the value to use for this feature based on the range and quality.
|
}
|
||||||
We do this by finding the difference between the low and high ends of the range.
|
|
||||||
This gives us the maximum increase at 100% quality. Then we multiply this number by
|
for (const i of modsToAdd) {
|
||||||
the quality to determine the actual increase. Lastly we add the actual increase to
|
if (i.json.Engineering) {
|
||||||
the low end of the range back in to determine the final value.
|
_addModifications(i.coriolisMod, i.json.Engineering.Modifiers, i.json.Engineering.Quality, i.json.Engineering.BlueprintName, i.json.Engineering.Level, i.json.Engineering.ExperimentalEffect);
|
||||||
Value = ((High End of Range - Low End of Range) * Quality) + Low End of Range
|
}
|
||||||
*/
|
}
|
||||||
let value = (((features[featureKey][1] * 100) - (features[featureKey][0] * 100) * Number(quality)) + (features[featureKey][0] * 100)) * 100;
|
// We don't have any information on it so guess it's priority 5 and disabled
|
||||||
module.setModValue(featureKey, value, true);
|
if (!ship.cargoHatch) {
|
||||||
});
|
ship.cargoHatch.enabled = false;
|
||||||
}
|
ship.cargoHatch.priority = 4;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Now update the ship's codes before returning it
|
||||||
|
return ship.updatePowerPrioritesString().updatePowerEnabledString().updateModificationsString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the modifications for a module
|
||||||
|
* @param {Module} module the module
|
||||||
|
* @param {Object} modifiers the modifiers
|
||||||
|
* @param {float} quality quality of the modifiers 0 to 1
|
||||||
|
* @param {Object} blueprint the blueprint of the modification
|
||||||
|
* @param {Object} grade the grade of the modification
|
||||||
|
* @param {Object} specialModifications special modification
|
||||||
|
*/
|
||||||
|
function _addModifications(module, modifiers, quality, blueprint, grade, specialModifications) {
|
||||||
|
if (!modifiers && !quality) return;
|
||||||
|
let special;
|
||||||
|
if (specialModifications) {
|
||||||
|
if (specialModifications == 'special_plasma_slug') {
|
||||||
|
if (module.symbol.match(/PlasmaAccelerator/i)) {
|
||||||
|
specialModifications = 'special_plasma_slug_pa';
|
||||||
|
} else {
|
||||||
|
specialModifications = 'special_plasma_slug_cooled';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
special = Modifications.specials[specialModifications];
|
||||||
|
}
|
||||||
|
// Add the blueprint definition, grade and special
|
||||||
|
if (blueprint) {
|
||||||
|
module.blueprint = getBlueprint(blueprint, module);
|
||||||
|
|
||||||
|
if (grade) {
|
||||||
|
module.blueprint.grade = Number(grade);
|
||||||
|
}
|
||||||
|
if (special) {
|
||||||
|
module.blueprint.special = special;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (modifiers) {
|
||||||
|
for (const i in modifiers) {
|
||||||
|
// Some special modifications
|
||||||
|
// Look up the modifiers to find what we need to do
|
||||||
|
const findMod = val => Object.keys(Modifications.modifierActions).find(elem => elem.toString().toLowerCase().replace(/(outfittingfieldtype_|persecond)/igm, '') === val.toString().toLowerCase().replace(/(outfittingfieldtype_|persecond)/igm, ''));
|
||||||
|
const modifierActions = Modifications.modifierActions[findMod(modifiers[i].Label)];
|
||||||
|
// TODO: Figure out how to scale this value.
|
||||||
|
if (!!modifiers[i].LessIsGood) {
|
||||||
|
|
||||||
|
}
|
||||||
|
let value = (modifiers[i].Value / modifiers[i].OriginalValue * 100 - 100) * 100;
|
||||||
|
if (value === Infinity) {
|
||||||
|
value = modifiers[i].Value * 100;
|
||||||
|
}
|
||||||
|
if (modifiers[i].Label.search('DamageFalloffRange') >= 0) {
|
||||||
|
value = (modifiers[i].Value / module.range - 1) * 100;
|
||||||
|
}
|
||||||
|
if (modifiers[i].Label.search('Resistance') >= 0) {
|
||||||
|
value = (modifiers[i].Value * 100) - (modifiers[i].OriginalValue * 100);
|
||||||
|
}
|
||||||
|
if (modifiers[i].Label.search('ShieldMultiplier') >= 0 || modifiers[i].Label.search('DefenceModifierHealthMultiplier') >= 0) {
|
||||||
|
value = ((100 + modifiers[i].Value) / (100 + modifiers[i].OriginalValue) * 100 - 100) * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Carry out the required changes
|
||||||
|
for (const action in modifierActions) {
|
||||||
|
if (isNaN(modifierActions[action])) {
|
||||||
|
module.setModValue(action, modifierActions[action]);
|
||||||
|
} else {
|
||||||
|
module.setModValue(action, value, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (quality) {
|
||||||
|
setQualityCB(module.blueprint, quality, (featureName, value) => module.setModValue(featureName, value, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,22 +40,12 @@
|
|||||||
window.dataLayer = window.dataLayer || [];
|
window.dataLayer = window.dataLayer || [];
|
||||||
function gtag(){dataLayer.push(arguments);}
|
function gtag(){dataLayer.push(arguments);}
|
||||||
gtag('js', new Date());
|
gtag('js', new Date());
|
||||||
|
|
||||||
gtag('config', 'UA-55840909-18');
|
gtag('config', 'UA-55840909-18');
|
||||||
</script>
|
</script>
|
||||||
|
</head>
|
||||||
|
<body style="background-color:#000;">
|
||||||
|
<section id="coriolis">
|
||||||
|
|
||||||
|
</section>
|
||||||
|
</body>
|
||||||
<!-- Bugsnag -->
|
</html>
|
||||||
<script src="https://d2wy8f7a9ursnm.cloudfront.net/v5.0.0/bugsnag.min.js"></script>
|
|
||||||
<script>
|
|
||||||
window.bugsnagClient = bugsnag('ba9fae819372850fb660755341fa6ef5', {appVersion: window.BUGSNAG_VERSION || undefined})
|
|
||||||
window.Bugsnag = window.bugsnagClient
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body style="background-color:#000;">
|
|
||||||
<section id="coriolis">
|
|
||||||
|
|
||||||
</section>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|||||||
@@ -183,4 +183,5 @@ footer {
|
|||||||
.announcement {
|
.announcement {
|
||||||
border: 1px @secondary solid;
|
border: 1px @secondary solid;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
margin: 5px;
|
||||||
|
}
|
||||||
@@ -9,6 +9,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
white-space: -moz-pre-wrap;
|
white-space: -moz-pre-wrap;
|
||||||
|
|||||||
@@ -41,24 +41,67 @@
|
|||||||
h2 {
|
h2 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
h4 {
|
||||||
background: @primary-bg;
|
text-transform: uppercase;
|
||||||
border: none;
|
font-family: @fStandard;
|
||||||
outline: none;
|
font-weight: normal;
|
||||||
color: @primary-disabled;
|
font-size: 1em;
|
||||||
|
margin: 1em;
|
||||||
&.json {
|
color: @warning;
|
||||||
display:block;
|
|
||||||
width:100%;
|
|
||||||
min-height: 10em;
|
|
||||||
resize: vertical;
|
|
||||||
user-select: text;
|
|
||||||
margin:2em 0;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.dismiss {
|
p {
|
||||||
background-color: @primary-bg;
|
margin: 1em;
|
||||||
}
|
text-wrap: pretty;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
clear: bottom;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
clear: both;
|
||||||
|
margin: 15px, 10px, 15px, 10px;
|
||||||
|
padding: top, 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
clear: bottom;
|
||||||
|
margin: 10px;
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
clear: bottom;
|
||||||
|
margin: 20px;
|
||||||
|
color: @primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.groll {
|
||||||
|
width: 6%;
|
||||||
|
margin: 5px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
background: @primary-bg;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
color: @primary-disabled;
|
||||||
|
|
||||||
|
&.json {
|
||||||
|
display:block;
|
||||||
|
width:100%;
|
||||||
|
min-height: 10em;
|
||||||
|
resize: vertical;
|
||||||
|
user-select: text;
|
||||||
|
margin:1em 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dismiss {
|
||||||
|
background-color: @primary-bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,12 +24,6 @@
|
|||||||
type="image/png"
|
type="image/png"
|
||||||
href="/192x192.png"
|
href="/192x192.png"
|
||||||
/>
|
/>
|
||||||
<!-- Bugsnag -->
|
|
||||||
<script src="https://d2wy8f7a9ursnm.cloudfront.net/v5.0.0/bugsnag.min.js"></script>
|
|
||||||
<script>
|
|
||||||
window.bugsnagClient = bugsnag('ba9fae819372850fb660755341fa6ef5', {appVersion: window.BUGSNAG_VERSION || undefined})
|
|
||||||
window.Bugsnag = window.bugsnagClient
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Apple/iOS headers -->
|
<!-- Apple/iOS headers -->
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||||
|
|||||||
82
src/sw.js
82
src/sw.js
@@ -1,46 +1,54 @@
|
|||||||
|
import {precacheAndRoute, createHandlerBoundToURL} from 'workbox-precaching';
|
||||||
|
import {NavigationRoute, registerRoute} from 'workbox-routing';
|
||||||
|
import {StaleWhileRevalidate, CacheFirst} from 'workbox-strategies';
|
||||||
|
import {CacheableResponsePlugin} from 'workbox-cacheable-response'
|
||||||
|
import {ExpirationPlugin} from 'workbox-expiration';
|
||||||
|
|
||||||
console.log('Hello from sw.js');
|
console.log('Hello from sw.js');
|
||||||
|
|
||||||
if (workbox) {
|
// See https://developer.chrome.com/docs/workbox/migration/migrate-from-v4/ for guide to changes made
|
||||||
console.log('Yay! Workbox is loaded 🎉');
|
console.log('Yay! Workbox is loaded 🎉');
|
||||||
workbox.precaching.precacheAndRoute(self.__precacheManifest);
|
precacheAndRoute(self.__WB_MANIFEST || []);
|
||||||
|
|
||||||
workbox.routing.registerNavigationRoute('/index.html');
|
const handler = createHandlerBoundToURL('/index.html');
|
||||||
|
const navigationRoute = new NavigationRoute(handler
|
||||||
|
// , {allowlist: [...], denylist: [...],}
|
||||||
|
);
|
||||||
|
registerRoute(navigationRoute);
|
||||||
|
|
||||||
workbox.routing.registerRoute(
|
|
||||||
/\.(?:png|jpg|jpeg|svg|gif)$/,
|
|
||||||
new workbox.strategies.CacheFirst({
|
|
||||||
plugins: [
|
|
||||||
new workbox.cacheableResponse.Plugin({
|
|
||||||
statuses: [0, 200]
|
|
||||||
})
|
|
||||||
]
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
workbox.routing.registerRoute(
|
registerRoute(
|
||||||
/\.(?:js|css)$/,
|
/\.(?:png|jpg|jpeg|svg|gif)$/,
|
||||||
new workbox.strategies.StaleWhileRevalidate({
|
new CacheFirst({
|
||||||
cacheName: 'static-resources',
|
plugins: [
|
||||||
})
|
new CacheableResponsePlugin({
|
||||||
);
|
statuses: [0, 200]
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
workbox.routing.registerRoute(
|
registerRoute(
|
||||||
new RegExp('https://fonts.(?:googleapis|gstatic).com/(.*)'),
|
/\.(?:js|css)$/,
|
||||||
new workbox.strategies.CacheFirst({
|
new StaleWhileRevalidate({
|
||||||
cacheName: 'google-fonts',
|
cacheName: 'static-resources',
|
||||||
plugins: [
|
})
|
||||||
new workbox.expiration.Plugin({
|
);
|
||||||
maxEntries: 30
|
|
||||||
}),
|
registerRoute(
|
||||||
new workbox.cacheableResponse.Plugin({
|
new RegExp('https://fonts.(?:googleapis|gstatic).com/(.*)'),
|
||||||
statuses: [0, 200]
|
new CacheFirst({
|
||||||
})
|
cacheName: 'google-fonts',
|
||||||
]
|
plugins: [
|
||||||
})
|
new ExpirationPlugin({
|
||||||
);
|
maxEntries: 30
|
||||||
} else {
|
}),
|
||||||
console.log('Boo! Workbox didn\'t load 😬');
|
new CacheableResponsePlugin({
|
||||||
}
|
statuses: [0, 200]
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
self.addEventListener('message', event => {
|
self.addEventListener('message', event => {
|
||||||
if (!event.data) {
|
if (!event.data) {
|
||||||
|
|||||||
81
webpack.common.js
Normal file
81
webpack.common.js
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
|
|
||||||
|
const pkgJson = require('./package');
|
||||||
|
const buildDate = new Date();
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
entry: {
|
||||||
|
main: './src/app/index.js'
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
// When requiring, you don't need to add these extensions
|
||||||
|
extensions: ['.js', '.jsx', '.json', '.less'],
|
||||||
|
fallback: {
|
||||||
|
// Consider replacing brwoserify-zlib-next c. 2016 package with pako, which it's just a wrapper for
|
||||||
|
/* Some of these polyfills may not even be necessary, and were added in an attempt to deal with build issues
|
||||||
|
while upgrading to Webpack v5 */
|
||||||
|
"zlib": require.resolve("browserify-zlib-next"),
|
||||||
|
"assert": require.resolve("assert/"),
|
||||||
|
"buffer": require.resolve("buffer/"),
|
||||||
|
"stream": require.resolve("stream-browserify"),
|
||||||
|
/*
|
||||||
|
"url": require.resolve("url/"),
|
||||||
|
"path": require.resolve("path-browserify"),
|
||||||
|
"crypto": require.resolve("crypto-browserify"),
|
||||||
|
"os": require.resolve("os-browserify/browser"),
|
||||||
|
"https": require.resolve("https-browserify"),
|
||||||
|
"http": require.resolve("stream-http"),
|
||||||
|
"vm": require.resolve("vm-browserify"),
|
||||||
|
"constants": require.resolve("constants-browserify"),
|
||||||
|
// "fs": false
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
},
|
||||||
|
optimization: {
|
||||||
|
usedExports: true
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
path: path.join(__dirname, 'build'),
|
||||||
|
chunkFilename: '[name].bundle.js',
|
||||||
|
// assetModuleFilename: '[contenthash][ext]',
|
||||||
|
publicPath: '/',
|
||||||
|
clean: true // we already do rimraf on the build dir, but this should obviate that
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
// new webpack.optimize.CommonsChunkPlugin({
|
||||||
|
// name: 'lib',
|
||||||
|
// filename: 'lib.js'
|
||||||
|
// }),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
inject: true,
|
||||||
|
template: path.join(__dirname, 'src/index.ejs'),
|
||||||
|
version: pkgJson.version,
|
||||||
|
// gapiKey: process.env.CORIOLIS_GAPI_KEY || '',
|
||||||
|
date: buildDate,
|
||||||
|
}),
|
||||||
|
new MiniCssExtractPlugin({
|
||||||
|
filename: 'app.css',
|
||||||
|
}),
|
||||||
|
// Solve missing Buffer polyfill that breaks module engineering
|
||||||
|
new webpack.ProvidePlugin({
|
||||||
|
Buffer: ['buffer', 'Buffer'],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{ test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader' ]},
|
||||||
|
{
|
||||||
|
test: /\.less$/,
|
||||||
|
use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader' ]
|
||||||
|
},
|
||||||
|
{ test: /\.(js|jsx)$/, use: ['babel-loader'], include: path.join(__dirname, 'src') },
|
||||||
|
{
|
||||||
|
test: /\.(jpe?g|svg|png|gif|ico|eot|ttf|woff|woff2?)(\?v=\d+\.\d+\.\d+)?$/i,
|
||||||
|
type: 'asset/resource',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,69 +1,27 @@
|
|||||||
const path = require('path');
|
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const { merge } = require('webpack-merge');
|
||||||
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
const common = require('./webpack.common.js');
|
||||||
const WebpackNotifierPlugin = require('webpack-notifier');
|
|
||||||
const pkgJson = require('./package');
|
|
||||||
const buildDate = new Date();
|
|
||||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
|
||||||
|
|
||||||
module.exports = {
|
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
|
const WebpackNotifierPlugin = require('webpack-notifier');
|
||||||
|
|
||||||
|
module.exports = merge(common, {
|
||||||
devtool: 'source-map',
|
devtool: 'source-map',
|
||||||
devServer: {
|
devServer: {
|
||||||
headers: { 'Access-Control-Allow-Origin': '*' }
|
headers: { 'Access-Control-Allow-Origin': '*' }
|
||||||
},
|
},
|
||||||
mode: 'development',
|
mode: 'development',
|
||||||
entry: {
|
|
||||||
main: './src/app/index.js',
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
// When requiring, you don't need to add these extensions
|
|
||||||
extensions: ['.js', '.jsx', '.json', '.less']
|
|
||||||
},
|
|
||||||
optimization: {
|
optimization: {
|
||||||
minimize: false,
|
minimize: false,
|
||||||
usedExports: true
|
|
||||||
},
|
|
||||||
output: {
|
|
||||||
path: path.join(__dirname, 'build'),
|
|
||||||
chunkFilename: '[name].bundle.js',
|
|
||||||
publicPath: '/'
|
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new CopyWebpackPlugin(['src/.htaccess', 'src/iframe.html', 'src/xdLocalStoragePostMessageApi.min.js']),
|
new CopyWebpackPlugin({
|
||||||
// new webpack.optimize.CommonsChunkPlugin({
|
patterns: [
|
||||||
// name: 'lib',
|
'src/.htaccess',
|
||||||
// filename: 'lib.js'
|
'src/iframe.html',
|
||||||
// }),
|
'src/xdLocalStoragePostMessageApi.min.js'
|
||||||
new HtmlWebpackPlugin({
|
]}),
|
||||||
inject: true,
|
|
||||||
template: path.join(__dirname, 'src/index.ejs'),
|
|
||||||
version: pkgJson.version,
|
|
||||||
date: buildDate,
|
|
||||||
gapiKey: process.env.CORIOLIS_GAPI_KEY || ''
|
|
||||||
}),
|
|
||||||
new ExtractTextPlugin({
|
|
||||||
filename: 'app.css',
|
|
||||||
disable: false,
|
|
||||||
allChunks: true
|
|
||||||
}),
|
|
||||||
new WebpackNotifierPlugin({ alwaysNotify: true }),
|
new WebpackNotifierPlugin({ alwaysNotify: true }),
|
||||||
new webpack.HotModuleReplacementPlugin(),
|
|
||||||
new webpack.NoEmitOnErrorsPlugin()
|
new webpack.NoEmitOnErrorsPlugin()
|
||||||
],
|
]
|
||||||
module: {
|
});
|
||||||
rules: [
|
|
||||||
{ test: /\.css$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader' }) },
|
|
||||||
{
|
|
||||||
test: /\.less$/,
|
|
||||||
loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader!less-loader' })
|
|
||||||
},
|
|
||||||
{ test: /\.(js|jsx)$/, loaders: ['babel-loader'], include: path.join(__dirname, 'src') },
|
|
||||||
{ test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff' },
|
|
||||||
{ test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff' },
|
|
||||||
{ test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/octet-stream' },
|
|
||||||
{ test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader' },
|
|
||||||
{ test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=image/svg+xml' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,54 +1,38 @@
|
|||||||
const path = require('path');
|
const { merge } = require('webpack-merge');
|
||||||
const webpack = require('webpack');
|
const common = require('./webpack.common.js');
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
|
||||||
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
|
||||||
const { InjectManifest } = require('workbox-webpack-plugin');
|
|
||||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
|
||||||
const { BugsnagSourceMapUploaderPlugin, BugsnagBuildReporterPlugin } = require('webpack-bugsnag-plugins');
|
|
||||||
const pkgJson = require('./package');
|
|
||||||
const buildDate = new Date();
|
|
||||||
|
|
||||||
module.exports = {
|
const path = require('path');
|
||||||
devtool: 'source-map',
|
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
entry: {
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
main: './src/app/index.js'
|
const { InjectManifest } = require('workbox-webpack-plugin');
|
||||||
},
|
const { max } = require('lodash');
|
||||||
resolve: {
|
|
||||||
extensions: ['.js', '.jsx', '.json', '.less']
|
module.exports = merge(common, {
|
||||||
},
|
// devtool: 'source-map',
|
||||||
output: {
|
|
||||||
path: path.join(__dirname, 'build'),
|
|
||||||
chunkFilename: '[name].bundle.js',
|
|
||||||
publicPath: '/',
|
|
||||||
globalObject: 'this'
|
|
||||||
},
|
|
||||||
mode: 'production',
|
mode: 'production',
|
||||||
optimization: {
|
optimization: {
|
||||||
minimize: true,
|
minimize: true,
|
||||||
usedExports: true
|
},
|
||||||
|
output: {
|
||||||
|
globalObject: 'this'
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new CopyWebpackPlugin(['src/.htaccess', { from: 'src/schemas', to: 'schemas' }, {
|
new CopyWebpackPlugin({
|
||||||
from: 'src/images/logo/*',
|
patterns: [
|
||||||
flatten: true,
|
'src/.htaccess',
|
||||||
to: ''
|
'src/iframe.html',
|
||||||
}, 'src/iframe.html', 'src/xdLocalStoragePostMessageApi.min.js']),
|
'src/xdLocalStoragePostMessageApi.min.js',
|
||||||
// new webpack.optimize.CommonsChunkPlugin({
|
{ from: 'src/schemas', to: 'schemas' },
|
||||||
// name: 'lib',
|
{
|
||||||
// filename: 'lib.[chunkhash:6].js'
|
from: 'src/images/logo/*',
|
||||||
// }),
|
to: '[name][ext]'
|
||||||
new HtmlWebpackPlugin({
|
}
|
||||||
inject: true,
|
]}),
|
||||||
template: path.join(__dirname, 'src/index.ejs'),
|
/* new HtmlWebpackPlugin({
|
||||||
uaTracking: process.env.CORIOLIS_UA_TRACKING || '',
|
// uaTracking: process.env.CORIOLIS_UA_TRACKING || '',
|
||||||
gapiKey: process.env.CORIOLIS_GAPI_KEY || '',
|
}), */
|
||||||
date: buildDate,
|
new MiniCssExtractPlugin({
|
||||||
version: pkgJson.version
|
filename: '[contenthash:6].css',
|
||||||
}),
|
|
||||||
new ExtractTextPlugin({
|
|
||||||
filename: '[hash:6].css',
|
|
||||||
disable: false,
|
|
||||||
allChunks: true
|
|
||||||
}),
|
}),
|
||||||
// new BugsnagBuildReporterPlugin({
|
// new BugsnagBuildReporterPlugin({
|
||||||
// apiKey: 'ba9fae819372850fb660755341fa6ef5',
|
// apiKey: 'ba9fae819372850fb660755341fa6ef5',
|
||||||
@@ -59,25 +43,11 @@ module.exports = {
|
|||||||
// overwrite: true,
|
// overwrite: true,
|
||||||
// appVersion: `${pkgJson.version}-${buildDate.toISOString()}`
|
// appVersion: `${pkgJson.version}-${buildDate.toISOString()}`
|
||||||
// }),
|
// }),
|
||||||
|
|
||||||
new InjectManifest({
|
new InjectManifest({
|
||||||
swSrc: './src/sw.js',
|
swSrc: './src/sw.js',
|
||||||
importWorkboxFrom: 'cdn',
|
|
||||||
swDest: 'service-worker.js'
|
swDest: 'service-worker.js'
|
||||||
}),
|
}),
|
||||||
],
|
|
||||||
module: {
|
]
|
||||||
rules: [
|
});
|
||||||
{ test: /\.css$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader' }) },
|
|
||||||
{
|
|
||||||
test: /\.less$/,
|
|
||||||
loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader!less-loader' })
|
|
||||||
},
|
|
||||||
{ test: /\.(js|jsx)$/, loader: 'babel-loader?cacheDirectory=true', include: path.join(__dirname, 'src') },
|
|
||||||
{ test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff' },
|
|
||||||
{ test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff' },
|
|
||||||
{ test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/octet-stream' },
|
|
||||||
{ test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader' },
|
|
||||||
{ test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=image/svg+xml' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|||||||
Reference in New Issue
Block a user