mirror of
https://github.com/EDCD/coriolis.git
synced 2025-12-09 14:45:35 +00:00
Compare commits
20 Commits
f747b25f26
...
dw2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9abb4f6d05 | ||
|
|
38038fcc32 | ||
|
|
9fa740f54e | ||
|
|
d37d69c3a7 | ||
|
|
78d8779641 | ||
|
|
352023f0fb | ||
|
|
3ea194d43e | ||
|
|
c6269192f0 | ||
|
|
841e6c3348 | ||
|
|
0febc581d1 | ||
|
|
dc6e398526 | ||
|
|
cb24c1fc69 | ||
|
|
90ad9de831 | ||
|
|
9360b1d574 | ||
|
|
08d2573d1f | ||
|
|
427b9af7de | ||
|
|
318d06d9f9 | ||
|
|
1f3c3726f2 | ||
|
|
71beda3a6c | ||
|
|
1d6644b531 |
6
.babelrc
6
.babelrc
@@ -7,8 +7,6 @@
|
|||||||
"@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",
|
||||||
@@ -30,7 +28,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"@babel/plugin-proposal-nullish-coalescing-operator",
|
"@babel/plugin-proposal-nullish-coalescing-operator",
|
||||||
["@babel/plugin-proposal-private-methods", { "loose": true }],
|
"@babel/plugin-proposal-do-expressions",
|
||||||
["@babel/plugin-proposal-private-property-in-object", { "loose": true }]
|
"@babel/plugin-proposal-function-bind"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,77 @@
|
|||||||
Dockerfile
|
|
||||||
.dockerignore
|
|
||||||
.gitignore
|
|
||||||
README.md
|
|
||||||
|
|
||||||
build
|
|
||||||
node_modules
|
node_modules
|
||||||
|
npm-debug.log
|
||||||
|
### Node template
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# TypeScript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
|
||||||
|
# next.js build output
|
||||||
|
.next
|
||||||
|
|
||||||
|
# nuxt.js build output
|
||||||
|
.nuxt
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless
|
||||||
|
|
||||||
|
|||||||
14
.gitattributes
vendored
14
.gitattributes
vendored
@@ -1,14 +0,0 @@
|
|||||||
# 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
|
|
||||||
28
.github/workflows/autodeploy.yml
vendored
28
.github/workflows/autodeploy.yml
vendored
@@ -1,28 +0,0 @@
|
|||||||
# This is a basic deployment workflow triggered by pushes to the alpha branch.
|
|
||||||
|
|
||||||
name: Auto-Deploy
|
|
||||||
|
|
||||||
# Controls when the action will run. Workflow runs when the alpha branch receives a push event
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- alpha
|
|
||||||
|
|
||||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
|
||||||
jobs:
|
|
||||||
downloadcode:
|
|
||||||
runs-on: self-hosted
|
|
||||||
steps:
|
|
||||||
- shell: bash
|
|
||||||
run: |
|
|
||||||
rm -Rf ./coriolis
|
|
||||||
rm -Rf ./coriolis-data
|
|
||||||
git clone https://github.com/alex-williams/coriolis.git --single-branch --branch alpha
|
|
||||||
git clone https://github.com/alex-williams/coriolis-data.git --single-branch --branch alpha
|
|
||||||
cd coriolis-data
|
|
||||||
npm install
|
|
||||||
cd ../coriolis
|
|
||||||
npm install
|
|
||||||
npm run build
|
|
||||||
sudo -u www-data cp -r ./build/* /var/www/newdisk/coriolis.brighter-applications.co.uk/
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -10,3 +10,4 @@ env
|
|||||||
.project
|
.project
|
||||||
.vscode/
|
.vscode/
|
||||||
docs/
|
docs/
|
||||||
|
package-lock.json
|
||||||
|
|||||||
16
.travis.yml
Normal file
16
.travis.yml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
language: node_js
|
||||||
|
notifications:
|
||||||
|
email: false
|
||||||
|
sudo: false
|
||||||
|
node_js:
|
||||||
|
- "4.8.1"
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- node_modules
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- git clone https://github.com/EDCD/coriolis-data.git ../coriolis-data
|
||||||
|
|
||||||
|
script:
|
||||||
|
- npm run lint
|
||||||
|
- npm test
|
||||||
49
Dockerfile
49
Dockerfile
@@ -1,25 +1,34 @@
|
|||||||
#syntax=docker/dockerfile:1.4
|
### STAGE 1: Build ###
|
||||||
# Run this from within this directory. Change the location of coriolis-data repo and image name/tag as needed.
|
FROM node:9.11.1-alpine as builder
|
||||||
# docker buildx build --build-context data=../coriolis-data --tag coriolis .
|
ARG branch=develop
|
||||||
|
ENV BRANCH=$branch
|
||||||
|
WORKDIR /src/app
|
||||||
|
RUN mkdir -p /src/app/coriolis
|
||||||
|
RUN mkdir -p /src/app/coriolis-data
|
||||||
|
|
||||||
FROM node:18-alpine
|
RUN apk add --update git
|
||||||
|
|
||||||
# TODO: For a production build, we may want to just build the bundle and copy that in. No need for local copy of source.
|
COPY . /src/app/coriolis
|
||||||
WORKDIR /app
|
|
||||||
ADD . .
|
|
||||||
COPY --from=data . /coriolis-data/
|
|
||||||
|
|
||||||
# Git is required before install if any modules (like coriolis-data) are loaded from github
|
RUN npm i -g npm
|
||||||
RUN apk update
|
|
||||||
RUN apk add git
|
|
||||||
|
|
||||||
WORKDIR /app/coriolis-data
|
# Set up coriolis-data
|
||||||
RUN npm install
|
WORKDIR /src/app/coriolis-data
|
||||||
WORKDIR /app
|
RUN git clone https://github.com/EDCD/coriolis-data.git .
|
||||||
RUN npm install
|
RUN git checkout ${BRANCH}
|
||||||
# Bundle for production config with webpack & log
|
RUN npm install --no-package-lock
|
||||||
RUN npm run build > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2)
|
RUN npm start
|
||||||
|
|
||||||
# Optimally, this will start a static asset server like nginx/apache. Currently, this will start dev webpack server.
|
# Set up coriolis
|
||||||
CMD ["npm", "start"]
|
WORKDIR /src/app/coriolis
|
||||||
EXPOSE 3300
|
RUN npm install --no-package-lock
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
|
||||||
|
### STAGE 2: Production Environment ###
|
||||||
|
FROM fholzer/nginx-brotli as web
|
||||||
|
COPY nginx.conf /etc/nginx/nginx.conf
|
||||||
|
COPY --from=builder /src/app/coriolis/build /usr/share/nginx/html
|
||||||
|
WORKDIR /usr/share/nginx/html
|
||||||
|
EXPOSE 80
|
||||||
|
CMD ["nginx", "-c", "/etc/nginx/nginx.conf", "-g", "daemon off;"]
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
#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
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
#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
|
|
||||||
24
LICENSE.md
24
LICENSE.md
@@ -1,24 +0,0 @@
|
|||||||
All Data and [associated JSON](https://github.com/EDCD/coriolis-data) files are intellectual property and copyright of Frontier Developments plc ('Frontier', 'Frontier Developments') and are subject to their
|
|
||||||
[terms and conditions](https://www.frontierstore.net/terms-and-conditions/).
|
|
||||||
|
|
||||||
The code (Javascript, CSS, HTML, and SVG files only) specificially for Coriolis.io is released under the MIT License.
|
|
||||||
|
|
||||||
Copyright (c) 2015 Coriolis.io, Colin McLeod
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software (Javascript, CSS, HTML, and SVG files only), and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
73
README.md
73
README.md
@@ -1,4 +1,4 @@
|
|||||||
[](https://discord.gg/0uwCh6R62aPRjk9w)
|
 [](https://travis-ci.org/EDCD/coriolis) [](https://discord.gg/0uwCh6R62aPRjk9w)
|
||||||
|
|
||||||
## About
|
## About
|
||||||
|
|
||||||
@@ -8,50 +8,51 @@ Coriolis was created using assets and imagery from Elite: Dangerous, with the pe
|
|||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
- [Submit issues](https://github.com/EDCD/coriolis/issues)
|
Please [submit issues](https://github.com/EDCD/coriolis/issues), or better yet [pull requests](https://github.com/EDCD/coriolis/pulls) for any corrections or additions to the database or the code.
|
||||||
- [Submit pull requests](https://github.com/EDCD/coriolis/pulls) targetting `develop` branch
|
|
||||||
- Chat to us on [Discord](https://discord.gg/0uwCh6R62aPRjk9w)!
|
### Translations
|
||||||
|
|
||||||
|
Please use the OneSky translation site to suggest new translations: http://edcd-coriolis.oneskyapp.com
|
||||||
|
These will be merged regularly by the project manager.
|
||||||
|
|
||||||
|
### Feature Requests, Suggestions & Bugs
|
||||||
|
|
||||||
|
Chat to us on [Discord](https://discord.gg/0uwCh6R62aPRjk9w)!
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
This release includes the ability to run the app as a Docker container.
|
See the [Developer's Guide](https://github.com/EDCD/coriolis/wiki/Developing-for-Coriolis) in the wiki.
|
||||||
```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:
|
Also see [the documentation site.](https://coriolis.willb.info/)
|
||||||
```sh
|
|
||||||
> git clone https://github.com/EDCD/coriolis.git
|
|
||||||
> git clone https://github.com/EDCD/coriolis-data.git
|
|
||||||
> cd ./coriolis-data
|
|
||||||
> npm install
|
|
||||||
> cd ../coriolis
|
|
||||||
> npm install
|
|
||||||
> npm start
|
|
||||||
```
|
|
||||||
|
|
||||||
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/EDCD/coriolis-data/wiki) for details on structure, etc.
|
See the [Data wiki](https://github.com/cmmcleod/coriolis-data/wiki) for details on structure, etc.
|
||||||
|
|
||||||
## Deployment
|
|
||||||
|
|
||||||
Follow the steps for [Development](#development) as above, but instead
|
## License
|
||||||
of `npm start` you'll want to:
|
|
||||||
|
|
||||||
```sh
|
All Data and [associated JSON](https://github.com/EDCD/coriolis-data) files are intellectual property and copyright of Frontier Developments plc ('Frontier', 'Frontier Developments') and are subject to their
|
||||||
> npm run build
|
[terms and conditions](https://www.frontierstore.net/terms-and-conditions/).
|
||||||
```
|
|
||||||
|
|
||||||
this will result in a `build/` directory being created containing all the necessary files.
|
The code (Javascript, CSS, HTML, and SVG files only) specificially for Coriolis.io is released under the MIT License.
|
||||||
|
|
||||||
After this you need to serve the files in some manner.
|
Copyright (c) 2015 Coriolis.io, Colin McLeod
|
||||||
Either configure your webserver to make the actual `build/` directory
|
|
||||||
visible on the web, or alternatively copy it to somewhere to serve it
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
from.
|
of this software (Javascript, CSS, HTML, and SVG files only), and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|||||||
@@ -1,50 +1,50 @@
|
|||||||
{
|
{
|
||||||
"type_6_transporter": {
|
"type_6_transporter": {
|
||||||
"Cargo": "A0p0tdFal8d8s8f4-----04040303430101-.Iw18UA==.Aw18UA==.",
|
"Cargo": "A0p0tdFal8d8s8f4-----04040303430101.Iw1/kA==.Aw1/kA==.",
|
||||||
"Miner": "A0p5tdFal8d8s8f42l2l---040403451q0101-.Iw18UA==.Aw18UA==.",
|
"Miner": "A0p5tdFal8d8s8f42l2l---040403451q0101.Iw1/kA==.Aw1/kA==.",
|
||||||
"Hopper": "A0p0tdFal8d0s8f41717---030302024300--.Iw18UA==.Aw18UA==."
|
"Hopper": "A0p0tdFal8d0s8f41717---030302024300-.Iw1/kA==.Aw1/kA==."
|
||||||
},
|
},
|
||||||
"type_7_transport": {
|
"type_7_transport": {
|
||||||
"Cargo": "A0p0tiFfliddsdf5--------0505040403480101--.Iw18eQ==.Aw18eQ==.",
|
"Cargo": "A0p0tiFfliddsdf5--------0505040403480101.Iw18aQ==.Aw18aQ==.",
|
||||||
"Miner": "A0pdtiFflid8sdf5--2l2l----0505041v03450000--.Iw18eQ==.Aw18eQ==."
|
"Miner": "A0pdtiFflid8sdf5--2l2l----0505041v03450000.Iw18aQ==.Aw18aQ==."
|
||||||
},
|
},
|
||||||
"federal_dropship": {
|
"federal_dropship": {
|
||||||
"Cargo": "A0pdtiFflnddsif4-1717------05040448--020201-.Iw18RQ==.Aw18RQ==."
|
"Cargo": "A0pdtiFflnddsif4-1717------05040448--020201.Iw18eQ==.Aw18eQ==."
|
||||||
},
|
},
|
||||||
"asp": {
|
"asp": {
|
||||||
"Miner": "A2pftfFflidfskf50s0s24242l2l---04054a1q02022o27-.Iw18eQ==.Aw18eQ==."
|
"Miner": "A2pftfFflidfskf50s0s24242l2l---04054a1q02022o27.Iw18WQ==.Aw18WQ==."
|
||||||
},
|
},
|
||||||
"imperial_clipper": {
|
"imperial_clipper": {
|
||||||
"Cargo": "A0p5tiFflndisnf4--0s0s----0605450302020101-.Iw18WQ==.Aw18WQ==.",
|
"Cargo": "A0p5tiFflndisnf4--0s0s----0605450302020101.Iw18aQ==.Aw18aQ==.",
|
||||||
"Dream": "A2pktkFflndpskf40v0v0s0s0404040n4k5n5d2b29292o--.AwRj4yWU1Yg=.CwBhCYy6YRigzPIA.",
|
"Dream": "A2pktkFflndpskf40v0v0s0s0404040n4k5n5d2b29292o-.AwRj4yWU1I==.CwBhCYy6YRigzLIA.",
|
||||||
"Current": "A0patkFflndfskf4-----------------.AwRj4yWU1Yg=.CwBhCYy6YRigzPIA."
|
"Current": "A0patkFflndfskf4----------------.AwRj4yWU1I==.CwBhCYy6YRigzLIA."
|
||||||
},
|
},
|
||||||
"type_9_heavy": {
|
"type_9_heavy": {
|
||||||
"Current": "A0patsFklndnsif6---------0706054a0303020224--.AwRj4yo5iA==.EwBhEYy6d6g=."
|
"Current": "A0patsFklndnsif6---------0706054a0303020224.AwRj4yoo.EwBhEYy6dsg=."
|
||||||
},
|
},
|
||||||
"python": {
|
"python": {
|
||||||
"Cargo": "A0patnFflidsssf5---------050505040448020201-.Iw18eAMQ.Aw18RQ==.",
|
"Cargo": "A0patnFflidsssf5---------050505040448020201.Iw18eQ==.Aw18eQ==.",
|
||||||
"Miner": "A0pktkFflidpspf50v0v0v2m2m0404--050505Ce4a1v02022o-.Iw18eAMQ.IwBhBYy6dkCYRA==.",
|
"Miner": "A0pktkFflidpspf50v0v0v2m2m0404--050505Ce4a1v02022o.Iw18eQ==.IwBhBYy6dkCYg===.",
|
||||||
"Dream": "A2pptkFfliduspf50v0v0v27270404040m5n5n4f2d2d032t0201-.Iw1+gDByUA==.EwBhEYy6e0VEA===.",
|
"Dream": "A2pptkFfliduspf50v0v0v27270404040m5n5n4f2d2d032t0201.Iw1+gDBxA===.EwBhEYy6e0WEA===.",
|
||||||
"Missile": "A0pttoFjljdystf52f2g2d2ePh----04044j03---00--.Iw18eAMQ.Aw18RQ==."
|
"Missile": "A0pttoFjljdystf52f2g2d2ePh----04044j03---002h.Iw18eQ==.Aw18eQ==."
|
||||||
},
|
},
|
||||||
"anaconda": {
|
"anaconda": {
|
||||||
"Dream": "A4putpFklndzsuf52c0o0o0o1m1m0q0q0404040l0b0100004k5n5n112d2d04-0303326b-.AwRj4yo5dzhA.MwBhCYy6duvARhEA.",
|
"Dream": "A4putpFklndzsuf52c0o0o0o1m1m0q0q0404040l0b0100004k5n5n112d2d04-0303326b.AwRj4yo5dyg=.MwBhCYy6duvARiA=.",
|
||||||
"Cargo": "A0patnFklndnsxf5----------------06050505040404-45030301-.Iw18ZUAxA===.Aw18ZXEA.",
|
"Cargo": "A0patnFklndnsxf5----------------06050505040404-45030301.Iw18ZVA=.Aw18ZVA=.",
|
||||||
"Current": "A0patnFklndksxf5----------------06050505040404-03034524-.Iw18ZUAxA===.Aw18ZXEA.",
|
"Current": "A0patnFklndksxf5----------------06050505040404-03034524.Iw18ZVA=.Aw18ZVA=.",
|
||||||
"Explorer": "A0patnFklndksxf5--------0202------f7050505040s37--2i4524-.AwRj4yVKJ9jCA===.AwhMIyumQRgkA===.",
|
"Explorer": "A0patnFklndksxf5--------0202------f7050505040s37-2f2i4524.AwRj4yVKJ9hA.AwhMIyumQRhEA===.",
|
||||||
"Test": "A4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04---0303326b-.Iw18ZUAxA===.Aw18ZXEA."
|
"Test": "A4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04---0303326b.Iw18ZVA=.Aw18ZVA=."
|
||||||
},
|
},
|
||||||
"diamondback_explorer": {
|
"diamondback_explorer": {
|
||||||
"Explorer": "A0p0tdFfldddsdf5---0202--320p432i----.AwRj4zTZaA==.AwiMIyqo."
|
"Explorer": "A0p0tdFfldddsdf5---0202--320p432i2f-.AwRj4zTYg===.AwiMIyoo."
|
||||||
},
|
},
|
||||||
"vulture": {
|
"vulture": {
|
||||||
"Bounty Hunter": "A3patcFalddksff31e1e0404-0l4a-5d27662j--.AwRj4z2Gg===.MwBhBYy6oJmAjLMQ."
|
"Bounty Hunter": "A3patcFalddksff31e1e0404-0l4a-5d27662j.AwRj4z2I.MwBhBYy6oJmAjLIA."
|
||||||
},
|
},
|
||||||
"fer_de_lance": {
|
"fer_de_lance": {
|
||||||
"Attack": "A2pfthFalidpsff31r0s0s0s0s000404-04-4a-5d27--.Iw18aAMQ.CwBhrSu8EZxEA===."
|
"Attack": "A2pfthFalidpsff31r0s0s0s0s000404-04-4a-5d27-.Iw18aQ==.CwBhrSu8EZyA."
|
||||||
},
|
},
|
||||||
"eagle": {
|
"eagle": {
|
||||||
"Figther": "A4p0t5F5l3d5s5f20p0p24-4053-2j---.Iw18gDJQ.Aw19kA==."
|
"Figther": "A4p0t5F5l3d5s5f20p0p24-4053-2j-.Iw18kA==.Aw18kA==."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,366 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"header": {
|
|
||||||
"appName": "Inara",
|
|
||||||
"appVersion": "1.0",
|
|
||||||
"appURL": "https:\/\/inara.cz\/cmdr-fleet\/123\/123\/",
|
|
||||||
"appCustomProperties": {
|
|
||||||
"inaraCommanderID": 123,
|
|
||||||
"inaraShipID": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"Ship": "krait_mkii",
|
|
||||||
"ShipID": 7,
|
|
||||||
"ShipName": "pancake hammer",
|
|
||||||
"ShipIdent": "PH-01",
|
|
||||||
"HullValue": 44160710,
|
|
||||||
"ModulesValue": 111274094,
|
|
||||||
"Rebuy": 7771743,
|
|
||||||
"Modules": [
|
|
||||||
{
|
|
||||||
"Slot": "largehardpoint1",
|
|
||||||
"Item": "hpt_mininglaser_fixed_small",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "largehardpoint2",
|
|
||||||
"Item": "hpt_cannon_gimbal_large",
|
|
||||||
"On": true,
|
|
||||||
"Engineering": {
|
|
||||||
"BlueprintName": "weapon_overcharged",
|
|
||||||
"Level": 2,
|
|
||||||
"Quality": 1,
|
|
||||||
"ExperimentalEffect": "special_auto_loader"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "largehardpoint3",
|
|
||||||
"Item": "hpt_cannon_gimbal_large",
|
|
||||||
"On": true,
|
|
||||||
"Engineering": {
|
|
||||||
"BlueprintName": "weapon_overcharged",
|
|
||||||
"Level": 2,
|
|
||||||
"Quality": 1,
|
|
||||||
"ExperimentalEffect": "special_auto_loader"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "mediumhardpoint1",
|
|
||||||
"Item": "hpt_basicmissilerack_fixed_medium",
|
|
||||||
"On": true,
|
|
||||||
"Engineering": {
|
|
||||||
"BlueprintName": "weapon_highcapacity",
|
|
||||||
"Level": 5,
|
|
||||||
"Quality": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "mediumhardpoint2",
|
|
||||||
"Item": "hpt_basicmissilerack_fixed_medium",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "tinyhardpoint1",
|
|
||||||
"Item": "hpt_heatsinklauncher_turret_tiny",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "tinyhardpoint2",
|
|
||||||
"Item": "hpt_cloudscanner_size0_class3",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "tinyhardpoint3",
|
|
||||||
"Item": "hpt_shieldbooster_size0_class5",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "tinyhardpoint4",
|
|
||||||
"Item": "hpt_shieldbooster_size0_class5",
|
|
||||||
"On": true,
|
|
||||||
"Priority": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot01_size6",
|
|
||||||
"Item": "int_cargorack_size6_class1",
|
|
||||||
"On": true,
|
|
||||||
"Priority": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot02_size6",
|
|
||||||
"Item": "int_cargorack_size6_class1",
|
|
||||||
"On": true,
|
|
||||||
"Priority": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot03_size5",
|
|
||||||
"Item": "int_guardianfsdbooster_size5",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot04_size5",
|
|
||||||
"Item": "int_fighterbay_size5_class1",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot05_size4",
|
|
||||||
"Item": "int_shieldgenerator_size4_class5",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot06_size3",
|
|
||||||
"Item": "int_dronecontrol_collection_size3_class4",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot07_size3",
|
|
||||||
"Item": "int_dronecontrol_collection_size3_class4",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot08_size2",
|
|
||||||
"Item": "int_refinery_size2_class2",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot09_size1",
|
|
||||||
"Item": "int_dronecontrol_prospector_size1_class4",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "powerplant",
|
|
||||||
"Item": "int_powerplant_size7_class5",
|
|
||||||
"On": true,
|
|
||||||
"Priority": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "mainengines",
|
|
||||||
"Item": "int_engine_size6_class5",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "frameshiftdrive",
|
|
||||||
"Item": "int_hyperdrive_size5_class5",
|
|
||||||
"On": true,
|
|
||||||
"Engineering": {
|
|
||||||
"BlueprintName": "fsd_longrange",
|
|
||||||
"Level": 2,
|
|
||||||
"Quality": 0.861
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "lifesupport",
|
|
||||||
"Item": "int_lifesupport_size4_class2",
|
|
||||||
"On": true,
|
|
||||||
"Priority": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "powerdistributor",
|
|
||||||
"Item": "int_powerdistributor_size7_class5",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "radar",
|
|
||||||
"Item": "int_sensors_size6_class2",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "fueltank",
|
|
||||||
"Item": "int_fueltank_size5_class3",
|
|
||||||
"On": true,
|
|
||||||
"Priority": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "armour",
|
|
||||||
"Item": "krait_mkii_armour_grade3",
|
|
||||||
"On": true,
|
|
||||||
"Priority": 1,
|
|
||||||
"Engineering": {
|
|
||||||
"BlueprintName": "armour_heavyduty",
|
|
||||||
"Level": 5,
|
|
||||||
"Quality": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"header": {
|
|
||||||
"appName": "Inara",
|
|
||||||
"appVersion": "1.0",
|
|
||||||
"appURL": "https:\/\/inara.cz\/cmdr-fleet\/123\/123\/",
|
|
||||||
"appCustomProperties": {
|
|
||||||
"inaraCommanderID": 123,
|
|
||||||
"inaraShipID": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"Ship": "diamondbackxl",
|
|
||||||
"ShipID": 11,
|
|
||||||
"ShipName": "star Hopper",
|
|
||||||
"ShipIdent": "PH-02",
|
|
||||||
"HullValue": 1615649,
|
|
||||||
"ModulesValue": 16981039,
|
|
||||||
"Rebuy": 929837,
|
|
||||||
"Modules": [
|
|
||||||
{
|
|
||||||
"Slot": "tinyhardpoint1",
|
|
||||||
"Item": "hpt_heatsinklauncher_turret_tiny",
|
|
||||||
"On": true,
|
|
||||||
"Value": 3072
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot01_size4",
|
|
||||||
"Item": "int_fuelscoop_size4_class5",
|
|
||||||
"On": true,
|
|
||||||
"Priority": 3,
|
|
||||||
"Value": 2862364
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot02_size4",
|
|
||||||
"Item": "int_guardianfsdbooster_size4",
|
|
||||||
"On": true,
|
|
||||||
"Value": 2847499
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot03_size3",
|
|
||||||
"Item": "int_shieldgenerator_size3_class2",
|
|
||||||
"On": true,
|
|
||||||
"Value": 18812,
|
|
||||||
"Engineering": {
|
|
||||||
"BlueprintName": "shieldgenerator_thermic",
|
|
||||||
"Level": 3,
|
|
||||||
"Quality": 1,
|
|
||||||
"ExperimentalEffect": "special_shield_health"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot04_size3",
|
|
||||||
"Item": "int_repairer_size3_class5",
|
|
||||||
"On": true,
|
|
||||||
"Value": 2302911
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot05_size2",
|
|
||||||
"Item": "int_buggybay_size2_class2",
|
|
||||||
"On": true,
|
|
||||||
"Priority": 3,
|
|
||||||
"Value": 21600
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot06_size2",
|
|
||||||
"Item": "int_cargorack_size2_class1",
|
|
||||||
"On": true,
|
|
||||||
"Priority": 1,
|
|
||||||
"Value": 2852
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot07_size1",
|
|
||||||
"Item": "int_supercruiseassist",
|
|
||||||
"On": true,
|
|
||||||
"Priority": 3,
|
|
||||||
"Value": 9121
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot08_size1",
|
|
||||||
"Item": "int_detailedsurfacescanner_tiny",
|
|
||||||
"On": true,
|
|
||||||
"Value": 250000,
|
|
||||||
"Engineering": {
|
|
||||||
"BlueprintName": "sensor_expanded",
|
|
||||||
"Level": 5,
|
|
||||||
"Quality": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "powerplant",
|
|
||||||
"Item": "int_powerplant_size4_class5",
|
|
||||||
"On": true,
|
|
||||||
"Priority": 1,
|
|
||||||
"Value": 1441233,
|
|
||||||
"Engineering": {
|
|
||||||
"BlueprintName": "powerplant_boosted",
|
|
||||||
"Level": 1,
|
|
||||||
"Quality": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "mainengines",
|
|
||||||
"Item": "int_engine_size4_class5",
|
|
||||||
"On": true,
|
|
||||||
"Value": 1610080,
|
|
||||||
"Engineering": {
|
|
||||||
"BlueprintName": "engine_dirty",
|
|
||||||
"Level": 5,
|
|
||||||
"Quality": 1,
|
|
||||||
"ExperimentalEffect": "special_engine_lightweight"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "frameshiftdrive",
|
|
||||||
"Item": "int_hyperdrive_size5_class5",
|
|
||||||
"On": true,
|
|
||||||
"Value": 5103953,
|
|
||||||
"Engineering": {
|
|
||||||
"BlueprintName": "fsd_longrange",
|
|
||||||
"Level": 5,
|
|
||||||
"Quality": 1,
|
|
||||||
"ExperimentalEffect": "special_fsd_lightweight"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "lifesupport",
|
|
||||||
"Item": "int_lifesupport_size3_class2",
|
|
||||||
"On": true,
|
|
||||||
"Value": 10133,
|
|
||||||
"Engineering": {
|
|
||||||
"BlueprintName": "misc_lightweight",
|
|
||||||
"Level": 3,
|
|
||||||
"Quality": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "powerdistributor",
|
|
||||||
"Item": "int_powerdistributor_size4_class5",
|
|
||||||
"On": true,
|
|
||||||
"Value": 389022,
|
|
||||||
"Engineering": {
|
|
||||||
"BlueprintName": "powerdistributor_highfrequency",
|
|
||||||
"Level": 4,
|
|
||||||
"Quality": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "radar",
|
|
||||||
"Item": "int_sensors_size3_class2",
|
|
||||||
"On": true,
|
|
||||||
"Value": 10133,
|
|
||||||
"Engineering": {
|
|
||||||
"BlueprintName": "sensor_lightweight",
|
|
||||||
"Level": 5,
|
|
||||||
"Quality": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "fueltank",
|
|
||||||
"Item": "int_fueltank_size5_class3",
|
|
||||||
"On": true,
|
|
||||||
"Priority": 1,
|
|
||||||
"Value": 97754
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "armour",
|
|
||||||
"Item": "diamondbackxl_armour_grade1",
|
|
||||||
"On": true,
|
|
||||||
"Priority": 1,
|
|
||||||
"Engineering": {
|
|
||||||
"BlueprintName": "armour_heavyduty",
|
|
||||||
"Level": 5,
|
|
||||||
"Quality": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"krait_mkii": {
|
|
||||||
"Imported pancake hammer": "A2pptkFflidussf52l1o1o2g2g020g040405051Ofr45C9C91oP3.Iw18eQ==.AwRgzKIkA===."
|
|
||||||
},
|
|
||||||
"diamondback_explorer": {
|
|
||||||
"Imported star Hopper": "A0pataFflddfsdf5---02---321P430iv6013w2i.Iw18SQ==.AwRm44GYpKg=."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,188 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"header": {
|
|
||||||
"appName": "Inara",
|
|
||||||
"appVersion": "1.0",
|
|
||||||
"appURL": "https:\/\/inara.cz\/cmdr-fleet\/123\/123\/",
|
|
||||||
"appCustomProperties": {
|
|
||||||
"inaraCommanderID": 123,
|
|
||||||
"inaraShipID": 123
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"Ship": "krait_mkii",
|
|
||||||
"ShipID": 7,
|
|
||||||
"ShipName": "pancake hammer",
|
|
||||||
"ShipIdent": "PH-01",
|
|
||||||
"HullValue": 44160710,
|
|
||||||
"ModulesValue": 111274094,
|
|
||||||
"Rebuy": 7771743,
|
|
||||||
"Modules": [
|
|
||||||
{
|
|
||||||
"Slot": "largehardpoint1",
|
|
||||||
"Item": "hpt_mininglaser_fixed_small",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "largehardpoint2",
|
|
||||||
"Item": "hpt_cannon_gimbal_large",
|
|
||||||
"On": true,
|
|
||||||
"Engineering": {
|
|
||||||
"BlueprintName": "weapon_overcharged",
|
|
||||||
"Level": 2,
|
|
||||||
"Quality": 1,
|
|
||||||
"ExperimentalEffect": "special_auto_loader"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "largehardpoint3",
|
|
||||||
"Item": "hpt_cannon_gimbal_large",
|
|
||||||
"On": true,
|
|
||||||
"Engineering": {
|
|
||||||
"BlueprintName": "weapon_overcharged",
|
|
||||||
"Level": 2,
|
|
||||||
"Quality": 1,
|
|
||||||
"ExperimentalEffect": "special_auto_loader"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "mediumhardpoint1",
|
|
||||||
"Item": "hpt_basicmissilerack_fixed_medium",
|
|
||||||
"On": true,
|
|
||||||
"Engineering": {
|
|
||||||
"BlueprintName": "weapon_highcapacity",
|
|
||||||
"Level": 5,
|
|
||||||
"Quality": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "mediumhardpoint2",
|
|
||||||
"Item": "hpt_basicmissilerack_fixed_medium",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "tinyhardpoint1",
|
|
||||||
"Item": "hpt_heatsinklauncher_turret_tiny",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "tinyhardpoint2",
|
|
||||||
"Item": "hpt_cloudscanner_size0_class3",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "tinyhardpoint3",
|
|
||||||
"Item": "hpt_shieldbooster_size0_class5",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "tinyhardpoint4",
|
|
||||||
"Item": "hpt_shieldbooster_size0_class5",
|
|
||||||
"On": true,
|
|
||||||
"Priority": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot01_size6",
|
|
||||||
"Item": "int_cargorack_size6_class1",
|
|
||||||
"On": true,
|
|
||||||
"Priority": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot02_size6",
|
|
||||||
"Item": "int_cargorack_size6_class1",
|
|
||||||
"On": true,
|
|
||||||
"Priority": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot03_size5",
|
|
||||||
"Item": "int_guardianfsdbooster_size5",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot04_size5",
|
|
||||||
"Item": "int_fighterbay_size5_class1",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot05_size4",
|
|
||||||
"Item": "int_shieldgenerator_size4_class5",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot06_size3",
|
|
||||||
"Item": "int_dronecontrol_collection_size3_class4",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot07_size3",
|
|
||||||
"Item": "int_dronecontrol_collection_size3_class4",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot08_size2",
|
|
||||||
"Item": "int_refinery_size2_class2",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "slot09_size1",
|
|
||||||
"Item": "int_dronecontrol_prospector_size1_class4",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "powerplant",
|
|
||||||
"Item": "int_powerplant_size7_class5",
|
|
||||||
"On": true,
|
|
||||||
"Priority": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "mainengines",
|
|
||||||
"Item": "int_engine_size6_class5",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "frameshiftdrive",
|
|
||||||
"Item": "int_hyperdrive_size5_class5",
|
|
||||||
"On": true,
|
|
||||||
"Engineering": {
|
|
||||||
"BlueprintName": "fsd_longrange",
|
|
||||||
"Level": 2,
|
|
||||||
"Quality": 0.861
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "lifesupport",
|
|
||||||
"Item": "int_lifesupport_size4_class2",
|
|
||||||
"On": true,
|
|
||||||
"Priority": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "powerdistributor",
|
|
||||||
"Item": "int_powerdistributor_size7_class5",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "radar",
|
|
||||||
"Item": "int_sensors_size6_class2",
|
|
||||||
"On": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "fueltank",
|
|
||||||
"Item": "int_fueltank_size5_class3",
|
|
||||||
"On": true,
|
|
||||||
"Priority": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Slot": "armour",
|
|
||||||
"Item": "krait_mkii_armour_grade3",
|
|
||||||
"On": true,
|
|
||||||
"Priority": 1,
|
|
||||||
"Engineering": {
|
|
||||||
"BlueprintName": "armour_heavyduty",
|
|
||||||
"Level": 5,
|
|
||||||
"Quality": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
@@ -18,13 +18,13 @@ describe('Import Modal', function() {
|
|||||||
const mockContext = {
|
const mockContext = {
|
||||||
language: getLanguage('en'),
|
language: getLanguage('en'),
|
||||||
sizeRatio: 1,
|
sizeRatio: 1,
|
||||||
openMenu: jest.fn(),
|
openMenu: jest.genMockFunction(),
|
||||||
closeMenu: jest.fn(),
|
closeMenu: jest.genMockFunction(),
|
||||||
showModal: jest.fn(),
|
showModal: jest.genMockFunction(),
|
||||||
hideModal: jest.fn(),
|
hideModal: jest.genMockFunction(),
|
||||||
tooltip: jest.fn(),
|
tooltip: jest.genMockFunction(),
|
||||||
termtip: jest.fn(),
|
termtip: jest.genMockFunction(),
|
||||||
onWindowResize: jest.fn()
|
onWindowResize: jest.genMockFunction()
|
||||||
};
|
};
|
||||||
|
|
||||||
let modal, render, ContextProvider = Utils.createContextProvider(mockContext);
|
let modal, render, ContextProvider = Utils.createContextProvider(mockContext);
|
||||||
@@ -110,25 +110,21 @@ describe('Import Modal', function() {
|
|||||||
it('catches an invalid backup', function() {
|
it('catches an invalid backup', function() {
|
||||||
const importData = require('./fixtures/valid-backup');
|
const importData = require('./fixtures/valid-backup');
|
||||||
let invalidImportData = Object.assign({}, importData);
|
let invalidImportData = Object.assign({}, importData);
|
||||||
// Remove Asp Miner build used in comparison
|
//invalidImportData.builds.asp = null; // Remove Asp Miner build used in comparison
|
||||||
delete(invalidImportData.builds.asp);
|
delete(invalidImportData.builds.asp);
|
||||||
|
|
||||||
pasteText('"this is not valid"');
|
pasteText('"this is not valid"');
|
||||||
expect(modal.state.importValid).toBeFalsy();
|
expect(modal.state.importValid).toBeFalsy();
|
||||||
expect(modal.state.errorMsg).toEqual('Must be an object or array!');
|
expect(modal.state.errorMsg).toEqual('Must be an object or array!');
|
||||||
|
|
||||||
pasteText('{ "builds": "Should not be a string" }');
|
pasteText('{ "builds": "Should not be a string" }');
|
||||||
expect(modal.state.importValid).toBeFalsy();
|
expect(modal.state.importValid).toBeFalsy();
|
||||||
expect(modal.state.errorMsg).toEqual('builds must be an object!');
|
expect(modal.state.errorMsg).toEqual('builds must be an object!');
|
||||||
|
pasteText(JSON.stringify(importData).replace('anaconda', 'invalid_ship'));
|
||||||
pasteText(JSON.stringify(importData).replace(/anaconda/g, 'invalid_ship'));
|
|
||||||
expect(modal.state.importValid).toBeFalsy();
|
expect(modal.state.importValid).toBeFalsy();
|
||||||
expect(Object.keys(modal.state.builds)).not.toContain('anaconda');
|
expect(modal.state.errorMsg).toEqual('"invalid_ship" is not a valid Ship Id!');
|
||||||
|
|
||||||
pasteText(JSON.stringify(importData).replace('Dream', ''));
|
pasteText(JSON.stringify(importData).replace('Dream', ''));
|
||||||
expect(modal.state.importValid).toBeFalsy();
|
expect(modal.state.importValid).toBeFalsy();
|
||||||
expect(Object.keys(modal.state.builds.imperial_clipper).length).toEqual(3);
|
expect(modal.state.errorMsg).toEqual('Imperial Clipper build "" must be a string at least 1 character long!');
|
||||||
|
|
||||||
pasteText(JSON.stringify(invalidImportData));
|
pasteText(JSON.stringify(invalidImportData));
|
||||||
expect(modal.state.importValid).toBeFalsy();
|
expect(modal.state.importValid).toBeFalsy();
|
||||||
expect(modal.state.errorMsg).toEqual('asp build "Miner" data is missing!');
|
expect(modal.state.errorMsg).toEqual('asp build "Miner" data is missing!');
|
||||||
@@ -148,7 +144,7 @@ describe('Import Modal', function() {
|
|||||||
expect(modal.state.singleBuild).toBe(true);
|
expect(modal.state.singleBuild).toBe(true);
|
||||||
clickProceed();
|
clickProceed();
|
||||||
expect(MockRouter.go.mock.calls.length).toBe(1);
|
expect(MockRouter.go.mock.calls.length).toBe(1);
|
||||||
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/anaconda?code=A4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04---0303326b-.AwRj4zNLeI%3D%3D.CwBhCYzBGW9qCTSqq5JA.&bn=Test%20My%20Ship');
|
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/anaconda?code=A4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04---0303326b.AwRj4zNLaA%3D%3D.CwBhCYzBGW9qCTSqq5xA.&bn=Test%20My%20Ship');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('catches an invalid build', function() {
|
it('catches an invalid build', function() {
|
||||||
@@ -173,7 +169,7 @@ describe('Import Modal', function() {
|
|||||||
expect(modal.state.singleBuild).toBe(true);
|
expect(modal.state.singleBuild).toBe(true);
|
||||||
clickProceed();
|
clickProceed();
|
||||||
expect(MockRouter.go.mock.calls.length).toBe(1);
|
expect(MockRouter.go.mock.calls.length).toBe(1);
|
||||||
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/anaconda?code=A4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04---0303326b-.AwRj4zNLeI%3D%3D.CwBhCYzBGW9qCTSqq5JA.H4sIAAAAAAAAE2MUe8HMwPD%2FPwMAAGvB0AkAAAA%3D&bn=Test%20My%20Ship');
|
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/anaconda?code=A4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04---0303326b.AwRj4zNLaA%3D%3D.CwBhCYzBGW9qCTSqq5xA.H4sIAAAAAAAAA2MUe8HMwPD%2FPwMAAGvB0AkAAAA%3D&bn=Test%20My%20Ship');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -190,7 +186,7 @@ describe('Import Modal', function() {
|
|||||||
expect(modal.state.singleBuild).toBe(true);
|
expect(modal.state.singleBuild).toBe(true);
|
||||||
clickProceed();
|
clickProceed();
|
||||||
expect(MockRouter.go.mock.calls.length).toBe(1);
|
expect(MockRouter.go.mock.calls.length).toBe(1);
|
||||||
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/asp?code=A0pftiFflfddsnf5------020202033c044002v6-2i-.AwRj4yvYg%3D%3D%3D.CwRgDBldHn5A.H4sIAAAAAAAAE2P858DAwPCXEUhwHPvx%2F78YG5AltB7I%2F8%2F0TwImJboDSPJ%2F%2B%2Ff%2Fv%2FKlX%2F%2F%2Fi3AwMTBIfARK%2FGf%2BJwVSxArStVAYqOjvz%2F%2F%2FJVo5GRhE2IBc4SKQSSz%2FDGEmCa398P8%2F%2F2%2BgTf%2F%2FA7kMAExxqlSAAAAA&bn=Multi-purpose%20Asp%20Explorer');
|
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/asp?code=A0pftiFflfddsnf5------020202033c044002v62f2i.AwRj4yvI.CwRgDBldHnJA.H4sIAAAAAAAAA2P858DAwPCXEUhwHPvx%2F78YG5AltB7I%2F8%2F0TwImJboDSPJ%2F%2B%2Ff%2Fv%2FKlX%2F%2F%2Fi3AwMTBIfARK%2FGf%2BJwVSxArStVAYqOjvz%2F%2F%2FJVo5GRhE2IBc4SKQSSz%2FDGEmCa398P8%2F%2F2%2BgTf%2F%2FA7kMAExxqlSAAAAA&bn=Multi-purpose%20Asp%20Explorer');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('imports a valid v4 build with modifications', function() {
|
it('imports a valid v4 build with modifications', function() {
|
||||||
@@ -202,11 +198,11 @@ describe('Import Modal', function() {
|
|||||||
expect(modal.state.singleBuild).toBe(true);
|
expect(modal.state.singleBuild).toBe(true);
|
||||||
clickProceed();
|
clickProceed();
|
||||||
expect(MockRouter.go.mock.calls.length).toBe(1);
|
expect(MockRouter.go.mock.calls.length).toBe(1);
|
||||||
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/imperial_courier?code=A0patzF5l0das8f31a1a270202000e402t0101----.AwRj4zOYg%3D%3D%3D.CwRgDBldLuZA.H4sIAAAAAAAAE12OPUvDYBSFT1OTfkRJjUkbbC3Yj8mlODgUISAtdOlety5ODv0Vgji7O7kJ%2FgzBQX%2BEY7Gg0NKhfY%2FnHQLFDBdynufe9%2BRMCmCb06g29oCgacjiRx6gY6oWKUT8UgLaszqQfHmSnpVFN1uSeXNsJVcj%2FA2EHlZkspIUpUc6UjTXGT85qwHuSEuVc%2F16r99kDQeSSjvSbSjpyUpNK10uJJ3aYqk6smwm1lQ9bOxw71TMm8VanEqq9JW1r3Qo%2BREOLnQHvbWmb7rZIu5VLIyGQGOukPv%2F0WQk5LeEAjPOUDwtAP6bShy2HKAz0HPO%2B5KsP25I79O2I7LvD%2Bz4Il1XAQAA&bn=Multi-purpose%20Imperial%20Courier');
|
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/imperial_courier?code=A0patzF5l0das8f31a1a270202000e402t0101-2f.AwRj4zKA.CwRgDBldLiQ%3D.H4sIAAAAAAAAA12OPUvDYBSFT1OTfkRJjUkbbC3Yj8mlODgUISAtdOlety5ODv0Vgji7O7kJ%2FgzBQX%2BEY7Gg0NKhfY%2FnHQLFDBdynufe9%2BRMCmCb06g29oCgacjiRx6gY6oWKUT8UgLaszqQfHmSnpVFN1uSeXNsJVcj%2FA2EHlZkspIUpUc6UjTXGT85qwHuSEuVc%2F16r99kDQeSSjvSbSjpyUpNK10uJJ3aYqk6smwm1lQ9bOxw71TMm8VanEqq9JW1r3Qo%2BREOLnQHvbWmb7rZIu5VLIyGQGOukPv%2F0WQk5LeEAjPOUDwtAP6bShy2HKAz0HPO%2B5KsP25I79O2I7LvD%2Bz4Il1XAQAA&bn=Multi-purpose%20Imperial%20Courier');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Import Detailed Builds Array', function() {
|
describe('Import Detaild Builds Array', function() {
|
||||||
|
|
||||||
beforeEach(reset);
|
beforeEach(reset);
|
||||||
|
|
||||||
@@ -244,7 +240,7 @@ describe('Import Modal', function() {
|
|||||||
expect(modal.state.singleBuild).toBe(true);
|
expect(modal.state.singleBuild).toBe(true);
|
||||||
clickProceed();
|
clickProceed();
|
||||||
expect(MockRouter.go.mock.calls.length).toBe(1);
|
expect(MockRouter.go.mock.calls.length).toBe(1);
|
||||||
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/federal_corvette?code=A2putsFklndzsxf50x0x7l28281919040404040402020l06p05sf63c5ifr--v66g--.AwRj4zNapI%3D%3D.CwRgDBldUExuBiIlWIA%3D.&bn=Imported%20Federal%20Corvette');
|
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/federal_corvette?code=A2putsFklndzsxf50x0x7l28281919040404040402020l06p05sf63c5ifr--v66g2f.AwRj4zNaqA%3D%3D.CwRgDBldUExuBiIlUA%3D%3D.H4sIAAAAAAAAA12STy8DURTFb1szU53Ga8dg2qqqDmJDIoKFxJImumYjVrVqfAALC4lNbcUnkLCoDbEQu0bSlQVhI8JHsJBIQ73rXMkwMYuT9%2Bb87nl%2F7ovoRSL6ikD6TYNINZg5XsWUo7pfrBikr2USlRyXyDuLAhr6ZHanNLOzD5tjOiskysk5dOBvfTB7bjeRW0MNG3ohSBq1bKKxKwyLLUAjmwjpPu4wJx4xVbNI57heDfbUKUAy2xaRUQZpllHoHMHxKqjhhF4LgjtJiFHDmqbrEeVnUJOax7%2FSdRfRwBNotv9wo5kAuZMD2egKyDYcdYl1OBki6z%2BZQjaFnBPyFCM1LefF%2BcgrY0es9FKwbW8ZYj9gmBbxRVRdglMh6BNqnwsk4ouoO4HSIehNoBuBRHwR1QOmsBvHmk6IfMbd2fdCEka%2BjNSexPWGoEkcyX6CnxbxRZQtd%2BPpym%2B31xFtn0iSFPkf%2BBkttZlzB9KDFyBuFRfAGV0Ogoff8SSsCfjjD5hGWtLIwZB%2FgX5Zt%2BLHMI9My7sp6nzgZzekswTxVvCOkq%2FSXqb%2F3zfLxh6HrwIAAA%3D%3D&bn=Imported%20Federal%20Corvette');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('imports a valid companion API build', function() {
|
it('imports a valid companion API build', function() {
|
||||||
@@ -256,7 +252,7 @@ describe('Import Modal', function() {
|
|||||||
expect(modal.state.singleBuild).toBe(true);
|
expect(modal.state.singleBuild).toBe(true);
|
||||||
clickProceed();
|
clickProceed();
|
||||||
expect(MockRouter.go.mock.calls.length).toBe(1);
|
expect(MockRouter.go.mock.calls.length).toBe(1);
|
||||||
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/beluga?code=A0pktsFplCdpsnf70t0t2727270004040404043c4fmimlmm04mc0iv62i--.AwRj4yusg%3D%3D%3D.CwRgDBldHi8IWIA%3D.&bn=Imported%20Beluga%20Liner');
|
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/beluga?code=A0pktsFplCdpsnf70t0t2727270004040404043c4fmimlmm04mc0iv62i2f.AwRj4yukg%3D%3D%3D.CwRgDBldHi8IUA%3D%3D.H4sIAAAAAAAAA2P8Z8%2FAwPCXEUiIKTMxMPCv%2F%2Ff%2FP8cFIPGf6Z8YTEr0GjMDg%2FJWICERBOTzn%2Fn7%2F7%2FIO5Ai5n9SIEWsQEIoSxAolfbt%2F3%2BJPk4GBhE7YQYGYVmgcuVnf4Aq%2FwOVAAAyiFctbgAAAA%3D%3D&bn=Imported%20Beluga%20Liner');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('imports a valid companion API build', function() {
|
it('imports a valid companion API build', function() {
|
||||||
@@ -268,7 +264,7 @@ describe('Import Modal', function() {
|
|||||||
expect(modal.state.singleBuild).toBe(true);
|
expect(modal.state.singleBuild).toBe(true);
|
||||||
clickProceed();
|
clickProceed();
|
||||||
expect(MockRouter.go.mock.calls.length).toBe(1);
|
expect(MockRouter.go.mock.calls.length).toBe(1);
|
||||||
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/type_7_transport?code=A0patfFflidasdf5----0404040005050504044d2402--.AwRj4yoo.CwRgDBlVK7HjEA%3D%3D.&bn=Imported%20Type-7%20Transporter');
|
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/type_7_transport?code=A0patfFflidasdf5----0404040005050504044d2402.AwRj4yrI.CwRgDBlVK7EiA%3D%3D%3D.&bn=Imported%20Type-7%20Transporter');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('imports a valid companion API build', function() {
|
it('imports a valid companion API build', function() {
|
||||||
@@ -280,7 +276,7 @@ describe('Import Modal', function() {
|
|||||||
expect(modal.state.singleBuild).toBe(true);
|
expect(modal.state.singleBuild).toBe(true);
|
||||||
clickProceed();
|
clickProceed();
|
||||||
expect(MockRouter.go.mock.calls.length).toBe(1);
|
expect(MockRouter.go.mock.calls.length).toBe(1);
|
||||||
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/cobra_mk_iii?code=A0p0tdFaldd3sdf4------34----2i--.AwRj4yqA.CwRgDMYExrezBig%3D.&bn=Imported%20Cobra%20Mk%20III');
|
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/cobra_mk_iii?code=A0p0tdFaldd3sdf4------34---2f2i.AwRj4yKA.CwRgDMYExrezBUg%3D.&bn=Imported%20Cobra%20Mk%20III');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -328,41 +324,4 @@ describe('Import Modal', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Imports SLEF data', () => {
|
|
||||||
beforeEach(reset);
|
|
||||||
|
|
||||||
it('imports a single valid SLEF build', () => {
|
|
||||||
const importData = require('./fixtures/slef-single-build.json');
|
|
||||||
pasteText(JSON.stringify(importData));
|
|
||||||
|
|
||||||
expect(modal.state.importValid).toBeTruthy();
|
|
||||||
expect(modal.state.errorMsg).toEqual(null);
|
|
||||||
expect(modal.state.singleBuild).toBe(true);
|
|
||||||
clickProceed();
|
|
||||||
expect(MockRouter.go.mock.calls.length).toBe(1);
|
|
||||||
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/krait_mkii?code=A2pptkFflidussf52l1o1o2g2g020g040405051Ofr45C9C91oP3.Iw18eQ%3D%3D.AwRgzKIkA%3D%3D%3D.&bn=Imported%20pancake%20hammer');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('imports multiple SLEF builds', () => {
|
|
||||||
const importData = require('./fixtures/slef-multiple-builds.json');
|
|
||||||
const expectedBuilds = require('./fixtures/slef-multiple-expected-builds.json');
|
|
||||||
pasteText(JSON.stringify(importData));
|
|
||||||
|
|
||||||
expect(modal.state.importValid).toBeTruthy();
|
|
||||||
expect(modal.state.errorMsg).toEqual(null);
|
|
||||||
expect(modal.state.singleBuild).toBe(false);
|
|
||||||
clickProceed();
|
|
||||||
expect(modal.state.processed).toBeTruthy();
|
|
||||||
clickImport();
|
|
||||||
|
|
||||||
const builds = Persist.getBuilds();
|
|
||||||
|
|
||||||
for (const shipModel in builds) {
|
|
||||||
for (const buildName in builds[shipModel]) {
|
|
||||||
expect(builds[shipModel][buildName])
|
|
||||||
.toEqual(expectedBuilds[shipModel][buildName]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
11
devServer.js
11
devServer.js
@@ -3,13 +3,24 @@ 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) {
|
||||||
|
|||||||
51
docker-compose.yml
Normal file
51
docker-compose.yml
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
version: '2.2'
|
||||||
|
|
||||||
|
services:
|
||||||
|
coriolis_prod:
|
||||||
|
image: edcd/coriolis:master
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- ./nginx.conf:/etc/nginx/nginx.conf
|
||||||
|
networks:
|
||||||
|
- web
|
||||||
|
labels:
|
||||||
|
- "traefik.docker.network=web"
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.basic.frontend.rule=Host:coriolis.io,coriolis.edcd.io"
|
||||||
|
- "traefik.basic.port=80"
|
||||||
|
- "traefik.basic.protocol=http"
|
||||||
|
|
||||||
|
coriolis_dev:
|
||||||
|
image: edcd/coriolis:develop
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- ./nginx.conf:/etc/nginx/nginx.conf
|
||||||
|
networks:
|
||||||
|
- web
|
||||||
|
labels:
|
||||||
|
- "traefik.docker.network=web"
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.basic.frontend.rule=Host:beta.coriolis.io,beta.coriolis.edcd.io"
|
||||||
|
- "traefik.basic.port=80"
|
||||||
|
- "traefik.basic.protocol=http"
|
||||||
|
|
||||||
|
coriolis_dw2:
|
||||||
|
image: edcd/coriolis:dw2
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- ./nginx.conf:/etc/nginx/nginx.conf
|
||||||
|
networks:
|
||||||
|
- web
|
||||||
|
labels:
|
||||||
|
- "traefik.docker.network=web"
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.basic.frontend.rule=Host:dw2.coriolis.io"
|
||||||
|
- "traefik.basic.port=80"
|
||||||
|
- "traefik.basic.protocol=http"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
networks:
|
||||||
|
web:
|
||||||
|
external: true
|
||||||
96
nginx.conf
Normal file
96
nginx.conf
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
worker_processes 1;
|
||||||
|
user nobody nobody;
|
||||||
|
error_log /tmp/error.log;
|
||||||
|
pid /tmp/nginx.pid;
|
||||||
|
|
||||||
|
events {
|
||||||
|
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
sendfile on;
|
||||||
|
client_body_temp_path /tmp/client_body;
|
||||||
|
fastcgi_temp_path /tmp/fastcgi_temp;
|
||||||
|
proxy_temp_path /tmp/proxy_temp;
|
||||||
|
scgi_temp_path /tmp/scgi_temp;
|
||||||
|
uwsgi_temp_path /tmp/uwsgi_temp;
|
||||||
|
access_log /tmp/access.log;
|
||||||
|
error_log /tmp/error.log;
|
||||||
|
|
||||||
|
# https://nginx.org/en/docs/http/ngx_http_gzip_module.html
|
||||||
|
# Enable gzip compression.
|
||||||
|
# Default: off
|
||||||
|
gzip off;
|
||||||
|
|
||||||
|
# Compression level (1-9).
|
||||||
|
# 5 is a perfect compromise between size and CPU usage, offering about
|
||||||
|
# 75% reduction for most ASCII files (almost identical to level 9).
|
||||||
|
# Default: 1
|
||||||
|
gzip_comp_level 5;
|
||||||
|
|
||||||
|
# Don't compress anything that's already small and unlikely to shrink much
|
||||||
|
# if at all (the default is 20 bytes, which is bad as that usually leads to
|
||||||
|
# larger files after gzipping).
|
||||||
|
# Default: 20
|
||||||
|
gzip_min_length 256;
|
||||||
|
|
||||||
|
# Compress data even for clients that are connecting to us via proxies,
|
||||||
|
# identified by the "Via" header (required for CloudFront).
|
||||||
|
# Default: off
|
||||||
|
gzip_proxied any;
|
||||||
|
|
||||||
|
# Tell proxies to cache both the gzipped and regular version of a resource
|
||||||
|
# whenever the client's Accept-Encoding capabilities header varies;
|
||||||
|
# Avoids the issue where a non-gzip capable client (which is extremely rare
|
||||||
|
# today) would display gibberish if their proxy gave them the gzipped version.
|
||||||
|
# Default: off
|
||||||
|
gzip_vary on;
|
||||||
|
|
||||||
|
# Compress all output labeled with one of the following MIME-types.
|
||||||
|
# text/html is always compressed by gzip module.
|
||||||
|
# Default: text/html
|
||||||
|
gzip_types *;
|
||||||
|
brotli on;
|
||||||
|
# brotli_static on;
|
||||||
|
brotli_types *;
|
||||||
|
# This should be turned on if you are going to have pre-compressed copies (.gz) of
|
||||||
|
# static files available. If not it should be left off as it will cause extra I/O
|
||||||
|
# for the check. It is best if you enable this in a location{} block for
|
||||||
|
# a specific directory, or on an individual server{} level.
|
||||||
|
# gzip_static on;
|
||||||
|
keepalive_timeout 3000;
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
index index.html;
|
||||||
|
server_name localhost;
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
autoindex on;
|
||||||
|
|
||||||
|
location ~* \.(?:manifest|appcache|html?|xml|json|css|js|map|jpg|jpeg|gif|png|ico|svg|eot|ttf|woff|woff2)$ {
|
||||||
|
add_header Access-Control-Allow-Origin *;
|
||||||
|
add_header Access-Control-Allow-Credentials true;
|
||||||
|
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
|
||||||
|
add_header Access-Control-Allow-Headers 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
location /service-worker.js {
|
||||||
|
expires -1;
|
||||||
|
add_header Access-Control-Allow-Origin *;
|
||||||
|
add_header Access-Control-Allow-Credentials true;
|
||||||
|
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
|
||||||
|
add_header Access-Control-Allow-Headers 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html =404;
|
||||||
|
}
|
||||||
|
location /iframe.html {
|
||||||
|
try_files $uri $uri/ /iframe.html =404;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12992
package-lock.json
generated
12992
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
95
package.json
95
package.json
@@ -1,19 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "coriolis_shipyard",
|
"name": "coriolis_shipyard",
|
||||||
"version": "3.0.1",
|
"version": "3.0.0",
|
||||||
"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 >= 10.13.0",
|
"engine": "node >= 4.8.1",
|
||||||
"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",
|
||||||
@@ -23,8 +18,7 @@
|
|||||||
"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)",
|
||||||
"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 -p --config webpack.config.prod.js",
|
||||||
"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"
|
||||||
},
|
},
|
||||||
@@ -61,7 +55,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.20.12",
|
"@babel/core": "^7.0.0",
|
||||||
"@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",
|
||||||
@@ -80,12 +74,15 @@
|
|||||||
"@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",
|
||||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
"appcache-webpack-plugin": "^1.4.0",
|
||||||
|
"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": "^10.2.4",
|
"copy-webpack-plugin": "^4.5.2",
|
||||||
"create-react-class": "^15.6.3",
|
"create-react-class": "^15.6.3",
|
||||||
"cross-env": "^5.2.0",
|
"cross-env": "^5.2.0",
|
||||||
"css-loader": "^6.7.3",
|
"css-loader": "^1.0.0",
|
||||||
"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",
|
||||||
@@ -96,66 +93,54 @@
|
|||||||
"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": "^3.1.0",
|
"expose-loader": "^0.7.5",
|
||||||
"express": "^4.18.2",
|
"express": "^4.16.3",
|
||||||
"html-webpack-plugin": "^5.5.0",
|
"extract-text-webpack-plugin": "^4.0.0-beta.0",
|
||||||
"jsen": "^0.6.6",
|
"file-loader": "^2.0.0",
|
||||||
|
"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": "^11.1.0",
|
"less-loader": "^4.1.0",
|
||||||
"mini-css-extract-plugin": "^2.7.2",
|
"react-addons-perf": "^15.4.2",
|
||||||
"react-container-dimensions": "^1.4.1",
|
"react-container-dimensions": "^1.4.1",
|
||||||
"react-testutils-additions": "^15.0.0",
|
"react-testutils-additions": "^16.0.0",
|
||||||
"react-transition-group": "^2.5.0",
|
"react-transition-group": "^2.5.0",
|
||||||
"rimraf": "^4.1.2",
|
"rimraf": "^2.6.1",
|
||||||
"rollup": "^3.17.2",
|
"rollup": "^0.66.2",
|
||||||
"style-loader": "^3.3.1",
|
"rollup-plugin-node-resolve": "^3.4.0",
|
||||||
"uglify-js": "^3.17.4",
|
"style-loader": "^0.23.0",
|
||||||
"webpack": "^5.75.0",
|
"uglify-js": "^3.4.9",
|
||||||
"webpack-cli": "^5.0.1",
|
"url-loader": "^1.1.1",
|
||||||
"webpack-dev-server": "^4.11.1",
|
"webpack": "^4.20.2",
|
||||||
"webpack-merge": "^5.8.0",
|
"webpack-bugsnag-plugins": "^1.2.2",
|
||||||
"webpack-notifier": "^1.15.0",
|
"webpack-cli": "^3.1.1",
|
||||||
"workbox-cacheable-response": "^6.5.4",
|
"webpack-dev-server": "^3.1.9",
|
||||||
"workbox-expiration": "^6.5.4",
|
"webpack-notifier": "^1.6.0",
|
||||||
"workbox-precaching": "^6.5.4",
|
"workbox-webpack-plugin": "^3.6.1"
|
||||||
"workbox-routing": "^6.5.4",
|
|
||||||
"workbox-strategies": "^6.5.4",
|
|
||||||
"workbox-webpack-plugin": "^6.5.4"
|
|
||||||
},
|
},
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"assert": "^1.5.0",
|
"@babel/polyfill": "^7.0.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",
|
||||||
"os-browserify": "^0.3.0",
|
"pako": "^1.0.6",
|
||||||
"pako": "^2.1.0",
|
|
||||||
"path-browserify": "^1.0.1",
|
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"react": "^15.6.2",
|
"react": "^15.5.4",
|
||||||
"react-dom": "^15.6.2",
|
"react-dom": "^15.5.4",
|
||||||
|
"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": "^4.0.3",
|
"react-number-editor": "Athanasius/react-number-editor.git#miggy",
|
||||||
"recharts": "^1.2.0",
|
"recharts": "^1.2.0",
|
||||||
"register-service-worker": "^1.7.2",
|
"register-service-worker": "^1.5.2",
|
||||||
"stream-browserify": "^3.0.0",
|
"superagent": "^3.8.3"
|
||||||
"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
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import ComparisonPage from './pages/ComparisonPage';
|
|||||||
import ShipyardPage from './pages/ShipyardPage';
|
import ShipyardPage from './pages/ShipyardPage';
|
||||||
import ErrorDetails from './pages/ErrorDetails';
|
import ErrorDetails from './pages/ErrorDetails';
|
||||||
|
|
||||||
|
|
||||||
const zlib = require('pako');
|
const zlib = require('pako');
|
||||||
const request = require('superagent');
|
const request = require('superagent');
|
||||||
|
|
||||||
@@ -73,6 +72,7 @@ export default class Coriolis extends React.Component {
|
|||||||
route: {},
|
route: {},
|
||||||
sizeRatio: Persist.getSizeRatio()
|
sizeRatio: Persist.getSizeRatio()
|
||||||
};
|
};
|
||||||
|
this._getAnnouncements();
|
||||||
Router('', (r) => this._setPage(ShipyardPage, r));
|
Router('', (r) => this._setPage(ShipyardPage, r));
|
||||||
Router('/import?', (r) => this._importBuild(r));
|
Router('/import?', (r) => this._importBuild(r));
|
||||||
Router('/import/:data', (r) => this._importBuild(r));
|
Router('/import/:data', (r) => this._importBuild(r));
|
||||||
@@ -93,39 +93,34 @@ 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.from(r.params.data, 'base64'), { to: 'string' });
|
const data = zlib.inflate(new Buffer(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);
|
||||||
let ship, importString;
|
let ship;
|
||||||
if (json) {
|
if (json && json.modules) {
|
||||||
if (json.length && json[0].data) { // SLEF
|
ship = CompanionApiUtils.shipFromJson(json);
|
||||||
if (json.length > 1) { // Multiple builds, open modal
|
} else if (json && json.Modules) {
|
||||||
importString = data;
|
ship = JournalUtils.shipFromLoadoutJSON(json);
|
||||||
} else { // Single build, import directly
|
|
||||||
ship = JournalUtils.shipFromLoadoutJSON(json[0].data);
|
|
||||||
}
|
|
||||||
} else { // not SLEF
|
|
||||||
if (json.modules) {
|
|
||||||
ship = CompanionApiUtils.shipFromJson(json);
|
|
||||||
} else if (json.Modules) {
|
|
||||||
ship = JournalUtils.shipFromLoadoutJSON(json);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ship) {
|
|
||||||
r.params.ship = ship.id;
|
|
||||||
r.params.code = ship.toString();
|
|
||||||
this._setPage(OutfittingPage, r);
|
|
||||||
} else if (importString) {
|
|
||||||
this._setPage(ShipyardPage, r);
|
|
||||||
this._showModal(<ModalImport importString={data}/>);
|
|
||||||
}
|
}
|
||||||
|
r.params.ship = ship.id;
|
||||||
|
r.params.code = ship.toString();
|
||||||
|
this._setPage(OutfittingPage, r)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this._onError('Failed to import ship', r.path, 0, 0, err);
|
this._onError('Failed to import ship', r.path, 0, 0, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _getAnnouncements() {
|
||||||
|
try {
|
||||||
|
const announces = await request.get('https://orbis.zone/api/announcement')
|
||||||
|
.query({ showInCoriolis: true });
|
||||||
|
this.setState({ announcements: announces.body });
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates / Sets the page and route context
|
* Updates / Sets the page and route context
|
||||||
* @param {[type]} page The page to be shown
|
* @param {[type]} page The page to be shown
|
||||||
@@ -149,6 +144,13 @@ 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,
|
||||||
@@ -392,18 +394,18 @@ export default class Coriolis extends React.Component {
|
|||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
let currentMenu = this.state.currentMenu;
|
let currentMenu = this.state.currentMenu;
|
||||||
|
|
||||||
return <div style={{ minHeight: '100%' }} onClick={this._closeMenu}
|
return <div style={{ minHeight: '100%' }} onClick={this._closeMenu}
|
||||||
className={this.state.noTouch ? 'no-touch' : null}>
|
className={this.state.noTouch ? 'no-touch' : null}>
|
||||||
<Header announcements={this.state.announcements} appCacheUpdate={this.state.appCacheUpdate}
|
<Header announcements={this.state.announcements} appCacheUpdate={this.state.appCacheUpdate}
|
||||||
currentMenu={currentMenu}/>
|
currentMenu={currentMenu}/>
|
||||||
<div className="announcement-container">{this.state.announcements.map(a => <Announcement
|
<div className="announcement-container">{this.state.announcements.map(a => <Announcement
|
||||||
text={a.text}/>)}</div>
|
text={a.message}/>)}</div>
|
||||||
{this.state.error ? this.state.error : this.state.page ? React.createElement(this.state.page, { currentMenu }) :
|
{this.state.error ? this.state.error : this.state.page ? React.createElement(this.state.page, { currentMenu }) :
|
||||||
<NotFoundPage/>}
|
<NotFoundPage/>}
|
||||||
{this.state.modal}
|
{this.state.modal}
|
||||||
{this.state.tooltip}
|
{this.state.tooltip}
|
||||||
<footer>
|
<footer>
|
||||||
|
|
||||||
<div className="right cap">
|
<div className="right cap">
|
||||||
<a href="https://github.com/EDCD/coriolis" target="_blank" rel="noopener noreferrer"
|
<a href="https://github.com/EDCD/coriolis" target="_blank" rel="noopener noreferrer"
|
||||||
title="Coriolis Github Project">{window.CORIOLIS_VERSION} - {window.CORIOLIS_DATE}</a>
|
title="Coriolis Github Project">{window.CORIOLIS_VERSION} - {window.CORIOLIS_DATE}</a>
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import Persist from './stores/Persist';
|
import Persist from './stores/Persist';
|
||||||
|
import ReactGA from 'react-ga';
|
||||||
|
|
||||||
|
ReactGA.initialize('UA-55840909-18');
|
||||||
let standalone = undefined;
|
let standalone = undefined;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,7 +74,6 @@ Router.go = function(path, state) {
|
|||||||
gaTrack(path);
|
gaTrack(path);
|
||||||
let ctx = new Context(path, state);
|
let ctx = new Context(path, state);
|
||||||
Router.dispatch(ctx);
|
Router.dispatch(ctx);
|
||||||
|
|
||||||
if (!ctx.unhandled) {
|
if (!ctx.unhandled) {
|
||||||
if (isStandAlone()) {
|
if (isStandAlone()) {
|
||||||
Persist.setState(ctx);
|
Persist.setState(ctx);
|
||||||
@@ -258,8 +259,16 @@ Route.prototype.match = function(path, params) {
|
|||||||
* @param {string} path Path to track
|
* @param {string} path Path to track
|
||||||
*/
|
*/
|
||||||
function gaTrack(path) {
|
function gaTrack(path) {
|
||||||
const _paq = window._paq || [];
|
const match = path.match(/\/outfit\/(.*)(\?code=.*)/);
|
||||||
_paq.push(['trackPageView']);
|
if (match) {
|
||||||
|
if (match[1]) {
|
||||||
|
ReactGA.ga('set', 'contentGroup1', match[1]);
|
||||||
|
}
|
||||||
|
if (match[2]) {
|
||||||
|
ReactGA.ga('set', 'contentGroup2', match[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ReactGA.pageview(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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 'auto-bind';
|
import { autoBind } from 'react-extras';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 { CoriolisLogo, MountFixed, MountGimballed, MountTurret } from './SvgIcons';
|
import { 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,7 +20,6 @@ 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',
|
||||||
@@ -39,17 +38,13 @@ 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',
|
||||||
'axmr': 'experimental',
|
'axmr': 'experimental',
|
||||||
'axmre': 'experimental',
|
|
||||||
'rcpl': 'experimental',
|
'rcpl': 'experimental',
|
||||||
'dtl': 'experimental',
|
'dtl': 'experimental',
|
||||||
'tbsc': 'experimental',
|
'tbsc': 'experimental',
|
||||||
@@ -83,13 +78,7 @@ const GRPCAT = {
|
|||||||
// Mining
|
// Mining
|
||||||
'scl': 'mining',
|
'scl': 'mining',
|
||||||
'pwa': 'mining',
|
'pwa': 'mining',
|
||||||
'sdm': 'mining',
|
'sdm': 'mining'
|
||||||
|
|
||||||
// Assists
|
|
||||||
'dc': '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 = {
|
||||||
@@ -99,26 +88,24 @@ 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', 'mlc'],
|
'limpet controllers': ['cc', 'fx', 'hb', 'pc', 'rpl'],
|
||||||
'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'],
|
||||||
'structural reinforcement': ['hr', 'mrp'],
|
'structural reinforcement': ['hr', 'mrp'],
|
||||||
'flight assists': ['dc', 'sua'],
|
'dc': ['dc'],
|
||||||
|
|
||||||
// Hardpoints
|
// Hardpoints
|
||||||
'lasers': ['pl', 'ul', 'bl'],
|
'lasers': ['pl', 'ul', 'bl'],
|
||||||
'projectiles': ['mc', 'advmc', 'c', 'fc', 'pa', 'rg'],
|
'projectiles': ['mc', 'c', 'fc', 'pa', 'rg'],
|
||||||
'ordnance': ['mr', 'tp', 'nl'],
|
'ordnance': ['mr', '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', 'axmce', 'axmr', 'axmre', 'ntp','rfl', 'tbrfl', 'tbsc', 'tbem', 'xs', 'sfn', 'rcpl', 'dtl', 'rsl', 'mahr',],
|
'experimental': ['axmc', 'axmr', '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'],
|
||||||
|
|
||||||
@@ -134,7 +121,7 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
onSelect: PropTypes.func.isRequired,
|
onSelect: PropTypes.func.isRequired,
|
||||||
diffDetails: PropTypes.func,
|
diffDetails: PropTypes.func,
|
||||||
m: PropTypes.object,
|
m: PropTypes.object,
|
||||||
ship: PropTypes.object.isRequired,
|
shipMass: PropTypes.number,
|
||||||
warning: PropTypes.func,
|
warning: PropTypes.func,
|
||||||
firstSlotId: PropTypes.string,
|
firstSlotId: PropTypes.string,
|
||||||
lastSlotId: PropTypes.string,
|
lastSlotId: PropTypes.string,
|
||||||
@@ -142,6 +129,10 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
slotDiv: PropTypes.object
|
slotDiv: PropTypes.object
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
shipMass: 0
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
@@ -163,15 +154,15 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
*/
|
*/
|
||||||
_initState(props, context) {
|
_initState(props, context) {
|
||||||
let translate = context.language.translate;
|
let translate = context.language.translate;
|
||||||
let { m, warning, onSelect, modules, ship } = props;
|
let { m, warning, shipMass, onSelect, modules, firstSlotId, lastSlotId } = props;
|
||||||
let list, currentGroup;
|
let list, currentGroup;
|
||||||
|
|
||||||
let buildGroup = this._buildGroup.bind(
|
let buildGroup = this._buildGroup.bind(
|
||||||
this,
|
this,
|
||||||
ship,
|
|
||||||
translate,
|
translate,
|
||||||
m,
|
m,
|
||||||
warning,
|
warning,
|
||||||
|
shipMass - (m && m.mass ? m.mass : 0),
|
||||||
(m, event) => {
|
(m, event) => {
|
||||||
this._hideDiff(event);
|
this._hideDiff(event);
|
||||||
onSelect(m);
|
onSelect(m);
|
||||||
@@ -217,30 +208,16 @@ 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) {
|
||||||
// If this is a missing module/weapon, skip it
|
list.push(<div ref={(elem) => this.groupElem = elem} key={category}
|
||||||
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 {
|
||||||
if (category == "mh"){
|
list.push(<div key={category} className={'select-category upp'}>{translate(category)}</div>);
|
||||||
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) {
|
||||||
if (category == "mh"){
|
list.push(<div key={category} className={'select-category upp'}>{translate(category)}</div>);
|
||||||
continue;
|
categoryHeader = true;
|
||||||
}
|
|
||||||
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}
|
||||||
@@ -271,36 +248,20 @@ 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 {Function} translate Translate function
|
* @param {Function} translate Translate function
|
||||||
* @param {Object} mountedModule Mounted Module
|
* @param {Object} mountedModule Mounted Module
|
||||||
* @param {Function} warningFunc Warning function
|
* @param {Function} warningFunc Warning function
|
||||||
|
* @param {number} mass Mass
|
||||||
* @param {function} onSelect Select/Mount callback
|
* @param {function} onSelect Select/Mount callback
|
||||||
* @param {string} grp Group name
|
* @param {string} grp Group name
|
||||||
* @param {Array} modules Available modules
|
* @param {Array} modules Available modules
|
||||||
|
* @param {string} firstSlotId id of first slot item
|
||||||
|
* @param {string} lastSlotId id of last slot item
|
||||||
* @return {React.Component} Available Module Group contents
|
* @return {React.Component} Available Module Group contents
|
||||||
*/
|
*/
|
||||||
_buildGroup(ship, translate, mountedModule, warningFunc, onSelect, grp, modules) {
|
_buildGroup(translate, mountedModule, warningFunc, mass, onSelect, grp, modules, firstSlotId, lastSlotId) {
|
||||||
let prevClass = null, prevRating = null, prevName;
|
let prevClass = null, prevRating = null, prevName;
|
||||||
let elems = [];
|
let elems = [];
|
||||||
|
|
||||||
@@ -316,25 +277,17 @@ 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 == 'mh' || m.grp == 'mm') {
|
|
||||||
// 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;
|
||||||
if (ModuleUtils.isShieldGenerator(m.grp)) {
|
if (ModuleUtils.isShieldGenerator(m.grp)) {
|
||||||
// Shield generators care about maximum hull mass
|
// Shield generators care about maximum hull mass
|
||||||
disabled = ship.hullMass > m.maxmass;
|
disabled = mass > m.maxmass;
|
||||||
// If the mounted module is experimental as well, we can replace it so
|
} else if (m.maxmass) {
|
||||||
// the maximum does not apply
|
// Thrusters care about total mass
|
||||||
} else if (m.experimental && (!mountedModule || !mountedModule.experimental)) {
|
disabled = mass + m.mass > m.maxmass;
|
||||||
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', {
|
||||||
warning: !disabled && warningFunc && warningFunc(m),
|
warning: !disabled && warningFunc && warningFunc(m),
|
||||||
active,
|
active,
|
||||||
@@ -429,7 +382,6 @@ 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}
|
||||||
@@ -441,20 +393,11 @@ 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={cn('lc', {disabled})}
|
className={'lc'}
|
||||||
onClick={handler}
|
onClick={() => clickHandler(i)}
|
||||||
>
|
>
|
||||||
{val.name}
|
{val.name}
|
||||||
</div>
|
</div>
|
||||||
@@ -573,15 +516,6 @@ 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._inaraShoppingList.bind(this);
|
this._eddbShoppingList = this._eddbShoppingList.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);
|
||||||
@@ -306,8 +306,8 @@ export default class CostSection extends TranslatedComponent {
|
|||||||
<tr className='main'>
|
<tr className='main'>
|
||||||
<th colSpan='2' className='sortable le' onClick={this._sortCostBy.bind(this,'m')}>
|
<th colSpan='2' className='sortable le' onClick={this._sortCostBy.bind(this,'m')}>
|
||||||
{translate('module')}
|
{translate('module')}
|
||||||
{shipDiscount ? <u className='cap optional-hide' style={{ marginLeft: '0.5em' }}>{`[${translate('ship')} ${formats.pct(-1 * shipDiscount)}]`}</u> : null}
|
{shipDiscount ? <u className='cap optional-hide' style={{ marginLeft: '0.5em' }}>{`[${translate('ship')} -${formats.pct(shipDiscount)}]`}</u> : null}
|
||||||
{moduleDiscount ? <u className='cap optional-hide' style={{ marginLeft: '0.5em' }}>{`[${translate('modules')} ${formats.pct(-1 * moduleDiscount)}]`}</u> : null}
|
{moduleDiscount ? <u className='cap optional-hide' style={{ marginLeft: '0.5em' }}>{`[${translate('modules')} -${formats.pct(moduleDiscount)}]`}</u> : null}
|
||||||
</th>
|
</th>
|
||||||
<th className='sortable le' onClick={this._sortCostBy.bind(this, 'cr')} >{translate('credits')}</th>
|
<th className='sortable le' onClick={this._sortCostBy.bind(this, 'cr')} >{translate('credits')}</th>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -328,9 +328,9 @@ export default class CostSection extends TranslatedComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open up a window for inara with a shopping list of our retrofit components
|
* Open up a window for EDDB with a shopping list of our retrofit components
|
||||||
*/
|
*/
|
||||||
_inaraShoppingList() {
|
_eddbShoppingList() {
|
||||||
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://inara.cz/inapi/corisearch.php?m=' + modIds.join(','));
|
window.open('https://eddb.io/station?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._inaraShoppingList} 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._eddbShoppingList} 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}
|
||||||
|
|||||||
@@ -52,12 +52,12 @@ export default class Defence extends TranslatedComponent {
|
|||||||
* @return {React.Component} contents
|
* @return {React.Component} contents
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
const { opponent, sys, opponentWep } = this.props;
|
const { ship, sys, opponentWep } = this.props;
|
||||||
const { language, tooltip, termtip } = this.context;
|
const { language, tooltip, termtip } = this.context;
|
||||||
const { formats, translate, units } = language;
|
const { formats, translate, units } = language;
|
||||||
const { shield, armour, shielddamage, armourdamage } = this.state;
|
const { shield, armour, shielddamage, armourdamage } = this.state;
|
||||||
|
|
||||||
const pd = opponent.standard[4].m;
|
const pd = ship.standard[4].m;
|
||||||
|
|
||||||
const shieldSourcesData = [];
|
const shieldSourcesData = [];
|
||||||
const effectiveShieldData = [];
|
const effectiveShieldData = [];
|
||||||
|
|||||||
@@ -104,10 +104,10 @@ export default class HardpointSlot extends Slot {
|
|||||||
onMouseOut={tooltip.bind(null, null)}>{translate('shotdmg')}: {formats.round1(m.getDamage())}</div> : null}
|
onMouseOut={tooltip.bind(null, null)}>{translate('shotdmg')}: {formats.round1(m.getDamage())}</div> : null}
|
||||||
{m.getEps() ? <div className={'l'} onMouseOver={termtip.bind(null, m.getClip() ? 'epsseps' : 'eps')}
|
{m.getEps() ? <div className={'l'} onMouseOver={termtip.bind(null, m.getClip() ? 'epsseps' : 'eps')}
|
||||||
onMouseOut={tooltip.bind(null, null)}>{translate('EPS')}: {formats.round1(m.getEps())}{u.MW} {m.getClip() ?
|
onMouseOut={tooltip.bind(null, null)}>{translate('EPS')}: {formats.round1(m.getEps())}{u.MW} {m.getClip() ?
|
||||||
<span>({formats.round1(m.getEps() * m.getSustainedFactor())}{u.MW})</span> : null}</div> : null}
|
<span>({formats.round1((m.getClip() * m.getEps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload()))}{u.MW})</span> : null}</div> : null}
|
||||||
{m.getHps() ? <div className={'l'} onMouseOver={termtip.bind(null, m.getClip() ? 'hpsshps' : 'hps')}
|
{m.getHps() ? <div className={'l'} onMouseOver={termtip.bind(null, m.getClip() ? 'hpsshps' : 'hps')}
|
||||||
onMouseOut={tooltip.bind(null, null)}>{translate('HPS')}: {formats.round1(m.getHps())} {m.getClip() ?
|
onMouseOut={tooltip.bind(null, null)}>{translate('HPS')}: {formats.round1(m.getHps())} {m.getClip() ?
|
||||||
<span>({formats.round1(m.getHps() * m.getSustainedFactor())})</span> : null}</div> : null}
|
<span>({formats.round1((m.getClip() * m.getHps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload()))})</span> : null}</div> : null}
|
||||||
{m.getDps() && m.getEps() ? <div className={'l'} onMouseOver={termtip.bind(null, 'dpe')}
|
{m.getDps() && m.getEps() ? <div className={'l'} onMouseOver={termtip.bind(null, 'dpe')}
|
||||||
onMouseOut={tooltip.bind(null, null)}>{translate('DPE')}: {formats.f1(m.getDps() / m.getEps())}</div> : null}
|
onMouseOut={tooltip.bind(null, null)}>{translate('DPE')}: {formats.f1(m.getDps() / m.getEps())}</div> : null}
|
||||||
{m.getRoF() ? <div className={'l'} onMouseOver={termtip.bind(null, 'rof')}
|
{m.getRoF() ? <div className={'l'} onMouseOver={termtip.bind(null, 'rof')}
|
||||||
@@ -121,7 +121,7 @@ export default class HardpointSlot extends Slot {
|
|||||||
{m.getShieldBoost() ? <div className={'l'}>+{formats.pct1(m.getShieldBoost())}</div> : null}
|
{m.getShieldBoost() ? <div className={'l'}>+{formats.pct1(m.getShieldBoost())}</div> : null}
|
||||||
{m.getAmmo() ? <div
|
{m.getAmmo() ? <div
|
||||||
className={'l'}>{translate('ammunition')}: {formats.int(m.getClip())}/{formats.int(m.getAmmo())}</div> : null}
|
className={'l'}>{translate('ammunition')}: {formats.int(m.getClip())}/{formats.int(m.getAmmo())}</div> : null}
|
||||||
{m.getReload() ? <div className={'l'}>{translate('wep_reload')}: {formats.round(m.getReload())}{u.s}</div> : null}
|
{m.getReload() ? <div className={'l'}>{translate('reload')}: {formats.round(m.getReload())}{u.s}</div> : null}
|
||||||
{m.getShotSpeed() ? <div
|
{m.getShotSpeed() ? <div
|
||||||
className={'l'}>{translate('shotspeed')}: {formats.int(m.getShotSpeed())}{u.mps}</div> : null}
|
className={'l'}>{translate('shotspeed')}: {formats.int(m.getShotSpeed())}{u.mps}</div> : null}
|
||||||
{m.getPiercing() ? <div className={'l'}>{translate('piercing')}: {formats.int(m.getPiercing())}</div> : null}
|
{m.getPiercing() ? <div className={'l'}>{translate('piercing')}: {formats.int(m.getPiercing())}</div> : null}
|
||||||
@@ -136,7 +136,6 @@ 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)}>
|
||||||
|
|||||||
@@ -149,14 +149,14 @@ export default class HardpointSlotSection extends SlotSection {
|
|||||||
<ul>
|
<ul>
|
||||||
<li className='lc' tabIndex='0' onClick={_fill.bind(this, 'pa', 'F')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['pa-F'] = smRef}>{translate('pa')}</li>
|
<li className='lc' tabIndex='0' onClick={_fill.bind(this, 'pa', 'F')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['pa-F'] = smRef}>{translate('pa')}</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div className='select-group cap'>{translate('rg')}</div>
|
|
||||||
<ul>
|
|
||||||
<li className='lc' tabIndex='0' onClick={_fill.bind(this, 'rg', 'F')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['rg-F'] = smRef}>{translate('rg')}</li>
|
|
||||||
</ul>
|
|
||||||
<div className='select-group cap'>{translate('nl')}</div>
|
<div className='select-group cap'>{translate('nl')}</div>
|
||||||
<ul>
|
<ul>
|
||||||
<li className='lc' tabIndex='0' onClick={_fill.bind(this, 'nl', 'F')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['nl-F'] = smRef}>{translate('nl')}</li>
|
<li className='lc' tabIndex='0' onClick={_fill.bind(this, 'nl', 'F')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['nl-F'] = smRef}>{translate('nl')}</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<div className='select-group cap'>{translate('ggc')}</div>
|
||||||
|
<ul>
|
||||||
|
<li className='lc' tabIndex='0' onClick={_fill.bind(this, 'ggc', 'F')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['ggc-F'] = smRef}>{translate('ggc')}</li>
|
||||||
|
</ul>
|
||||||
<div className='select-group cap'>{translate('rfl')}</div>
|
<div className='select-group cap'>{translate('rfl')}</div>
|
||||||
<ul>
|
<ul>
|
||||||
<li className='c' tabIndex='0' onClick={_fill.bind(this, 'rfl', 'F')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['rfl-F'] = smRef}><MountFixed className='lg'/></li>
|
<li className='c' tabIndex='0' onClick={_fill.bind(this, 'rfl', 'F')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['rfl-F'] = smRef}><MountFixed className='lg'/></li>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { Ships } from 'coriolis-data/dist';
|
|||||||
import Persist from '../stores/Persist';
|
import Persist from '../stores/Persist';
|
||||||
import { toDetailedExport } from '../shipyard/Serializer';
|
import { toDetailedExport } from '../shipyard/Serializer';
|
||||||
import Ship from '../shipyard/Ship';
|
import Ship from '../shipyard/Ship';
|
||||||
|
import ModalBatchOrbis from './ModalBatchOrbis';
|
||||||
import ModalDeleteAll from './ModalDeleteAll';
|
import ModalDeleteAll from './ModalDeleteAll';
|
||||||
import ModalExport from './ModalExport';
|
import ModalExport from './ModalExport';
|
||||||
import ModalHelp from './ModalHelp';
|
import ModalHelp from './ModalHelp';
|
||||||
@@ -240,6 +241,43 @@ export default class Header extends TranslatedComponent {
|
|||||||
/>);
|
/>);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uploads all ship-builds to orbis
|
||||||
|
* @param {e} e Event
|
||||||
|
*/
|
||||||
|
_uploadAllBuildsToOrbis(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const data = Persist.getBuilds();
|
||||||
|
let postObject = [];
|
||||||
|
for (const ship in data) {
|
||||||
|
for (const code in data[ship]) {
|
||||||
|
const shipModel = ship;
|
||||||
|
if (!shipModel) {
|
||||||
|
throw 'No such ship found: "' + ship + '"';
|
||||||
|
}
|
||||||
|
const shipTemplate = Ships[shipModel];
|
||||||
|
const shipPostObject = {};
|
||||||
|
let shipInstance = new Ship(shipModel, shipTemplate.properties, shipTemplate.slots);
|
||||||
|
shipInstance.buildWith(null);
|
||||||
|
shipInstance.buildFrom(data[ship][code]);
|
||||||
|
shipPostObject.coriolisId = shipInstance.id;
|
||||||
|
shipPostObject.coriolisShip = shipInstance;
|
||||||
|
|
||||||
|
shipPostObject.coriolisShip.url = window.location.origin + outfitURL(shipModel, data[ship][code], code);
|
||||||
|
shipPostObject.title = code || shipInstance.id;
|
||||||
|
shipPostObject.description = code || shipInstance.id;
|
||||||
|
shipPostObject.ShipName = shipInstance.id;
|
||||||
|
shipPostObject.Ship = shipInstance.id;
|
||||||
|
postObject.push(shipPostObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(postObject);
|
||||||
|
|
||||||
|
this.context.showModal(<ModalBatchOrbis
|
||||||
|
ships={postObject}
|
||||||
|
/>);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show export modal with detailed export
|
* Show export modal with detailed export
|
||||||
* @param {SyntheticEvent} e Event
|
* @param {SyntheticEvent} e Event
|
||||||
@@ -311,7 +349,7 @@ export default class Header extends TranslatedComponent {
|
|||||||
_getShipsMenu() {
|
_getShipsMenu() {
|
||||||
let shipList = [];
|
let shipList = [];
|
||||||
|
|
||||||
for (let s of this.shipOrder) {
|
for (let s in Ships) {
|
||||||
shipList.push(<ActiveLink key={s} href={outfitURL(s)} className='block'>{Ships[s].properties.name}</ActiveLink>);
|
shipList.push(<ActiveLink key={s} href={outfitURL(s)} className='block'>{Ships[s].properties.name}</ActiveLink>);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,10 +426,7 @@ 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()) {
|
announcements.push(<Announcement text={announce.message} />);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
announcements.push(<Announcement text={announce.text} />);
|
|
||||||
announcements.push(<hr/>);
|
announcements.push(<hr/>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -461,6 +496,7 @@ export default class Header extends TranslatedComponent {
|
|||||||
{translate('builds')} & {translate('comparisons')}
|
{translate('builds')} & {translate('comparisons')}
|
||||||
<li><Link href="#" className='block' onClick={this._showBackup.bind(this)}>{translate('backup')}</Link></li>
|
<li><Link href="#" className='block' onClick={this._showBackup.bind(this)}>{translate('backup')}</Link></li>
|
||||||
<li><Link href="#" className='block' onClick={this._showDetailedExport.bind(this)}>{translate('detailed export')}</Link></li>
|
<li><Link href="#" className='block' onClick={this._showDetailedExport.bind(this)}>{translate('detailed export')}</Link></li>
|
||||||
|
<li><Link href="#" className='block' onClick={this._uploadAllBuildsToOrbis.bind(this)}>{translate('upload all builds to orbis')}</Link></li>
|
||||||
<li><Link href="#" className='block' onClick={this._showImport.bind(this)}>{translate('import')}</Link></li>
|
<li><Link href="#" className='block' onClick={this._showImport.bind(this)}>{translate('import')}</Link></li>
|
||||||
<li><Link href="#" className='block' onClick={this._showDeleteAll.bind(this)}>{translate('delete all')}</Link></li>
|
<li><Link href="#" className='block' onClick={this._showDeleteAll.bind(this)}>{translate('delete all')}</Link></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ export default class InternalSlot extends Slot {
|
|||||||
{ m.rangeLS ? <div className={'l'}>{translate('range')}: {m.rangeLS}{u.Ls}</div> : null }
|
{ m.rangeLS ? <div className={'l'}>{translate('range')}: {m.rangeLS}{u.Ls}</div> : null }
|
||||||
{ m.rangeLS === null ? <div className={'l'}>∞{u.Ls}</div> : null }
|
{ m.rangeLS === null ? <div className={'l'}>∞{u.Ls}</div> : null }
|
||||||
{ m.rangeRating ? <div className={'l'}>{translate('range')}: {m.rangeRating}</div> : null }
|
{ m.rangeRating ? <div className={'l'}>{translate('range')}: {m.rangeRating}</div> : null }
|
||||||
|
{ m.maximum ? <div className={'l'}>{translate('max')}: {(m.maximum)}</div> : null }
|
||||||
{ m.passengers ? <div className={'l'}>{translate('passengers')}: {m.passengers}</div> : null }
|
{ m.passengers ? <div className={'l'}>{translate('passengers')}: {m.passengers}</div> : null }
|
||||||
{ m.getRegenerationRate() ? <div className='l'>{translate('regen')}: {formats.round1(m.getRegenerationRate())}{u.ps}</div> : null }
|
{ m.getRegenerationRate() ? <div className='l'>{translate('regen')}: {formats.round1(m.getRegenerationRate())}{u.ps}</div> : null }
|
||||||
{ m.getBrokenRegenerationRate() ? <div className='l'>{translate('brokenregen')}: {formats.round1(m.getBrokenRegenerationRate())}{u.ps}</div> : null }
|
{ m.getBrokenRegenerationRate() ? <div className='l'>{translate('brokenregen')}: {formats.round1(m.getBrokenRegenerationRate())}{u.ps}</div> : null }
|
||||||
@@ -88,7 +89,6 @@ 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>;
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
93
src/app/components/ModalBatchOrbis.jsx
Normal file
93
src/app/components/ModalBatchOrbis.jsx
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import request from 'superagent';
|
||||||
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
|
import { orbisUpload } from '../utils/ShortenUrl';
|
||||||
|
import Persist from '../stores/Persist';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Permalink modal
|
||||||
|
*/
|
||||||
|
export default class ModalBatchOrbis extends TranslatedComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
ships: PropTypes.any.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param {Object} props React Component properties
|
||||||
|
*/
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
orbisCreds: Persist.getOrbisCreds(),
|
||||||
|
resp: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send ship to Orbis.zone
|
||||||
|
* @param {SyntheticEvent} e React Event
|
||||||
|
* @return {Promise} Promise sending post request to orbis
|
||||||
|
*/
|
||||||
|
sendToOrbis(e) {
|
||||||
|
let agent;
|
||||||
|
try {
|
||||||
|
agent = request.agent(); // apparently this crashes somehow
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
if (!agent) {
|
||||||
|
agent = request;
|
||||||
|
}
|
||||||
|
const API_ORBIS = 'https://orbis.zone/api/builds/add/batch';
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
agent
|
||||||
|
.post(API_ORBIS)
|
||||||
|
.withCredentials()
|
||||||
|
.redirects(0)
|
||||||
|
.set('Content-Type', 'application/json')
|
||||||
|
.send(this.props.ships)
|
||||||
|
.end((err, response) => {
|
||||||
|
console.log(response);
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
this.setState({ resp: response.text });
|
||||||
|
reject('Bad Request');
|
||||||
|
} else {
|
||||||
|
this.setState({ resp: 'All builds uploaded. Check https://orbis.zone' });
|
||||||
|
resolve('All builds uploaded. Check https://orbis.zone');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
reject(e.message ? e.message : e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the modal
|
||||||
|
* @return {React.Component} Modal Content
|
||||||
|
*/
|
||||||
|
render() {
|
||||||
|
let translate = this.context.language.translate;
|
||||||
|
this.sendToOrbis = this.sendToOrbis.bind(this);
|
||||||
|
|
||||||
|
return <div className='modal' onClick={ (e) => e.stopPropagation() }>
|
||||||
|
<h2>{translate('permalink')}</h2>
|
||||||
|
<br/>
|
||||||
|
<a className='button' href="https://orbis.zone/api/auth">Log in / signup to Orbis</a>
|
||||||
|
<br/><br/>
|
||||||
|
<h3 >{translate('success')}</h3>
|
||||||
|
<input value={this.state.resp} readOnly size={25} onFocus={ (e) => e.target.select() }/>
|
||||||
|
<br/><br/>
|
||||||
|
<p>Orbis.zone is currently in a trial period, and may be wiped at any time as development progresses. Some elements are also still placeholders.</p>
|
||||||
|
<button className={'l cb dismiss cap'} disabled={!!this.state.failed} onClick={this.sendToOrbis}>{translate('PHASE_UPLOAD_ORBIS')}</button>
|
||||||
|
<button className={'r dismiss cap'} onClick={this.context.hideModal}>{translate('close')}</button>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,10 +11,7 @@ import * as ModuleUtils from '../shipyard/ModuleUtils';
|
|||||||
import { fromDetailedBuild } from '../shipyard/Serializer';
|
import { fromDetailedBuild } from '../shipyard/Serializer';
|
||||||
import { Download } from './SvgIcons';
|
import { Download } from './SvgIcons';
|
||||||
import { outfitURL } from '../utils/UrlGenerators';
|
import { outfitURL } from '../utils/UrlGenerators';
|
||||||
import { shipFromJson, shipModelFromJson } from '../utils/CompanionApiUtils';
|
import * as CompanionApiUtils from '../utils/CompanionApiUtils';
|
||||||
import { shipFromLoadoutJSON } from '../utils/JournalUtils';
|
|
||||||
|
|
||||||
const zlib = require('pako');
|
|
||||||
|
|
||||||
const textBuildRegex = new RegExp('^\\[([\\w \\-]+)\\]\n');
|
const textBuildRegex = new RegExp('^\\[([\\w \\-]+)\\]\n');
|
||||||
const lineRegex = new RegExp('^([\\dA-Z]{1,2}): (\\d)([A-I])[/]?([FGT])?([SD])? ([\\w\\- ]+)');
|
const lineRegex = new RegExp('^([\\dA-Z]{1,2}): (\\d)([A-I])[/]?([FGT])?([SD])? ([\\w\\- ]+)');
|
||||||
@@ -89,7 +86,6 @@ export default class ModalImport extends TranslatedComponent {
|
|||||||
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
importString: PropTypes.string, // Optional: Default data for import modal
|
|
||||||
builds: PropTypes.object, // Optional: Import object
|
builds: PropTypes.object, // Optional: Import object
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -103,12 +99,11 @@ export default class ModalImport extends TranslatedComponent {
|
|||||||
this.state = {
|
this.state = {
|
||||||
builds: props.builds,
|
builds: props.builds,
|
||||||
canEdit: !props.builds,
|
canEdit: !props.builds,
|
||||||
loadoutEvent: null,
|
|
||||||
comparisons: null,
|
comparisons: null,
|
||||||
shipDiscount: null,
|
shipDiscount: null,
|
||||||
moduleDiscount: null,
|
moduleDiscount: null,
|
||||||
errorMsg: null,
|
errorMsg: null,
|
||||||
importString: props.importString || null,
|
importString: null,
|
||||||
importValid: false,
|
importValid: false,
|
||||||
insurance: null
|
insurance: null
|
||||||
};
|
};
|
||||||
@@ -116,28 +111,12 @@ export default class ModalImport extends TranslatedComponent {
|
|||||||
this._process = this._process.bind(this);
|
this._process = this._process.bind(this);
|
||||||
this._import = this._import.bind(this);
|
this._import = this._import.bind(this);
|
||||||
this._importBackup = this._importBackup.bind(this);
|
this._importBackup = this._importBackup.bind(this);
|
||||||
this._importLoadout = this._importLoadout.bind(this);
|
|
||||||
this._importDetailedArray = this._importDetailedArray.bind(this);
|
this._importDetailedArray = this._importDetailedArray.bind(this);
|
||||||
this._importTextBuild = this._importTextBuild.bind(this);
|
this._importTextBuild = this._importTextBuild.bind(this);
|
||||||
this._importCompanionApiBuild = this._importCompanionApiBuild.bind(this);
|
this._importCompanionApiBuild = this._importCompanionApiBuild.bind(this);
|
||||||
this._validateImport = this._validateImport.bind(this);
|
this._validateImport = this._validateImport.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Import a Loadout event from Elite: Dangerous journal files
|
|
||||||
* @param {Object} data Loadout event
|
|
||||||
* @throws {string} If import fails
|
|
||||||
*/
|
|
||||||
_importLoadout(data) {
|
|
||||||
if (data && data.Ship && data.Modules) {
|
|
||||||
const deflated = zlib.deflate(JSON.stringify(data), { to: 'string' });
|
|
||||||
let compressed = btoa(deflated);
|
|
||||||
this.setState({loadoutEvent: compressed});
|
|
||||||
} else {
|
|
||||||
throw 'Loadout event must contain Ship and Modules';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Import a Coriolis backup
|
* Import a Coriolis backup
|
||||||
* @param {Object} importData Backup Data
|
* @param {Object} importData Backup Data
|
||||||
@@ -180,7 +159,7 @@ export default class ModalImport extends TranslatedComponent {
|
|||||||
}
|
}
|
||||||
// Check for module discount
|
// Check for module discount
|
||||||
if (!isNaN(importData.moduleDiscount)) {
|
if (!isNaN(importData.moduleDiscount)) {
|
||||||
this.setState({ moduleDiscount: importData.moduleDiscount * 1 });
|
this.setState({ shipDiscount: importData.moduleDiscount * 1 });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof importData.insurance == 'string') {
|
if (typeof importData.insurance == 'string') {
|
||||||
@@ -216,8 +195,8 @@ export default class ModalImport extends TranslatedComponent {
|
|||||||
* @throws {string} if parse/import fails
|
* @throws {string} if parse/import fails
|
||||||
*/
|
*/
|
||||||
_importCompanionApiBuild(build) {
|
_importCompanionApiBuild(build) {
|
||||||
const shipModel = shipModelFromJson(build);
|
const shipModel = CompanionApiUtils.shipModelFromJson(build);
|
||||||
const ship = shipFromJson(build);
|
const ship = CompanionApiUtils.shipFromJson(build);
|
||||||
|
|
||||||
let builds = {};
|
let builds = {};
|
||||||
builds[shipModel] = {};
|
builds[shipModel] = {};
|
||||||
@@ -323,30 +302,6 @@ export default class ModalImport extends TranslatedComponent {
|
|||||||
this.setState({ builds, singleBuild: true });
|
this.setState({ builds, singleBuild: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Import SLEF formatted builds. Sets state to a map of the builds on success
|
|
||||||
* and flags if there was only a single build.
|
|
||||||
*
|
|
||||||
* @param {string} importData - Array of the list of builds.
|
|
||||||
* @throws {string} If parse / import fails
|
|
||||||
*/
|
|
||||||
_importSlefBuilds(importData) {
|
|
||||||
const builds = importData.reduce((memo, { data }) => {
|
|
||||||
const shipModel = shipModelFromJson(data);
|
|
||||||
const ship = shipFromLoadoutJSON(data);
|
|
||||||
const shipTemplate = Ships[shipModel];
|
|
||||||
const shipName = data.ShipName || shipTemplate.properties.name;
|
|
||||||
|
|
||||||
const key = `Imported ${shipName}`;
|
|
||||||
memo[shipModel] = {};
|
|
||||||
memo[shipModel][key] = ship.toString();
|
|
||||||
|
|
||||||
return memo;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
this.setState({ builds, singleBuild: Object.keys(builds).length === 1 });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate the import string / text box contents
|
* Validate the import string / text box contents
|
||||||
* @param {SyntheticEvent} event Event
|
* @param {SyntheticEvent} event Event
|
||||||
@@ -381,10 +336,8 @@ export default class ModalImport extends TranslatedComponent {
|
|||||||
throw 'Must be an object or array!';
|
throw 'Must be an object or array!';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (importData?.[0]?.header?.appName) { // has SLEF envelope?
|
if (importData.modules != null && importData.modules.Armour != null) { // Only the companion API has this information
|
||||||
this._importSlefBuilds(importData);
|
this._importCompanionApiBuild(importData); // Single sihp definition
|
||||||
} else if (importData.modules != null && importData.modules.Armour != null) { // Only the companion API has this information
|
|
||||||
this._importCompanionApiBuild(importData); // Single ship definition
|
|
||||||
} else if (importData.ship != null && importData.ship.modules != null && importData.ship.modules.Armour != null) { // Only the companion API has this information
|
} else if (importData.ship != null && importData.ship.modules != null && importData.ship.modules.Armour != null) { // Only the companion API has this information
|
||||||
this._importCompanionApiBuild(importData.ship); // Complete API dump
|
this._importCompanionApiBuild(importData.ship); // Complete API dump
|
||||||
} else if (importData instanceof Array) { // Must be detailed export json
|
} else if (importData instanceof Array) { // Must be detailed export json
|
||||||
@@ -392,14 +345,12 @@ export default class ModalImport extends TranslatedComponent {
|
|||||||
} else if (importData.ship && typeof importData.name !== undefined) { // Using JSON from a single ship build export
|
} else if (importData.ship && typeof importData.name !== undefined) { // Using JSON from a single ship build export
|
||||||
this._importDetailedArray([importData]); // Convert to array with singleobject
|
this._importDetailedArray([importData]); // Convert to array with singleobject
|
||||||
this.setState({ singleBuild: true });
|
this.setState({ singleBuild: true });
|
||||||
} else if (importData.Modules != null && importData.Modules[0] != null) {
|
|
||||||
this._importLoadout(importData);
|
|
||||||
} else { // Using Backup JSON
|
} else { // Using Backup JSON
|
||||||
this._importBackup(importData);
|
this._importBackup(importData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
// console.log(e.stack);
|
||||||
this.setState({ errorMsg: (typeof e == 'string') ? e : 'Cannot Parse the data!' });
|
this.setState({ errorMsg: (typeof e == 'string') ? e : 'Cannot Parse the data!' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -413,10 +364,6 @@ export default class ModalImport extends TranslatedComponent {
|
|||||||
_process() {
|
_process() {
|
||||||
let builds = null, comparisons = null;
|
let builds = null, comparisons = null;
|
||||||
|
|
||||||
if (this.state.loadoutEvent) {
|
|
||||||
return Router.go(`/import?data=${this.state.loadoutEvent}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If only importing a single build go straight to the outfitting page
|
// If only importing a single build go straight to the outfitting page
|
||||||
if (this.state.singleBuild) {
|
if (this.state.singleBuild) {
|
||||||
builds = this.state.builds;
|
builds = this.state.builds;
|
||||||
@@ -533,7 +480,7 @@ export default class ModalImport extends TranslatedComponent {
|
|||||||
if (!state.processed) {
|
if (!state.processed) {
|
||||||
importStage = (
|
importStage = (
|
||||||
<div>
|
<div>
|
||||||
<textarea spellCheck={false} className='cb json' ref={node => this.importField = node} onChange={this._validateImport} defaultValue={this.state.importString} placeholder={translate('PHRASE_IMPORT')} />
|
<textarea className='cb json' ref={node => this.importField = node} onChange={this._validateImport} defaultValue={this.state.importString} placeholder={translate('PHRASE_IMPORT')} />
|
||||||
<button id='proceed' className='l cap' onClick={this._process} disabled={!state.importValid} >{translate('proceed')}</button>
|
<button id='proceed' className='l cap' onClick={this._process} disabled={!state.importValid} >{translate('proceed')}</button>
|
||||||
<div className='l warning' style={{ marginLeft:'3em' }}>{state.errorMsg}</div>
|
<div className='l warning' style={{ marginLeft:'3em' }}>{state.errorMsg}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -570,7 +517,7 @@ export default class ModalImport extends TranslatedComponent {
|
|||||||
{comparisonRows}
|
{comparisonRows}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.state.canEdit) {
|
if(this.state.canEdit) {
|
||||||
|
|||||||
141
src/app/components/ModalOrbis.jsx
Normal file
141
src/app/components/ModalOrbis.jsx
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
|
import { orbisUpload } from '../utils/ShortenUrl';
|
||||||
|
import Persist from '../stores/Persist';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Permalink modal
|
||||||
|
*/
|
||||||
|
export default class ModalOrbis extends TranslatedComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
ship: PropTypes.any.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param {Object} props React Component properties
|
||||||
|
*/
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
orbisCreds: Persist.getOrbisCreds(),
|
||||||
|
orbisUrl: '...',
|
||||||
|
ship: this.props.ship,
|
||||||
|
authenticatedStatus: 'Checking...'
|
||||||
|
};
|
||||||
|
this.orbisCategory = this.orbisCategory.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send ship to Orbis.zone
|
||||||
|
* @param {SyntheticEvent} e React Event
|
||||||
|
*/
|
||||||
|
sendToOrbis(e) {
|
||||||
|
const target = e.target;
|
||||||
|
target.disabled = true;
|
||||||
|
this.setState({ orbisUrl: 'Sending...' }, () => {
|
||||||
|
orbisUpload(this.props.ship, this.state.orbisCreds)
|
||||||
|
.then(orbisUrl => {
|
||||||
|
target.disabled = false;
|
||||||
|
this.setState({ orbisUrl });
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
target.disabled = false;
|
||||||
|
this.setState({ orbisUrl: 'Error - ' + err });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Orbis.zone auth status
|
||||||
|
* @returns {Object} auth status
|
||||||
|
*/
|
||||||
|
getOrbisAuthStatus() {
|
||||||
|
return fetch('https://orbis.zone/api/checkauth', {
|
||||||
|
credentials: 'include',
|
||||||
|
mode: 'cors'
|
||||||
|
})
|
||||||
|
.then(data => data.json())
|
||||||
|
.then(res => {
|
||||||
|
this.setState({ authenticatedStatus: res.status || res.error });
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
this.setState({ authenticatedStatus: err.message });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for changing cmdr name
|
||||||
|
* @param {SyntheticEvent} e React Event
|
||||||
|
*/
|
||||||
|
orbisPasswordHandler(e) {
|
||||||
|
let password = e.target.value;
|
||||||
|
this.setState({ orbisCreds: { email: this.state.orbisCreds.email, password } }, () => {
|
||||||
|
Persist.setOrbisCreds(this.state.orbisCreds);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for changing cmdr name
|
||||||
|
* @param {SyntheticEvent} e React Event
|
||||||
|
*/
|
||||||
|
orbisUsername(e) {
|
||||||
|
let orbisUsername = e.target.value;
|
||||||
|
this.setState({ orbisCreds: { email: orbisUsername, password: this.state.orbisCreds.password } }, () => {
|
||||||
|
Persist.setOrbisCreds(this.state.orbisCreds);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for changing category
|
||||||
|
* @param {SyntheticEvent} e React Event
|
||||||
|
*/
|
||||||
|
orbisCategory(e) {
|
||||||
|
let ship = this.state.ship;
|
||||||
|
let cat = e.target.value;
|
||||||
|
ship.category = cat;
|
||||||
|
this.setState({ship});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the modal
|
||||||
|
* @return {React.Component} Modal Content
|
||||||
|
*/
|
||||||
|
render() {
|
||||||
|
let translate = this.context.language.translate;
|
||||||
|
this.orbisPasswordHandler = this.orbisPasswordHandler.bind(this);
|
||||||
|
this.orbisUsername = this.orbisUsername.bind(this);
|
||||||
|
this.sendToOrbis = this.sendToOrbis.bind(this);
|
||||||
|
this.getOrbisAuthStatus();
|
||||||
|
return <div className='modal' onClick={ (e) => e.stopPropagation() }>
|
||||||
|
<h2>{translate('upload to orbis')}</h2>
|
||||||
|
<br/>
|
||||||
|
<label>Orbis auth status: </label>
|
||||||
|
<input value={this.state.authenticatedStatus} readOnly size={25} onFocus={ (e) => e.target.select() }/>
|
||||||
|
<br/><br/>
|
||||||
|
<a className='button' href="https://orbis.zone/api/auth">Log in / signup to Orbis</a>
|
||||||
|
<br/><br/>
|
||||||
|
<h3>Category</h3>
|
||||||
|
<select onChange={this.orbisCategory}>
|
||||||
|
<option value="">No Category</option>
|
||||||
|
<option>Combat</option>
|
||||||
|
<option>Mining</option>
|
||||||
|
<option>Trading</option>
|
||||||
|
<option>Exploration</option>
|
||||||
|
<option>Passenger Liner</option>
|
||||||
|
<option>PvP</option>
|
||||||
|
</select>
|
||||||
|
<br/><br/>
|
||||||
|
<h3 >{translate('Orbis link')}</h3>
|
||||||
|
<input value={this.state.orbisUrl} readOnly size={25} onFocus={ (e) => e.target.select() }/>
|
||||||
|
<br/><br/>
|
||||||
|
<p>Orbis.zone is currently in a trial period, and may be wiped at any time as development progresses. Some elements are also still placeholders.</p>
|
||||||
|
<button className={'l cb dismiss cap'} disabled={!!this.state.failed} onClick={this.sendToOrbis}>{translate('PHASE_UPLOAD_ORBIS')}</button>
|
||||||
|
<button className={'r dismiss cap'} onClick={this.context.hideModal}>{translate('close')}</button>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,8 +3,6 @@ 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
|
||||||
@@ -58,6 +56,7 @@ 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) {
|
||||||
@@ -110,18 +109,17 @@ export default class ModalShoppingList extends TranslatedComponent {
|
|||||||
*/
|
*/
|
||||||
sendToEDEng(event) {
|
sendToEDEng(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let translate = this.context.language.translate;
|
|
||||||
const target = event.target;
|
const target = event.target;
|
||||||
target.disabled = this.state.blueprints.length > 0;
|
target.disabled = this.state.blueprints.length > 0;
|
||||||
if (this.state.blueprints.length === 0) {
|
if (this.state.blueprints.length === 0) {
|
||||||
target.innerText = translate('No modded components.');
|
target.innerText = 'No modded components.';
|
||||||
target.disabled = true;
|
target.disabled = true;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
target.innerText = translate('Send to EDEngineer');
|
target.innerText = 'Send to EDEngineer';
|
||||||
target.disabled = false;
|
target.disabled = false;
|
||||||
}, 3000);
|
}, 3000);
|
||||||
} else {
|
} else {
|
||||||
target.innerText = translate('Sending...');
|
target.innerText = 'Sending...';
|
||||||
}
|
}
|
||||||
let countSent = 0;
|
let countSent = 0;
|
||||||
let countTotal = this.state.blueprints.length;
|
let countTotal = this.state.blueprints.length;
|
||||||
@@ -141,70 +139,12 @@ export default class ModalShoppingList extends TranslatedComponent {
|
|||||||
countSent++;
|
countSent++;
|
||||||
if (countSent === countTotal) {
|
if (countSent === countTotal) {
|
||||||
target.disabled = false;
|
target.disabled = false;
|
||||||
target.innerText = translate('Send to EDEngineer');
|
target.innerText = 'Send to EDEngineer';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
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) {
|
|
||||||
blueprints.push({
|
|
||||||
"item": module.m.symbol,
|
|
||||||
"blueprint": module.m.blueprint.special.edname
|
|
||||||
});
|
|
||||||
}
|
|
||||||
for (const g in module.m.blueprint.grades) {
|
|
||||||
if (!module.m.blueprint.grades.hasOwnProperty(g)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (g < module.m.blueprint.grade) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
blueprints.push({
|
|
||||||
"item": module.m.symbol,
|
|
||||||
"blueprint": module.m.blueprint.fdname,
|
|
||||||
"grade": module.m.blueprint.grade,
|
|
||||||
"highestGradePercentage":1.0
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//create JSON to encode
|
|
||||||
let baseJson = {
|
|
||||||
"version":1,
|
|
||||||
"name":ship.name, // 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
|
||||||
*/
|
*/
|
||||||
@@ -236,18 +176,6 @@ export default class ModalShoppingList extends TranslatedComponent {
|
|||||||
mats[i] = module.m.blueprint.grades[g].components[i] * this.state.matsPerGrade[g];
|
mats[i] = module.m.blueprint.grades[g].components[i] * this.state.matsPerGrade[g];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -300,36 +228,34 @@ 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>
|
<h2>{translate('PHRASE_SHOPPING_MATS')}</h2>
|
||||||
<label>{translate('Grade 1 rolls ')}</label>
|
<label>Grade 1 rolls </label>
|
||||||
<input id={1} type={'number'} min={0} defaultValue={this.state.matsPerGrade[1]} onChange={this.changeHandler} />
|
<input id={1} type={'number'} min={0} defaultValue={this.state.matsPerGrade[1]} onChange={this.changeHandler} />
|
||||||
<br/>
|
<br/>
|
||||||
<label>{translate('Grade 2 rolls ')}</label>
|
<label>Grade 2 rolls </label>
|
||||||
<input id={2} type={'number'} min={0} defaultValue={this.state.matsPerGrade[2]} onChange={this.changeHandler} />
|
<input id={2} type={'number'} min={0} defaultValue={this.state.matsPerGrade[2]} onChange={this.changeHandler} />
|
||||||
<br/>
|
<br/>
|
||||||
<label>{translate('Grade 3 rolls ')}</label>
|
<label>Grade 3 rolls </label>
|
||||||
<input id={3} type={'number'} min={0} value={this.state.matsPerGrade[3]} onChange={this.changeHandler} />
|
<input id={3} type={'number'} min={0} value={this.state.matsPerGrade[3]} onChange={this.changeHandler} />
|
||||||
<br/>
|
<br/>
|
||||||
<label>{translate('Grade 4 rolls ')}</label>
|
<label>Grade 4 rolls </label>
|
||||||
<input id={4} type={'number'} min={0} value={this.state.matsPerGrade[4]} onChange={this.changeHandler} />
|
<input id={4} type={'number'} min={0} value={this.state.matsPerGrade[4]} onChange={this.changeHandler} />
|
||||||
<br/>
|
<br/>
|
||||||
<label>{translate('Grade 5 rolls ')}</label>
|
<label>Grade 5 rolls </label>
|
||||||
<input id={5} type={'number'} min={0} value={this.state.matsPerGrade[5]} onChange={this.changeHandler} />
|
<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} />
|
<textarea className='cb json' readOnly value={this.state.matsList} />
|
||||||
</div>
|
</div>
|
||||||
<label hidden={!compatible} className={'l cap'}>{translate('CMDR Name')}</label>
|
<label hidden={!compatible} className={'l cap'}>CMDR Name </label>
|
||||||
<br/>
|
<br/>
|
||||||
<select hidden={!compatible} className={'cmdr-select l cap'} onChange={this.cmdrChangeHandler} defaultValue={this.state.cmdrName}>
|
<select hidden={!compatible} className={'cmdr-select l cap'} onChange={this.cmdrChangeHandler} defaultValue={this.state.cmdrName}>
|
||||||
{this.state.cmdrs.map(e => <option key={e}>{e}</option>)}
|
{this.state.cmdrs.map(e => <option key={e}>{e}</option>)}
|
||||||
</select>
|
</select>
|
||||||
<br/>
|
<br/>
|
||||||
<p hidden={!this.state.failed} id={'failed'} className={'l'}>{translate('PHRASE_FAIL_EDENGINEER')}</p>
|
<p hidden={!this.state.failed} id={'failed'} className={'l'}>Failed to send to EDEngineer (Launch EDEngineer and make sure the API is started then refresh the page.)</p>
|
||||||
<p hidden={compatible} id={'browserbad'} className={'l'}>{translate('PHRASE_FIREFOX_EDENGINEER')}</p>
|
<p hidden={compatible} id={'browserbad'} className={'l'}>Sending to EDEngineer is not compatible with Firefox's security settings. Please try again with Chrome.</p>
|
||||||
<button className={'l cb dismiss cap'} disabled={!!this.state.failed || !compatible} onClick={this.sendToEDEng}>{translate('Send to EDEngineer')}</button>
|
<button className={'l cb dismiss cap'} disabled={!!this.state.failed || !compatible} onClick={this.sendToEDEng}>{translate('Send To EDEngineer')}</button>
|
||||||
<button style={{marginTop: 5}} className={'l cb dismiss cap'} disabled={!!this.state.failed} onClick={this.sendToEDOMH}>{translate('Send to EDOMH')}</button>
|
|
||||||
<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,8 +3,7 @@ import PropTypes from 'prop-types';
|
|||||||
import TranslatedComponent from './TranslatedComponent';
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
import cn from 'classnames';
|
import cn from 'classnames';
|
||||||
import NumberEditor from 'react-number-editor';
|
import NumberEditor from 'react-number-editor';
|
||||||
import { isChangeValueBeneficial } from '../utils/BlueprintFunctions';
|
import { isValueBeneficial } from '../utils/BlueprintFunctions';
|
||||||
import { Modifications } from 'coriolis-data/dist';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modification
|
* Modification
|
||||||
@@ -44,7 +43,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);
|
ship.setModification(m, name, value, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +79,6 @@ export default class Modification extends TranslatedComponent {
|
|||||||
let { translate, formats, units } = this.context.language;
|
let { translate, formats, units } = this.context.language;
|
||||||
let { m, name } = this.props;
|
let { m, name } = this.props;
|
||||||
let modValue = m.getChange(name);
|
let modValue = m.getChange(name);
|
||||||
let isOverwrite = Modifications.modifications[name].method === 'overwrite';
|
|
||||||
|
|
||||||
if (name === 'damagedist') {
|
if (name === 'damagedist') {
|
||||||
// We don't show damage distribution
|
// We don't show damage distribution
|
||||||
@@ -119,10 +117,10 @@ export default class Modification extends TranslatedComponent {
|
|||||||
</td>
|
</td>
|
||||||
<td style={{ textAlign: 'center' }} className={
|
<td style={{ textAlign: 'center' }} className={
|
||||||
modValue ?
|
modValue ?
|
||||||
isChangeValueBeneficial(name, modValue) ? 'secondary' : 'warning' :
|
isValueBeneficial(name, modValue) ? 'secondary' : 'warning' :
|
||||||
''
|
''
|
||||||
}>
|
}>
|
||||||
{formats.f2(modValue / 100) || 0}{isOverwrite ? '' : '%'}
|
{formats.f2(modValue / 100) || 0}%
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -436,7 +436,7 @@ export default class ModificationsMenu extends TranslatedComponent {
|
|||||||
let specialLabel;
|
let specialLabel;
|
||||||
let specialTt;
|
let specialTt;
|
||||||
if (m.blueprint && m.blueprint.special) {
|
if (m.blueprint && m.blueprint.special) {
|
||||||
specialLabel = translate(m.blueprint.special.name);
|
specialLabel = m.blueprint.special.name;
|
||||||
specialTt = specialToolTip(translate, m.blueprint.grades[m.blueprint.grade], m.grp, m, m.blueprint.special.edname);
|
specialTt = specialToolTip(translate, m.blueprint.grades[m.blueprint.grade], m.grp, m, m.blueprint.special.edname);
|
||||||
} else {
|
} else {
|
||||||
specialLabel = translate('PHRASE_SELECT_SPECIAL');
|
specialLabel = translate('PHRASE_SELECT_SPECIAL');
|
||||||
@@ -478,7 +478,7 @@ export default class ModificationsMenu extends TranslatedComponent {
|
|||||||
<tbody>
|
<tbody>
|
||||||
{ showRolls ?
|
{ showRolls ?
|
||||||
<tr>
|
<tr>
|
||||||
<td tabIndex="0" className={ cn('section-menu button-inline-menu', { active: false }) }> { translate('mroll') }: </td>
|
<td tabIndex="0" className={ cn('section-menu button-inline-menu', { active: false }) }> { translate('roll') }: </td>
|
||||||
<td tabIndex="0" className={ cn('section-menu button-inline-menu', { active: blueprintCv === 0 }) } style={{ cursor: 'pointer' }} onClick={_rollWorst} onKeyDown={ this._keyDown } onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_WORST')} onMouseOut={tooltip.bind(null, null)}> { translate('0%') } </td>
|
<td tabIndex="0" className={ cn('section-menu button-inline-menu', { active: blueprintCv === 0 }) } style={{ cursor: 'pointer' }} onClick={_rollWorst} onKeyDown={ this._keyDown } onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_WORST')} onMouseOut={tooltip.bind(null, null)}> { translate('0%') } </td>
|
||||||
<td tabIndex="0" className={ cn('section-menu button-inline-menu', { active: blueprintCv === 50 })} style={{ cursor: 'pointer' }} onClick={_rollFifty} onKeyDown={ this._keyDown } onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_FIFTY')} onMouseOut={tooltip.bind(null, null)}> { translate('50%') } </td>
|
<td tabIndex="0" className={ cn('section-menu button-inline-menu', { active: blueprintCv === 50 })} style={{ cursor: 'pointer' }} onClick={_rollFifty} onKeyDown={ this._keyDown } onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_FIFTY')} onMouseOut={tooltip.bind(null, null)}> { translate('50%') } </td>
|
||||||
<td tabIndex="0" className={ cn('section-menu button-inline-menu', { active: blueprintCv === 100 })} style={{ cursor: 'pointer' }} onClick={_rollFull} onKeyDown={ this._keyDown } onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_BEST')} onMouseOut={tooltip.bind(null, null)}> { translate('100%') } </td>
|
<td tabIndex="0" className={ cn('section-menu button-inline-menu', { active: blueprintCv === 100 })} style={{ cursor: 'pointer' }} onClick={_rollFull} onKeyDown={ this._keyDown } onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_BEST')} onMouseOut={tooltip.bind(null, null)}> { translate('100%') } </td>
|
||||||
|
|||||||
@@ -243,13 +243,8 @@ export default class Offence extends TranslatedComponent {
|
|||||||
<td className='ri'><span onMouseOver={termtip.bind(null, baseSDpsTooltipDetails)} onMouseOut={tooltip.bind(null, null)}>{formats.f1(weapon.sdps.base.total)}</span></td>
|
<td className='ri'><span onMouseOver={termtip.bind(null, baseSDpsTooltipDetails)} onMouseOut={tooltip.bind(null, null)}>{formats.f1(weapon.sdps.base.total)}</span></td>
|
||||||
<td className='ri'><span onMouseOver={termtip.bind(null, effectiveShieldsSDpsTooltipDetails)} onMouseOut={tooltip.bind(null, null)}>{formats.f1(weapon.sdps.shields.total)}</span></td>
|
<td className='ri'><span onMouseOver={termtip.bind(null, effectiveShieldsSDpsTooltipDetails)} onMouseOut={tooltip.bind(null, null)}>{formats.f1(weapon.sdps.shields.total)}</span></td>
|
||||||
<td className='ri'><span onMouseOver={termtip.bind(null, effectivenessShieldsTooltipDetails)} onMouseOut={tooltip.bind(null, null)}>{formats.pct1(weapon.effectiveness.shields.total)}</span></td>
|
<td className='ri'><span onMouseOver={termtip.bind(null, effectivenessShieldsTooltipDetails)} onMouseOut={tooltip.bind(null, null)}>{formats.pct1(weapon.effectiveness.shields.total)}</span></td>
|
||||||
|
|
||||||
<td className='ri'><span>{formats.f1(weapon.effectiveness.shields.dpe)}</span></td>
|
|
||||||
|
|
||||||
<td className='ri'><span onMouseOver={termtip.bind(null, effectiveArmourSDpsTooltipDetails)} onMouseOut={tooltip.bind(null, null)}>{formats.f1(weapon.sdps.armour.total)}</span></td>
|
<td className='ri'><span onMouseOver={termtip.bind(null, effectiveArmourSDpsTooltipDetails)} onMouseOut={tooltip.bind(null, null)}>{formats.f1(weapon.sdps.armour.total)}</span></td>
|
||||||
<td className='ri'><span onMouseOver={termtip.bind(null, effectivenessArmourTooltipDetails)} onMouseOut={tooltip.bind(null, null)}>{formats.pct1(weapon.effectiveness.armour.total)}</span></td>
|
<td className='ri'><span onMouseOver={termtip.bind(null, effectivenessArmourTooltipDetails)} onMouseOut={tooltip.bind(null, null)}>{formats.pct1(weapon.effectiveness.armour.total)}</span></td>
|
||||||
|
|
||||||
<td className='ri'><span>{formats.f1(weapon.effectiveness.armour.dpe)}</span></td>
|
|
||||||
</tr>);
|
</tr>);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,20 +271,15 @@ export default class Offence extends TranslatedComponent {
|
|||||||
<tr className='main'>
|
<tr className='main'>
|
||||||
<th rowSpan='2' className='sortable' onClick={sortOrder.bind(this, 'n')}>{translate('weapon')}</th>
|
<th rowSpan='2' className='sortable' onClick={sortOrder.bind(this, 'n')}>{translate('weapon')}</th>
|
||||||
<th colSpan='1'>{translate('overall')}</th>
|
<th colSpan='1'>{translate('overall')}</th>
|
||||||
<th colSpan='3'>{translate('opponent\'s shields')}</th>
|
<th colSpan='2'>{translate('opponent\'s shields')}</th>
|
||||||
<th colSpan='3'>{translate('opponent\'s armour')}</th>
|
<th colSpan='2'>{translate('opponent\'s armour')}</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th className='lft sortable' onMouseOver={termtip.bind(null, 'TT_EFFECTIVE_SDPS_SHIELDS')} onMouseOut={tooltip.bind(null, null)} onClick={sortOrder.bind(this, 'esdpss')}>{'sdps'}</th>
|
<th className='lft sortable' onMouseOver={termtip.bind(null, 'TT_EFFECTIVE_SDPS_SHIELDS')} onMouseOut={tooltip.bind(null, null)} onClick={sortOrder.bind(this, 'esdpss')}>{'sdps'}</th>
|
||||||
<th className='lft sortable' onMouseOver={termtip.bind(null, 'TT_EFFECTIVE_SDPS_SHIELDS')} onMouseOut={tooltip.bind(null, null)} onClick={sortOrder.bind(this, 'esdpss')}>{'sdps'}</th>
|
<th className='lft sortable' onMouseOver={termtip.bind(null, 'TT_EFFECTIVE_SDPS_SHIELDS')} onMouseOut={tooltip.bind(null, null)} onClick={sortOrder.bind(this, 'esdpss')}>{'sdps'}</th>
|
||||||
<th className='sortable' onMouseOver={termtip.bind(null, 'TT_EFFECTIVENESS_SHIELDS')} onMouseOut={tooltip.bind(null, null)}onClick={sortOrder.bind(this, 'es')}>{'eft'}</th>
|
<th className='sortable' onMouseOver={termtip.bind(null, 'TT_EFFECTIVENESS_SHIELDS')} onMouseOut={tooltip.bind(null, null)}onClick={sortOrder.bind(this, 'es')}>{'eft'}</th>
|
||||||
|
|
||||||
<th className='sortable'>{'dpe'}</th>
|
|
||||||
|
|
||||||
<th className='lft sortable' onMouseOver={termtip.bind(null, 'TT_EFFECTIVE_SDPS_ARMOUR')} onMouseOut={tooltip.bind(null, null)}onClick={sortOrder.bind(this, 'esdpsh')}>{'sdps'}</th>
|
<th className='lft sortable' onMouseOver={termtip.bind(null, 'TT_EFFECTIVE_SDPS_ARMOUR')} onMouseOut={tooltip.bind(null, null)}onClick={sortOrder.bind(this, 'esdpsh')}>{'sdps'}</th>
|
||||||
<th className='sortable' onMouseOver={termtip.bind(null, 'TT_EFFECTIVENESS_ARMOUR')} onMouseOut={tooltip.bind(null, null)}onClick={sortOrder.bind(this, 'eh')}>{'eft'}</th>
|
<th className='sortable' onMouseOver={termtip.bind(null, 'TT_EFFECTIVENESS_ARMOUR')} onMouseOut={tooltip.bind(null, null)}onClick={sortOrder.bind(this, 'eh')}>{'eft'}</th>
|
||||||
|
|
||||||
<th className='sortable'>{'dpe'}</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -300,10 +290,8 @@ export default class Offence extends TranslatedComponent {
|
|||||||
<td className='ri'><span onMouseOver={termtip.bind(null, totalSDpsTooltipDetails)} onMouseOut={tooltip.bind(null, null)}>={formats.f1(totalSDps)}</span></td>
|
<td className='ri'><span onMouseOver={termtip.bind(null, totalSDpsTooltipDetails)} onMouseOut={tooltip.bind(null, null)}>={formats.f1(totalSDps)}</span></td>
|
||||||
<td className='ri'><span onMouseOver={termtip.bind(null, totalShieldsSDpsTooltipDetails)} onMouseOut={tooltip.bind(null, null)}>={formats.f1(totalShieldsSDps)}</span></td>
|
<td className='ri'><span onMouseOver={termtip.bind(null, totalShieldsSDpsTooltipDetails)} onMouseOut={tooltip.bind(null, null)}>={formats.f1(totalShieldsSDps)}</span></td>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td></td>
|
|
||||||
<td className='ri'><span onMouseOver={termtip.bind(null, totalArmourSDpsTooltipDetails)} onMouseOut={tooltip.bind(null, null)}>={formats.f1(totalArmourSDps)}</span></td>
|
<td className='ri'><span onMouseOver={termtip.bind(null, totalArmourSDpsTooltipDetails)} onMouseOut={tooltip.bind(null, null)}>={formats.f1(totalArmourSDps)}</span></td>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ export default class OutfittingSubpages extends TranslatedComponent {
|
|||||||
<th style={{ width:'25%' }} className={cn({ active: tab == 'power' })} onClick={this._showTab.bind(this, 'power')} >{translate('power and costs')}</th>
|
<th style={{ width:'25%' }} className={cn({ active: tab == 'power' })} onClick={this._showTab.bind(this, 'power')} >{translate('power and costs')}</th>
|
||||||
<th style={{ width:'25%' }} className={cn({ active: tab == 'profiles' })} onClick={this._showTab.bind(this, 'profiles')} >{translate('profiles')}</th>
|
<th style={{ width:'25%' }} className={cn({ active: tab == 'profiles' })} onClick={this._showTab.bind(this, 'profiles')} >{translate('profiles')}</th>
|
||||||
<th style={{ width:'25%' }} className={cn({ active: tab == 'offence' })} onClick={this._showTab.bind(this, 'offence')} >{translate('offence')}</th>
|
<th style={{ width:'25%' }} className={cn({ active: tab == 'offence' })} onClick={this._showTab.bind(this, 'offence')} >{translate('offence')}</th>
|
||||||
<th style={{ width:'25%' }} className={cn({ active: tab == 'defence' })} onClick={this._showTab.bind(this, 'defence')} >{translate('tab_defence')}</th>
|
<th style={{ width:'25%' }} className={cn({ active: tab == 'defence' })} onClick={this._showTab.bind(this, 'defence')} >{translate('defence')}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -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 'auto-bind';
|
import { autoBind } from 'react-extras';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ export default class ShipSummaryTable extends TranslatedComponent {
|
|||||||
const speedTooltip = canThrust ? 'TT_SUMMARY_SPEED' : 'TT_SUMMARY_SPEED_NONFUNCTIONAL';
|
const speedTooltip = canThrust ? 'TT_SUMMARY_SPEED' : 'TT_SUMMARY_SPEED_NONFUNCTIONAL';
|
||||||
const canBoost = ship.canBoost(cargo, ship.fuelCapacity);
|
const canBoost = ship.canBoost(cargo, ship.fuelCapacity);
|
||||||
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 sgMetrics = Calc.shieldMetrics(ship, pips.sys);
|
const sgMetrics = Calc.shieldMetrics(ship, pips.sys);
|
||||||
const shipBoost = canBoost ? Calc.calcBoost(ship) : 'No Boost';
|
const shipBoost = canBoost ? Calc.calcBoost(ship) : 'No Boost';
|
||||||
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);
|
||||||
@@ -72,7 +71,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 colSpan={5} className={ cn({ 'bg-warning-disabled': !canJump }) }>{translate('jump range')}</th>
|
<th colSpan={5}>{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>
|
||||||
<th rowSpan={2}>{translate('DPS')}</th>
|
<th rowSpan={2}>{translate('DPS')}</th>
|
||||||
@@ -86,15 +85,15 @@ 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 onMouseEnter={termtip.bind(null, 'TT_SUMMARY_BOOST_TIME', { cap: 0 })} onMouseLeave={hide} rowSpan={2}>{translate('boost time')}</th>
|
||||||
<th rowSpan={2}>{translate('resting heat (Beta)')}</th>
|
<th rowSpan={2}>{translate('resting heat (Beta)')}</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th className={ cn({ 'lft': true, 'bg-warning-disabled': !canJump }) }>{translate('max')}</th>
|
<th className='lft'>{translate('max')}</th>
|
||||||
<th className={ cn({ 'bg-warning-disabled': !canJump }) }>{translate('unladen')}</th>
|
<th>{translate('unladen')}</th>
|
||||||
<th className={ cn({ 'bg-warning-disabled': !canJump }) }>{translate('laden')}</th>
|
<th>{translate('laden')}</th>
|
||||||
<th className={ cn({ 'bg-warning-disabled': !canJump }) }>{translate('total unladen')}</th>
|
<th>{translate('total unladen')}</th>
|
||||||
<th className={ cn({ 'bg-warning-disabled': !canJump }) }>{translate('total laden')}</th>
|
<th>{translate('total laden')}</th>
|
||||||
<th className='lft'>{translate('hull')}</th>
|
<th className='lft'>{translate('hull')}</th>
|
||||||
<th>{translate('unladen')}</th>
|
<th>{translate('unladen')}</th>
|
||||||
<th>{translate('laden')}</th>
|
<th>{translate('laden')}</th>
|
||||||
@@ -104,11 +103,11 @@ 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><span onMouseEnter={termtip.bind(null, 'TT_SUMMARY_MAX_SINGLE_JUMP', { cap: 0 })} onMouseLeave={hide}>{f2(Calc.jumpRange(ship.unladenMass + ship.standard[2].m.getMaxFuelPerJump(), ship.standard[2].m, ship.standard[2].m.getMaxFuelPerJump(), ship))}{u.LY}</span></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><span onMouseEnter={termtip.bind(null, 'TT_SUMMARY_UNLADEN_SINGLE_JUMP', { cap: 0 })} onMouseLeave={hide}>{f2(Calc.jumpRange(ship.unladenMass + ship.fuelCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}</span></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><span onMouseEnter={termtip.bind(null, 'TT_SUMMARY_LADEN_SINGLE_JUMP', { cap: 0 })} onMouseLeave={hide}>{f2(Calc.jumpRange(ship.unladenMass + ship.fuelCapacity + ship.cargoCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}</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_TOTAL_JUMP', { cap: 0 })} onMouseLeave={hide}>{f2(Calc.totalJumpRange(ship.unladenMass + ship.fuelCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}</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_TOTAL_JUMP', { cap: 0 })} onMouseLeave={hide}>{f2(Calc.totalJumpRange(ship.unladenMass + ship.fuelCapacity + ship.cargoCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}</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>
|
||||||
@@ -160,10 +159,10 @@ export default class ShipSummaryTable extends TranslatedComponent {
|
|||||||
<td>{formats.pct1(ship.shieldThermRes)}</td>
|
<td>{formats.pct1(ship.shieldThermRes)}</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
|
|
||||||
<td>{int(ship && sgMetrics.summary > 0 ? sgMetrics.summary : 0)}{u.MJ}</td>
|
<td>{int(ship && ship.shield > 0 ? ship.shield : 0)}{u.MJ}</td>
|
||||||
<td>{int(ship && sgMetrics.summary > 0 ? sgMetrics.summary / sgMetrics.explosive.base : 0)}{u.MJ}</td>
|
<td>{int(ship && ship.shield > 0 ? ship.shield * ((1 / (1 - (ship.shieldExplRes)))) : 0)}{u.MJ}</td>
|
||||||
<td>{int(ship && sgMetrics.summary ? sgMetrics.summary / sgMetrics.kinetic.base : 0)}{u.MJ}</td>
|
<td>{int(ship && ship.shield > 0 ? ship.shield * ((1 / (1 - (ship.shieldKinRes)))) : 0)}{u.MJ}</td>
|
||||||
<td>{int(ship && sgMetrics.summary ? sgMetrics.summary / sgMetrics.thermal.base : 0)}{u.MJ}</td>
|
<td>{int(ship && ship.shield > 0 ? ship.shield * ((1 / (1 - (ship.shieldThermRes)))) : 0)}{u.MJ}</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td>{sgMetrics && sgMetrics.recover === Math.Inf ? translate('Never') : formats.time(sgMetrics.recover)}</td>
|
<td>{sgMetrics && sgMetrics.recover === Math.Inf ? translate('Never') : formats.time(sgMetrics.recover)}</td>
|
||||||
<td>{sgMetrics && sgMetrics.recharge === Math.Inf ? translate('Never') : formats.time(sgMetrics.recharge)}</td>
|
<td>{sgMetrics && sgMetrics.recharge === Math.Inf ? translate('Never') : formats.time(sgMetrics.recharge)}</td>
|
||||||
@@ -198,11 +197,11 @@ export default class ShipSummaryTable extends TranslatedComponent {
|
|||||||
<td>{formats.pct1(ship.hullKinRes)}</td>
|
<td>{formats.pct1(ship.hullKinRes)}</td>
|
||||||
<td>{formats.pct1(ship.hullThermRes)}</td>
|
<td>{formats.pct1(ship.hullThermRes)}</td>
|
||||||
<td>{formats.pct1(ship.hullCausRes)}</td>
|
<td>{formats.pct1(ship.hullCausRes)}</td>
|
||||||
<td>{int(armourMetrics.total)}</td>
|
<td>{int(ship.armour)}</td>
|
||||||
<td>{int(armourMetrics.total / armourMetrics.explosive.total)}</td>
|
<td>{int(ship.armour * ((1 / (1 - (ship.hullExplRes)))))}</td>
|
||||||
<td>{int(armourMetrics.total/ armourMetrics.kinetic.total)}</td>
|
<td>{int(ship.armour * ((1 / (1 - (ship.hullKinRes)))))}</td>
|
||||||
<td>{int(armourMetrics.total / armourMetrics.thermal.total)}</td>
|
<td>{int(ship.armour * ((1 / (1 - (ship.hullThermRes)))))}</td>
|
||||||
<td>{int(armourMetrics.total/ armourMetrics.caustic.total)}</td>
|
<td>{int(ship.armour * ((1 / (1 - (ship.hullCausRes)))))}</td>
|
||||||
<td>{int(armourMetrics.modulearmour)}</td>
|
<td>{int(armourMetrics.modulearmour)}</td>
|
||||||
<td>{int(armourMetrics.moduleprotection * 100) + '%'}</td>
|
<td>{int(armourMetrics.moduleprotection * 100) + '%'}</td>
|
||||||
|
|
||||||
|
|||||||
@@ -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,7 +99,6 @@ 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
|
||||||
@@ -109,11 +108,6 @@ 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 = '';
|
||||||
@@ -133,8 +127,8 @@ export default class Slot extends TranslatedComponent {
|
|||||||
menu = <AvailableModulesMenu
|
menu = <AvailableModulesMenu
|
||||||
className={this._getClassNames()}
|
className={this._getClassNames()}
|
||||||
modules={availableModules()}
|
modules={availableModules()}
|
||||||
|
shipMass={ship.hullMass}
|
||||||
m={m}
|
m={m}
|
||||||
ship={ship}
|
|
||||||
onSelect={onSelect}
|
onSelect={onSelect}
|
||||||
warning={warning}
|
warning={warning}
|
||||||
diffDetails={diffDetails.bind(ship, this.context.language)}
|
diffDetails={diffDetails.bind(ship, this.context.language)}
|
||||||
@@ -144,16 +138,13 @@ 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>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -195,15 +195,6 @@ export default class SlotSection extends TranslatedComponent {
|
|||||||
if (targetSlot && canMount(this.props.ship, targetSlot, m.grp, m.class)) {
|
if (targetSlot && canMount(this.props.ship, targetSlot, m.grp, m.class)) {
|
||||||
const mCopy = m.clone();
|
const mCopy = m.clone();
|
||||||
this.props.ship.use(targetSlot, mCopy, false);
|
this.props.ship.use(targetSlot, mCopy, false);
|
||||||
let experimentalNum = this.props.ship.hardpoints
|
|
||||||
.filter(s => s.m && s.m.experimental).length;
|
|
||||||
// Remove the module on the last slot if we now exceed the number of
|
|
||||||
// experimentals allowed
|
|
||||||
if (m.experimental && 4 < experimentalNum) {
|
|
||||||
this.props.ship.updateStats(originSlot, null, originSlot.m);
|
|
||||||
originSlot.m = null; // Empty the slot
|
|
||||||
originSlot.discountedCost = 0;
|
|
||||||
}
|
|
||||||
// Copy power info
|
// Copy power info
|
||||||
targetSlot.enabled = originSlot.enabled;
|
targetSlot.enabled = originSlot.enabled;
|
||||||
targetSlot.priority = originSlot.priority;
|
targetSlot.priority = originSlot.priority;
|
||||||
|
|||||||
@@ -93,11 +93,6 @@ 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) {
|
||||||
@@ -114,8 +109,8 @@ export default class StandardSlot extends TranslatedComponent {
|
|||||||
menu = <AvailableModulesMenu
|
menu = <AvailableModulesMenu
|
||||||
className='standard'
|
className='standard'
|
||||||
modules={modules}
|
modules={modules}
|
||||||
|
shipMass={ModuleUtils.isShieldGenerator(m.grp) ? ship.hullMass : ship.unladenMass}
|
||||||
m={m}
|
m={m}
|
||||||
ship={ship}
|
|
||||||
onSelect={onSelect}
|
onSelect={onSelect}
|
||||||
warning={warning}
|
warning={warning}
|
||||||
diffDetails={diffDetails.bind(ship, this.context.language)}
|
diffDetails={diffDetails.bind(ship, this.context.language)}
|
||||||
@@ -129,7 +124,7 @@ 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} {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={'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={'r'}>{formats.round(mass)}{units.T}</div>
|
<div className={'r'}>{formats.round(mass)}{units.T}</div>
|
||||||
<div/>
|
<div/>
|
||||||
<div className={'cb'}>
|
<div className={'cb'}>
|
||||||
@@ -149,8 +144,7 @@ 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 }
|
||||||
{ m.getInfo() ? <div className='l'>{translate(m.getInfo())}</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='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>
|
||||||
|
|||||||
@@ -20,16 +20,28 @@ export default class StandardSlotSection extends SlotSection {
|
|||||||
super(props, context, 'standard', 'core internal');
|
super(props, context, 'standard', 'core internal');
|
||||||
this._optimizeStandard = this._optimizeStandard.bind(this);
|
this._optimizeStandard = this._optimizeStandard.bind(this);
|
||||||
this._selectBulkhead = this._selectBulkhead.bind(this);
|
this._selectBulkhead = this._selectBulkhead.bind(this);
|
||||||
|
this._showDW2Menu = this._showDW2Menu.bind(this);
|
||||||
|
this._dw2 = this._dw2.bind(this);
|
||||||
this.selectedRefId = null;
|
this.selectedRefId = null;
|
||||||
this.firstRefId = 'maxjump';
|
this.firstRefId = 'maxjump';
|
||||||
this.lastRefId = 'racer';
|
this.lastRefId = 'dw2';
|
||||||
|
this.state = {
|
||||||
|
showDW2: false,
|
||||||
|
DW2Tier: -1,
|
||||||
|
DW2Eng: -1,
|
||||||
|
DW2Role: '',
|
||||||
|
DW2Gfsb: false,
|
||||||
|
DW2Gpp: false,
|
||||||
|
DW2Fighter: false
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle focus if the component updates
|
* Handle focus if the component updates
|
||||||
* @param {Object} prevProps React Component properties
|
* @param {Object} prevProps React Component properties
|
||||||
*/
|
*/
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
this._handleSectionFocus(prevProps,this.firstRefId, this.lastRefId);
|
this._handleSectionFocus(prevProps, this.firstRefId, this.lastRefId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,6 +84,114 @@ export default class StandardSlotSection extends SlotSection {
|
|||||||
this._close();
|
this._close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DW2 Build
|
||||||
|
*/
|
||||||
|
_dw2() {
|
||||||
|
this.selectedRefId = 'dw2';
|
||||||
|
this.setState({ showDW2: false });
|
||||||
|
ShipRoles.dw2Build(this.props.ship, this.state.DW2Tier, this.state.DW2Eng, this.state.DW2Role, this.state.DW2Gfsb, this.state.DW2Gpp, this.state.DW2Fighter);
|
||||||
|
this.props.ship.updateModificationsString();
|
||||||
|
this.props.onChange();
|
||||||
|
this.props.onCargoChange(this.props.ship.cargoCapacity);
|
||||||
|
this.props.onFuelChange(this.props.ship.fuelCapacity);
|
||||||
|
this._close();
|
||||||
|
}
|
||||||
|
|
||||||
|
_showDW2Menu(translate) {
|
||||||
|
return (
|
||||||
|
<div className='select' onClick={(e) => e.stopPropagation()} onContextMenu={stopCtxPropagation}>
|
||||||
|
<div className='select-group cap'>{translate('Tier')}</div>
|
||||||
|
<ul id={'tier'}>
|
||||||
|
<li className={cn({ active: this.state.DW2Tier === 1 }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Tier: 1 })} onKeyDown={this._keyDown}
|
||||||
|
>{translate('1 - Max. Jump Range, Unshielded')}</li>
|
||||||
|
<li className={cn({ active: this.state.DW2Tier === 2 }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Tier: 2 })} onKeyDown={this._keyDown}
|
||||||
|
>{translate('2 - Max. Jump Range, Minimal Shields')}</li>
|
||||||
|
<li className={cn({ active: this.state.DW2Tier === 3 }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Tier: 3 })} onKeyDown={this._keyDown}
|
||||||
|
>{translate('3 - Max. Jump Range, Optimal Shields')}</li>
|
||||||
|
<li className={cn({ active: this.state.DW2Tier === 4 }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Tier: 4 })} onKeyDown={this._keyDown}
|
||||||
|
>{translate('4 - Max. Jump Range, Optimal Shields & Thrusters')}</li>
|
||||||
|
</ul>
|
||||||
|
<hr/>
|
||||||
|
<div className='select-group cap'>{translate('Engineering Level')}</div>
|
||||||
|
<ul id={'engLevel'}>
|
||||||
|
<li className={cn({ active: this.state.DW2Eng === 1 }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Eng: 1 })} onKeyDown={this._keyDown}
|
||||||
|
>{translate('No engineering')}</li>
|
||||||
|
<li className={cn({ active: this.state.DW2Eng === 2 }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Eng: 2 })} onKeyDown={this._keyDown}
|
||||||
|
>{translate('Only Felicity Farseer and Elvira Martuuk')}</li>
|
||||||
|
<li className={cn({ active: this.state.DW2Eng === 3 }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Eng: 3 })} onKeyDown={this._keyDown}
|
||||||
|
>{translate('All exploration engineers')}</li>
|
||||||
|
</ul>
|
||||||
|
<hr/>
|
||||||
|
<div className='select-group cap'>{translate('Role')}</div>
|
||||||
|
<ul id={'role'}>
|
||||||
|
<li className={cn({ active: this.state.DW2Role === 'exploration' }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Role: 'exploration' })}
|
||||||
|
onKeyDown={this._keyDown}
|
||||||
|
>{translate('Space exploration')}</li>
|
||||||
|
<li className={cn({ active: this.state.DW2Role === 'surface' }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Role: 'surface' })}
|
||||||
|
onKeyDown={this._keyDown}
|
||||||
|
>{translate('Surface exploration')}</li>
|
||||||
|
<li className={cn({ active: this.state.DW2Role === 'materialProspector' }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Role: 'materialProspector' })}
|
||||||
|
onKeyDown={this._keyDown}
|
||||||
|
>{translate('Material prospector')}</li>
|
||||||
|
<li className={cn({ active: this.state.DW2Role === 'propectorMining' }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Role: 'propectorMining' })}
|
||||||
|
onKeyDown={this._keyDown}
|
||||||
|
>{translate('Prospector/Sapper Miner')}</li>
|
||||||
|
<li className={cn({ active: this.state.DW2Role === 'bigRigMining' }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Role: 'bigRigMining' })}
|
||||||
|
onKeyDown={this._keyDown}
|
||||||
|
>{translate('Big Rig, full mining')}</li>
|
||||||
|
<li className={cn({ active: this.state.DW2Role === 'fuelRat' }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Role: 'fuelRat' })} onKeyDown={this._keyDown}
|
||||||
|
>{translate('Fuel Rat')}</li>
|
||||||
|
<li className={cn({ active: this.state.DW2Role === 'mechanic' }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Role: 'mechanic' })} onKeyDown={this._keyDown}
|
||||||
|
>{translate('Mechanic')}</li>
|
||||||
|
<li className={cn({ active: this.state.DW2Role === 'trucker' }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Role: 'trucker' })} onKeyDown={this._keyDown}
|
||||||
|
>{translate('Trucker')}</li>
|
||||||
|
</ul>
|
||||||
|
<hr/>
|
||||||
|
<ul>
|
||||||
|
<li className={cn({ active: this.state.DW2Gfsb === true }, 'lc')}
|
||||||
|
onClick={() => this.setState({ DW2Gfsb: this.state.DW2Gfsb !== true })}>
|
||||||
|
Add Guardian FSD Booster
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li className={cn({ active: this.state.DW2Gpp === true }, 'lc')}
|
||||||
|
onClick={() => this.setState({ DW2Gpp: this.state.DW2Gpp !== true })}>
|
||||||
|
Add Guardian Power Plant
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li className={cn({ active: this.state.DW2Fighter === true }, 'lc')}
|
||||||
|
onClick={() => this.setState({ DW2Fighter: this.state.DW2Fighter !== true })}>
|
||||||
|
Add Fighter
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<hr/>
|
||||||
|
<ul>
|
||||||
|
<li onClick={this._dw2} className={cn('lc')} tabIndex="0"
|
||||||
|
onKeyDown={this._keyDown}>
|
||||||
|
<button className="button">Apply</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Miner Build
|
* Miner Build
|
||||||
* @param {Boolean} shielded True if shield generator should be included
|
* @param {Boolean} shielded True if shield generator should be included
|
||||||
@@ -177,7 +297,6 @@ export default class StandardSlotSection extends SlotSection {
|
|||||||
warning={m => m instanceof Module ? m.getMaxMass() < (ship.unladenMass + cargo + fuel - st[1].m.mass + m.mass) : m.maxmass < (ship.unladenMass + cargo + fuel - st[1].m.mass + m.mass)}
|
warning={m => m instanceof Module ? m.getMaxMass() < (ship.unladenMass + cargo + fuel - st[1].m.mass + m.mass) : m.maxmass < (ship.unladenMass + cargo + fuel - st[1].m.mass + m.mass)}
|
||||||
/>;
|
/>;
|
||||||
|
|
||||||
|
|
||||||
slots[3] = <StandardSlot
|
slots[3] = <StandardSlot
|
||||||
key='fsd'
|
key='fsd'
|
||||||
slot={st[2]}
|
slot={st[2]}
|
||||||
@@ -232,7 +351,7 @@ export default class StandardSlotSection extends SlotSection {
|
|||||||
selected={currentMenu == st[6]}
|
selected={currentMenu == st[6]}
|
||||||
onChange={this.props.onChange}
|
onChange={this.props.onChange}
|
||||||
ship={ship}
|
ship={ship}
|
||||||
warning= {m => m.fuel < st[2].m.maxfuel} // Show warning when fuel tank is smaller than FSD Max Fuel
|
warning={m => m.fuel < st[2].m.maxfuel} // Show warning when fuel tank is smaller than FSD Max Fuel
|
||||||
/>;
|
/>;
|
||||||
|
|
||||||
return slots;
|
return slots;
|
||||||
@@ -245,19 +364,34 @@ export default class StandardSlotSection extends SlotSection {
|
|||||||
*/
|
*/
|
||||||
_getSectionMenu(translate) {
|
_getSectionMenu(translate) {
|
||||||
let planetaryDisabled = this.props.ship.internal.length < 4;
|
let planetaryDisabled = this.props.ship.internal.length < 4;
|
||||||
|
if (this.state.showDW2 === true) {
|
||||||
|
return this._showDW2Menu(translate);
|
||||||
|
}
|
||||||
return <div className='select' onClick={(e) => e.stopPropagation()} onContextMenu={stopCtxPropagation}>
|
return <div className='select' onClick={(e) => e.stopPropagation()} onContextMenu={stopCtxPropagation}>
|
||||||
<ul>
|
<ul>
|
||||||
<li className='lc' tabIndex="0" onClick={this._optimizeStandard} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['maxjump'] = smRef}>{translate('Maximize Jump Range')}</li>
|
<li className='lc' tabIndex="0" onClick={this._optimizeStandard} onKeyDown={this._keyDown}
|
||||||
|
ref={smRef => this.sectionRefArr['maxjump'] = smRef}>{translate('Maximize Jump Range')}</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div className='select-group cap'>{translate('roles')}</div>
|
<div className='select-group cap'>{translate('roles')}</div>
|
||||||
<ul>
|
<ul>
|
||||||
<li className='lc' tabIndex="0" onClick={this._multiPurpose.bind(this, false, 0)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['multipurpose'] = smRef}>{translate('Multi-purpose')}</li>
|
<li className='lc' tabIndex="0" onClick={this._multiPurpose.bind(this, false, 0)} onKeyDown={this._keyDown}
|
||||||
<li className='lc' tabIndex="0" onClick={this._multiPurpose.bind(this, true, 2)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['combat'] = smRef}>{translate('Combat')}</li>
|
ref={smRef => this.sectionRefArr['multipurpose'] = smRef}>{translate('Multi-purpose')}</li>
|
||||||
<li className='lc' tabIndex="0" onClick={this._optimizeCargo.bind(this, true)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['trader'] = smRef}>{translate('Trader')}</li>
|
<li className='lc' tabIndex="0" onClick={this._multiPurpose.bind(this, true, 2)} onKeyDown={this._keyDown}
|
||||||
<li className='lc' tabIndex="0" onClick={this._optimizeExplorer.bind(this, false)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['explorer'] = smRef}>{translate('Explorer')}</li>
|
ref={smRef => this.sectionRefArr['combat'] = smRef}>{translate('Combat')}</li>
|
||||||
<li className={cn('lc', { disabled: planetaryDisabled })} tabIndex={planetaryDisabled ? '' : '0'} onClick={!planetaryDisabled && this._optimizeExplorer.bind(this, true)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['planetary'] = smRef}>{translate('Planetary Explorer')}</li>
|
<li className='lc' tabIndex="0" onClick={this._optimizeCargo.bind(this, true)} onKeyDown={this._keyDown}
|
||||||
<li className='lc' tabIndex="0" onClick={this._optimizeMiner.bind(this, true)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['miner'] = smRef}>{translate('Miner')}</li>
|
ref={smRef => this.sectionRefArr['trader'] = smRef}>{translate('Trader')}</li>
|
||||||
<li className='lc' tabIndex="0" onClick={this._optimizeRacer.bind(this)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['racer'] = smRef}>{translate('Racer')}</li>
|
<li className='lc' tabIndex="0" onClick={this._optimizeExplorer.bind(this, false)} onKeyDown={this._keyDown}
|
||||||
|
ref={smRef => this.sectionRefArr['explorer'] = smRef}>{translate('Explorer')}</li>
|
||||||
|
<li className={cn('lc', { disabled: planetaryDisabled })} tabIndex={planetaryDisabled ? '' : '0'}
|
||||||
|
onClick={!planetaryDisabled && this._optimizeExplorer.bind(this, true)} onKeyDown={this._keyDown}
|
||||||
|
ref={smRef => this.sectionRefArr['planetary'] = smRef}>{translate('Planetary Explorer')}</li>
|
||||||
|
<li className='lc' tabIndex="0" onClick={this._optimizeMiner.bind(this, true)} onKeyDown={this._keyDown}
|
||||||
|
ref={smRef => this.sectionRefArr['miner'] = smRef}>{translate('Miner')}</li>
|
||||||
|
<li className='lc' tabIndex="0" onClick={this._optimizeRacer.bind(this)} onKeyDown={this._keyDown}
|
||||||
|
ref={smRef => this.sectionRefArr['racer'] = smRef}>{translate('Racer')}</li>
|
||||||
|
<li className='lc' tabIndex="0" onClick={() => this.setState({ showDW2: !this.state.showDW2 })}
|
||||||
|
onKeyDown={this._keyDown}
|
||||||
|
ref={smRef => this.sectionRefArr['dw2'] = smRef}>{translate('DW2')}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -247,8 +247,7 @@ export class OrbisIcon extends SvgIcon {
|
|||||||
<path d="m155.34 679.12 173.25-190.21-15.626-13.721-170.9 190.4zm31.01 31.714 202.41-169.1-16.418-14.417-198.76 170.43z"/>
|
<path d="m155.34 679.12 173.25-190.21-15.626-13.721-170.9 190.4zm31.01 31.714 202.41-169.1-16.418-14.417-198.76 170.43z"/>
|
||||||
<path d="m702.66 178.87-173.25 190.21 15.625 13.721 170.9-190.4zm-31.01-31.714-202.41 169.1 16.418 14.417 198.76-170.43z" />
|
<path d="m702.66 178.87-173.25 190.21 15.625 13.721 170.9-190.4zm-31.01-31.714-202.41 169.1 16.418 14.417 198.76-170.43z" />
|
||||||
<rect transform="matrix(-.7071 -.7071 .7071 -.7071 429.34 1036.2)" x="387.09" y="420.77" width="84.379" height="16.859" />
|
<rect transform="matrix(-.7071 -.7071 .7071 -.7071 429.34 1036.2)" x="387.09" y="420.77" width="84.379" height="16.859" />
|
||||||
</g>
|
</g>);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ import * as IT from './it';
|
|||||||
import * as RU from './ru';
|
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 KO from './ko';
|
|
||||||
import * as d3 from 'd3';
|
import * as d3 from 'd3';
|
||||||
|
|
||||||
let fallbackTerms = EN.terms;
|
let fallbackTerms = EN.terms;
|
||||||
@@ -29,8 +27,6 @@ export function getLanguage(langCode) {
|
|||||||
case 'ru': lang = RU; break;
|
case 'ru': lang = RU; break;
|
||||||
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 'ko': lang = KO; break;
|
|
||||||
default:
|
default:
|
||||||
lang = EN;
|
lang = EN;
|
||||||
}
|
}
|
||||||
@@ -98,7 +94,5 @@ export const Languages = {
|
|||||||
fr: 'Français',
|
fr: 'Français',
|
||||||
ru: 'ру́сский',
|
ru: 'ру́сский',
|
||||||
pl: 'polski',
|
pl: 'polski',
|
||||||
pt: 'português',
|
pt: 'português'
|
||||||
cn: '中文',
|
|
||||||
ko: '한국어'
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
export const formats = {
|
|
||||||
decimal: '.',
|
|
||||||
thousands: ',',
|
|
||||||
grouping: [3],
|
|
||||||
currency: ['¥', ''],
|
|
||||||
dateTime: '%a %b %e %X %Y',
|
|
||||||
date: '%Y年%m月%d日',
|
|
||||||
time: '%H:%M:%S',
|
|
||||||
periods: ['AM', 'PM'],
|
|
||||||
days: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],
|
|
||||||
shortDays: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'],
|
|
||||||
months: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
|
|
||||||
shortMonths: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月']
|
|
||||||
};
|
|
||||||
|
|
||||||
export { default as terms } from './cn.json';
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -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';
|
||||||
File diff suppressed because one or more lines are too long
@@ -63,7 +63,7 @@
|
|||||||
"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_BOOST_TIME": "Time between each boost with 4 pips to ENG",
|
||||||
"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",
|
||||||
@@ -81,9 +81,6 @@
|
|||||||
"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_FIREFOX_EDENGINEER": "Sending to EDEngineer is not compatible with Firefox's security settings. Please try again with Chrome.",
|
|
||||||
"MISSING_MODULES": "Missing Modules",
|
|
||||||
"am": "Auto Field-Maintenance Unit",
|
"am": "Auto Field-Maintenance Unit",
|
||||||
"bh": "Bulkheads",
|
"bh": "Bulkheads",
|
||||||
"bl": "Beam Laser",
|
"bl": "Beam Laser",
|
||||||
@@ -94,7 +91,6 @@
|
|||||||
"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",
|
||||||
@@ -110,17 +106,10 @@
|
|||||||
"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",
|
||||||
"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",
|
||||||
@@ -162,13 +151,10 @@
|
|||||||
"sfn": "Shutdown Field Neutraliser",
|
"sfn": "Shutdown Field Neutraliser",
|
||||||
"sg": "Shield Generator",
|
"sg": "Shield Generator",
|
||||||
"ss": "Surface Scanners",
|
"ss": "Surface Scanners",
|
||||||
"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",
|
||||||
@@ -186,7 +172,6 @@
|
|||||||
"ammunition": "Ammo",
|
"ammunition": "Ammo",
|
||||||
"secs": "s",
|
"secs": "s",
|
||||||
"rebuildsperbay": "Rebuilds per bay",
|
"rebuildsperbay": "Rebuilds per bay",
|
||||||
"mroll": "Roll",
|
|
||||||
"worst": "Worst",
|
"worst": "Worst",
|
||||||
"average": "Average",
|
"average": "Average",
|
||||||
"random": "Random",
|
"random": "Random",
|
||||||
@@ -216,10 +201,9 @@
|
|||||||
"internal protection": "Internal protection",
|
"internal protection": "Internal protection",
|
||||||
"external protection": "External protection",
|
"external protection": "External protection",
|
||||||
"engagement range": "Engagement range",
|
"engagement range": "Engagement range",
|
||||||
"boost interval": "Boost interval",
|
"boost time": "Boost time",
|
||||||
"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",
|
||||||
@@ -336,7 +320,6 @@
|
|||||||
"never": "never",
|
"never": "never",
|
||||||
"stock": "stock",
|
"stock": "stock",
|
||||||
"boost": "boost",
|
"boost": "boost",
|
||||||
"tab_defence": "defence",
|
|
||||||
"federation rank 1": "Recruit",
|
"federation rank 1": "Recruit",
|
||||||
"federation rank 2": "Cadet",
|
"federation rank 2": "Cadet",
|
||||||
"federation rank 3": "Midshipman",
|
"federation rank 3": "Midshipman",
|
||||||
|
|||||||
@@ -59,7 +59,7 @@
|
|||||||
"empty all": "vide tout",
|
"empty all": "vide tout",
|
||||||
"Enter Name": "Entrer nom",
|
"Enter Name": "Entrer nom",
|
||||||
"Explorer": "explorateur",
|
"Explorer": "explorateur",
|
||||||
"farthest range": "gamme la plus rapide",
|
"fastest range": "gamme la plus rapide",
|
||||||
"fuel": "carburant",
|
"fuel": "carburant",
|
||||||
"fuel level": "niveau de carburant",
|
"fuel level": "niveau de carburant",
|
||||||
"full tank": "Réservoir plein",
|
"full tank": "Réservoir plein",
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
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';
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -2,15 +2,15 @@ export const formats = {
|
|||||||
decimal: ',',
|
decimal: ',',
|
||||||
thousands: '.',
|
thousands: '.',
|
||||||
grouping: [3],
|
grouping: [3],
|
||||||
currency: ['$', ''],
|
currency: ['', ' €'],
|
||||||
dateTime: '%A, %e de %B de %Y, %X',
|
dateTime: '%A, %e de %B de %Y, %X',
|
||||||
date: '%d/%m/%Y',
|
date: '%d/%m/%Y',
|
||||||
time: '%H:%M:%S',
|
time: '%H:%M:%S',
|
||||||
periods: ['AM', 'PM'],
|
periods: ['AM', 'PM'],
|
||||||
days: ['domingo', 'segunda', 'terça', 'quarta', 'quinta', 'sexta', 'sábado'],
|
days: ['domingo', 'lunes', 'martes', 'miércoles', 'jueves', 'viernes', 'sábado'],
|
||||||
shortDays: ['dom', 'seg', 'ter', 'qua', 'qui', 'sex', 'sab'],
|
shortDays: ['dom', 'lun', 'mar', 'mié', 'jue', 'vie', 'sáb'],
|
||||||
months: ['janeiro', 'fevereiro', 'março', 'abril', 'maio', 'junho', 'julho', 'agosto', 'setembro', 'outubro', 'novembro', 'dezembro'],
|
months: ['enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio', 'julio', 'agosto', 'septiembre', 'octubre', 'noviembre', 'diciembre'],
|
||||||
shortMonths: ['jan', 'fev', 'mar', 'abr', 'mai', 'jun', 'jul', 'ago', 'set', 'out', 'nov', 'dez']
|
shortMonths: ['ene', 'feb', 'mar', 'abr', 'may', 'jun', 'jul', 'ago', 'sep', 'oct', 'nov', 'dic']
|
||||||
};
|
};
|
||||||
|
|
||||||
export { default as terms } from './pt.json';
|
export { default as terms } from './pt.json';
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
1161
src/app/i18n/ru.json
1161
src/app/i18n/ru.json
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,12 @@
|
|||||||
|
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'));
|
||||||
|
|||||||
@@ -94,6 +94,39 @@ export default class AboutPage extends Page {
|
|||||||
</a>
|
</a>
|
||||||
.
|
.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h3>Supporting Coriolis</h3>
|
||||||
|
<p>
|
||||||
|
Coriolis is an open source project, and I work on it in my free time.
|
||||||
|
I have set up a patreon at{' '}
|
||||||
|
<a href="https://www.patreon.com/coriolis_elite">
|
||||||
|
patreon.com/coriolis_elite
|
||||||
|
</a>
|
||||||
|
, which will be used to keep Coriolis up to date and the servers
|
||||||
|
running.
|
||||||
|
</p>
|
||||||
|
<form
|
||||||
|
action="https://www.paypal.com/cgi-bin/webscr"
|
||||||
|
method="post"
|
||||||
|
target="_top"
|
||||||
|
>
|
||||||
|
<input type="hidden" name="cmd" value="_s-xclick" />
|
||||||
|
<input type="hidden" name="hosted_button_id" value="SJBKT2SWEEU68" />
|
||||||
|
<input
|
||||||
|
type="image"
|
||||||
|
src="https://www.paypalobjects.com/en_AU/i/btn/btn_donate_SM.gif"
|
||||||
|
border="0"
|
||||||
|
name="submit"
|
||||||
|
alt="PayPal – The safer, easier way to pay online!"
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
alt=""
|
||||||
|
border="0"
|
||||||
|
src="https://www.paypalobjects.com/en_AU/i/scr/pixel.gif"
|
||||||
|
width="1"
|
||||||
|
height="1"
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,9 +45,6 @@ export default class ErrorDetails extends React.Component {
|
|||||||
return <div className='error'>
|
return <div className='error'>
|
||||||
<h1>Jameson, we have a problem..</h1>
|
<h1>Jameson, we have a problem..</h1>
|
||||||
<h1><small>{error.message}</small></h1>
|
<h1><small>{error.message}</small></h1>
|
||||||
Import Error handling has been improved, but still isn't perfect. <br/>MOST Import failures are a result of missing modules in Coriolis, <br />OR incorrect import strings generated by third party apps. If you're seeing this page, we may have failed to handle the errors in your import correctly. Please see 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/>
|
|
||||||
<br/>
|
<br/>
|
||||||
{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 }
|
{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 }
|
||||||
<br/>
|
<br/>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
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';
|
||||||
@@ -18,6 +19,7 @@ import {
|
|||||||
LinkIcon,
|
LinkIcon,
|
||||||
ShoppingIcon,
|
ShoppingIcon,
|
||||||
MatIcon,
|
MatIcon,
|
||||||
|
OrbisIcon
|
||||||
} from '../components/SvgIcons';
|
} from '../components/SvgIcons';
|
||||||
import LZString from 'lz-string';
|
import LZString from 'lz-string';
|
||||||
import ShipSummaryTable from '../components/ShipSummaryTable';
|
import ShipSummaryTable from '../components/ShipSummaryTable';
|
||||||
@@ -35,6 +37,7 @@ import OutfittingSubpages from '../components/OutfittingSubpages';
|
|||||||
import ModalExport from '../components/ModalExport';
|
import ModalExport from '../components/ModalExport';
|
||||||
import ModalPermalink from '../components/ModalPermalink';
|
import ModalPermalink from '../components/ModalPermalink';
|
||||||
import ModalShoppingList from '../components/ModalShoppingList';
|
import ModalShoppingList from '../components/ModalShoppingList';
|
||||||
|
import ModalOrbis from '../components/ModalOrbis';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Document Title Generator
|
* Document Title Generator
|
||||||
@@ -57,6 +60,7 @@ 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);
|
||||||
@@ -677,9 +681,26 @@ export default class OutfittingPage extends Page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open up a window for inara with a shopping list of our components
|
* Generate Orbis link
|
||||||
*/
|
*/
|
||||||
_inaraShoppingList() {
|
_genOrbis() {
|
||||||
|
const data = {};
|
||||||
|
const ship = this.state.ship;
|
||||||
|
ship.coriolisId = ship.id;
|
||||||
|
data.coriolisShip = ship;
|
||||||
|
data.url = window.location.href;
|
||||||
|
data.title = this.state.buildName || ship.id;
|
||||||
|
data.description = this.state.buildName || ship.id;
|
||||||
|
data.ShipName = ship.id;
|
||||||
|
data.Ship = ship.id;
|
||||||
|
console.log(data);
|
||||||
|
this.context.showModal(<ModalOrbis ship={data} />);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open up a window for EDDB with a shopping list of our components
|
||||||
|
*/
|
||||||
|
_eddbShoppingList() {
|
||||||
const ship = this.state.ship;
|
const ship = this.state.ship;
|
||||||
|
|
||||||
const shipId = Ships[ship.id].eddbID;
|
const shipId = Ships[ship.id].eddbID;
|
||||||
@@ -692,7 +713,7 @@ export default class OutfittingPage extends Page {
|
|||||||
|
|
||||||
// Open up the relevant URL
|
// Open up the relevant URL
|
||||||
window.open(
|
window.open(
|
||||||
'https://inara.cz/inapi/corisearch.php?s=' + shipId + '&m=' + modIds.join(',')
|
'https://eddb.io/station?s=' + shipId + '&m=' + modIds.join(',')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -912,7 +933,7 @@ export default class OutfittingPage extends Page {
|
|||||||
<Download className="lg" />
|
<Download className="lg" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={this._inaraShoppingList}
|
onClick={this._eddbShoppingList}
|
||||||
onMouseOver={termtip.bind(null, 'PHRASE_SHOPPING_LIST')}
|
onMouseOver={termtip.bind(null, 'PHRASE_SHOPPING_LIST')}
|
||||||
onMouseOut={hide}
|
onMouseOut={hide}
|
||||||
>
|
>
|
||||||
@@ -925,6 +946,13 @@ export default class OutfittingPage extends Page {
|
|||||||
>
|
>
|
||||||
<LinkIcon className="lg" />
|
<LinkIcon className="lg" />
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={this._genOrbis}
|
||||||
|
onMouseOver={termtip.bind(null, 'PHASE_UPLOAD_ORBIS')}
|
||||||
|
onMouseOut={hide}
|
||||||
|
>
|
||||||
|
<OrbisIcon className="lg" />
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={this._genShoppingList}
|
onClick={this._genShoppingList}
|
||||||
onMouseOver={termtip.bind(null, 'PHRASE_SHOPPING_MATS')}
|
onMouseOver={termtip.bind(null, 'PHRASE_SHOPPING_MATS')}
|
||||||
|
|||||||
@@ -50,6 +50,19 @@ export default class Page extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pages are 'pure' components that only render when props, state, or context changes.
|
||||||
|
* This method performs a shallow comparison to determine change.
|
||||||
|
*
|
||||||
|
* @param {Object} np Next/Incoming properties
|
||||||
|
* @param {Object} ns Next/Incoming state
|
||||||
|
* @param {Object} nc Next/Incoming context
|
||||||
|
* @return {Boolean} True if props, state, or context has changed
|
||||||
|
*/
|
||||||
|
shouldComponentUpdate(np, ns, nc) {
|
||||||
|
return !shallowEqual(this.props, np) || !shallowEqual(this.state, ns) || !shallowEqual(this.context, nc);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the window title upon mount
|
* Update the window title upon mount
|
||||||
*/
|
*/
|
||||||
@@ -62,14 +75,6 @@ export default class Page extends React.Component {
|
|||||||
*/
|
*/
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
document.title = this.state.title || 'Coriolis';
|
document.title = this.state.title || 'Coriolis';
|
||||||
try {
|
|
||||||
(window.adsbygoogle = window.adsbygoogle || []).push({
|
|
||||||
google_ad_client: "ca-pub-3709458261881414",
|
|
||||||
enable_page_level_ads: true
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -126,14 +126,12 @@ export default class ShipyardPage extends Page {
|
|||||||
title: 'Coriolis EDCD Edition - Shipyard',
|
title: 'Coriolis EDCD Edition - Shipyard',
|
||||||
shipPredicate: 'name',
|
shipPredicate: 'name',
|
||||||
shipDesc: true,
|
shipDesc: true,
|
||||||
shipSummaries: ShipyardPage.cachedShipSummaries,
|
shipSummaries: ShipyardPage.cachedShipSummaries
|
||||||
compare: {},
|
|
||||||
groupCompared: false,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Higlight the current ship in the table on mouse over
|
* Higlight the current ship in the table
|
||||||
* @param {String} shipId Ship Id
|
* @param {String} shipId Ship Id
|
||||||
* @param {SyntheticEvent} event Event
|
* @param {SyntheticEvent} event Event
|
||||||
*/
|
*/
|
||||||
@@ -142,24 +140,6 @@ export default class ShipyardPage extends Page {
|
|||||||
this.setState({ shipId });
|
this.setState({ shipId });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Toggle compare highlighting for ships in the table
|
|
||||||
* @param {String} shipId Ship Id
|
|
||||||
*/
|
|
||||||
_toggleCompare(shipId) {
|
|
||||||
let compare = this.state.compare;
|
|
||||||
compare[shipId] = !compare[shipId];
|
|
||||||
this.setState({ compare });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Toggle grouping of compared ships in the table
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_toggleGroupCompared() {
|
|
||||||
this.setState({groupCompared: !this.state.groupCompared})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update state with the specified sort predicates
|
* Update state with the specified sort predicates
|
||||||
* @param {String} shipPredicate Sort predicate - property name
|
* @param {String} shipPredicate Sort predicate - property name
|
||||||
@@ -200,11 +180,10 @@ export default class ShipyardPage extends Page {
|
|||||||
style={{ height: '1.5em' }}
|
style={{ height: '1.5em' }}
|
||||||
className={cn({
|
className={cn({
|
||||||
highlighted: noTouch && this.state.shipId === s.id,
|
highlighted: noTouch && this.state.shipId === s.id,
|
||||||
comparehighlight: this.state.compare[s.id],
|
|
||||||
})}
|
})}
|
||||||
onMouseEnter={noTouch && this._highlightShip.bind(this, s.id)}
|
onMouseEnter={noTouch && this._highlightShip.bind(this, s.id)}
|
||||||
onClick={() => this._toggleCompare(s.id)}
|
|
||||||
>
|
>
|
||||||
|
<td className="ri">{s.manufacturer}</td>
|
||||||
<td className="ri">{fInt(s.retailCost)}</td>
|
<td className="ri">{fInt(s.retailCost)}</td>
|
||||||
<td className="ri cap">{translate(SizeMap[s.class])}</td>
|
<td className="ri cap">{translate(SizeMap[s.class])}</td>
|
||||||
<td className="ri">{fInt(s.crew)}</td>
|
<td className="ri">{fInt(s.crew)}</td>
|
||||||
@@ -255,7 +234,7 @@ export default class ShipyardPage extends Page {
|
|||||||
let hide = this.context.tooltip.bind(null, null);
|
let hide = this.context.tooltip.bind(null, null);
|
||||||
let fInt = formats.int;
|
let fInt = formats.int;
|
||||||
let fRound = formats.round;
|
let fRound = formats.round;
|
||||||
let { shipSummaries, shipPredicate, shipPredicateIndex, compare, groupCompared } = this.state;
|
let { shipSummaries, shipPredicate, shipPredicateIndex } = this.state;
|
||||||
let sortShips = (predicate, index) =>
|
let sortShips = (predicate, index) =>
|
||||||
this._sortShips.bind(this, predicate, index);
|
this._sortShips.bind(this, predicate, index);
|
||||||
|
|
||||||
@@ -288,15 +267,6 @@ export default class ShipyardPage extends Page {
|
|||||||
valB = val;
|
valB = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (groupCompared) {
|
|
||||||
if (compare[a.id] && !compare[b.id]) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!compare[a.id] && compare[b.id]) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (valA == valB) {
|
if (valA == valB) {
|
||||||
if (a.name > b.name) {
|
if (a.name > b.name) {
|
||||||
return 1;
|
return 1;
|
||||||
@@ -328,10 +298,8 @@ export default class ShipyardPage extends Page {
|
|||||||
style={{ height: '1.5em' }}
|
style={{ height: '1.5em' }}
|
||||||
className={cn({
|
className={cn({
|
||||||
highlighted: noTouch && this.state.shipId === s.id,
|
highlighted: noTouch && this.state.shipId === s.id,
|
||||||
comparehighlight: this.state.compare[s.id],
|
|
||||||
})}
|
})}
|
||||||
onMouseEnter={noTouch && this._highlightShip.bind(this, s.id)}
|
onMouseEnter={noTouch && this._highlightShip.bind(this, s.id)}
|
||||||
onClick={() => this._toggleCompare(s.id)}
|
|
||||||
>
|
>
|
||||||
<td className="le">
|
<td className="le">
|
||||||
<Link href={'/outfit/' + s.id}>{s.name} {s.beta === true ? '(Beta)' : null}</Link>
|
<Link href={'/outfit/' + s.id}>{s.name} {s.beta === true ? '(Beta)' : null}</Link>
|
||||||
@@ -342,10 +310,18 @@ export default class ShipyardPage extends Page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="page" style={{fontSize: sizeRatio + 'em'}}>
|
<div className="page" style={{ fontSize: sizeRatio + 'em' }}>
|
||||||
<div className="content-wrapper">
|
<div
|
||||||
<div className="shipyard-table-wrapper">
|
style={{
|
||||||
<table style={{width: '12em', position: 'absolute', zIndex: 1}} className="shipyard-table">
|
whiteSpace: 'nowrap',
|
||||||
|
margin: '0 auto',
|
||||||
|
fontSize: '0.8em',
|
||||||
|
position: 'relative',
|
||||||
|
display: 'inline-block',
|
||||||
|
maxWidth: '100%'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<table style={{ width: '12em', position: 'absolute', zIndex: 1 }}>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th className="le rgt"> </th>
|
<th className="le rgt"> </th>
|
||||||
@@ -363,10 +339,17 @@ export default class ShipyardPage extends Page {
|
|||||||
{shipRows}
|
{shipRows}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div style={{ overflowX: 'auto', maxWidth: '100%' }}>
|
<div style={{ overflowX: 'scroll', maxWidth: '100%' }}>
|
||||||
<table style={{ marginLeft: 'calc(12em - 1px)', zIndex: 0 }} className="shipyard-table">
|
<table style={{ marginLeft: 'calc(12em - 1px)', zIndex: 0 }}>
|
||||||
<thead>
|
<thead>
|
||||||
<tr className="main">
|
<tr className="main">
|
||||||
|
<th
|
||||||
|
rowSpan={3}
|
||||||
|
className="sortable"
|
||||||
|
onClick={sortShips('manufacturer')}
|
||||||
|
>
|
||||||
|
{translate('manufacturer')}
|
||||||
|
</th>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
<th
|
<th
|
||||||
rowSpan={3}
|
rowSpan={3}
|
||||||
@@ -544,7 +527,7 @@ export default class ShipyardPage extends Page {
|
|||||||
</th>
|
</th>
|
||||||
<th
|
<th
|
||||||
className="sortable"
|
className="sortable"
|
||||||
onMouseEnter={termtip.bind(null, 'power distributor')}
|
onMouseEnter={termtip.bind(null, 'power distriubtor')}
|
||||||
onMouseLeave={hide}
|
onMouseLeave={hide}
|
||||||
onClick={sortShips('standard', 4)}
|
onClick={sortShips('standard', 4)}
|
||||||
>
|
>
|
||||||
@@ -614,10 +597,6 @@ export default class ShipyardPage extends Page {
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="table-tools" >
|
|
||||||
<label><input type="checkbox" checked={this.state.groupCompared} onClick={() => this._toggleGroupCompared()}/>{translate('Group highlighted ships')}</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,9 +14,8 @@ export function jumpRange(mass, fsd, fuel, ship) {
|
|||||||
const fsdOptimalMass = fsd instanceof Module ? fsd.getOptMass() : fsd.optmass;
|
const fsdOptimalMass = fsd instanceof Module ? fsd.getOptMass() : fsd.optmass;
|
||||||
let jumpAddition = 0;
|
let jumpAddition = 0;
|
||||||
if (ship) {
|
if (ship) {
|
||||||
mass += ship.reserveFuelCapacity || 0;
|
|
||||||
for (const module of ship.internal) {
|
for (const module of ship.internal) {
|
||||||
if (module && module.m && module.m.grp === 'gfsb' && ship.getSlotStatus(module) == 3) {
|
if (module && module.m && module.m.grp === 'gfsb') {
|
||||||
jumpAddition += module.m.getJumpBoost();
|
jumpAddition += module.m.getJumpBoost();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -341,34 +340,67 @@ export function shieldMetrics(ship, sys) {
|
|||||||
const maxSysResistance = this.sysResistance(4);
|
const maxSysResistance = this.sysResistance(4);
|
||||||
|
|
||||||
let shield = {};
|
let shield = {};
|
||||||
|
const dimReturnLine = (res) => 1 - (1 - res) * 0.7;
|
||||||
|
|
||||||
const shieldGeneratorSlot = ship.findInternalByGroup('sg');
|
const shieldGeneratorSlot = ship.findInternalByGroup('sg');
|
||||||
if (shieldGeneratorSlot && shieldGeneratorSlot.enabled && shieldGeneratorSlot.m) {
|
if (shieldGeneratorSlot && shieldGeneratorSlot.enabled && shieldGeneratorSlot.m) {
|
||||||
const shieldGenerator = shieldGeneratorSlot.m;
|
const shieldGenerator = shieldGeneratorSlot.m;
|
||||||
|
let res = {
|
||||||
|
kin: shieldGenerator.kinres,
|
||||||
|
therm: shieldGenerator.thermres,
|
||||||
|
expl: shieldGenerator.explres
|
||||||
|
};
|
||||||
// Boosters
|
// Boosters
|
||||||
let boost = 1;
|
let boost = 1;
|
||||||
let boosterExplDmg = 1;
|
let boosterExplDmg = 1;
|
||||||
let boosterKinDmg = 1;
|
let boosterKinDmg = 1;
|
||||||
let boosterThermDmg = 1;
|
let boosterThermDmg = 1;
|
||||||
|
// const explDim = dimReturnLine(shieldGenerator.explres);
|
||||||
|
// const thermDim = dimReturnLine(shieldGenerator.thermres);
|
||||||
|
// const kinDim = dimReturnLine(shieldGenerator.kinres);
|
||||||
for (let slot of ship.hardpoints) {
|
for (let slot of ship.hardpoints) {
|
||||||
if (slot.enabled && slot.m && slot.m.grp == 'sb') {
|
if (slot.enabled && slot.m && slot.m.grp == 'sb') {
|
||||||
boost += slot.m.getShieldBoost();
|
boost += slot.m.getShieldBoost();
|
||||||
|
res.expl += slot.m.getExplosiveResistance();
|
||||||
|
res.kin += slot.m.getKineticResistance();
|
||||||
|
res.therm += slot.m.getThermalResistance();
|
||||||
boosterExplDmg = boosterExplDmg * (1 - slot.m.getExplosiveResistance());
|
boosterExplDmg = boosterExplDmg * (1 - slot.m.getExplosiveResistance());
|
||||||
boosterKinDmg = boosterKinDmg * (1 - slot.m.getKineticResistance());
|
boosterKinDmg = boosterKinDmg * (1 - slot.m.getKineticResistance());
|
||||||
boosterThermDmg = boosterThermDmg * (1 - slot.m.getThermalResistance());
|
boosterThermDmg = boosterThermDmg * (1 - slot.m.getThermalResistance());
|
||||||
}
|
}
|
||||||
|
if (slot.m && slot.m.grp == 'gsrp') {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Calculate diminishing returns for boosters
|
// Calculate diminishing returns for boosters
|
||||||
// Diminishing returns not currently in-game
|
// Diminishing returns not currently in-game
|
||||||
// boost = Math.min(boost, (1 - Math.pow(Math.E, -0.7 * boost)) * 2.5);
|
// boost = Math.min(boost, (1 - Math.pow(Math.E, -0.7 * boost)) * 2.5);
|
||||||
|
|
||||||
|
|
||||||
// Remove base shield generator strength
|
// Remove base shield generator strength
|
||||||
boost -= 1;
|
boost -= 1;
|
||||||
|
|
||||||
|
// if (res.expl > explDim) {
|
||||||
|
// const overage = (res.expl - explDim) * 0.5;
|
||||||
|
// res.expl = explDim + overage;
|
||||||
|
// boosterExplDmg = explDim + overage;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (res.therm > thermDim) {
|
||||||
|
// const overage = (res.therm - thermDim) * 0.5;
|
||||||
|
// res.therm = thermDim + overage;
|
||||||
|
// boosterThermDmg = thermDim + overage;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (res.kin > kinDim) {
|
||||||
|
// const overage = (res.kin - kinDim) * 0.5;
|
||||||
|
// res.kin = kinDim + overage;
|
||||||
|
// boosterKinDmg = kinDim + overage;
|
||||||
|
// }
|
||||||
let shieldAddition = 0;
|
let shieldAddition = 0;
|
||||||
if (ship) {
|
if (ship) {
|
||||||
for (const module of ship.internal) {
|
for (const module of ship.internal) {
|
||||||
if (module && module.m && module.m.grp === 'gsrp' && module.enabled) {
|
if (module && module.m && module.m.grp === 'gsrp') {
|
||||||
shieldAddition += module.m.getShieldAddition();
|
shieldAddition += module.m.getShieldAddition();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -383,8 +415,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
|
||||||
let capacitorDrain = (shieldGenerator.getBrokenRegenerationRate() * shieldGenerator.getDistDraw()) - sysRechargeRate;
|
let capacitorDrain = (shieldGenerator.getBrokenRegenerationRate() * 0.6) - sysRechargeRate;
|
||||||
|
|
||||||
let capacitorLifetime = powerDistributor.getSystemsCapacity() / capacitorDrain;
|
let capacitorLifetime = powerDistributor.getSystemsCapacity() / capacitorDrain;
|
||||||
|
|
||||||
let recover = 16;
|
let recover = 16;
|
||||||
@@ -400,7 +431,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 / shieldGenerator.getDistDraw());
|
recover += remainingShieldToRecover / (sysRechargeRate / 0.6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -409,7 +440,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() * shieldGenerator.getDistDraw()) - sysRechargeRate;
|
capacitorDrain = (shieldGenerator.getRegenerationRate() * 0.6) - sysRechargeRate;
|
||||||
capacitorLifetime = powerDistributor.getSystemsCapacity() / capacitorDrain;
|
capacitorLifetime = powerDistributor.getSystemsCapacity() / capacitorDrain;
|
||||||
|
|
||||||
let recharge = 0;
|
let recharge = 0;
|
||||||
@@ -425,7 +456,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 / shieldGenerator.getDistDraw());
|
recharge += remainingShieldToRecharge / (sysRechargeRate / 0.6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,7 +465,6 @@ export function shieldMetrics(ship, sys) {
|
|||||||
boosters: boostersStrength,
|
boosters: boostersStrength,
|
||||||
addition: shieldAddition,
|
addition: shieldAddition,
|
||||||
cells: ship.shieldCells,
|
cells: ship.shieldCells,
|
||||||
summary: generatorStrength + boostersStrength + shieldAddition,
|
|
||||||
total: generatorStrength + boostersStrength + ship.shieldCells + shieldAddition,
|
total: generatorStrength + boostersStrength + ship.shieldCells + shieldAddition,
|
||||||
recover,
|
recover,
|
||||||
recharge,
|
recharge,
|
||||||
@@ -467,7 +497,7 @@ export function shieldMetrics(ship, sys) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
let sgExplosiveDmg = 1 - shieldGenerator.getExplosiveResistance();
|
let sgExplosiveDmg = 1 - shieldGenerator.getExplosiveResistance();
|
||||||
let sgSbExplosiveDmg = diminishingReturnsShields(sgExplosiveDmg, sgExplosiveDmg * boosterExplDmg);
|
let sgSbExplosiveDmg = diminishDamageMult(sgExplosiveDmg * 0.7, (1 - shieldGenerator.getExplosiveResistance()) * boosterExplDmg);
|
||||||
/** @type {ShieldDamageMults} */
|
/** @type {ShieldDamageMults} */
|
||||||
shield.explosive = {
|
shield.explosive = {
|
||||||
generator: sgExplosiveDmg,
|
generator: sgExplosiveDmg,
|
||||||
@@ -479,7 +509,7 @@ export function shieldMetrics(ship, sys) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let sgKineticDmg = 1 - shieldGenerator.getKineticResistance();
|
let sgKineticDmg = 1 - shieldGenerator.getKineticResistance();
|
||||||
let sgSbKineticDmg = diminishingReturnsShields(sgKineticDmg, sgKineticDmg * boosterKinDmg);
|
let sgSbKineticDmg = diminishDamageMult(sgKineticDmg * 0.7, (1 - shieldGenerator.getKineticResistance()) * boosterKinDmg);
|
||||||
/** @type {ShieldDamageMults} */
|
/** @type {ShieldDamageMults} */
|
||||||
shield.kinetic = {
|
shield.kinetic = {
|
||||||
generator: sgKineticDmg,
|
generator: sgKineticDmg,
|
||||||
@@ -491,7 +521,7 @@ export function shieldMetrics(ship, sys) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let sgThermalDmg = 1 - shieldGenerator.getThermalResistance();
|
let sgThermalDmg = 1 - shieldGenerator.getThermalResistance();
|
||||||
let sgSbThermalDmg = diminishingReturnsShields(sgThermalDmg , sgThermalDmg * boosterThermDmg);
|
let sgSbThermalDmg = diminishDamageMult(sgThermalDmg * 0.7, (1 - shieldGenerator.getThermalResistance()) * boosterThermDmg);
|
||||||
/** @type {ShieldDamageMults} */
|
/** @type {ShieldDamageMults} */
|
||||||
shield.thermal = {
|
shield.thermal = {
|
||||||
generator: sgThermalDmg,
|
generator: sgThermalDmg,
|
||||||
@@ -531,28 +561,58 @@ export function armourMetrics(ship) {
|
|||||||
let moduleArmour = 0;
|
let moduleArmour = 0;
|
||||||
let moduleProtection = 1;
|
let moduleProtection = 1;
|
||||||
const bulkheads = ship.bulkheads.m;
|
const bulkheads = ship.bulkheads.m;
|
||||||
let hullExplDmgs = [];
|
let hullExplDmg = 1;
|
||||||
let hullKinDmgs = [];
|
let hullKinDmg = 1;
|
||||||
let hullThermDmgs = [];
|
let hullThermDmg = 1;
|
||||||
let hullCausDmgs = [];
|
let hullCausDmg = 1;
|
||||||
|
// const dimReturnLine = (res) => 1 - (1 - res) * 0.7;
|
||||||
|
// let res = {
|
||||||
|
// kin: 0,
|
||||||
|
// therm: 0,
|
||||||
|
// expl: 0
|
||||||
|
// };
|
||||||
// Armour from HRPs and module armour from MRPs
|
// Armour from HRPs and module armour from MRPs
|
||||||
for (let slot of ship.internal) {
|
for (let slot of ship.internal) {
|
||||||
if (slot.m && slot.enabled && (slot.m.grp === 'hr' || slot.m.grp === 'ghrp' || slot.m.grp == 'mahr')) {
|
if (slot.m && (slot.m.grp === 'hr' || slot.m.grp === 'ghrp' || slot.m.grp == 'mahr')) {
|
||||||
armourReinforcement += slot.m.getHullReinforcement();
|
armourReinforcement += slot.m.getHullReinforcement();
|
||||||
// Hull boost for HRPs is applied against the ship's base armour
|
// Hull boost for HRPs is applied against the ship's base armour
|
||||||
armourReinforcement += ship.baseArmour * slot.m.getModValue('hullboost') / 10000;
|
armourReinforcement += ship.baseArmour * slot.m.getModValue('hullboost') / 10000;
|
||||||
hullExplDmgs.push(1 - slot.m.getExplosiveResistance());
|
// res.expl += slot.m.getExplosiveResistance();
|
||||||
hullKinDmgs.push(1 - slot.m.getKineticResistance());
|
// res.kin += slot.m.getKineticResistance();
|
||||||
hullThermDmgs.push(1 - slot.m.getThermalResistance());
|
// res.therm += slot.m.getThermalResistance();
|
||||||
hullCausDmgs.push(1 - slot.m.getCausticResistance());
|
hullExplDmg = hullExplDmg * (1 - slot.m.getExplosiveResistance());
|
||||||
|
hullKinDmg = hullKinDmg * (1 - slot.m.getKineticResistance());
|
||||||
|
hullThermDmg = hullThermDmg * (1 - slot.m.getThermalResistance());
|
||||||
|
hullCausDmg = hullCausDmg * (1 - slot.m.getCausticResistance());
|
||||||
}
|
}
|
||||||
if (slot.m && slot.enabled && (slot.m.grp == 'mrp' || slot.m.grp == 'gmrp')) {
|
if (slot.m && (slot.m.grp == 'mrp' || slot.m.grp == 'gmrp')) {
|
||||||
moduleArmour += slot.m.getIntegrity();
|
moduleArmour += slot.m.getIntegrity();
|
||||||
moduleProtection = moduleProtection * (1 - slot.m.getProtection());
|
moduleProtection = moduleProtection * (1 - slot.m.getProtection());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
moduleProtection = 1 - moduleProtection;
|
moduleProtection = 1 - moduleProtection;
|
||||||
|
|
||||||
|
// const explDim = dimReturnLine(bulkheads.explres);
|
||||||
|
// const thermDim = dimReturnLine(bulkheads.thermres);
|
||||||
|
// const kinDim = dimReturnLine(bulkheads.kinres);
|
||||||
|
// if (res.expl > explDim) {
|
||||||
|
// const overage = (res.expl - explDim) * 0.5;
|
||||||
|
// res.expl = explDim + overage;
|
||||||
|
// hullExplDmg = explDim + overage;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (res.therm > thermDim) {
|
||||||
|
// const overage = (res.therm - thermDim) * 0.5;
|
||||||
|
// res.therm = thermDim + overage;
|
||||||
|
// hullThermDmg = thermDim + overage;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (res.kin > kinDim) {
|
||||||
|
// const overage = (res.kin - kinDim) * 0.5;
|
||||||
|
// res.kin = kinDim + overage;
|
||||||
|
// hullKinDmg = kinDim + overage;
|
||||||
|
// }
|
||||||
|
|
||||||
const armour = {
|
const armour = {
|
||||||
bulkheads: armourBulkheads,
|
bulkheads: armourBulkheads,
|
||||||
reinforcement: armourReinforcement,
|
reinforcement: armourReinforcement,
|
||||||
@@ -569,8 +629,8 @@ export function armourMetrics(ship) {
|
|||||||
total: 1
|
total: 1
|
||||||
};
|
};
|
||||||
|
|
||||||
let armourExplDmg = 1 - ship.bulkheads.m.getExplosiveResistance();
|
let armourExplDmg = diminishDamageMult(0.7, 1 - ship.bulkheads.m.getExplosiveResistance());
|
||||||
let armourReinforcedExplDmg = diminishingReturnsArmour(armourExplDmg, ...hullExplDmgs);
|
let armourReinforcedExplDmg = diminishDamageMult(0.7, (1 - ship.bulkheads.m.getExplosiveResistance()) * hullExplDmg);
|
||||||
armour.explosive = {
|
armour.explosive = {
|
||||||
bulkheads: armourExplDmg,
|
bulkheads: armourExplDmg,
|
||||||
reinforcement: armourReinforcedExplDmg / armourExplDmg,
|
reinforcement: armourReinforcedExplDmg / armourExplDmg,
|
||||||
@@ -578,8 +638,8 @@ export function armourMetrics(ship) {
|
|||||||
res: 1 - armourReinforcedExplDmg
|
res: 1 - armourReinforcedExplDmg
|
||||||
};
|
};
|
||||||
|
|
||||||
let armourKinDmg = 1 - ship.bulkheads.m.getKineticResistance();
|
let armourKinDmg = diminishDamageMult(0.7, 1 - ship.bulkheads.m.getKineticResistance());
|
||||||
let armourReinforcedKinDmg = diminishingReturnsArmour(armourKinDmg, ...hullKinDmgs);
|
let armourReinforcedKinDmg = diminishDamageMult(0.7, (1 - ship.bulkheads.m.getKineticResistance()) * hullKinDmg);
|
||||||
armour.kinetic = {
|
armour.kinetic = {
|
||||||
bulkheads: armourKinDmg,
|
bulkheads: armourKinDmg,
|
||||||
reinforcement: armourReinforcedKinDmg / armourKinDmg,
|
reinforcement: armourReinforcedKinDmg / armourKinDmg,
|
||||||
@@ -587,8 +647,8 @@ export function armourMetrics(ship) {
|
|||||||
res: 1 - armourReinforcedKinDmg
|
res: 1 - armourReinforcedKinDmg
|
||||||
};
|
};
|
||||||
|
|
||||||
let armourThermDmg = 1 - ship.bulkheads.m.getThermalResistance();
|
let armourThermDmg = diminishDamageMult(0.7, 1 - ship.bulkheads.m.getThermalResistance());
|
||||||
let armourReinforcedThermDmg = diminishingReturnsArmour(armourThermDmg, ...hullThermDmgs);
|
let armourReinforcedThermDmg = diminishDamageMult(0.7, (1 - ship.bulkheads.m.getThermalResistance()) * hullThermDmg);
|
||||||
armour.thermal = {
|
armour.thermal = {
|
||||||
bulkheads: armourThermDmg,
|
bulkheads: armourThermDmg,
|
||||||
reinforcement: armourReinforcedThermDmg / armourThermDmg,
|
reinforcement: armourReinforcedThermDmg / armourThermDmg,
|
||||||
@@ -596,8 +656,8 @@ export function armourMetrics(ship) {
|
|||||||
res: 1 - armourReinforcedThermDmg
|
res: 1 - armourReinforcedThermDmg
|
||||||
};
|
};
|
||||||
|
|
||||||
let armourCausDmg = 1 - ship.bulkheads.m.getCausticResistance();
|
let armourCausDmg = diminishDamageMult(0.7, 1 - ship.bulkheads.m.getCausticResistance());
|
||||||
let armourReinforcedCausDmg = diminishingReturnsArmour(armourCausDmg, ...hullCausDmgs);
|
let armourReinforcedCausDmg = diminishDamageMult(0.7, (1 - ship.bulkheads.m.getCausticResistance()) * hullCausDmg);
|
||||||
armour.caustic = {
|
armour.caustic = {
|
||||||
bulkheads: armourCausDmg,
|
bulkheads: armourCausDmg,
|
||||||
reinforcement: armourReinforcedCausDmg / armourCausDmg,
|
reinforcement: armourReinforcedCausDmg / armourCausDmg,
|
||||||
@@ -843,14 +903,12 @@ export function _weaponSustainedDps(m, opponent, opponentShields, opponentArmour
|
|||||||
shields: {
|
shields: {
|
||||||
range: 1,
|
range: 1,
|
||||||
sys: opponentHasShields ? opponentShields.absolute.sys : 1,
|
sys: opponentHasShields ? opponentShields.absolute.sys : 1,
|
||||||
resistance: 1,
|
resistance: 1
|
||||||
dpe: 1
|
|
||||||
},
|
},
|
||||||
armour: {
|
armour: {
|
||||||
range: 1,
|
range: 1,
|
||||||
hardness: 1,
|
hardness: 1,
|
||||||
resistance: 1,
|
resistance: 1
|
||||||
dpe: 1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -910,19 +968,11 @@ export function _weaponSustainedDps(m, opponent, opponentShields, opponentArmour
|
|||||||
weapon.damage.shields.total = weapon.damage.shields.absolute + weapon.damage.shields.explosive + weapon.damage.shields.kinetic + weapon.damage.shields.thermal;
|
weapon.damage.shields.total = weapon.damage.shields.absolute + weapon.damage.shields.explosive + weapon.damage.shields.kinetic + weapon.damage.shields.thermal;
|
||||||
weapon.damage.armour.total = weapon.damage.armour.absolute + weapon.damage.armour.explosive + weapon.damage.armour.kinetic + weapon.damage.armour.thermal;
|
weapon.damage.armour.total = weapon.damage.armour.absolute + weapon.damage.armour.explosive + weapon.damage.armour.kinetic + weapon.damage.armour.thermal;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
weapon.effectiveness.shields.resistance *= shieldsResistance;
|
weapon.effectiveness.shields.resistance *= shieldsResistance;
|
||||||
weapon.effectiveness.armour.resistance *= armourResistance;
|
weapon.effectiveness.armour.resistance *= armourResistance;
|
||||||
|
|
||||||
|
|
||||||
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() / m.getSustainedFactor();
|
|
||||||
weapon.effectiveness.armour.dpe = weapon.damage.armour.total / m.getEps() / m.getSustainedFactor();
|
|
||||||
|
|
||||||
|
|
||||||
return weapon;
|
return weapon;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -964,10 +1014,7 @@ export function timeToDrainWep(ship, wep) {
|
|||||||
*/
|
*/
|
||||||
export function timeToDeplete(amount, dps, eps, capacity, recharge) {
|
export function timeToDeplete(amount, dps, eps, capacity, recharge) {
|
||||||
const drainPerSecond = eps - recharge;
|
const drainPerSecond = eps - recharge;
|
||||||
// If there is nothing to remove, we're don instantly
|
if (drainPerSecond <= 0) {
|
||||||
if (!amount) {
|
|
||||||
return 0;
|
|
||||||
} if (drainPerSecond <= 0) {
|
|
||||||
// Simple result
|
// Simple result
|
||||||
return amount / dps;
|
return amount / dps;
|
||||||
} else {
|
} else {
|
||||||
@@ -986,50 +1033,15 @@ export function timeToDeplete(amount, dps, eps, capacity, recharge) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether diminishing returns should be applied to shield damage
|
* Applies diminishing returns to resistances.
|
||||||
* multipliers and does so if necessary.
|
* @param {number} diminishFrom The base resistance up to which no diminishing returns are applied.
|
||||||
* @param {number} shieldMult Damage multiplier of shield generator
|
* @param {number} damageMult Resistance as damage multiplier
|
||||||
* @param {number} combinedMult Damage multiplier of shields and shield boosters
|
* @returns {number} Actual damage multiplier
|
||||||
* @returns {number} Overall damage multiplier
|
|
||||||
*/
|
*/
|
||||||
export function diminishingReturnsShields(shieldMult, combinedMult) {
|
export function diminishDamageMult(diminishFrom, damageMult) {
|
||||||
let max = shieldMult * 0.7;
|
if (damageMult > diminishFrom) {
|
||||||
if (combinedMult < max) {
|
return damageMult;
|
||||||
return mapIntoDiminishingRange(max / 2, max, combinedMult);
|
|
||||||
} else {
|
} else {
|
||||||
return combinedMult;
|
return (diminishFrom / 2) + 0.5 * damageMult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether diminishing returns should be applied to armour damage
|
|
||||||
* multipliers and does so if necessary.
|
|
||||||
* @param {...any} mults Damage multipliers of alloys and hull reinforcement
|
|
||||||
* packages
|
|
||||||
* @returns {number} Overall damage multiplier
|
|
||||||
*/
|
|
||||||
export function diminishingReturnsArmour(...mults) {
|
|
||||||
let max = Math.min(0.7, ...mults);
|
|
||||||
let combined = mults.reduce((aggr, v) => aggr * v);
|
|
||||||
let diminished = mapIntoDiminishingRange(0.35, max, combined);
|
|
||||||
if (diminished < 0.7) {
|
|
||||||
return diminished;
|
|
||||||
} else {
|
|
||||||
return combined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies diminishing returns to a damage multiplier. Effictively, the range
|
|
||||||
* [`0`, `max`]` is mapped into the range [`min`, `max`] for the value `now`.
|
|
||||||
* It can also happen, that `now` is outside of the range [`min`, `max`], then
|
|
||||||
* `now` is actually improved, i.e. enlarged.
|
|
||||||
* @param {number} min Best theoretical damage multiplier
|
|
||||||
* @param {number} max Damage multiplier from which diminishing returns start to
|
|
||||||
* be applied
|
|
||||||
* @param {number} now The current damage multiplier
|
|
||||||
* @returns {number} Remapped damage multiplier
|
|
||||||
*/
|
|
||||||
export function mapIntoDiminishingRange(min, max, now) {
|
|
||||||
return min + (max - min) * (now / max);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -57,9 +57,6 @@ export const ModuleGroupToName = {
|
|||||||
ghrp: 'Guardian Hull Reinforcement Package',
|
ghrp: 'Guardian Hull Reinforcement Package',
|
||||||
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',
|
|
||||||
mlc: "Multi Limpet Controller",
|
|
||||||
rpl: "Repair Limpet Controller",
|
|
||||||
|
|
||||||
// Hard Points
|
// Hard Points
|
||||||
bl: 'Beam Laser',
|
bl: 'Beam Laser',
|
||||||
@@ -209,7 +206,7 @@ export const ShipFacets = [
|
|||||||
i: 9
|
i: 9
|
||||||
},
|
},
|
||||||
{ // 10
|
{ // 10
|
||||||
title: 'farthest range',
|
title: 'fastest range',
|
||||||
props: ['unladenFastestRange', 'ladenFastestRange'],
|
props: ['unladenFastestRange', 'ladenFastestRange'],
|
||||||
lbls: ['unladen', 'laden'],
|
lbls: ['unladen', 'laden'],
|
||||||
unit: 'LY',
|
unit: 'LY',
|
||||||
|
|||||||
@@ -59,7 +59,14 @@ export default class Module {
|
|||||||
} else if (modification.method === 'overwrite') {
|
} else if (modification.method === 'overwrite') {
|
||||||
result = modifierActions[name];
|
result = modifierActions[name];
|
||||||
} else {
|
} else {
|
||||||
result = (((1 + result / multiplier) * (1 + modifierActions[name])) - 1) * multiplier;
|
// rate of fire is special, as it's really burst interval. Handle that here
|
||||||
|
let mod = null;
|
||||||
|
if (name === 'rof') {
|
||||||
|
mod = 1 / (1 + modifierActions[name]) - 1;
|
||||||
|
} else {
|
||||||
|
mod = modifierActions[name];
|
||||||
|
}
|
||||||
|
result = (((1 + result / multiplier) * (1 + mod)) - 1) * multiplier;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,7 +77,7 @@ export default class Module {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a value for a given modification ID
|
* Set a value for a given modification ID
|
||||||
* @param {String} name The name of the modification
|
* @param {Number} 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,13 +88,7 @@ export default class Module {
|
|||||||
if (!this.origVals) {
|
if (!this.origVals) {
|
||||||
this.origVals = {};
|
this.origVals = {};
|
||||||
}
|
}
|
||||||
if (!valueiswithspecial) {
|
if (valueiswithspecial && this.blueprint && this.blueprint.special) {
|
||||||
// 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]) {
|
||||||
@@ -104,7 +105,14 @@ export default class Module {
|
|||||||
} else if (modification.method === 'overwrite') {
|
} else if (modification.method === 'overwrite') {
|
||||||
value = null;
|
value = null;
|
||||||
} else {
|
} else {
|
||||||
value = ((value / 10000 + 1) / (1 + modifierActions[name]) - 1) * 10000;
|
// rate of fire is special, as it's really burst interval. Handle that here
|
||||||
|
let mod = null;
|
||||||
|
if (name === 'rof') {
|
||||||
|
mod = 1 / (1 + modifierActions[name]) - 1;
|
||||||
|
} else {
|
||||||
|
mod = modifierActions[name];
|
||||||
|
}
|
||||||
|
value = ((value / 10000 + 1) / (1 + mod) - 1) * 10000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -119,17 +127,10 @@ 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 {Boolean} modified Whether to return the raw or modified value
|
* @param {Number} 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) {
|
||||||
if (name == 'rof' && isNaN(this[name])) {
|
|
||||||
let fireint = this['fireint'];
|
|
||||||
if (!isNaN(fireint)) {
|
|
||||||
this['rof'] = 1 / fireint;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let val;
|
let val;
|
||||||
if (modified) {
|
if (modified) {
|
||||||
val = this._getModifiedValue(name);
|
val = this._getModifiedValue(name);
|
||||||
@@ -165,20 +166,14 @@ export default class Module {
|
|||||||
modValue = value - baseValue;
|
modValue = value - baseValue;
|
||||||
} else if (name === 'shieldboost' || name === 'hullboost') {
|
} else if (name === 'shieldboost' || name === 'hullboost') {
|
||||||
modValue = (1 + value) / (1 + baseValue) - 1;
|
modValue = (1 + value) / (1 + baseValue) - 1;
|
||||||
} else if (name === 'rof') {
|
|
||||||
let burst = this.get('burst', true) || 1;
|
|
||||||
let burstInt = 1 / (this.get('burstrof', true) / 1);
|
|
||||||
|
|
||||||
let interval = burst / value;
|
|
||||||
let newFireint = (interval - (burst - 1) * burstInt);
|
|
||||||
modValue = newFireint / this['fireint'] - 1;
|
|
||||||
} else { // multiplicative
|
} else { // multiplicative
|
||||||
modValue = baseValue == 0 ? 0 : value / baseValue - 1;
|
modValue = value / baseValue - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modification.type === 'percentage') {
|
if (modification.type === 'percentage') {
|
||||||
modValue = modValue * 10000;
|
modValue = modValue * 10000;
|
||||||
} else if (modification.type === 'numeric') {
|
} else if (modification.type === 'numeric' && name !== 'burst' &&
|
||||||
|
name !== 'burstrof') {
|
||||||
modValue = modValue * 100;
|
modValue = modValue * 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,14 +191,7 @@ export default class Module {
|
|||||||
*/
|
*/
|
||||||
getPretty(name, modified = true, places = 2) {
|
getPretty(name, modified = true, places = 2) {
|
||||||
const formattingOptions = STATS_FORMATTING[name];
|
const formattingOptions = STATS_FORMATTING[name];
|
||||||
let val;
|
let val = this.get(name, modified) || 0;
|
||||||
if (formattingOptions && formattingOptions.synthetic) {
|
|
||||||
val = (this[formattingOptions.synthetic]).call(this, modified);
|
|
||||||
} else {
|
|
||||||
val = this.get(name, modified);
|
|
||||||
}
|
|
||||||
val = val || 0;
|
|
||||||
|
|
||||||
if (formattingOptions && formattingOptions.format.startsWith('pct')) {
|
if (formattingOptions && formattingOptions.format.startsWith('pct')) {
|
||||||
return 100 * val;
|
return 100 * val;
|
||||||
}
|
}
|
||||||
@@ -262,17 +250,12 @@ export default class Module {
|
|||||||
} else if (name === 'shieldboost' || name === 'hullboost') {
|
} else if (name === 'shieldboost' || name === 'hullboost') {
|
||||||
result = (1 + result) * (1 + modValue) - 1;
|
result = (1 + result) * (1 + modValue) - 1;
|
||||||
} else {
|
} else {
|
||||||
// Rate of fire modifiers are special as they actually are modifiers
|
|
||||||
// for fire interval. Translate them accordingly here:
|
|
||||||
if (name == 'rof') {
|
|
||||||
modValue = 1 / (1 + modValue) - 1;
|
|
||||||
}
|
|
||||||
result = result * (1 + modValue);
|
result = result * (1 + modValue);
|
||||||
}
|
}
|
||||||
} else if (name === 'burstrof' || name === 'burst') {
|
} else if (name === 'burstrof') {
|
||||||
// Burst and burst rate of fire are special, as it can not exist but
|
// Burst and burst rate of fire are special, as it can not exist but
|
||||||
// have a modification
|
// have a modification
|
||||||
result = modValue;
|
result = modValue / 100;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -294,7 +277,11 @@ export default class Module {
|
|||||||
formatModifiedValue(name, language, unit, val) {
|
formatModifiedValue(name, language, unit, val) {
|
||||||
const formattingOptions = STATS_FORMATTING[name];
|
const formattingOptions = STATS_FORMATTING[name];
|
||||||
if (val === undefined) {
|
if (val === undefined) {
|
||||||
val = this.getPretty(name, true);
|
if (formattingOptions && formattingOptions.synthetic) {
|
||||||
|
val = (this[formattingOptions.synthetic]).call(this, true);
|
||||||
|
} else {
|
||||||
|
val = this._getModifiedValue(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val = val || 0;
|
val = val || 0;
|
||||||
@@ -364,18 +351,14 @@ export default class Module {
|
|||||||
|
|
||||||
if (formattingOptions && formattingOptions.change) {
|
if (formattingOptions && formattingOptions.change) {
|
||||||
let changeFormatting = formattingOptions.change;
|
let changeFormatting = formattingOptions.change;
|
||||||
let baseVal = this[name] || 0;
|
let baseVal = this[name];
|
||||||
let absVal = this._getModifiedValue(name);
|
let absVal = this._getModifiedValue(name);
|
||||||
if (changeFormatting === 'additive') {
|
if (changeFormatting === 'additive') {
|
||||||
val = absVal - baseVal;
|
val = absVal - baseVal;
|
||||||
} else if (changeFormatting === 'multiplicative') {
|
} else if (changeFormatting === 'multiplicative') {
|
||||||
val = absVal / baseVal - 1;
|
val = absVal / baseVal - 1;
|
||||||
}
|
}
|
||||||
if (Modifications.modifications[name].method === 'overwrite') {
|
val *= 10000;
|
||||||
val *= 100;
|
|
||||||
} else {
|
|
||||||
val *= 10000;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
@@ -439,15 +422,6 @@ 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
|
||||||
@@ -598,9 +572,20 @@ export default class Module {
|
|||||||
* @return {Number} the falloff of this module
|
* @return {Number} the falloff of this module
|
||||||
*/
|
*/
|
||||||
getFalloff(modified = true) {
|
getFalloff(modified = true) {
|
||||||
|
if (!modified) {
|
||||||
|
const range = this.getRange(false);
|
||||||
|
const falloff = this.get('falloff', false);
|
||||||
|
return (falloff > range ? range : falloff);
|
||||||
|
}
|
||||||
|
|
||||||
// Falloff from range is mapped to range
|
// Falloff from range is mapped to range
|
||||||
if (modified && this.mods && this.mods['fallofffromrange']) {
|
if (this.mods && this.mods['fallofffromrange']) {
|
||||||
return this.getRange();
|
return this.getRange();
|
||||||
|
// Need to find out if we have a focused modification, in which case our
|
||||||
|
// falloff is scaled to range
|
||||||
|
} else if (this.blueprint && this.blueprint.name === 'Focused') {
|
||||||
|
const rangeMod = this.getModValue('range') / 10000;
|
||||||
|
return this.falloff * (1 + rangeMod);
|
||||||
// Standard falloff calculation
|
// Standard falloff calculation
|
||||||
} else {
|
} else {
|
||||||
const range = this.getRange();
|
const range = this.getRange();
|
||||||
@@ -654,6 +639,15 @@ export default class Module {
|
|||||||
return this.get('protection', modified);
|
return this.get('protection', modified);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the delay for this module
|
||||||
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
||||||
|
* @return {Number} the delay of this module
|
||||||
|
*/
|
||||||
|
getDelay(modified = true) {
|
||||||
|
return this.get('delay', modified);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the duration for this module
|
* Get the duration for this module
|
||||||
* @param {Boolean} [modified=true] Whether to take modifications into account
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
||||||
@@ -709,7 +703,8 @@ export default class Module {
|
|||||||
let result = 0;
|
let result = 0;
|
||||||
if (this['maxmass']) {
|
if (this['maxmass']) {
|
||||||
result = this['maxmass'];
|
result = this['maxmass'];
|
||||||
if (result && modified && !ModuleUtils.isShieldGenerator(this['grp'])) {
|
// max mass is only modified for non-shield boosters
|
||||||
|
if (result && modified && this.grp !== 'sg') {
|
||||||
let mult = this.getModValue('optmass') / 10000;
|
let mult = this.getModValue('optmass') / 10000;
|
||||||
if (mult) { result = result * (1 + mult); }
|
if (mult) { result = result * (1 + mult); }
|
||||||
}
|
}
|
||||||
@@ -798,6 +793,24 @@ export default class Module {
|
|||||||
return this.get('distdraw', modified);
|
return this.get('distdraw', modified);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the thermal load for this module
|
||||||
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
||||||
|
* @return {Number} the thermal load of this module
|
||||||
|
*/
|
||||||
|
getThermalLoad(modified = true) {
|
||||||
|
return this.get('thermload', modified);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the rounds per shot for this module
|
||||||
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
||||||
|
* @return {Number} the rounds per shot of this module
|
||||||
|
*/
|
||||||
|
getRoundsPerShot(modified = true) {
|
||||||
|
return this.get('roundspershot', modified);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the DPS for this module
|
* Get the DPS for this module
|
||||||
* @param {Boolean} [modified=true] Whether to take modifications into account
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
||||||
@@ -821,39 +834,25 @@ export default class Module {
|
|||||||
return this.getDps(modified) / this.getEps(modified);
|
return this.getDps(modified) / this.getEps(modified);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the factor that gets applied when calculating certain "sustained"
|
|
||||||
* values, e.g. `SDPS = this.getSustainedFactor() * DPS`.
|
|
||||||
* @param {Boolean} [modified=true] Whether to take modifications into account
|
|
||||||
*/
|
|
||||||
getSustainedFactor(modified = true) {
|
|
||||||
let clipSize = this.getClip(modified);
|
|
||||||
if (clipSize) {
|
|
||||||
// If auto-loader is applied, effective clip size will be nearly doubled
|
|
||||||
// as you get one reload for every two shots fired.
|
|
||||||
if (this.blueprint && this.blueprint.special && this.blueprint.special.edname === 'special_auto_loader' && modified) {
|
|
||||||
clipSize += clipSize - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let burstSize = this.get('burst', modified) || 1;
|
|
||||||
let rof = this.getRoF(modified);
|
|
||||||
// rof averages burstfire + pause until next interval but for sustained
|
|
||||||
// rof we need to take another burst without pause into account
|
|
||||||
let burstOverhead = (burstSize - 1) / (this.get('burstrof', modified) || 1);
|
|
||||||
let srof = clipSize / ((clipSize - burstSize) / rof + burstOverhead + this.getReload(modified));
|
|
||||||
return srof / rof;
|
|
||||||
} else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the SDPS for this module
|
* Get the SDPS for this module
|
||||||
* @param {Boolean} [modified=true] Whether to take modifications into account
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
||||||
* @return {Number} The SDPS of this module
|
* @return {Number} The SDPS of this module
|
||||||
*/
|
*/
|
||||||
getSDps(modified = true) {
|
getSDps(modified = true) {
|
||||||
return this.getDps(modified) * this.getSustainedFactor(modified);
|
let dps = this.getDps(modified);
|
||||||
|
if (this.getClip(modified)) {
|
||||||
|
let clipSize = this.getClip(modified);
|
||||||
|
// If auto-loader is applied, effective clip size will be nearly doubled
|
||||||
|
// as you get one reload for every two shots fired.
|
||||||
|
if (this.blueprint && this.blueprint.special && this.blueprint.special.edname === 'special_auto_loader' && modified) {
|
||||||
|
clipSize += clipSize - 1;
|
||||||
|
}
|
||||||
|
let timeToDeplete = clipSize / this.getRoF(modified);
|
||||||
|
return dps * timeToDeplete / (timeToDeplete + this.getReload(modified));
|
||||||
|
} else {
|
||||||
|
return dps;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -877,7 +876,7 @@ export default class Module {
|
|||||||
*/
|
*/
|
||||||
getHps(modified = true) {
|
getHps(modified = true) {
|
||||||
// HPS is a synthetic value
|
// HPS is a synthetic value
|
||||||
let heat = this.get('thermload', modified);
|
let heat = this.getThermalLoad(modified);
|
||||||
// We don't use rpshot here as dist draw is per combined shot
|
// We don't use rpshot here as dist draw is per combined shot
|
||||||
let rof = this.getRoF(modified) || 1;
|
let rof = this.getRoF(modified) || 1;
|
||||||
|
|
||||||
@@ -914,6 +913,24 @@ export default class Module {
|
|||||||
return this.get('reload', modified);
|
return this.get('reload', modified);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the burst size for this module
|
||||||
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
||||||
|
* @return {Number} the burst size of this module
|
||||||
|
*/
|
||||||
|
getBurst(modified = true) {
|
||||||
|
return this.get('burst', modified);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the burst rate of fire for this module
|
||||||
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
||||||
|
* @return {Number} the burst rate of fire of this module
|
||||||
|
*/
|
||||||
|
getBurstRoF(modified = true) {
|
||||||
|
return this.get('burstrof', modified);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the rate of fire for this module.
|
* Get the rate of fire for this module.
|
||||||
* The rate of fire is a combination value, and needs to take in to account
|
* The rate of fire is a combination value, and needs to take in to account
|
||||||
@@ -924,8 +941,8 @@ export default class Module {
|
|||||||
* @return {Number} the rate of fire for this module
|
* @return {Number} the rate of fire for this module
|
||||||
*/
|
*/
|
||||||
getRoF(modified = true) {
|
getRoF(modified = true) {
|
||||||
const burst = this.get('burst', modified) || 1;
|
const burst = this.getBurst(modified) || 1;
|
||||||
const burstRoF = this.get('burstrof', modified) || 1;
|
const burstRoF = this.getBurstRoF(modified) || 1;
|
||||||
const intRoF = this.get('rof', modified);
|
const intRoF = this.get('rof', modified);
|
||||||
|
|
||||||
return burst / (((burst - 1) / burstRoF) + 1 / intRoF);
|
return burst / (((burst - 1) / burstRoF) + 1 / intRoF);
|
||||||
|
|||||||
@@ -13,19 +13,6 @@ 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
|
||||||
*/
|
*/
|
||||||
@@ -54,7 +41,6 @@ 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)
|
||||||
@@ -178,13 +164,13 @@ export default class ModuleSet {
|
|||||||
/**
|
/**
|
||||||
* Finds the lightest usable Shield Generator
|
* Finds the lightest usable Shield Generator
|
||||||
* @param {number} hullMass Ship hull mass
|
* @param {number} hullMass Ship hull mass
|
||||||
* @return {Object} Thruster
|
* @param {string} rating The optional rating of the shield
|
||||||
|
* @return {Object} Shield Generator
|
||||||
*/
|
*/
|
||||||
lightestShieldGenerator(hullMass) {
|
lightestShieldGenerator(hullMass, rating) {
|
||||||
let sg = this.internal.sg[0];
|
let sg = this.internal.sg[0];
|
||||||
|
|
||||||
for (let s of this.internal.sg) {
|
for (let s of this.internal.sg) {
|
||||||
if (s.mass < sg.mass && s.maxmass > hullMass) {
|
if ((!rating || rating === s.rating) && s.mass <= sg.mass && s.maxmass > hullMass) {
|
||||||
sg = s;
|
sg = s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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', 'ews'];
|
const UNIQUE_MODULES = ['psg', 'sg', 'bsg', 'rf', 'fs', 'fh', 'gfsb'];
|
||||||
|
|
||||||
// Constants for modifications struct
|
// Constants for modifications struct
|
||||||
const SLOT_ID_DONE = -1;
|
const SLOT_ID_DONE = -1;
|
||||||
@@ -492,18 +492,25 @@ 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 {boolean} isAbsolute True if value is an absolute value and not a modification value
|
* @param {bool} sentfromui True if this update was sent from the UI
|
||||||
|
* @param {bool} isAbsolute True if value is an absolute value and not a
|
||||||
|
* modification value
|
||||||
*/
|
*/
|
||||||
setModification(m, name, value, isAbsolute = false) {
|
setModification(m, name, value, sentfromui, isAbsolute) {
|
||||||
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, isAbsolute);
|
m.setPretty(name, value, sentfromui);
|
||||||
} else {
|
} else {
|
||||||
m.setModValue(name, value, false);
|
// Resistance modifiers scale with the base value
|
||||||
|
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
|
||||||
@@ -536,7 +543,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();
|
||||||
@@ -1301,7 +1308,7 @@ export default class Ship {
|
|||||||
let fsd = this.standard[2].m; // Frame Shift Drive;
|
let fsd = this.standard[2].m; // Frame Shift Drive;
|
||||||
let { unladenMass, fuelCapacity } = this;
|
let { unladenMass, fuelCapacity } = this;
|
||||||
this.unladenRange = this.calcUnladenRange(); // Includes fuel weight for jump
|
this.unladenRange = this.calcUnladenRange(); // Includes fuel weight for jump
|
||||||
this.fullTankRange = Calc.jumpRange(unladenMass + fuelCapacity, fsd, fuelCapacity, this); // Full Tank
|
this.fullTankRange = Calc.jumpRange(unladenMass + fuelCapacity, fsd, this); // Full Tank
|
||||||
this.ladenRange = this.calcLadenRange(); // Includes full tank and caro
|
this.ladenRange = this.calcLadenRange(); // Includes full tank and caro
|
||||||
this.unladenFastestRange = Calc.totalJumpRange(unladenMass + this.fuelCapacity, fsd, fuelCapacity, this);
|
this.unladenFastestRange = Calc.totalJumpRange(unladenMass + this.fuelCapacity, fsd, fuelCapacity, this);
|
||||||
this.ladenFastestRange = Calc.totalJumpRange(unladenMass + this.fuelCapacity + this.cargoCapacity, fsd, fuelCapacity, this);
|
this.ladenFastestRange = Calc.totalJumpRange(unladenMass + this.fuelCapacity + this.cargoCapacity, fsd, fuelCapacity, this);
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import * as ModuleUtils from './ModuleUtils';
|
import * as ModuleUtils from './ModuleUtils';
|
||||||
|
import { Modifications } from 'coriolis-data/dist';
|
||||||
import { canMount } from '../utils/SlotFunctions';
|
import { canMount } from '../utils/SlotFunctions';
|
||||||
|
import { getBlueprint, setPercent } from '../utils/BlueprintFunctions';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standard / typical role for multi-purpose or combat (if shielded with better bulkheads)
|
* Standard / typical role for multi-purpose or combat (if shielded with better bulkheads)
|
||||||
@@ -14,7 +16,7 @@ export function multiPurpose(ship, shielded, bulkheadIndex) {
|
|||||||
.useBulkhead(bulkheadIndex);
|
.useBulkhead(bulkheadIndex);
|
||||||
|
|
||||||
if (shielded) {
|
if (shielded) {
|
||||||
ship.internal.some(function(slot) {
|
ship.internal.some(function (slot) {
|
||||||
if (canMount(ship, slot, 'sg')) { // Assuming largest slot can hold an eligible shield
|
if (canMount(ship, slot, 'sg')) { // Assuming largest slot can hold an eligible shield
|
||||||
ship.use(slot, ModuleUtils.findInternal('sg', slot.maxClass, 'A'));
|
ship.use(slot, ModuleUtils.findInternal('sg', slot.maxClass, 'A'));
|
||||||
ship.setSlotEnabled(slot, true);
|
ship.setSlotEnabled(slot, true);
|
||||||
@@ -24,6 +26,577 @@ export function multiPurpose(ship, shielded, bulkheadIndex) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Distant Worlds 2 role
|
||||||
|
* Tiers:
|
||||||
|
* 1- Max. Jump Range, Unshielded
|
||||||
|
* 2- Max. Jump Range, Minimal Shields
|
||||||
|
* 3- Max. Jump Range, Optimal Shields
|
||||||
|
* 4- Max. Jump Range, Optimal Shields & Thrusters
|
||||||
|
*
|
||||||
|
* Engineering level:
|
||||||
|
* No engineering
|
||||||
|
* Only Felicity Farseer and Elvira Martuuk
|
||||||
|
* All exploration related engineers
|
||||||
|
*
|
||||||
|
* Role
|
||||||
|
* Exploration
|
||||||
|
* Surface exploration
|
||||||
|
* Big Rig, full mining
|
||||||
|
* Saper / Prospector mining
|
||||||
|
* Fuel rat
|
||||||
|
* Repair rat
|
||||||
|
* Mechanic
|
||||||
|
* Trucker
|
||||||
|
*
|
||||||
|
* @param ship {Ship} Ship instance
|
||||||
|
* @param tier {Number}
|
||||||
|
* @param engineeringLevel {Number}
|
||||||
|
* @param role {String}
|
||||||
|
* @param gfsb {Boolean} add Guardian FSD Booster
|
||||||
|
* @param gpp {Boolean} add Guardian Power Plant
|
||||||
|
* @param fighter {Boolean} add fighter if supported
|
||||||
|
*/
|
||||||
|
export function dw2Build(ship, tier, engineeringLevel, role, gfsb, gpp, fighter) {
|
||||||
|
ship
|
||||||
|
.emptyInternal()
|
||||||
|
.emptyHardpoints()
|
||||||
|
.emptyUtility();
|
||||||
|
const fsd = ModuleUtils.findStandard('fsd', ship.standard[2].maxClass, 'A');
|
||||||
|
ship.use(ship.standard[2], fsd);
|
||||||
|
ship.use(ship.standard[3], ModuleUtils.findStandard('ls', ship.standard[3].maxClass, 'D'));
|
||||||
|
ship.use(ship.standard[4], ModuleUtils.findStandard('pd', 1, 'D'));
|
||||||
|
ship.use(ship.standard[5], ModuleUtils.findStandard('s', ship.standard[5].maxClass, 'D'));
|
||||||
|
const fuelNeeded = ship.standard[2].m.maxfuel * 2;
|
||||||
|
const fuelTank = ship.availCS.standard[6]
|
||||||
|
.filter(e => e.fuel)
|
||||||
|
.filter(e => e.fuel >= fuelNeeded);
|
||||||
|
ship.use(ship.standard[6], fuelTank[0]);
|
||||||
|
ship.useBulkhead(0, false);
|
||||||
|
if (engineeringLevel === 2) {
|
||||||
|
const bp = getBlueprint('FSD_LongRange', ship.standard[2]);
|
||||||
|
bp.grade = 5;
|
||||||
|
bp.special = Modifications.specials['special_fsd_heavy'];
|
||||||
|
ship.standard[2].m.blueprint = bp;
|
||||||
|
setPercent(ship, ship.standard[2].m, 100);
|
||||||
|
// Sensors G3 LW
|
||||||
|
const sBP = getBlueprint('Sensor_Sensor_LightWeight', ship.standard[5]);
|
||||||
|
sBP.grade = 3;
|
||||||
|
ship.standard[5].m.blueprint = sBP;
|
||||||
|
setPercent(ship, ship.standard[5].m, 100);
|
||||||
|
} else if (engineeringLevel === 3) {
|
||||||
|
// Armour G5 HD + Deep Plating
|
||||||
|
const armourBP = getBlueprint('Armour_HeavyDuty', ship.bulkheads);
|
||||||
|
armourBP.grade = 5;
|
||||||
|
armourBP.special = Modifications.specials['special_armour_chunky'];
|
||||||
|
ship.bulkheads.m.blueprint = armourBP;
|
||||||
|
setPercent(ship, ship.bulkheads.m, 100);
|
||||||
|
// FSD G5 IR + Mass Manager
|
||||||
|
const fsdBP = getBlueprint('FSD_LongRange', ship.standard[2]);
|
||||||
|
fsdBP.grade = 5;
|
||||||
|
fsdBP.special = Modifications.specials['special_fsd_heavy'];
|
||||||
|
ship.standard[2].m.blueprint = fsdBP;
|
||||||
|
setPercent(ship, ship.standard[2].m, 100);
|
||||||
|
// LS G4 LW
|
||||||
|
const lsBP = getBlueprint('LifeSupport_LightWeight', ship.standard[3]);
|
||||||
|
lsBP.grade = 4;
|
||||||
|
ship.standard[3].m.blueprint = lsBP;
|
||||||
|
setPercent(ship, ship.standard[3].m, 100);
|
||||||
|
// Sensors G5 LW
|
||||||
|
const sBP = getBlueprint('Sensor_Sensor_LightWeight', ship.standard[5]);
|
||||||
|
sBP.grade = 5;
|
||||||
|
ship.standard[5].m.blueprint = sBP;
|
||||||
|
setPercent(ship, ship.standard[5].m, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ship.id === 'imperial_clipper') {
|
||||||
|
const fs = ModuleUtils.findInternal('fs', 4, 'A');
|
||||||
|
const slot = ship.internal.filter(a => a.maxClass === 4)[0];
|
||||||
|
ship.use(slot, fs);
|
||||||
|
} else if (ship.id === 'imperial_cutter') {
|
||||||
|
const fs = ModuleUtils.findInternal('fs', 6, 'A');
|
||||||
|
const slot = ship.internal.filter(a => a.maxClass === 6)[0];
|
||||||
|
ship.use(slot, fs);
|
||||||
|
} else if (fsd.class === 2 && fsd.rating === 'A') {
|
||||||
|
let fs = ModuleUtils.findInternal('fs', 2, 'A');
|
||||||
|
let slot = ship.internal.filter(a => a.maxClass >= 2).filter(a => a.maxClass >= fs.class)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||||
|
[0];
|
||||||
|
if (slot.m) {
|
||||||
|
fs = ModuleUtils.findInternal('fs', 1, 'A');
|
||||||
|
slot = ship.internal.filter(a => a.maxClass === 1)[0];
|
||||||
|
ship.use(slot, fs);
|
||||||
|
} else {
|
||||||
|
ship.use(slot, fs);
|
||||||
|
}
|
||||||
|
} else if (fsd.class === 3 && fsd.rating === 'A') {
|
||||||
|
let fs = ModuleUtils.findInternal('fs', 3, 'B');
|
||||||
|
let slot = ship.internal.filter(a => a.maxClass >= 3).filter(a => a.maxClass >= fs.class)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||||
|
[0];
|
||||||
|
if (slot.m) {
|
||||||
|
fs = ModuleUtils.findInternal('fs', 2, 'A');
|
||||||
|
slot = ship.internal.filter(a => a.maxClass === 2)[0];
|
||||||
|
ship.use(slot, fs);
|
||||||
|
} else {
|
||||||
|
ship.use(slot, fs);
|
||||||
|
}
|
||||||
|
} else if (fsd.class === 4 && fsd.rating === 'A') {
|
||||||
|
let fs = ModuleUtils.findInternal('fs', 4, 'b');
|
||||||
|
let slot = ship.internal.filter(a => a.maxClass >= 4).filter(a => a.maxClass >= fs.class)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||||
|
[0];
|
||||||
|
if (slot.m) {
|
||||||
|
fs = ModuleUtils.findInternal('fs', 3, 'A');
|
||||||
|
slot = ship.internal.filter(a => a.maxClass === 3)[0];
|
||||||
|
ship.use(slot, fs);
|
||||||
|
} else {
|
||||||
|
ship.use(slot, fs);
|
||||||
|
}
|
||||||
|
} else if (fsd.class === 5 && fsd.rating === 'A') {
|
||||||
|
let fs = ModuleUtils.findInternal('fs', 5, 'B');
|
||||||
|
let slot = ship.internal.filter(a => a.maxClass >= 5).filter(a => a.maxClass >= fs.class)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||||
|
[0];
|
||||||
|
if (slot.m) {
|
||||||
|
fs = ModuleUtils.findInternal('fs', 4, 'A');
|
||||||
|
slot = ship.internal.filter(a => a.maxClass === 4).filter(a => a.maxClass >= fs.class)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||||
|
[0];
|
||||||
|
if (fs) {
|
||||||
|
ship.use(slot, fs);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (fs) {
|
||||||
|
ship.use(slot, fs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (fsd.class === 6 && fsd.rating === 'A') {
|
||||||
|
let fs = ModuleUtils.findInternal('fs', 6, 'B');
|
||||||
|
let slot = ship.internal.filter(a => a.maxClass >= 6)
|
||||||
|
.filter(a => a.maxClass >= fs.class)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||||
|
[0];
|
||||||
|
if (slot.m) {
|
||||||
|
fs = ModuleUtils.findInternal('fs', 5, 'A');
|
||||||
|
slot = ship.internal.filter(a => a.maxClass === 5)[0];
|
||||||
|
if (fs) {
|
||||||
|
ship.use(slot, fs);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (fs) {
|
||||||
|
ship.use(slot, fs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (fsd.class === 7 && fsd.rating === 'A') {
|
||||||
|
let fs = ModuleUtils.findInternal('fs', 7, 'B');
|
||||||
|
let slot = ship.internal.filter(a => a.maxClass >= 7).filter(a => a.maxClass >= fs.class)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||||
|
[0];
|
||||||
|
if (slot && slot.m) {
|
||||||
|
fs = ModuleUtils.findInternal('fs', 6, 'A');
|
||||||
|
slot = ship.internal.filter(a => a.maxClass === 6)[0];
|
||||||
|
if (fs) {
|
||||||
|
ship.use(slot, fs);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (fs) {
|
||||||
|
ship.use(slot, fs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tier !== 1) {
|
||||||
|
const fuelNeeded = ship.standard[2].m.maxfuel * 3;
|
||||||
|
const fuelTank = ship.availCS.standard[6]
|
||||||
|
.filter(e => e.fuel)
|
||||||
|
.filter(e => e.fuel >= fuelNeeded);
|
||||||
|
if (fuelTank[0]) {
|
||||||
|
ship.use(ship.standard[6], fuelTank[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tier === 2) {
|
||||||
|
if (ship.id === 'alliance_chieftain' || ship.id === 'alliance_crusader' || ship.id === 'federal_gunship' || ship.id === 'vulture') {
|
||||||
|
const hrp = ModuleUtils.findInternal('hrp', 3, 'D');
|
||||||
|
const slot = ship.internal.filter(e => e.eligible && e.maxClass === 3);
|
||||||
|
if (hrp) {
|
||||||
|
ship.use(slot, hrp);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const sg = ship.getAvailableModules().lightestShieldGenerator(ship.ladenMass);
|
||||||
|
const slot = ship.internal.filter(a => !a.m)
|
||||||
|
.filter(a => a.maxClass >= sg.class)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||||
|
[0];
|
||||||
|
if (sg) {
|
||||||
|
ship.use(slot, sg);
|
||||||
|
}
|
||||||
|
if (engineeringLevel === 2) {
|
||||||
|
// ELP G3
|
||||||
|
const shieldBP = getBlueprint('ShieldGenerator_Optimised', ship.findShieldGenerator());
|
||||||
|
shieldBP.grade = 3;
|
||||||
|
ship.findShieldGenerator().blueprint = shieldBP;
|
||||||
|
setPercent(ship, ship.findShieldGenerator(), 100);
|
||||||
|
} else if (engineeringLevel === 3) {
|
||||||
|
// ELP G5
|
||||||
|
const shieldBP = getBlueprint('ShieldGenerator_Optimised', ship.findShieldGenerator());
|
||||||
|
shieldBP.grade = 5;
|
||||||
|
ship.findShieldGenerator().blueprint = shieldBP;
|
||||||
|
setPercent(ship, ship.findShieldGenerator(), 100);
|
||||||
|
}
|
||||||
|
// const shieldOrder = [1, 2, 3, 4, 5, 6, 7, 8].reverse();
|
||||||
|
// const shieldInternals = ship.internal.filter(a => !a.m)
|
||||||
|
// .filter(a => (!a.eligible) || a.eligible.sg)
|
||||||
|
// .filter(a => a.maxClass >= sg.class)
|
||||||
|
// .sort((a, b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass));
|
||||||
|
// for (let i = 0; i < shieldInternals.length; i++) {
|
||||||
|
// if (canMount(ship, shieldInternals[i], 'sg')) {
|
||||||
|
// ship.use(shieldInternals[i], sg);
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
} else if (tier === 3 || tier === 4) {
|
||||||
|
const sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass, 'A');
|
||||||
|
const slot = ship.internal.filter(a => !a.m)
|
||||||
|
.filter(a => a.maxClass >= sg.class)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||||
|
[0];
|
||||||
|
if (sg) {
|
||||||
|
ship.use(slot, sg);
|
||||||
|
}
|
||||||
|
if (engineeringLevel === 1) {
|
||||||
|
// ELP G3
|
||||||
|
const shieldBP = getBlueprint('ShieldGenerator_Optimised', ship.findShieldGenerator());
|
||||||
|
shieldBP.grade = 3;
|
||||||
|
shieldBP.special = Modifications.specials['special_shield_lightweight'];
|
||||||
|
ship.findShieldGenerator().blueprint = shieldBP;
|
||||||
|
setPercent(ship, ship.findShieldGenerator(), 100);
|
||||||
|
} else if (engineeringLevel === 2) {
|
||||||
|
// ELP G5
|
||||||
|
const shieldBP = getBlueprint('ShieldGenerator_Optimised', ship.findShieldGenerator());
|
||||||
|
shieldBP.grade = 5;
|
||||||
|
shieldBP.special = Modifications.specials['special_shield_lightweight'];
|
||||||
|
ship.findShieldGenerator().blueprint = shieldBP;
|
||||||
|
setPercent(ship, ship.findShieldGenerator(), 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tier === 4) {
|
||||||
|
let t;
|
||||||
|
if (canMount(ship, ship.standard[1], 't', ship.standard[1].maxClass - 1)) {
|
||||||
|
t = ModuleUtils.findStandard('t', ship.standard[1].maxClass - 1, 'A');
|
||||||
|
} else {
|
||||||
|
t = ModuleUtils.findStandard('t', ship.standard[1].maxClass, 'A');
|
||||||
|
}
|
||||||
|
if (t) {
|
||||||
|
ship.use(ship.standard[1], t);
|
||||||
|
}
|
||||||
|
if (engineeringLevel === 1) {
|
||||||
|
// DD G3
|
||||||
|
const tBP = getBlueprint('Engine_Dirty', ship.standard[1]);
|
||||||
|
tBP.grade = 3;
|
||||||
|
tBP.special = Modifications.specials['special_engine_lightweight'];
|
||||||
|
ship.standard[1].m.blueprint = tBP;
|
||||||
|
setPercent(ship, ship.standard[1].m, 100);
|
||||||
|
} else if (engineeringLevel === 2) {
|
||||||
|
// DD G5
|
||||||
|
const tBP = getBlueprint('Engine_Dirty', ship.standard[1]);
|
||||||
|
tBP.grade = 5;
|
||||||
|
tBP.special = Modifications.specials['special_engine_lightweight'];
|
||||||
|
ship.standard[1].m.blueprint = tBP;
|
||||||
|
setPercent(ship, ship.standard[1].m, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tier === 4 || tier === 3) {
|
||||||
|
if (engineeringLevel === 3) {
|
||||||
|
const pd = ship.availCS.standard[4]
|
||||||
|
.filter(d => d.rating === 'D')
|
||||||
|
.filter(d => (d.engcap * 1.728) >= ship.boostEnergy)
|
||||||
|
.sort((a, b) => a.class.toString().localeCompare(b.class.toString()))[0];
|
||||||
|
if (pd) {
|
||||||
|
ship.use(ship.standard[4], pd);
|
||||||
|
}
|
||||||
|
// CE G5
|
||||||
|
const pdBP = getBlueprint('PowerDistributor_HighFrequency', ship.standard[4]);
|
||||||
|
pdBP.grade = 5;
|
||||||
|
pdBP.special = Modifications.specials['special_powerdistributor_capacity'];
|
||||||
|
ship.standard[4].m.blueprint = pdBP;
|
||||||
|
setPercent(ship, ship.standard[4].m, 100);
|
||||||
|
} else {
|
||||||
|
const pd = ship.availCS.standard[4]
|
||||||
|
.filter(d => d.rating === 'D')
|
||||||
|
.sort((a, b) => a.engcap > b.engcap)
|
||||||
|
[0];
|
||||||
|
if (pd) {
|
||||||
|
ship.use(ship.standard[4], pd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (tier === 4) {
|
||||||
|
if (engineeringLevel === 3) {
|
||||||
|
const pd = ship.availCS.standard[4]
|
||||||
|
.filter(d => d.rating === 'D')
|
||||||
|
.sort((a, b) => b.class.toString().localeCompare(a.class.toString()))[0];
|
||||||
|
if (pd) {
|
||||||
|
ship.use(ship.standard[4], pd);
|
||||||
|
}
|
||||||
|
// CE G5
|
||||||
|
const pdBP = getBlueprint('PowerDistributor_HighFrequency', ship.standard[4]);
|
||||||
|
pdBP.grade = 5;
|
||||||
|
pdBP.special = Modifications.specials['special_powerdistributor_capacity'];
|
||||||
|
ship.standard[4].m.blueprint = pdBP;
|
||||||
|
setPercent(ship, ship.standard[4].m, 100);
|
||||||
|
} else {
|
||||||
|
const pd = ship.availCS.standard[4]
|
||||||
|
.filter(d => d.rating === 'D')
|
||||||
|
.sort((a, b) => b.class.toString().localeCompare(a.class.toString()))[0];
|
||||||
|
if (pd) {
|
||||||
|
ship.use(ship.standard[4], pd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ship.fighterHangars && fighter) {
|
||||||
|
const slot = ship.internal.filter(s => s.maxClass >= 5 && !s.m)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||||
|
[0];
|
||||||
|
const mod = ModuleUtils.findInternal('fh', 5, 'D');
|
||||||
|
if (slot && mod) {
|
||||||
|
ship.use(slot, mod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tier === 1) {
|
||||||
|
const pd = ModuleUtils.findStandard('pd', 1, 'D');
|
||||||
|
if (pd) {
|
||||||
|
ship.use(ship.standard[4]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let dssPriority = 0;
|
||||||
|
let srvPriority = 0;
|
||||||
|
let afmu = true;
|
||||||
|
let cargo = false;
|
||||||
|
let miningLaserPriority = 0;
|
||||||
|
let refinery = false;
|
||||||
|
let collector = false;
|
||||||
|
let prospector = false;
|
||||||
|
let miningTools = false;
|
||||||
|
let refuelLimpets = false;
|
||||||
|
let repairLimpets = false;
|
||||||
|
console.log(role);
|
||||||
|
if (role === 'exploration') {
|
||||||
|
dssPriority = 2;
|
||||||
|
afmu = true;
|
||||||
|
} else if (role === 'surface') {
|
||||||
|
dssPriority = 2;
|
||||||
|
srvPriority = 2;
|
||||||
|
} else if (role === 'materialProspector') {
|
||||||
|
miningLaserPriority = 2;
|
||||||
|
srvPriority = 1;
|
||||||
|
} else if (role === 'propectorMining') {
|
||||||
|
dssPriority = 1;
|
||||||
|
prospector = true;
|
||||||
|
miningLaserPriority = 1;
|
||||||
|
cargo = true;
|
||||||
|
miningTools = true;
|
||||||
|
|
||||||
|
} else if (role === 'bigRigMining') {
|
||||||
|
dssPriority = 1;
|
||||||
|
miningLaserPriority = 2;
|
||||||
|
cargo = true;
|
||||||
|
collector = true;
|
||||||
|
refinery = true;
|
||||||
|
miningTools = true;
|
||||||
|
|
||||||
|
} else if (role === 'fuelRat') {
|
||||||
|
refuelLimpets = true;
|
||||||
|
cargo = true;
|
||||||
|
srvPriority = 1;
|
||||||
|
|
||||||
|
} else if (role === 'mechanic') {
|
||||||
|
repairLimpets = true;
|
||||||
|
cargo = true;
|
||||||
|
srvPriority = 1;
|
||||||
|
} else if (role === 'trucker') {
|
||||||
|
cargo = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dssPriority === 2) {
|
||||||
|
const mod = ModuleUtils.findModule('ss', '2i');
|
||||||
|
const slot = ship.internal.filter(s => !s.m)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||||
|
console.log(slot);
|
||||||
|
console.log(mod);
|
||||||
|
ship.use(slot, mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (srvPriority === 2) {
|
||||||
|
let mod;
|
||||||
|
let slot = ship.internal.filter(s => !s.m)
|
||||||
|
.filter(s => s.maxClass >= 6)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||||
|
if (slot) {
|
||||||
|
mod = ModuleUtils.findModule('pv', 'v2');
|
||||||
|
ship.use(slot, mod);
|
||||||
|
} else if (!slot) {
|
||||||
|
slot = ship.internal.filter(s => !s.m)
|
||||||
|
.filter(s => s.maxClass >= 4)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||||
|
if (slot) {
|
||||||
|
mod = ModuleUtils.findModule('pv', 'v4');
|
||||||
|
ship.use(slot, mod);
|
||||||
|
} else {
|
||||||
|
slot = ship.internal.filter(s => !s.m)
|
||||||
|
.filter(s => s.maxClass >= 2)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||||
|
if (slot) {
|
||||||
|
mod = ModuleUtils.findModule('pv', 'v6');
|
||||||
|
ship.use(slot, mod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cargo === true) {
|
||||||
|
const slot = ship.internal.filter(s => !s.m)
|
||||||
|
.sort((a, b) => b.maxClass.toString().localeCompare(a.maxClass.toString()))[0];
|
||||||
|
const mod = ModuleUtils.findInternal('cr', slot.maxClass, 'E');
|
||||||
|
ship.use(slot, mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refuelLimpets === true) {
|
||||||
|
const mod = ModuleUtils.findModule('fx', 'F4');
|
||||||
|
const slot = ship.internal.filter(s => !s.m)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||||
|
ship.use(mod, slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (repairLimpets === true) {
|
||||||
|
const slot = ship.internal.filter(s => !s.m)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||||
|
let mod;
|
||||||
|
if (slot.maxClass >= 3) {
|
||||||
|
mod = ModuleUtils.findModule('rpl', '9e');
|
||||||
|
} else {
|
||||||
|
mod = ModuleUtils.findModule('rpl', '9s');
|
||||||
|
}
|
||||||
|
ship.use(mod, slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prospector === true) {
|
||||||
|
const slot = ship.internal.filter(s => !s.m)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||||
|
let mod;
|
||||||
|
if (slot.maxClass >= 3) {
|
||||||
|
mod = ModuleUtils.findModule('pc', 'P9');
|
||||||
|
} else {
|
||||||
|
mod = ModuleUtils.findModule('pc', 'P4');
|
||||||
|
}
|
||||||
|
ship.use(mod, slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collector === true) {
|
||||||
|
const slots = ship.internal.filter(s => !s.m)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()));
|
||||||
|
if (slots.length >= 2) {
|
||||||
|
let slot = slots.find(s => s.maxClass >= 5);
|
||||||
|
let mod;
|
||||||
|
if (slot) {
|
||||||
|
mod = ModuleUtils.findInternal('cc', slot.maxClass, 'D');
|
||||||
|
} else if (slots.find(s => s.maxClass <= 4)) {
|
||||||
|
slot = slots.find(s => s.maxClass <= 4);
|
||||||
|
mod = ModuleUtils.findInternal('cc', slot.maxClass, 'D');
|
||||||
|
}
|
||||||
|
ship.use(slot, mod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refinery === true) {
|
||||||
|
const slots = ship.internal.filter(s => !s.m)
|
||||||
|
.filter(s => s.maxClass >= 4)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||||
|
if (slots) {
|
||||||
|
const mod = ModuleUtils.findInternal('rf', 4, 'A');
|
||||||
|
ship.use(slots, mod);
|
||||||
|
} else {
|
||||||
|
const slot = ship.internal.filter(s => !s.m)
|
||||||
|
.filter(s => s.maxClass <= 3)
|
||||||
|
.sort((a, b) => b.maxClass.toString().localeCompare(a.maxClass.toString()))[0];
|
||||||
|
const mod = ModuleUtils.findInternal('rf', slot.maxClass, 'A');
|
||||||
|
ship.use(slots, mod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dssPriority === 1) {
|
||||||
|
const slot = ship.internal.filter(s => !s.m)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||||
|
const dss = ModuleUtils.findInternal('ss', 1, 'C')
|
||||||
|
if (slot) {
|
||||||
|
ship.use(slot, dss);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (srvPriority === 1) {
|
||||||
|
const slot = ship.internal.filter(s => !s.m)
|
||||||
|
.filter(s => s.maxClass >= 2)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()));
|
||||||
|
if (slot.find(s => s.maxClass >= 4)) {
|
||||||
|
const slot = slot.find(s => s.maxClass >= 4);
|
||||||
|
const srv = ModuleUtils.findInternal('pv', 4, 'G')
|
||||||
|
ship.use(slot, srv);
|
||||||
|
} else if (slot.find(s => s.maxClass >= 2)) {
|
||||||
|
const slot = slot.find(s => s.maxClass >= 2);
|
||||||
|
const srv = ModuleUtils.findInternal('pv', 2, 'G')
|
||||||
|
ship.use(slot, srv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gfsb === true) {
|
||||||
|
const slots = ship.internal.filter(s => !s.m)
|
||||||
|
.filter(s => s.maxClass >= 1)
|
||||||
|
.sort((a, b) => b.maxClass.toString().localeCompare(a.maxClass.toString()));
|
||||||
|
if (slots.find(s => s.maxClass >= 5)) {
|
||||||
|
const mod = ModuleUtils.findInternal('gfsb', 5, 'H');
|
||||||
|
ship.use(slots.find(s => s.maxClass >= 5), mod)
|
||||||
|
} else if (slots.find(s => s.maxClass >= 4)) {
|
||||||
|
const mod = ModuleUtils.findInternal('gfsb', 4, 'H');
|
||||||
|
ship.use(slots.find(s => s.maxClass >= 4), mod)
|
||||||
|
} else if (slots.find(s => s.maxClass >= 3)) {
|
||||||
|
const mod = ModuleUtils.findInternal('gfsb', 3, 'H');
|
||||||
|
ship.use(slots.find(s => s.maxClass >= 3), mod)
|
||||||
|
} else if (slots.find(s => s.maxClass >= 2)) {
|
||||||
|
const mod = ModuleUtils.findInternal('gfsb', 2, 'H');
|
||||||
|
ship.use(slots.find(s => s.maxClass >= 2), mod)
|
||||||
|
} else if (slots.find(s => s.maxClass >= 1)) {
|
||||||
|
const mod = ModuleUtils.findInternal('gfsb', 1, 'H');
|
||||||
|
ship.use(slots.find(s => s.maxClass >= 1), mod)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// const pp = ship.getAvailableModules().lightestPowerPlant(Math.max(ship.powerRetracted, ship.powerDeployed), 'A');
|
||||||
|
// const t = ship.getAvailableModules().lightestThruster(ship.ladenMass);
|
||||||
|
// ship.use(ship.standard[0], pp);
|
||||||
|
// ship.use(ship.standard[1], t);
|
||||||
|
|
||||||
|
// ship.useLightestStandard(standardOpts);
|
||||||
|
ship.updatePowerGenerated()
|
||||||
|
.updatePowerUsed()
|
||||||
|
.recalculateMass()
|
||||||
|
.updateJumpStats()
|
||||||
|
.recalculateShield()
|
||||||
|
.recalculateShieldCells()
|
||||||
|
.recalculateArmour()
|
||||||
|
.recalculateDps()
|
||||||
|
.recalculateEps()
|
||||||
|
.recalculateHps()
|
||||||
|
.updateMovement()
|
||||||
|
.updateModificationsString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trader Role
|
* Trader Role
|
||||||
* @param {Ship} ship Ship instance
|
* @param {Ship} ship Ship instance
|
||||||
@@ -36,7 +609,7 @@ export function trader(ship, shielded, standardOpts) {
|
|||||||
let sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
|
let sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
|
||||||
ship.useStandard('A')
|
ship.useStandard('A')
|
||||||
.use(ship.standard[3], ModuleUtils.standard(3, ship.standard[3].maxClass + 'D')) // D Life Support
|
.use(ship.standard[3], ModuleUtils.standard(3, ship.standard[3].maxClass + 'D')) // D Life Support
|
||||||
.use(ship.standard[1], ModuleUtils.standard(1, ship.standard[1].maxClass + 'D')) // D Life Support
|
.use(ship.standard[1], ModuleUtils.standard(1, ship.standard[1].maxClass + 'D')) // D Power Plant
|
||||||
.use(ship.standard[4], ModuleUtils.standard(4, ship.standard[4].maxClass + 'D')) // D Life Support
|
.use(ship.standard[4], ModuleUtils.standard(4, ship.standard[4].maxClass + 'D')) // D Life Support
|
||||||
.use(ship.standard[5], ModuleUtils.standard(5, ship.standard[5].maxClass + 'D')); // D Sensors
|
.use(ship.standard[5], ModuleUtils.standard(5, ship.standard[5].maxClass + 'D')); // D Sensors
|
||||||
|
|
||||||
@@ -45,7 +618,7 @@ export function trader(ship, shielded, standardOpts) {
|
|||||||
.filter(a => (!a.eligible) || a.eligible.sg)
|
.filter(a => (!a.eligible) || a.eligible.sg)
|
||||||
.filter(a => a.maxClass >= sg.class)
|
.filter(a => a.maxClass >= sg.class)
|
||||||
.sort((a, b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass));
|
.sort((a, b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass));
|
||||||
shieldInternals.some(function(slot) {
|
shieldInternals.some(function (slot) {
|
||||||
if (canMount(ship, slot, 'sg')) { // Assuming largest slot can hold an eligible shield
|
if (canMount(ship, slot, 'sg')) { // Assuming largest slot can hold an eligible shield
|
||||||
const shield = ModuleUtils.findInternal('sg', slot.maxClass, 'A');
|
const shield = ModuleUtils.findInternal('sg', slot.maxClass, 'A');
|
||||||
if (shield && shield.maxmass > ship.hullMass) {
|
if (shield && shield.maxmass > ship.hullMass) {
|
||||||
@@ -87,11 +660,11 @@ export function trader(ship, shielded, standardOpts) {
|
|||||||
*/
|
*/
|
||||||
export function explorer(ship, planetary) {
|
export function explorer(ship, planetary) {
|
||||||
let standardOpts = { ppRating: 'A' },
|
let standardOpts = { ppRating: 'A' },
|
||||||
heatSinkCount = 2, // Fit 2 heat sinks if possible
|
heatSinkCount = 2, // Fit 2 heat sinks if possible
|
||||||
usedSlots = [],
|
usedSlots = [],
|
||||||
sgSlot,
|
sgSlot,
|
||||||
fuelScoopSlot,
|
fuelScoopSlot,
|
||||||
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
|
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
|
||||||
|
|
||||||
if (!planetary) { // Non-planetary explorers don't really need to boost
|
if (!planetary) { // Non-planetary explorers don't really need to boost
|
||||||
standardOpts.pd = '1D';
|
standardOpts.pd = '1D';
|
||||||
@@ -216,9 +789,9 @@ export function explorer(ship, planetary) {
|
|||||||
export function miner(ship, shielded) {
|
export function miner(ship, shielded) {
|
||||||
shielded = true;
|
shielded = true;
|
||||||
let standardOpts = { ppRating: 'A' },
|
let standardOpts = { ppRating: 'A' },
|
||||||
miningLaserCount = 2,
|
miningLaserCount = 2,
|
||||||
usedSlots = [],
|
usedSlots = [],
|
||||||
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
|
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
|
||||||
|
|
||||||
// Cargo hatch should be enabled
|
// Cargo hatch should be enabled
|
||||||
ship.setSlotEnabled(ship.cargoHatch, true);
|
ship.setSlotEnabled(ship.cargoHatch, true);
|
||||||
@@ -269,7 +842,7 @@ export function miner(ship, shielded) {
|
|||||||
|
|
||||||
// Dual mining lasers of highest possible class; remove anything else
|
// Dual mining lasers of highest possible class; remove anything else
|
||||||
const miningLaserOrder = [2, 3, 4, 1, 0];
|
const miningLaserOrder = [2, 3, 4, 1, 0];
|
||||||
const miningLaserHardpoints = ship.hardpoints.concat().sort(function(a, b) {
|
const miningLaserHardpoints = ship.hardpoints.concat().sort(function (a, b) {
|
||||||
return miningLaserOrder.indexOf(a.maxClass) - miningLaserOrder.indexOf(b.maxClass);
|
return miningLaserOrder.indexOf(a.maxClass) - miningLaserOrder.indexOf(b.maxClass);
|
||||||
});
|
});
|
||||||
for (let s of miningLaserHardpoints) {
|
for (let s of miningLaserHardpoints) {
|
||||||
@@ -283,7 +856,7 @@ export function miner(ship, shielded) {
|
|||||||
|
|
||||||
// Number of collector limpets required to be active is a function of the size of the ship and the power of the lasers
|
// Number of collector limpets required to be active is a function of the size of the ship and the power of the lasers
|
||||||
const miningLaserDps = ship.hardpoints.filter(h => h.m != null)
|
const miningLaserDps = ship.hardpoints.filter(h => h.m != null)
|
||||||
.reduce(function(a, b) {
|
.reduce(function (a, b) {
|
||||||
return a + b.m.getDps();
|
return a + b.m.getDps();
|
||||||
}, 0);
|
}, 0);
|
||||||
// Find out how many internal slots we have, and their potential cargo size
|
// Find out how many internal slots we have, and their potential cargo size
|
||||||
@@ -314,7 +887,7 @@ export function miner(ship, shielded) {
|
|||||||
|
|
||||||
// Power distributor to power the mining lasers indefinitely
|
// Power distributor to power the mining lasers indefinitely
|
||||||
const wepRateRequired = ship.hardpoints.filter(h => h.m != null)
|
const wepRateRequired = ship.hardpoints.filter(h => h.m != null)
|
||||||
.reduce(function(a, b) {
|
.reduce(function (a, b) {
|
||||||
return a + b.m.getEps();
|
return a + b.m.getEps();
|
||||||
}, 0);
|
}, 0);
|
||||||
standardOpts.pd = ship.getAvailableModules().matchingPowerDist({ weprate: wepRateRequired }).id;
|
standardOpts.pd = ship.getAvailableModules().matchingPowerDist({ weprate: wepRateRequired }).id;
|
||||||
@@ -336,9 +909,9 @@ export function miner(ship, shielded) {
|
|||||||
*/
|
*/
|
||||||
export function racer(ship) {
|
export function racer(ship) {
|
||||||
let standardOpts = {},
|
let standardOpts = {},
|
||||||
usedSlots = [],
|
usedSlots = [],
|
||||||
sgSlot,
|
sgSlot,
|
||||||
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
|
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
|
||||||
|
|
||||||
// Cargo hatch can be disabled
|
// Cargo hatch can be disabled
|
||||||
ship.setSlotEnabled(ship.cargoHatch, false);
|
ship.setSlotEnabled(ship.cargoHatch, false);
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ export const STATS_FORMATTING = {
|
|||||||
'ammo': { 'format': 'int', },
|
'ammo': { 'format': 'int', },
|
||||||
'boot': { 'format': 'int', 'unit': 'secs' },
|
'boot': { 'format': 'int', 'unit': 'secs' },
|
||||||
'brokenregen': { 'format': 'round1', 'unit': 'ps' },
|
'brokenregen': { 'format': 'round1', 'unit': 'ps' },
|
||||||
'burst': { 'format': 'int', 'change': 'additive' },
|
'burst': { 'format': 'int' },
|
||||||
'burstrof': { 'format': 'round1', 'unit': 'ps', 'change': 'additive' },
|
'burstrof': { 'format': 'round1', 'unit': 'ps' },
|
||||||
'causres': { 'format': 'pct' },
|
'causres': { 'format': 'pct' },
|
||||||
'clip': { 'format': 'int' },
|
'clip': { 'format': 'int' },
|
||||||
'damage': { 'format': 'round' },
|
'damage': { 'format': 'round' },
|
||||||
@@ -61,7 +61,7 @@ export const STATS_FORMATTING = {
|
|||||||
'ranget': { 'format': 'f1', 'unit': 's' },
|
'ranget': { 'format': 'f1', 'unit': 's' },
|
||||||
'regen': { 'format': 'round1', 'unit': 'ps' },
|
'regen': { 'format': 'round1', 'unit': 'ps' },
|
||||||
'reload': { 'format': 'int', 'unit': 's' },
|
'reload': { 'format': 'int', 'unit': 's' },
|
||||||
'rof': { 'format': 'round1', 'unit': 'ps', 'synthetic': 'getRoF', 'higherbetter': true },
|
'rof': { 'format': 'round1', 'unit': 'ps' },
|
||||||
'angle': { 'format': 'round1', 'unit': 'ang' },
|
'angle': { 'format': 'round1', 'unit': 'ang' },
|
||||||
'scanrate': { 'format': 'int' },
|
'scanrate': { 'format': 'int' },
|
||||||
'scantime': { 'format': 'round1', 'unit': 's' },
|
'scantime': { 'format': 'round1', 'unit': 's' },
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ const LS_KEY_SIZE_RATIO = 'sizeRatio';
|
|||||||
const LS_KEY_TOOLTIPS = 'tooltips';
|
const LS_KEY_TOOLTIPS = 'tooltips';
|
||||||
const LS_KEY_MODULE_RESISTANCES = 'moduleResistances';
|
const LS_KEY_MODULE_RESISTANCES = 'moduleResistances';
|
||||||
const LS_KEY_ROLLS = 'matsPerGrade';
|
const LS_KEY_ROLLS = 'matsPerGrade';
|
||||||
|
const LS_KEY_ORBIS = 'orbis';
|
||||||
|
|
||||||
let LS;
|
let LS;
|
||||||
|
|
||||||
@@ -94,6 +95,7 @@ export class Persist extends EventEmitter {
|
|||||||
let buildJson = _get(LS_KEY_BUILDS);
|
let buildJson = _get(LS_KEY_BUILDS);
|
||||||
let comparisonJson = _get(LS_KEY_COMPARISONS);
|
let comparisonJson = _get(LS_KEY_COMPARISONS);
|
||||||
|
|
||||||
|
this.orbisCreds = _get(LS_KEY_ORBIS) || { email: '', password: '' };
|
||||||
this.onStorageChange = this.onStorageChange.bind(this);
|
this.onStorageChange = this.onStorageChange.bind(this);
|
||||||
this.langCode = _getString(LS_KEY_LANG) || 'en';
|
this.langCode = _getString(LS_KEY_LANG) || 'en';
|
||||||
this.insurance = insurance && Insurance[insurance.toLowerCase()] !== undefined ? insurance : 'standard';
|
this.insurance = insurance && Insurance[insurance.toLowerCase()] !== undefined ? insurance : 'standard';
|
||||||
@@ -167,6 +169,10 @@ export class Persist extends EventEmitter {
|
|||||||
this.matsPerGrade = JSON.parse(newValue);
|
this.matsPerGrade = JSON.parse(newValue);
|
||||||
this.emit('matsPerGrade', this.matsPerGrade);
|
this.emit('matsPerGrade', this.matsPerGrade);
|
||||||
break;
|
break;
|
||||||
|
case LS_KEY_ORBIS:
|
||||||
|
this.orbisCreds = JSON.parse(newValue);
|
||||||
|
this.emit('orbis', this.orbisCreds);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// On JSON.Parse Error - don't sync or do anything
|
// On JSON.Parse Error - don't sync or do anything
|
||||||
@@ -192,6 +198,24 @@ export class Persist extends EventEmitter {
|
|||||||
this.emit('language', langCode);
|
this.emit('language', langCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current orbis.zone credentials
|
||||||
|
* @return {String} language code
|
||||||
|
*/
|
||||||
|
getOrbisCreds() {
|
||||||
|
return this.orbisCreds;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update and save the orbis.zone credentials
|
||||||
|
* @param {Object} creds object with username and password properties.
|
||||||
|
*/
|
||||||
|
setOrbisCreds(creds) {
|
||||||
|
this.langCode = creds;
|
||||||
|
_put(LS_KEY_ORBIS, creds);
|
||||||
|
this.emit('orbis', creds);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show tooltips setting
|
* Show tooltips setting
|
||||||
* @param {boolean} show Optional - update setting
|
* @param {boolean} show Optional - update setting
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
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';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a tooltip with details of a blueprint's specials
|
* Generate a tooltip with details of a blueprint's specials
|
||||||
@@ -281,25 +280,6 @@ export function isValueBeneficial(feature, value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Is the change as shown beneficial?
|
|
||||||
* @param {string} feature The name of the feature
|
|
||||||
* @param {number} value The value of the feature as percentage change
|
|
||||||
* @returns True if the value is beneficial
|
|
||||||
*/
|
|
||||||
export function isChangeValueBeneficial(feature, value) {
|
|
||||||
let changeHigherBetter = STATS_FORMATTING[feature].higherbetter;
|
|
||||||
if (changeHigherBetter === undefined) {
|
|
||||||
return isValueBeneficial(feature, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (changeHigherBetter) {
|
|
||||||
return value > 0;
|
|
||||||
} else {
|
|
||||||
return value < 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a blueprint with a given name and an optional module
|
* Get a blueprint with a given name and an optional module
|
||||||
* @param {string} name The name of the blueprint
|
* @param {string} name The name of the blueprint
|
||||||
@@ -327,43 +307,26 @@ export function setPercent(ship, m, percent) {
|
|||||||
ship.clearModifications(m);
|
ship.clearModifications(m);
|
||||||
// Pick given value as multiplier
|
// Pick given value as multiplier
|
||||||
const mult = percent / 100;
|
const mult = percent / 100;
|
||||||
setQualityCB(m.blueprint, mult, (featureName, value) => ship.setModification(m, featureName, value));
|
const features = m.blueprint.grades[m.blueprint.grade].features;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the blueprint quality and fires a callback for each property affected.
|
|
||||||
* @param {Object} blueprint The ship for which to perform the modifications
|
|
||||||
* @param {Number} quality The quality to apply - float number 0 to 1.
|
|
||||||
* @param {Function} cb The Callback to run for each property. Function (featureName, value)
|
|
||||||
*/
|
|
||||||
export function setQualityCB(blueprint, quality, cb) {
|
|
||||||
// Pick given value as multiplier
|
|
||||||
const features = blueprint.grades[blueprint.grade].features;
|
|
||||||
for (const featureName in features) {
|
for (const featureName in features) {
|
||||||
let value;
|
let value;
|
||||||
if (Modifications.modifications[featureName].higherbetter) {
|
if (Modifications.modifications[featureName].higherbetter) {
|
||||||
// Higher is better, but is this making it better or worse?
|
// Higher is better, but is this making it better or worse?
|
||||||
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
||||||
value = features[featureName][1] + ((features[featureName][0] - features[featureName][1]) * quality);
|
value = features[featureName][1] + ((features[featureName][0] - features[featureName][1]) * mult);
|
||||||
} else {
|
} else {
|
||||||
value = features[featureName][0] + ((features[featureName][1] - features[featureName][0]) * quality);
|
value = features[featureName][0] + ((features[featureName][1] - features[featureName][0]) * mult);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Higher is worse, but is this making it better or worse?
|
// Higher is worse, but is this making it better or worse?
|
||||||
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
||||||
value = features[featureName][0] + ((features[featureName][1] - features[featureName][0]) * quality);
|
value = features[featureName][0] + ((features[featureName][1] - features[featureName][0]) * mult);
|
||||||
} else {
|
} else {
|
||||||
value = features[featureName][1] + ((features[featureName][0] - features[featureName][1]) * quality);
|
value = features[featureName][1] + ((features[featureName][0] - features[featureName][1]) * mult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Modifications.modifications[featureName].type == 'percentage') {
|
_setValue(ship, m, featureName, value);
|
||||||
value = value * 10000;
|
|
||||||
} else if (Modifications.modifications[featureName].type == 'numeric') {
|
|
||||||
value = value * 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
cb(featureName, value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,6 +340,23 @@ export function setRandom(ship, m) {
|
|||||||
setPercent(ship, m, Math.random() * 100);
|
setPercent(ship, m, Math.random() * 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a modification feature value
|
||||||
|
* @param {Object} ship The ship for which to perform the modifications
|
||||||
|
* @param {Object} m The module for which to perform the modifications
|
||||||
|
* @param {string} featureName The feature being set
|
||||||
|
* @param {number} value The value being set for the feature
|
||||||
|
*/
|
||||||
|
function _setValue(ship, m, featureName, value) {
|
||||||
|
if (Modifications.modifications[featureName].type == 'percentage') {
|
||||||
|
ship.setModification(m, featureName, value * 10000);
|
||||||
|
} else if (Modifications.modifications[featureName].type == 'numeric') {
|
||||||
|
ship.setModification(m, featureName, value * 100);
|
||||||
|
} else {
|
||||||
|
ship.setModification(m, featureName, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide 'percent' primary query
|
* Provide 'percent' primary query
|
||||||
* @param {Object} m The module for which to perform the query
|
* @param {Object} m The module for which to perform the query
|
||||||
@@ -392,7 +372,9 @@ export function getPercent(m) {
|
|||||||
|
|
||||||
let value = _getValue(m, featureName);
|
let value = _getValue(m, featureName);
|
||||||
let mult;
|
let mult;
|
||||||
if (Modifications.modifications[featureName].higherbetter) {
|
if (featureName == 'shieldboost') {
|
||||||
|
mult = ((1 + value) * (1 + m.shieldboost)) - 1 - m.shieldboost;
|
||||||
|
} else if (Modifications.modifications[featureName].higherbetter) {
|
||||||
// Higher is better, but is this making it better or worse?
|
// Higher is better, but is this making it better or worse?
|
||||||
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
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);
|
mult = Math.round((value - features[featureName][1]) / (features[featureName][0] - features[featureName][1]) * 100);
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ export const SHIP_FD_NAME_TO_CORIOLIS_NAME = {
|
|||||||
'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',
|
||||||
|
|||||||
@@ -1,395 +1,293 @@
|
|||||||
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, setQualityCB } from './BlueprintFunctions';
|
import { getBlueprint } from './BlueprintFunctions';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if an imported module is valid
|
* Obtain a module given its FD Name
|
||||||
* @param {Object} module the module to check
|
* @param {string} fdname the FD Name of the module
|
||||||
* @param {Object} moduleType the type of module to check
|
* @return {Module} the module
|
||||||
* @return {boolean} true if the module is valid
|
*/
|
||||||
*/
|
function _moduleFromFdName(fdname) {
|
||||||
function _isValidImportedModule(module, moduleType) {
|
if (!fdname) return null;
|
||||||
// First of all, has the _moduleFromFdName function returned 'null'?
|
fdname = fdname.toLowerCase();
|
||||||
if (!module){
|
// Check standard modules
|
||||||
return false
|
for (const grp in Modules.standard) {
|
||||||
}
|
if (Modules.standard.hasOwnProperty(grp)) {
|
||||||
else {
|
for (const i in Modules.standard[grp]) {
|
||||||
return true
|
if (Modules.standard[grp][i].symbol && Modules.standard[grp][i].symbol.toLowerCase() === fdname) {
|
||||||
}
|
// 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
|
||||||
function _moduleFromFdName(fdname) {
|
for (const grp in Modules.hardpoints) {
|
||||||
if (!fdname) return null;
|
if (Modules.hardpoints.hasOwnProperty(grp)) {
|
||||||
fdname = fdname.toLowerCase();
|
for (const i in Modules.hardpoints[grp]) {
|
||||||
// Check standard modules
|
if (Modules.hardpoints[grp][i].symbol && Modules.hardpoints[grp][i].symbol.toLowerCase() === fdname) {
|
||||||
for (const grp in Modules.standard) {
|
// Found it
|
||||||
if (Modules.standard.hasOwnProperty(grp)) {
|
return new Module({ template: Modules.hardpoints[grp][i] });
|
||||||
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]) {
|
||||||
// Check hardpoint modules
|
if (Modules.internal[grp][i].symbol && Modules.internal[grp][i].symbol.toLowerCase() === fdname) {
|
||||||
for (const grp in Modules.hardpoints) {
|
// Found it
|
||||||
if (Modules.hardpoints.hasOwnProperty(grp)) {
|
return new Module({ template: Modules.internal[grp][i] });
|
||||||
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
|
/**
|
||||||
for (const grp in Modules.internal) {
|
* Build a ship from the journal Loadout event JSON
|
||||||
if (Modules.internal.hasOwnProperty(grp)) {
|
* @param {object} json the Loadout event JSON
|
||||||
for (const i in Modules.internal[grp]) {
|
* @return {Ship} the built ship
|
||||||
if (Modules.internal[grp][i].symbol && Modules.internal[grp][i].symbol.toLowerCase() === fdname) {
|
*/
|
||||||
// Found it
|
export function shipFromLoadoutJSON(json) {
|
||||||
return new Module({ template: Modules.internal[grp][i] });
|
// Start off building a basic ship
|
||||||
}
|
const shipModel = shipModelFromJson(json);
|
||||||
}
|
if (!shipModel) {
|
||||||
}
|
throw 'No such ship found: "' + json.Ship + '"';
|
||||||
}
|
}
|
||||||
|
const shipTemplate = Ships[shipModel];
|
||||||
// Not found
|
|
||||||
return null;
|
let ship = new Ship(shipModel, shipTemplate.properties, shipTemplate.slots);
|
||||||
}
|
ship.buildWith(null);
|
||||||
|
// Initial Ship building, don't do engineering yet.
|
||||||
/**
|
let modsToAdd = [];
|
||||||
* Build a ship from the journal Loadout event JSON
|
|
||||||
* @param {object} json the Loadout event JSON
|
for (const module of json.Modules) {
|
||||||
* @return {Ship} the built ship
|
switch (module.Slot.toLowerCase()) {
|
||||||
*/
|
// Cargo Hatch.
|
||||||
export function shipFromLoadoutJSON(json) {
|
case 'cargohatch':
|
||||||
// Start off building a basic ship
|
ship.cargoHatch.enabled = module.On;
|
||||||
const shipModel = shipModelFromJson(json);
|
ship.cargoHatch.priority = module.Priority;
|
||||||
if (!shipModel) {
|
break;
|
||||||
throw 'No such ship found: "' + json.Ship + '"';
|
// Add the bulkheads
|
||||||
}
|
case 'armour':
|
||||||
const shipTemplate = Ships[shipModel];
|
if (module.Item.toLowerCase().endsWith('_armour_grade1')) {
|
||||||
|
ship.useBulkhead(0, true);
|
||||||
let ship = new Ship(shipModel, shipTemplate.properties, shipTemplate.slots);
|
} else if (module.Item.toLowerCase().endsWith('_armour_grade2')) {
|
||||||
ship.buildWith(null);
|
ship.useBulkhead(1, true);
|
||||||
// Initial Ship building, don't do engineering yet.
|
} else if (module.Item.toLowerCase().endsWith('_armour_grade3')) {
|
||||||
let modsToAdd = [];
|
ship.useBulkhead(2, true);
|
||||||
|
} else if (module.Item.toLowerCase().endsWith('_armour_mirrored')) {
|
||||||
for (const module of json.Modules) {
|
ship.useBulkhead(3, true);
|
||||||
switch (module.Slot.toLowerCase()) {
|
} else if (module.Item.toLowerCase().endsWith('_armour_reactive')) {
|
||||||
// Cargo Hatch.
|
ship.useBulkhead(4, true);
|
||||||
case 'cargohatch':
|
} else {
|
||||||
ship.cargoHatch.enabled = module.On;
|
throw 'Unknown bulkheads "' + module.Item + '"';
|
||||||
ship.cargoHatch.priority = module.Priority;
|
}
|
||||||
break;
|
ship.bulkheads.enabled = true;
|
||||||
// Add the bulkheads
|
if (module.Engineering) _addModifications(ship.bulkheads.m, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
||||||
case 'armour':
|
break;
|
||||||
if (module.Item.toLowerCase().endsWith('_armour_grade1')) {
|
case 'powerplant':
|
||||||
ship.useBulkhead(0, true);
|
const powerplant = _moduleFromFdName(module.Item);
|
||||||
} else if (module.Item.toLowerCase().endsWith('_armour_grade2')) {
|
ship.use(ship.standard[0], powerplant, true);
|
||||||
ship.useBulkhead(1, true);
|
ship.standard[0].enabled = module.On;
|
||||||
} else if (module.Item.toLowerCase().endsWith('_armour_grade3')) {
|
ship.standard[0].priority = module.Priority;
|
||||||
ship.useBulkhead(2, true);
|
if (module.Engineering) _addModifications(powerplant, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
||||||
} else if (module.Item.toLowerCase().endsWith('_armour_mirrored')) {
|
break;
|
||||||
ship.useBulkhead(3, true);
|
case 'mainengines':
|
||||||
} else if (module.Item.toLowerCase().endsWith('_armour_reactive')) {
|
const thrusters = _moduleFromFdName(module.Item);
|
||||||
ship.useBulkhead(4, true);
|
ship.use(ship.standard[1], thrusters, true);
|
||||||
} else {
|
ship.standard[1].enabled = module.On;
|
||||||
throw 'Unknown bulkheads "' + module.Item + '"';
|
ship.standard[1].priority = module.Priority;
|
||||||
}
|
if (module.Engineering) _addModifications(thrusters, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
||||||
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);
|
case 'frameshiftdrive':
|
||||||
break;
|
const frameshiftdrive = _moduleFromFdName(module.Item);
|
||||||
case 'powerplant':
|
ship.use(ship.standard[2], frameshiftdrive, true);
|
||||||
let powerplant = _moduleFromFdName(module.Item);
|
ship.standard[2].enabled = module.On;
|
||||||
// Check the powerplant returned is valid
|
ship.standard[2].priority = module.Priority;
|
||||||
if (!_isValidImportedModule(powerplant, 'powerplant'))
|
if (module.Engineering) _addModifications(frameshiftdrive, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
||||||
{
|
break;
|
||||||
powerplant = _moduleFromFdName('Int_Missing_Powerplant');
|
case 'lifesupport':
|
||||||
module.Engineering = null;
|
const lifesupport = _moduleFromFdName(module.Item);
|
||||||
}
|
ship.use(ship.standard[3], lifesupport, true);
|
||||||
ship.use(ship.standard[0], powerplant, true);
|
ship.standard[3].enabled = module.On === true;
|
||||||
ship.standard[0].enabled = module.On;
|
ship.standard[3].priority = module.Priority;
|
||||||
ship.standard[0].priority = module.Priority;
|
if (module.Engineering) _addModifications(lifesupport, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
||||||
if (module.Engineering) _addModifications(powerplant, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
break;
|
||||||
break;
|
case 'powerdistributor':
|
||||||
case 'mainengines':
|
const powerdistributor = _moduleFromFdName(module.Item);
|
||||||
let thrusters = _moduleFromFdName(module.Item);
|
ship.use(ship.standard[4], powerdistributor, true);
|
||||||
// Check the thrusters returned is valid
|
ship.standard[4].enabled = module.On;
|
||||||
if (!_isValidImportedModule(thrusters, 'thrusters'))
|
ship.standard[4].priority = module.Priority;
|
||||||
{
|
if (module.Engineering) _addModifications(powerdistributor, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
||||||
thrusters = _moduleFromFdName('Int_Missing_Engine');
|
break;
|
||||||
module.Engineering = null;
|
case 'radar':
|
||||||
}
|
const sensors = _moduleFromFdName(module.Item);
|
||||||
ship.use(ship.standard[1], thrusters, true);
|
ship.use(ship.standard[5], sensors, true);
|
||||||
ship.standard[1].enabled = module.On;
|
ship.standard[5].enabled = module.On;
|
||||||
ship.standard[1].priority = module.Priority;
|
ship.standard[5].priority = module.Priority;
|
||||||
if (module.Engineering) _addModifications(thrusters, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
if (module.Engineering) _addModifications(sensors, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
||||||
break;
|
break;
|
||||||
case 'frameshiftdrive':
|
case 'fueltank':
|
||||||
let frameshiftdrive = _moduleFromFdName(module.Item);
|
const fueltank = _moduleFromFdName(module.Item);
|
||||||
// Check the frameshiftdrive returned is valid
|
ship.use(ship.standard[6], fueltank, true);
|
||||||
if (!_isValidImportedModule(frameshiftdrive, 'frameshiftdrive'))
|
ship.standard[6].enabled = true;
|
||||||
{
|
ship.standard[6].priority = 0;
|
||||||
frameshiftdrive = _moduleFromFdName('Int_Missing_Hyperdrive');
|
break;
|
||||||
module.Engineering = null;
|
default:
|
||||||
}
|
}
|
||||||
ship.use(ship.standard[2], frameshiftdrive, true);
|
if (module.Slot.toLowerCase().search(/hardpoint/) !== -1) {
|
||||||
ship.standard[2].enabled = module.On;
|
// Add hardpoints
|
||||||
ship.standard[2].priority = module.Priority;
|
let hardpoint;
|
||||||
if (module.Engineering) _addModifications(frameshiftdrive, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
let hardpointClassNum = -1;
|
||||||
break;
|
let hardpointSlotNum = -1;
|
||||||
case 'lifesupport':
|
let hardpointArrayNum = 0;
|
||||||
let lifesupport = _moduleFromFdName(module.Item);
|
for (let i in shipTemplate.slots.hardpoints) {
|
||||||
// Check the lifesupport returned is valid
|
if (shipTemplate.slots.hardpoints[i] === hardpointClassNum) {
|
||||||
if (!_isValidImportedModule(lifesupport, 'lifesupport'))
|
// Another slot of the same class
|
||||||
{
|
hardpointSlotNum++;
|
||||||
lifesupport = _moduleFromFdName('Int_Missing_LifeSupport');
|
} else {
|
||||||
module.Engineering = null;
|
// The first slot of a new class
|
||||||
}
|
hardpointClassNum = shipTemplate.slots.hardpoints[i];
|
||||||
ship.use(ship.standard[3], lifesupport, true);
|
hardpointSlotNum = 1;
|
||||||
ship.standard[3].enabled = module.On === true;
|
}
|
||||||
ship.standard[3].priority = module.Priority;
|
|
||||||
if (module.Engineering) _addModifications(lifesupport, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
// Now that we know what we're looking for, find it
|
||||||
break;
|
const hardpointName = HARDPOINT_NUM_TO_CLASS[hardpointClassNum] + 'Hardpoint' + hardpointSlotNum;
|
||||||
case 'powerdistributor':
|
const hardpointSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === hardpointName.toLowerCase());
|
||||||
let powerdistributor = _moduleFromFdName(module.Item);
|
if (!hardpointSlot) {
|
||||||
// Check the powerdistributor returned is valid
|
// This can happen with old imports that don't contain new hardpoints
|
||||||
if (!_isValidImportedModule(powerdistributor, 'powerdistributor'))
|
} else if (!hardpointSlot) {
|
||||||
{
|
// No module
|
||||||
powerdistributor = _moduleFromFdName('Int_Missing_PowerDistributor');
|
} else {
|
||||||
module.Engineering = null;
|
hardpoint = _moduleFromFdName(hardpointSlot.Item);
|
||||||
}
|
ship.use(ship.hardpoints[hardpointArrayNum], hardpoint, true);
|
||||||
ship.use(ship.standard[4], powerdistributor, true);
|
ship.hardpoints[hardpointArrayNum].enabled = hardpointSlot.On;
|
||||||
ship.standard[4].enabled = module.On;
|
ship.hardpoints[hardpointArrayNum].priority = hardpointSlot.Priority;
|
||||||
ship.standard[4].priority = module.Priority;
|
modsToAdd.push({ coriolisMod: hardpoint, json: hardpointSlot });
|
||||||
if (module.Engineering) _addModifications(powerdistributor, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
}
|
||||||
break;
|
hardpointArrayNum++;
|
||||||
case 'radar':
|
}
|
||||||
let sensors = _moduleFromFdName(module.Item);
|
}
|
||||||
// Check the sensors returned is valid
|
}
|
||||||
if (!_isValidImportedModule(sensors, 'sensors'))
|
|
||||||
{
|
let internalSlotNum = 0;
|
||||||
sensors = _moduleFromFdName('Int_Missing_Sensors');
|
let militarySlotNum = 1;
|
||||||
module.Engineering = null;
|
for (let i in shipTemplate.slots.internal) {
|
||||||
}
|
if (!shipTemplate.slots.internal.hasOwnProperty(i)) {
|
||||||
ship.use(ship.standard[5], sensors, true);
|
continue;
|
||||||
ship.standard[5].enabled = module.On;
|
}
|
||||||
ship.standard[5].priority = module.Priority;
|
const isMilitary = isNaN(shipTemplate.slots.internal[i]) ? shipTemplate.slots.internal[i].name == 'Military' : false;
|
||||||
if (module.Engineering) _addModifications(sensors, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
|
|
||||||
break;
|
// The internal slot might be a standard or a military slot. Military slots have a different naming system
|
||||||
case 'fueltank':
|
let internalSlot = null;
|
||||||
let fueltank = _moduleFromFdName(module.Item);
|
if (isMilitary) {
|
||||||
// Check the fueltank returned is valid
|
const internalName = 'Military0' + militarySlotNum;
|
||||||
if (!_isValidImportedModule(fueltank, 'fueltank'))
|
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase());
|
||||||
{
|
militarySlotNum++;
|
||||||
fueltank = _moduleFromFdName('Int_Missing_FuelTank');
|
} else {
|
||||||
}
|
// Slot numbers are not contiguous so handle skips.
|
||||||
ship.use(ship.standard[6], fueltank, true);
|
for (; internalSlot === null && internalSlotNum < 99; internalSlotNum++) {
|
||||||
ship.standard[6].enabled = true;
|
// Slot sizes have no relationship to the actual size, either, so check all possibilities
|
||||||
ship.standard[6].priority = 0;
|
for (let slotsize = 0; slotsize < 9; slotsize++) {
|
||||||
break;
|
const internalName = 'Slot' + (internalSlotNum <= 9 ? '0' : '') + internalSlotNum + '_Size' + slotsize;
|
||||||
default:
|
if (json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase())) {
|
||||||
}
|
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase());
|
||||||
if (module.Slot.toLowerCase().search(/hardpoint/) !== -1) {
|
break;
|
||||||
// Add hardpoints
|
}
|
||||||
let hardpoint;
|
}
|
||||||
let hardpointClassNum = -1;
|
}
|
||||||
let hardpointSlotNum = -1;
|
}
|
||||||
let hardpointArrayNum = 0;
|
|
||||||
for (let i in shipTemplate.slots.hardpoints) {
|
if (!internalSlot) {
|
||||||
if (shipTemplate.slots.hardpoints[i] === hardpointClassNum) {
|
// This can happen with old imports that don't contain new slots
|
||||||
// Another slot of the same class
|
} else {
|
||||||
hardpointSlotNum++;
|
const internalJson = internalSlot;
|
||||||
} else {
|
const internal = _moduleFromFdName(internalJson.Item);
|
||||||
// The first slot of a new class
|
ship.use(ship.internal[i], internal, true);
|
||||||
hardpointClassNum = shipTemplate.slots.hardpoints[i];
|
ship.internal[i].enabled = internalJson.On === true;
|
||||||
hardpointSlotNum = 1;
|
ship.internal[i].priority = internalJson.Priority;
|
||||||
}
|
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;
|
|
||||||
const hardpointSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === hardpointName.toLowerCase());
|
for (const i of modsToAdd) {
|
||||||
if (!hardpointSlot) {
|
if (i.json.Engineering) {
|
||||||
// This can happen with old imports that don't contain new hardpoints
|
_addModifications(i.coriolisMod, i.json.Engineering.Modifiers, i.json.Engineering.BlueprintName, i.json.Engineering.Level, i.json.Engineering.ExperimentalEffect);
|
||||||
} else {
|
}
|
||||||
hardpoint = _moduleFromFdName(hardpointSlot.Item);
|
}
|
||||||
// Check the hardpoint module returned is valid
|
// We don't have any information on it so guess it's priority 5 and disabled
|
||||||
if (!_isValidImportedModule(hardpoint, 'hardpoint')){
|
if (!ship.cargoHatch) {
|
||||||
// Check if it's a Utility or Hardpoint
|
ship.cargoHatch.enabled = false;
|
||||||
if (hardpointSlot.Slot.toLowerCase().search(/tiny/))
|
ship.cargoHatch.priority = 4;
|
||||||
{
|
}
|
||||||
// Use the missing_hardpoint module 'Missing Hardpoint' which will inform the user that the module is missing
|
|
||||||
hardpoint = _moduleFromFdName('Hpt_Missing_Hardpoint');
|
// Now update the ship's codes before returning it
|
||||||
}
|
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
|
||||||
ship.use(ship.hardpoints[hardpointArrayNum], hardpoint, true);
|
* @param {Module} module the module
|
||||||
ship.hardpoints[hardpointArrayNum].enabled = hardpointSlot.On;
|
* @param {Object} modifiers the modifiers
|
||||||
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, blueprint, grade, specialModifications) {
|
||||||
modsToAdd.push({ coriolisMod: hardpoint, json: hardpointSlot });
|
if (!modifiers) return;
|
||||||
}
|
let special;
|
||||||
}
|
if (specialModifications) {
|
||||||
hardpointArrayNum++;
|
special = Modifications.specials[specialModifications];
|
||||||
}
|
}
|
||||||
}
|
// Add the blueprint definition, grade and special
|
||||||
}
|
if (blueprint) {
|
||||||
|
module.blueprint = getBlueprint(blueprint, module);
|
||||||
let internalSlotNum = 0;
|
if (grade) {
|
||||||
let militarySlotNum = 1;
|
module.blueprint.grade = Number(grade);
|
||||||
for (let i in shipTemplate.slots.internal) {
|
}
|
||||||
if (!shipTemplate.slots.internal.hasOwnProperty(i)) {
|
if (special) {
|
||||||
continue;
|
module.blueprint.special = special;
|
||||||
}
|
}
|
||||||
const isMilitary = isNaN(shipTemplate.slots.internal[i]) ? shipTemplate.slots.internal[i].name == 'Military' : false;
|
}
|
||||||
const isPlanetary = isNaN(shipTemplate.slots.internal[i]) ? shipTemplate.slots.internal[i].name == 'PlanetaryApproachSuite' : false;
|
for (const i in modifiers) {
|
||||||
|
// Some special modifications
|
||||||
// The internal slot might be a standard or a military slot, or a planetary slot. Military and Planetary slots have a different naming system
|
// Look up the modifiers to find what we need to do
|
||||||
let internalSlot = null;
|
const findMod = val => Object.keys(Modifications.modifierActions).find(elem => elem.toString().toLowerCase().replace(/(outfittingfieldtype_|persecond)/igm, '') === val.toString().toLowerCase().replace(/(outfittingfieldtype_|persecond)/igm, ''));
|
||||||
if (isMilitary) {
|
const modifierActions = Modifications.modifierActions[findMod(modifiers[i].Label)];
|
||||||
const internalName = 'Military0' + militarySlotNum;
|
// TODO: Figure out how to scale this value.
|
||||||
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase());
|
if (!!modifiers[i].LessIsGood) {
|
||||||
militarySlotNum++;
|
|
||||||
} else if (isPlanetary) {
|
}
|
||||||
const internalName = 'PlanetaryApproachSuite';
|
let value = (modifiers[i].Value / modifiers[i].OriginalValue * 100 - 100) * 100;
|
||||||
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase());
|
if (value === Infinity) {
|
||||||
} else {
|
value = modifiers[i].Value * 100;
|
||||||
// Slot numbers are not contiguous so handle skips.
|
}
|
||||||
for (; internalSlot === null && internalSlotNum < 99; internalSlotNum++) {
|
if (modifiers[i].Label.search('Resistance') >= 0) {
|
||||||
// Slot sizes have no relationship to the actual size, either, so check all possibilities
|
value = (modifiers[i].Value * 100) - (modifiers[i].OriginalValue * 100);
|
||||||
for (let slotsize = 0; slotsize < 9; slotsize++) {
|
}
|
||||||
const internalName = 'Slot' + (internalSlotNum <= 9 ? '0' : '') + internalSlotNum + '_Size' + slotsize;
|
if (modifiers[i].Label.search('ShieldMultiplier') >= 0 || modifiers[i].Label.search('DefenceModifierHealthMultiplier') >= 0) {
|
||||||
if (json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase())) {
|
value = ((100 + modifiers[i].Value) / (100 + modifiers[i].OriginalValue) * 100 - 100) * 100;
|
||||||
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase());
|
}
|
||||||
break;
|
|
||||||
}
|
// Carry out the required changes
|
||||||
}
|
for (const action in modifierActions) {
|
||||||
}
|
if (isNaN(modifierActions[action])) {
|
||||||
}
|
module.setModValue(action, modifierActions[action]);
|
||||||
|
} else {
|
||||||
if (!internalSlot) {
|
module.setModValue(action, value, true);
|
||||||
// This can happen with old imports that don't contain new slots
|
}
|
||||||
} else {
|
}
|
||||||
const internalJson = internalSlot;
|
}
|
||||||
let internal = _moduleFromFdName(internalJson.Item);
|
}
|
||||||
// Check the internal module returned is valid
|
|
||||||
if (!_isValidImportedModule(internal, 'internal'))
|
|
||||||
{
|
|
||||||
internal = _moduleFromFdName('Int_Missing_Module');
|
|
||||||
ship.use(ship.internal[i], internal, true);
|
|
||||||
ship.internal[i].enabled = internalJson.On === true;
|
|
||||||
ship.internal[i].priority = internalJson.Priority;
|
|
||||||
//throw 'Unknown internal module: "' + module.Item + '"';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ship.use(ship.internal[i], internal, true);
|
|
||||||
ship.internal[i].enabled = internalJson.On === true;
|
|
||||||
ship.internal[i].priority = internalJson.Priority;
|
|
||||||
modsToAdd.push({ coriolisMod: internal, json: internalSlot });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const i of modsToAdd) {
|
|
||||||
if (i.json.Engineering) {
|
|
||||||
_addModifications(i.coriolisMod, i.json.Engineering.Modifiers, i.json.Engineering.Quality, i.json.Engineering.BlueprintName, i.json.Engineering.Level, i.json.Engineering.ExperimentalEffect);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// We don't have any information on it so guess it's priority 5 and disabled
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ function orbisShorten(url, success, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const API_ORBIS = 'https://api.orbis.zone/ships';
|
const API_ORBIS = 'https://orbis.zone/api/builds/add';
|
||||||
/**
|
/**
|
||||||
* Upload to Orbis
|
* Upload to Orbis
|
||||||
* @param {object} ship The URL to shorten
|
* @param {object} ship The URL to shorten
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Persist from '../stores/Persist';
|
import Persist from '../stores/Persist';
|
||||||
import * as ModuleUtils from '../shipyard/ModuleUtils';
|
import * as ModuleUtils from '../shipyard/ModuleUtils';
|
||||||
import Module from '../shipyard/Module';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if a slot on a ship can mount a module of a particular class and group
|
* Determine if a slot on a ship can mount a module of a particular class and group
|
||||||
@@ -140,21 +139,20 @@ function diff(format, mVal, mmVal) {
|
|||||||
export function diffDetails(language, m, mm) {
|
export function diffDetails(language, m, mm) {
|
||||||
let { formats, translate, units } = language;
|
let { formats, translate, units } = language;
|
||||||
let propDiffs = [];
|
let propDiffs = [];
|
||||||
m = new Module(m);
|
|
||||||
|
|
||||||
// Module-specific items
|
// Module-specific items
|
||||||
|
|
||||||
if (m.grp === 'pp') {
|
if (m.grp === 'pp') {
|
||||||
let mPowerGeneration = m.getPowerGeneration() || 0;
|
let mPowerGeneration = m.pgen || 0;
|
||||||
let mmPowerGeneration = mm ? mm.getPowerGeneration() : 0;
|
let mmPowerGeneration = mm ? mm.getPowerGeneration() : 0;
|
||||||
if (mPowerGeneration != mmPowerGeneration) propDiffs.push(<div key='pgen'>{translate('pgen')}: <span className={diffClass(mPowerGeneration, mmPowerGeneration)}>{diff(formats.round, mPowerGeneration, mmPowerGeneration)}{units.MW}</span></div>);
|
if (mPowerGeneration != mmPowerGeneration) propDiffs.push(<div key='pgen'>{translate('pgen')}: <span className={diffClass(mPowerGeneration, mmPowerGeneration)}>{diff(formats.round, mPowerGeneration, mmPowerGeneration)}{units.MJ}</span></div>);
|
||||||
} else {
|
} else {
|
||||||
let mPowerUsage = m.getPowerUsage() || 0;
|
let mPowerUsage = m.power || 0;
|
||||||
let mmPowerUsage = mm ? mm.getPowerUsage() || 0 : 0;
|
let mmPowerUsage = mm ? mm.getPowerUsage() || 0 : 0;
|
||||||
if (mPowerUsage != mmPowerUsage) propDiffs.push(<div key='power'>{translate('power')}: <span className={diffClass(mPowerUsage, mmPowerUsage, true)}>{diff(formats.round, mPowerUsage, mmPowerUsage)}{units.MW}</span></div>);
|
if (mPowerUsage != mmPowerUsage) propDiffs.push(<div key='power'>{translate('power')}: <span className={diffClass(mPowerUsage, mmPowerUsage, true)}>{diff(formats.round, mPowerUsage, mmPowerUsage)}{units.MJ}</span></div>);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mDps = m.getDps() || 0;
|
let mDps = m.damage * (m.rpshot || 1) * (m.rof || 1);
|
||||||
let mmDps = mm ? mm.getDps() || 0 : 0;
|
let mmDps = mm ? mm.getDps() || 0 : 0;
|
||||||
if (mDps && mDps != mmDps) propDiffs.push(<div key='dps'>{translate('dps')}: <span className={diffClass(mmDps, mDps, true)}>{diff(formats.round, mDps, mmDps)}</span></div>);
|
if (mDps && mDps != mmDps) propDiffs.push(<div key='dps'>{translate('dps')}: <span className={diffClass(mmDps, mDps, true)}>{diff(formats.round, mDps, mmDps)}</span></div>);
|
||||||
|
|
||||||
@@ -166,7 +164,7 @@ export function diffDetails(language, m, mm) {
|
|||||||
|
|
||||||
if (mAffectsShield) {
|
if (mAffectsShield) {
|
||||||
if (m.grp == 'sb') { // Both m and mm must be utility modules if this is true
|
if (m.grp == 'sb') { // Both m and mm must be utility modules if this is true
|
||||||
newShield = this.calcShieldStrengthWith(null, m.getShieldBoost() - (mm ? mm.getShieldBoost() || 0 : 0));
|
newShield = this.calcShieldStrengthWith(null, m.shieldboost - (mm ? mm.getShieldBoost() || 0 : 0));
|
||||||
} else {
|
} else {
|
||||||
newShield = this.calcShieldStrengthWith(m);
|
newShield = this.calcShieldStrengthWith(m);
|
||||||
}
|
}
|
||||||
@@ -181,7 +179,7 @@ export function diffDetails(language, m, mm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m.grp === 'mrp') {
|
if (m.grp === 'mrp') {
|
||||||
let mProtection = m.getProtection();
|
let mProtection = m.protection;
|
||||||
let mmProtection = mm ? mm.getProtection() || 0 : 0;
|
let mmProtection = mm ? mm.getProtection() || 0 : 0;
|
||||||
if (mProtection != mmProtection) {
|
if (mProtection != mmProtection) {
|
||||||
propDiffs.push(<div key='protection'>{translate('protection')}: <span className={diffClass(mmProtection, mProtection, true)}>{diff(formats.pct, mProtection, mmProtection)}</span></div>);
|
propDiffs.push(<div key='protection'>{translate('protection')}: <span className={diffClass(mmProtection, mProtection, true)}>{diff(formats.pct, mProtection, mmProtection)}</span></div>);
|
||||||
@@ -189,7 +187,7 @@ export function diffDetails(language, m, mm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m.grp === 'hr') {
|
if (m.grp === 'hr') {
|
||||||
let mHullReinforcement = m.getHullReinforcement();
|
let mHullReinforcement = m.hullreinforcement;
|
||||||
let mmHullReinforcement = mm ? mm.getHullReinforcement() || 0 : 0;
|
let mmHullReinforcement = mm ? mm.getHullReinforcement() || 0 : 0;
|
||||||
if (mHullReinforcement && mHullReinforcement != mmHullReinforcement) propDiffs.push(<div key='hullreinforcement'>{translate('hullreinforcement')}: <span className={diffClass(mmHullReinforcement, mHullReinforcement, true)}>{diff(formats.round, mHullReinforcement, mmHullReinforcement)}</span></div>);
|
if (mHullReinforcement && mHullReinforcement != mmHullReinforcement) propDiffs.push(<div key='hullreinforcement'>{translate('hullreinforcement')}: <span className={diffClass(mmHullReinforcement, mHullReinforcement, true)}>{diff(formats.round, mHullReinforcement, mmHullReinforcement)}</span></div>);
|
||||||
}
|
}
|
||||||
@@ -221,7 +219,7 @@ export function diffDetails(language, m, mm) {
|
|||||||
let mmCost = mm ? mm.cost : 0;
|
let mmCost = mm ? mm.cost : 0;
|
||||||
if (mCost != mmCost) propDiffs.push(<div key='cost'>{translate('cost')}: <span className={diffClass(mCost, mmCost, true) }>{formats.int(mCost ? Math.round(mCost * (1 - Persist.getModuleDiscount())) : 0)}{units.CR}</span></div>);
|
if (mCost != mmCost) propDiffs.push(<div key='cost'>{translate('cost')}: <span className={diffClass(mCost, mmCost, true) }>{formats.int(mCost ? Math.round(mCost * (1 - Persist.getModuleDiscount())) : 0)}{units.CR}</span></div>);
|
||||||
|
|
||||||
let mMass = m.getMass() || 0;
|
let mMass = m.mass || 0;
|
||||||
let mmMass = mm ? mm.getMass() : 0;
|
let mmMass = mm ? mm.getMass() : 0;
|
||||||
if (mMass != mmMass) propDiffs.push(<div key='mass'>{translate('mass')}: <span className={diffClass(mMass, mmMass, true)}>{diff(formats.round, mMass, mmMass)}{units.T}</span></div>);
|
if (mMass != mmMass) propDiffs.push(<div key='mass'>{translate('mass')}: <span className={diffClass(mMass, mmMass, true)}>{diff(formats.round, mMass, mmMass)}{units.T}</span></div>);
|
||||||
|
|
||||||
@@ -242,7 +240,7 @@ export function diffDetails(language, m, mm) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mIntegrity = m.getIntegrity() || 0;
|
let mIntegrity = m.integrity || 0;
|
||||||
let mmIntegrity = mm ? mm.getIntegrity() || 0 : 0;
|
let mmIntegrity = mm ? mm.getIntegrity() || 0 : 0;
|
||||||
if (mIntegrity != mmIntegrity) {
|
if (mIntegrity != mmIntegrity) {
|
||||||
propDiffs.push(<div key='integrity'>{translate('integrity')}: <span className={diffClass(mmIntegrity, mIntegrity, true)}>{diff(formats.round, mIntegrity, mmIntegrity)}</span></div>);
|
propDiffs.push(<div key='integrity'>{translate('integrity')}: <span className={diffClass(mmIntegrity, mIntegrity, true)}>{diff(formats.round, mIntegrity, mmIntegrity)}</span></div>);
|
||||||
|
|||||||
@@ -8,8 +8,6 @@
|
|||||||
<meta name="description" content="A ship builder, outfitting and comparison
|
<meta name="description" content="A ship builder, outfitting and comparison
|
||||||
tool for Elite Dangerous">
|
tool for Elite Dangerous">
|
||||||
<meta name="mobile-web-app-capable" content="yes">
|
<meta name="mobile-web-app-capable" content="yes">
|
||||||
|
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0,
|
<meta name="viewport" content="width=device-width, initial-scale=1.0,
|
||||||
maximum-scale=1.0, user-scalable=0">
|
maximum-scale=1.0, user-scalable=0">
|
||||||
<link rel="manifest" href="/manifest.json">
|
<link rel="manifest" href="/manifest.json">
|
||||||
@@ -27,25 +25,48 @@
|
|||||||
<meta name="msapplication-TileImage" content="/mstile-144x144.png">
|
<meta name="msapplication-TileImage" content="/mstile-144x144.png">
|
||||||
<meta name="msapplication-config" content="/browserconfig.xml">
|
<meta name="msapplication-config" content="/browserconfig.xml">
|
||||||
<meta name="theme-color" content="#000000">
|
<meta name="theme-color" content="#000000">
|
||||||
<!-- <script data-ad-client="ca-pub-3709458261881414" async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> -->
|
|
||||||
<script>
|
<script>
|
||||||
window.CORIOLIS_GAPI_KEY = '<%- htmlWebpackPlugin.options.gapiKey %>';
|
window.CORIOLIS_GAPI_KEY = '<%- htmlWebpackPlugin.options.gapiKey %>';
|
||||||
window.CORIOLIS_VERSION = '<%- htmlWebpackPlugin.options.version %>';
|
window.CORIOLIS_VERSION = '<%- htmlWebpackPlugin.options.version %>';
|
||||||
window.CORIOLIS_DATE = '<%- htmlWebpackPlugin.options.date.toISOString().slice(0, 10) %>';
|
window.CORIOLIS_DATE = '<%- htmlWebpackPlugin.options.date.toISOString().slice(0, 10) %>';
|
||||||
window.BUGSNAG_VERSION = '<%- htmlWebpackPlugin.options.version + '-' + htmlWebpackPlugin.options.date.toISOString() %>';
|
window.BUGSNAG_VERSION = '<%- htmlWebpackPlugin.options.version + '-' + htmlWebpackPlugin.options.date.toISOString() %>';
|
||||||
</script>
|
</script>
|
||||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
<% if (htmlWebpackPlugin.options.uaTracking) { %>
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-55840909-18"></script>
|
<script>
|
||||||
<script>
|
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
|
||||||
window.dataLayer = window.dataLayer || [];
|
ga('create', '<%- htmlWebpackPlugin.options.uaTracking %>', 'auto');
|
||||||
function gtag(){dataLayer.push(arguments);}
|
ga('send', 'pageview');
|
||||||
gtag('js', new Date());
|
|
||||||
gtag('config', 'UA-55840909-18');
|
|
||||||
</script>
|
</script>
|
||||||
</head>
|
<script async src='https://www.google-analytics.com/analytics.js'></script>
|
||||||
<body style="background-color:#000;">
|
<% } %>
|
||||||
<section id="coriolis">
|
|
||||||
|
|
||||||
</section>
|
<!-- Piwik -->
|
||||||
</body>
|
<!-- <script type="text/javascript">
|
||||||
</html>
|
var _paq = _paq || [];
|
||||||
|
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
|
||||||
|
_paq.push(["setCookieDomain", "*.coriolis.edcd.io"]);
|
||||||
|
_paq.push(['trackPageView']);
|
||||||
|
_paq.push(['enableLinkTracking']);
|
||||||
|
(function() {
|
||||||
|
var u="//stats.isadankme.me/";
|
||||||
|
_paq.push(['setTrackerUrl', u+'piwik.php']);
|
||||||
|
_paq.push(['setSiteId', '4']);
|
||||||
|
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
||||||
|
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
|
||||||
|
})();
|
||||||
|
</script>-->
|
||||||
|
<!-- End Piwik Code -->
|
||||||
|
|
||||||
|
<!-- 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>
|
||||||
|
</head>
|
||||||
|
<body style="background-color:#000;">
|
||||||
|
<section id="coriolis"></section>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
@bgDarken: 40%;
|
@bgDarken: 40%;
|
||||||
@disabledDarken: 15%;
|
@disabledDarken: 15%;
|
||||||
@bgTransparency: 10%;
|
@bgTransparency: 10%;
|
||||||
@bgHighlight: 5%;
|
|
||||||
@fgHighlight: 10%;
|
|
||||||
|
|
||||||
// Foreground colors
|
// Foreground colors
|
||||||
@fg: #CCC;
|
@fg: #CCC;
|
||||||
@@ -23,14 +21,9 @@
|
|||||||
@bgBlack: #000;
|
@bgBlack: #000;
|
||||||
@primary-bg: fadeout(darken(@primary, 47%), 15%);
|
@primary-bg: fadeout(darken(@primary, 47%), 15%);
|
||||||
@alt-primary-bg: fadeout(darken(@primary, 42%), 15%); // Lighter brown background
|
@alt-primary-bg: fadeout(darken(@primary, 42%), 15%); // Lighter brown background
|
||||||
@secondary-bg: fadeout(darken(@secondary, @bgDarken), @bgTransparency); // Blue background
|
@secondary-bg: fadeout(darken(@secondary, @bgDarken), @bgTransparency); // Brown background
|
||||||
@warning-bg: fadeout(darken(@warning, @bgDarken), @bgTransparency); // Dark Red
|
@warning-bg: fadeout(darken(@warning, @bgDarken), @bgTransparency); // Dark Red
|
||||||
|
|
||||||
@alt-primary-bg-highlighted: lighten(@alt-primary-bg, @bgHighlight);
|
|
||||||
@fg-highlighted: lighten(@fg, @fgHighlight);
|
|
||||||
@primary-darker: darken(@primary, 30%);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.fg {
|
.fg {
|
||||||
color: @fg;
|
color: @fg;
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ textarea {
|
|||||||
width:100%;
|
width:100%;
|
||||||
min-height: 10em;
|
min-height: 10em;
|
||||||
resize: vertical;
|
resize: vertical;
|
||||||
user-select: text;
|
user-select: auto;
|
||||||
margin:2em 0;
|
margin:2em 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,45 +49,4 @@ a.ship {
|
|||||||
font-size: 0.7em;
|
font-size: 0.7em;
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.shipyard-table-wrapper {
|
|
||||||
white-space: nowrap;
|
|
||||||
margin: 0 auto;
|
|
||||||
font-size: 0.8em;
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.shipyard-table{
|
|
||||||
tbody tr.comparehighlight{
|
|
||||||
background-color: @secondary-bg;
|
|
||||||
color: @fg-highlighted;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.shipyard-table-wrapper {
|
|
||||||
border-bottom: 1px solid @primary-darker;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shipyard-table-wrapper div .shipyard-table td:last-child {
|
|
||||||
border-right: 1px solid @primary-darker;
|
|
||||||
}
|
|
||||||
.shipyard-table-wrapper > .shipyard-table td:first-child {
|
|
||||||
border-left: 1px solid @primary-darker;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content-wrapper{
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0 auto;
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-tools{
|
|
||||||
text-align: left;
|
|
||||||
color: @primary;
|
|
||||||
label{
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -52,7 +52,7 @@ tbody tr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.no-touch &.highlight:hover, .no-touch &.highlighted {
|
.no-touch &.highlight:hover, .no-touch &.highlighted {
|
||||||
background-color: @alt-primary-bg-highlighted; //@warning-bg;
|
background-color: @warning-bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:nth-child(odd){
|
&:nth-child(odd){
|
||||||
@@ -84,5 +84,3 @@ td {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,98 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<title>Coriolis EDCD Edition</title>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<link rel="stylesheet" href="<%= htmlWebpackPlugin.files.css[0] %>" />
|
|
||||||
<!-- Standard headers -->
|
|
||||||
<meta
|
|
||||||
name="description"
|
|
||||||
content="A ship builder, outfitting and comparison
|
|
||||||
tool for Elite Dangerous"
|
|
||||||
/>
|
|
||||||
<meta name="mobile-web-app-capable" content="yes" />
|
|
||||||
<meta
|
|
||||||
name="viewport"
|
|
||||||
content="width=device-width, initial-scale=1.0,
|
|
||||||
maximum-scale=1.0, user-scalable=0"
|
|
||||||
/>
|
|
||||||
<link rel="manifest" href="/manifest.json" />
|
|
||||||
<link rel="shortcut icon" href=/favicon2.ico>
|
|
||||||
<link
|
|
||||||
rel="icon"
|
|
||||||
sizes="152x152 192x192"
|
|
||||||
type="image/png"
|
|
||||||
href="/192x192.png"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- Apple/iOS headers -->
|
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
||||||
<meta name="apple-mobile-web-app-title" content="Coriolis" />
|
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
|
|
||||||
|
|
||||||
<!-- Microsoft Windows Phone/Tablet headers -->
|
|
||||||
<meta name="msapplication-TileColor" content="#000000" />
|
|
||||||
<meta name="msapplication-TileImage" content="/mstile-144x144.png" />
|
|
||||||
<meta name="msapplication-config" content="/browserconfig.xml" />
|
|
||||||
<meta name="theme-color" content="#000000" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<body style="background-color:#000;">
|
|
||||||
<section id="coriolis">
|
|
||||||
<div class="modal">
|
|
||||||
<h2>
|
|
||||||
Please migrate to <a href="https://coriolis.io">coriolis.io</a>
|
|
||||||
</h2>
|
|
||||||
You are currently on coriolis.<strong>.edcd</strong>.io This domain is
|
|
||||||
considered deprecated. To migrate your builds, copy the below text and
|
|
||||||
go to
|
|
||||||
<a
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
href="https://coriolis.io"
|
|
||||||
>this link</a
|
|
||||||
>, press ctrl + i and then paste in the data. (If you are on mobile,
|
|
||||||
you can go to the settings and hit import)
|
|
||||||
<div>
|
|
||||||
<textarea id="data" class="cb json"></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</body>
|
|
||||||
<script>
|
|
||||||
const LS = localStorage;
|
|
||||||
/**
|
|
||||||
* Safe localstorage get string
|
|
||||||
* @param {String} key key
|
|
||||||
* @return {String} The stored string
|
|
||||||
*/
|
|
||||||
function _getString(key) {
|
|
||||||
return LS ? LS.getItem(key) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Safe localstorage get
|
|
||||||
* @param {String} key key
|
|
||||||
* @return {object | number} The stored data
|
|
||||||
*/
|
|
||||||
function _get(key) {
|
|
||||||
let str = _getString(key);
|
|
||||||
try {
|
|
||||||
return str ? JSON.parse(str) : null;
|
|
||||||
} catch (e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const textarea = document.querySelector("#data");
|
|
||||||
const data = {
|
|
||||||
builds: _get("builds") || {},
|
|
||||||
comparisons: _get("comparisons") || {},
|
|
||||||
insurance: _get("insurance") || "standard",
|
|
||||||
shipDiscount: _get("shipDiscount") || 0,
|
|
||||||
moduleDiscount: _get("moduleDiscount") || 0
|
|
||||||
};
|
|
||||||
textarea.textContent = JSON.stringify(data, null, 2);
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
81
src/sw.js
81
src/sw.js
@@ -1,54 +1,45 @@
|
|||||||
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');
|
||||||
|
|
||||||
// See https://developer.chrome.com/docs/workbox/migration/migrate-from-v4/ for guide to changes made
|
if (workbox) {
|
||||||
console.log('Yay! Workbox is loaded 🎉');
|
console.log('Yay! Workbox is loaded 🎉');
|
||||||
precacheAndRoute(self.__WB_MANIFEST || []);
|
workbox.precaching.precacheAndRoute(self.__precacheManifest);
|
||||||
|
|
||||||
const handler = createHandlerBoundToURL('/index.html');
|
workbox.routing.registerNavigationRoute('/index.html');
|
||||||
const navigationRoute = new NavigationRoute(handler
|
|
||||||
// , {allowlist: [...], denylist: [...],}
|
|
||||||
);
|
|
||||||
registerRoute(navigationRoute);
|
|
||||||
|
|
||||||
|
workbox.routing.registerRoute(
|
||||||
|
new RegExp('/(.*?)'),
|
||||||
|
workbox.strategies.staleWhileRevalidate({
|
||||||
|
plugins: [
|
||||||
|
new workbox.cacheableResponse.Plugin({
|
||||||
|
statuses: [0, 200]
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
registerRoute(
|
workbox.routing.registerRoute(
|
||||||
/\.(?:png|jpg|jpeg|svg|gif)$/,
|
new RegExp('https://fonts.(?:googleapis|gstatic).com/(.*)'),
|
||||||
new CacheFirst({
|
workbox.strategies.cacheFirst({
|
||||||
plugins: [
|
cacheName: 'google-fonts',
|
||||||
new CacheableResponsePlugin({
|
plugins: [
|
||||||
statuses: [0, 200]
|
new workbox.expiration.Plugin({
|
||||||
})
|
maxEntries: 30
|
||||||
]
|
}),
|
||||||
})
|
new workbox.cacheableResponse.Plugin({
|
||||||
);
|
statuses: [0, 200]
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
registerRoute(
|
try {
|
||||||
/\.(?:js|css)$/,
|
workbox.googleAnalytics.initialize();
|
||||||
new StaleWhileRevalidate({
|
} catch (e) {
|
||||||
cacheName: 'static-resources',
|
console.log('Probably an ad-blocker');
|
||||||
})
|
}
|
||||||
);
|
} else {
|
||||||
|
console.log('Boo! Workbox didn\'t load 😬');
|
||||||
registerRoute(
|
}
|
||||||
new RegExp('https://fonts.(?:googleapis|gstatic).com/(.*)'),
|
|
||||||
new CacheFirst({
|
|
||||||
cacheName: 'google-fonts',
|
|
||||||
plugins: [
|
|
||||||
new ExpirationPlugin({
|
|
||||||
maxEntries: 30
|
|
||||||
}),
|
|
||||||
new CacheableResponsePlugin({
|
|
||||||
statuses: [0, 200]
|
|
||||||
})
|
|
||||||
]
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
self.addEventListener('message', event => {
|
self.addEventListener('message', event => {
|
||||||
if (!event.data) {
|
if (!event.data) {
|
||||||
|
|||||||
@@ -1,81 +0,0 @@
|
|||||||
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,27 +1,69 @@
|
|||||||
|
const path = require('path');
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const { merge } = require('webpack-merge');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
const common = require('./webpack.common.js');
|
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||||
|
|
||||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
|
||||||
const WebpackNotifierPlugin = require('webpack-notifier');
|
const WebpackNotifierPlugin = require('webpack-notifier');
|
||||||
|
const pkgJson = require('./package');
|
||||||
|
const buildDate = new Date();
|
||||||
|
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
|
|
||||||
module.exports = merge(common, {
|
module.exports = {
|
||||||
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({
|
new CopyWebpackPlugin(['src/.htaccess', 'src/iframe.html', 'src/xdLocalStoragePostMessageApi.min.js']),
|
||||||
patterns: [
|
// new webpack.optimize.CommonsChunkPlugin({
|
||||||
'src/.htaccess',
|
// name: 'lib',
|
||||||
'src/iframe.html',
|
// filename: 'lib.js'
|
||||||
'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,37 +1,54 @@
|
|||||||
const { merge } = require('webpack-merge');
|
|
||||||
const common = require('./webpack.common.js');
|
|
||||||
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
const webpack = require('webpack');
|
||||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||||
const { InjectManifest } = require('workbox-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 = merge(common, {
|
module.exports = {
|
||||||
// devtool: 'source-map',
|
devtool: 'source-map',
|
||||||
|
entry: {
|
||||||
|
main: './src/app/index.js'
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js', '.jsx', '.json', '.less']
|
||||||
|
},
|
||||||
|
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({
|
new CopyWebpackPlugin(['src/.htaccess', { from: 'src/schemas', to: 'schemas' }, {
|
||||||
patterns: [
|
from: 'src/images/logo/*',
|
||||||
'src/.htaccess',
|
flatten: true,
|
||||||
'src/iframe.html',
|
to: ''
|
||||||
'src/xdLocalStoragePostMessageApi.min.js',
|
}, 'src/iframe.html', 'src/xdLocalStoragePostMessageApi.min.js']),
|
||||||
{ from: 'src/schemas', to: 'schemas' },
|
// new webpack.optimize.CommonsChunkPlugin({
|
||||||
{
|
// name: 'lib',
|
||||||
from: 'src/images/logo/*',
|
// filename: 'lib.[chunkhash:6].js'
|
||||||
to: '[name][ext]'
|
// }),
|
||||||
}
|
new HtmlWebpackPlugin({
|
||||||
]}),
|
inject: true,
|
||||||
/* new HtmlWebpackPlugin({
|
template: path.join(__dirname, 'src/index.ejs'),
|
||||||
// uaTracking: process.env.CORIOLIS_UA_TRACKING || '',
|
uaTracking: process.env.CORIOLIS_UA_TRACKING || '',
|
||||||
}), */
|
gapiKey: process.env.CORIOLIS_GAPI_KEY || '',
|
||||||
new MiniCssExtractPlugin({
|
date: buildDate,
|
||||||
filename: '[contenthash:6].css',
|
version: pkgJson.version
|
||||||
|
}),
|
||||||
|
new ExtractTextPlugin({
|
||||||
|
filename: '[hash:6].css',
|
||||||
|
disable: false,
|
||||||
|
allChunks: true
|
||||||
}),
|
}),
|
||||||
// new BugsnagBuildReporterPlugin({
|
// new BugsnagBuildReporterPlugin({
|
||||||
// apiKey: 'ba9fae819372850fb660755341fa6ef5',
|
// apiKey: 'ba9fae819372850fb660755341fa6ef5',
|
||||||
@@ -42,11 +59,25 @@ module.exports = merge(common, {
|
|||||||
// 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