mirror of
https://github.com/EDCD/coriolis.git
synced 2025-12-10 07:05:35 +00:00
Compare commits
122 Commits
jenkins
...
special-ke
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
934593fe2a | ||
|
|
e4a826592f | ||
|
|
cee4c32551 | ||
|
|
081d8fb86a | ||
|
|
3dfd563d90 | ||
|
|
fd08cd219c | ||
|
|
6a15326d31 | ||
|
|
608ecc51b7 | ||
|
|
fcef26ebbb | ||
|
|
ba6d758ed5 | ||
|
|
43aa3e4e79 | ||
|
|
18f0e060a7 | ||
|
|
c7547e8baf | ||
|
|
ffff242abe | ||
|
|
b44c66b986 | ||
|
|
ae77ec6256 | ||
|
|
4f1e32b154 | ||
|
|
af37c2bfc5 | ||
|
|
5d4ab6f2ad | ||
|
|
0c9db53057 | ||
|
|
b689605ac2 | ||
|
|
baab91e371 | ||
|
|
70e69c7099 | ||
|
|
f4534fd3eb | ||
|
|
93594e1a65 | ||
|
|
b5e449ea54 | ||
|
|
0ff4b849aa | ||
|
|
b99e38043f | ||
|
|
28e3a59473 | ||
|
|
b20290fb60 | ||
|
|
2734beb6f8 | ||
|
|
345eec528c | ||
|
|
7a17e18a76 | ||
|
|
4697677457 | ||
|
|
7d8a5a1368 | ||
|
|
dd7402bd0e | ||
|
|
65592b0fc6 | ||
|
|
0ab66023a6 | ||
|
|
d6fad098ee | ||
|
|
1b5730d337 | ||
|
|
439b615b1b | ||
|
|
a8b30594dc | ||
|
|
9b6b1d328c | ||
|
|
ac2e2e4d69 | ||
|
|
3a5fb31860 | ||
|
|
c610eb8627 | ||
|
|
94980270c4 | ||
|
|
c685e002e3 | ||
|
|
1f665eed9e | ||
|
|
0c4fc1fd9a | ||
|
|
0fc033363e | ||
|
|
fb6e9538bc | ||
|
|
95b98fc4ed | ||
|
|
1840dafed0 | ||
|
|
1ad82b116c | ||
|
|
7bdd17504b | ||
|
|
2d820bb5d5 | ||
|
|
2e14512ed8 | ||
|
|
48ed583c6d | ||
|
|
dd444a17f3 | ||
|
|
2ea63c711e | ||
|
|
6d6d31db25 | ||
|
|
e9273dcb9b | ||
|
|
2bdc4562c6 | ||
|
|
9e8a5323e9 | ||
|
|
8e001063b3 | ||
|
|
dc88fab4c5 | ||
|
|
dfca917e50 | ||
|
|
ef7dfd6ca1 | ||
|
|
435c1b6d45 | ||
|
|
c5c9abe588 | ||
|
|
363735d36b | ||
|
|
2741e7701b | ||
|
|
3be442ea60 | ||
|
|
34cbeca201 | ||
|
|
b37e73ead6 | ||
|
|
ee775521d6 | ||
|
|
5f84aaef1b | ||
|
|
99ac58d999 | ||
|
|
f128a1e87d | ||
|
|
8c0768b451 | ||
|
|
319307136c | ||
|
|
a498452943 | ||
|
|
4b854b8305 | ||
|
|
b400db8216 | ||
|
|
fb811faf5e | ||
|
|
deeb525433 | ||
|
|
1cb88115f6 | ||
|
|
a181791500 | ||
|
|
94eec120da | ||
|
|
48092d4395 | ||
|
|
2457c30b94 | ||
|
|
593f069806 | ||
|
|
a073692632 | ||
|
|
7752d5c9db | ||
|
|
544e5acaef | ||
|
|
9ab35bbaf9 | ||
|
|
98782da200 | ||
|
|
2936364934 | ||
|
|
01e1609a9f | ||
|
|
f85a03a9ae | ||
|
|
2703c2aa23 | ||
|
|
954921c231 | ||
|
|
8bed35a8ba | ||
|
|
9f4ae60577 | ||
|
|
ee3c50e27d | ||
|
|
03020743b3 | ||
|
|
001fed67b7 | ||
|
|
3894915740 | ||
|
|
68fd13e8dc | ||
|
|
fdf16cd959 | ||
|
|
d916c67fe0 | ||
|
|
d8a8e224f4 | ||
|
|
e1c115747c | ||
|
|
e9b6d71606 | ||
|
|
e03e249d2f | ||
|
|
0cfb0b6878 | ||
|
|
600df162aa | ||
|
|
94141aa3c5 | ||
|
|
aca90d7077 | ||
|
|
a66fa8e83f | ||
|
|
194db07057 |
@@ -1,2 +0,0 @@
|
|||||||
node_modules
|
|
||||||
npm-debug.log
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
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;
|
|
||||||
|
|
||||||
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)$ {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
77
.dockerignore
Normal file
77
.dockerignore
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
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
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
"title": "Coriolis",
|
"title": "Coriolis",
|
||||||
"description": "Coriolis Shipyard for Elite Dangerous",
|
"description": "Coriolis Shipyard for Elite Dangerous",
|
||||||
"repository": "https://github.com/EDCD/coriolis",
|
"repository": "https://github.com/EDCD/coriolis",
|
||||||
"site": "https://coriolis.edcd.io",
|
"site": "https://coriolis.io",
|
||||||
"author": "https://github.com/edcd",
|
"author": "https://github.com/edcd",
|
||||||
"image": "./src/images/logo/192x192.png"
|
"image": "./src/images/logo/192x192.png"
|
||||||
}
|
}
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
"title": "Coriolis",
|
"title": "Coriolis",
|
||||||
"description": "Coriolis Shipyard for Elite Dangerous",
|
"description": "Coriolis Shipyard for Elite Dangerous",
|
||||||
"repository": "https://github.com/EDCD/coriolis",
|
"repository": "https://github.com/EDCD/coriolis",
|
||||||
"site": "https://coriolis.edcd.io",
|
"site": "https://coriolis.io",
|
||||||
"author": "https://github.com/edcd",
|
"author": "https://github.com/edcd",
|
||||||
"image": "./src/images/logo/192x192.png"
|
"image": "./src/images/logo/192x192.png"
|
||||||
}
|
}
|
||||||
@@ -100,4 +100,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
13
.gitlab-ci.yml
Normal file
13
.gitlab-ci.yml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
image: docker:stable
|
||||||
|
services:
|
||||||
|
- docker:dind
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- Build image
|
||||||
|
|
||||||
|
docker build:
|
||||||
|
stage: Build image
|
||||||
|
script:
|
||||||
|
- img build --build-arg branch=$CI_COMMIT_REF_NAME -t edcd/coriolis:$CI_COMMIT_REF_NAME .
|
||||||
|
- echo "$REGISTRY_PASSWORD" | img login --username "$REGISTRY_USER" --password-stdin
|
||||||
|
- img push edcd/coriolis:$CI_COMMIT_REF_NAME
|
||||||
@@ -6,29 +6,29 @@ WORKDIR /src/app
|
|||||||
RUN mkdir -p /src/app/coriolis
|
RUN mkdir -p /src/app/coriolis
|
||||||
RUN mkdir -p /src/app/coriolis-data
|
RUN mkdir -p /src/app/coriolis-data
|
||||||
|
|
||||||
COPY ./coriolis/ /src/app/coriolis
|
RUN apk add --update git
|
||||||
COPY ./coriolis-data/ /src/app/coriolis-data
|
|
||||||
|
|
||||||
RUN apk update
|
COPY . /src/app/coriolis
|
||||||
RUN apk add git
|
|
||||||
|
|
||||||
RUN npm i -g npm
|
RUN npm i -g npm
|
||||||
|
|
||||||
# Set up coriolis-data
|
# Set up coriolis-data
|
||||||
WORKDIR /src/app/coriolis-data
|
WORKDIR /src/app/coriolis-data
|
||||||
RUN git fetch --all
|
RUN git clone https://github.com/EDCD/coriolis-data.git .
|
||||||
|
RUN git checkout ${BRANCH}
|
||||||
RUN npm install --no-package-lock
|
RUN npm install --no-package-lock
|
||||||
RUN npm start
|
RUN npm start
|
||||||
|
|
||||||
|
# Set up coriolis
|
||||||
WORKDIR /src/app/coriolis
|
WORKDIR /src/app/coriolis
|
||||||
RUN git fetch --all
|
RUN git checkout ${BRANCH}
|
||||||
RUN npm install --no-package-lock
|
RUN npm install --no-package-lock
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
|
|
||||||
### STAGE 2: Production Environment ###
|
### STAGE 2: Production Environment ###
|
||||||
FROM nginx:1.13.12-alpine as web
|
FROM fholzer/nginx-brotli as web
|
||||||
COPY coriolis/.docker/nginx.conf /etc/nginx/nginx.conf
|
COPY nginx.conf /etc/nginx/nginx.conf
|
||||||
COPY --from=builder /src/app/coriolis/build /usr/share/nginx/html
|
COPY --from=builder /src/app/coriolis/build /usr/share/nginx/html
|
||||||
WORKDIR /usr/share/nginx/html
|
WORKDIR /usr/share/nginx/html
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
23
Jenkinsfile
vendored
23
Jenkinsfile
vendored
@@ -1,23 +0,0 @@
|
|||||||
pipeline {
|
|
||||||
agent any
|
|
||||||
stages {
|
|
||||||
stage('Get coriolis-data') {
|
|
||||||
steps {
|
|
||||||
sh '''YES=`echo $GIT_BRANCH | awk -F / \'{print $2}\'`
|
|
||||||
export BRANCH=`git rev-parse --abbrev-ref $YES`
|
|
||||||
rm -rf $WORKSPACE/../coriolis-data
|
|
||||||
git clone https://github.com/edcd/coriolis-data.git $WORKSPACE/../coriolis-data
|
|
||||||
cd ../coriolis-data
|
|
||||||
git fetch --all
|
|
||||||
git checkout $BRANCH'''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Build') {
|
|
||||||
steps {
|
|
||||||
sshagent (credentials: ['63c9de04-3213-47c3-8345-2f3442097a5b']) {
|
|
||||||
sh 'ssh -p 56499 -o StrictHostKeyChecking=no willb@172.17.0.1 echo hi'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
24
LICENSE.md
Normal file
24
LICENSE.md
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
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.
|
||||||
@@ -29,6 +29,8 @@ Also see [the documentation site.](https://coriolis.willb.info/)
|
|||||||
|
|
||||||
See the [Data wiki](https://github.com/cmmcleod/coriolis-data/wiki) for details on structure, etc.
|
See the [Data wiki](https://github.com/cmmcleod/coriolis-data/wiki) for details on structure, etc.
|
||||||
|
|
||||||
|
You can find hosted and compiled versions of these data-jsons under https://coriolis.io/data/ and https://beta.coriolis.io/data/.
|
||||||
|
You might want to load these as depedency instead of reyling on the npm-dependency.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ version: '2.2'
|
|||||||
services:
|
services:
|
||||||
coriolis_prod:
|
coriolis_prod:
|
||||||
image: edcd/coriolis:master
|
image: edcd/coriolis:master
|
||||||
|
build:
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
args:
|
||||||
|
branch: master
|
||||||
restart: always
|
restart: always
|
||||||
volumes:
|
volumes:
|
||||||
- ./nginx.conf:/etc/nginx/nginx.conf
|
- ./nginx.conf:/etc/nginx/nginx.conf
|
||||||
@@ -17,6 +21,10 @@ services:
|
|||||||
|
|
||||||
coriolis_dev:
|
coriolis_dev:
|
||||||
image: edcd/coriolis:develop
|
image: edcd/coriolis:develop
|
||||||
|
build:
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
args:
|
||||||
|
branch: develop
|
||||||
restart: always
|
restart: always
|
||||||
volumes:
|
volumes:
|
||||||
- ./nginx.conf:/etc/nginx/nginx.conf
|
- ./nginx.conf:/etc/nginx/nginx.conf
|
||||||
129
nginx.conf
129
nginx.conf
@@ -1,61 +1,96 @@
|
|||||||
worker_processes 2;
|
worker_processes 1;
|
||||||
error_log ./nginx.error.log;
|
user nobody nobody;
|
||||||
worker_rlimit_nofile 8192;
|
error_log /tmp/error.log;
|
||||||
pid nginx.pid;
|
pid /tmp/nginx.pid;
|
||||||
|
|
||||||
events {
|
events {
|
||||||
worker_connections 1024;
|
|
||||||
multi_accept on;
|
worker_connections 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
http {
|
http {
|
||||||
|
|
||||||
access_log off;
|
include /etc/nginx/mime.types;
|
||||||
charset UTF-8;
|
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;
|
||||||
|
|
||||||
types {
|
# https://nginx.org/en/docs/http/ngx_http_gzip_module.html
|
||||||
text/html html htm shtml;
|
# Enable gzip compression.
|
||||||
text/css css;
|
# Default: off
|
||||||
text/xml xml rss;
|
gzip off;
|
||||||
image/gif gif;
|
|
||||||
image/jpeg jpeg jpg;
|
|
||||||
application/x-javascript js;
|
|
||||||
text/plain txt;
|
|
||||||
image/png png;
|
|
||||||
image/svg+xml svg;
|
|
||||||
image/x-icon ico;
|
|
||||||
application/pdf pdf;
|
|
||||||
text/cache-manifest appcache;
|
|
||||||
}
|
|
||||||
|
|
||||||
gzip on;
|
# Compression level (1-9).
|
||||||
gzip_vary on;
|
# 5 is a perfect compromise between size and CPU usage, offering about
|
||||||
gzip_proxied any;
|
# 75% reduction for most ASCII files (almost identical to level 9).
|
||||||
gzip_comp_level 6;
|
# Default: 1
|
||||||
gzip_buffers 16 8k;
|
gzip_comp_level 5;
|
||||||
gzip_http_version 1.1;
|
|
||||||
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
|
|
||||||
|
|
||||||
server {
|
# Don't compress anything that's already small and unlikely to shrink much
|
||||||
listen 3301;
|
# if at all (the default is 20 bytes, which is bad as that usually leads to
|
||||||
server_name localhost;
|
# larger files after gzipping).
|
||||||
root ./build/;
|
# Default: 20
|
||||||
index index.html;
|
gzip_min_length 256;
|
||||||
|
|
||||||
location ~* \.(?:manifest|appcache|html?|xml|json|css|js|map|jpg|jpeg|gif|png|ico|svg|eot|ttf|woff|woff2)$ {
|
# Compress data even for clients that are connecting to us via proxies,
|
||||||
expires -1;
|
# identified by the "Via" header (required for CloudFront).
|
||||||
add_header Access-Control-Allow-Origin *;
|
# 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-Credentials true;
|
||||||
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
|
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';
|
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;
|
access_log off;
|
||||||
}
|
}
|
||||||
|
location / {
|
||||||
location / {
|
try_files $uri $uri/ /index.html =404;
|
||||||
try_files $uri $uri/ /index.html =404;
|
}
|
||||||
}
|
location /iframe.html {
|
||||||
location /iframe.html {
|
try_files $uri $uri/ /iframe.html =404;
|
||||||
try_files $uri $uri/ /iframe.html =404;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/EDCD/coriolis"
|
"url": "https://github.com/EDCD/coriolis"
|
||||||
},
|
},
|
||||||
"homepage": "https://coriolis.edcd.io",
|
"homepage": "https://coriolis.io",
|
||||||
"bugs": "https://github.com/EDCD/coriolis/issues",
|
"bugs": "https://github.com/EDCD/coriolis/issues",
|
||||||
"private": true,
|
"private": true,
|
||||||
"engine": "node >= 4.8.1",
|
"engine": "node >= 4.8.1",
|
||||||
@@ -120,6 +120,7 @@
|
|||||||
"webpack-notifier": "^1.6.0",
|
"webpack-notifier": "^1.6.0",
|
||||||
"workbox-webpack-plugin": "^3.6.1"
|
"workbox-webpack-plugin": "^3.6.1"
|
||||||
},
|
},
|
||||||
|
"sideEffects": false,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/polyfill": "^7.0.0",
|
"@babel/polyfill": "^7.0.0",
|
||||||
"browserify-zlib-next": "^1.0.1",
|
"browserify-zlib-next": "^1.0.1",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Router from './Router';
|
import Router from './Router';
|
||||||
import { register } from 'register-service-worker'
|
import { register } from 'register-service-worker';
|
||||||
import { EventEmitter } from 'fbemitter';
|
import { EventEmitter } from 'fbemitter';
|
||||||
import { getLanguage } from './i18n/Language';
|
import { getLanguage } from './i18n/Language';
|
||||||
import Persist from './stores/Persist';
|
import Persist from './stores/Persist';
|
||||||
@@ -72,7 +72,7 @@ export default class Coriolis extends React.Component {
|
|||||||
route: {},
|
route: {},
|
||||||
sizeRatio: Persist.getSizeRatio()
|
sizeRatio: Persist.getSizeRatio()
|
||||||
};
|
};
|
||||||
this._getAnnouncements()
|
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));
|
||||||
@@ -105,18 +105,20 @@ export default class Coriolis extends React.Component {
|
|||||||
}
|
}
|
||||||
r.params.ship = ship.id;
|
r.params.ship = ship.id;
|
||||||
r.params.code = ship.toString();
|
r.params.code = ship.toString();
|
||||||
this._setPage(OutfittingPage, r);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_getAnnouncements() {
|
async _getAnnouncements() {
|
||||||
return request.get('https://orbis.zone/api/announcement')
|
try {
|
||||||
.query({showInCoriolis: true})
|
const announces = await request.get('https://orbis.zone/api/announcement')
|
||||||
.then(announces => {
|
.query({ showInCoriolis: true });
|
||||||
this.setState({ announcements: announces.body })
|
this.setState({ announcements: announces.body });
|
||||||
})
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -351,27 +353,27 @@ export default class Coriolis extends React.Component {
|
|||||||
const self = this;
|
const self = this;
|
||||||
if (process.env.NODE_ENV === 'production') {
|
if (process.env.NODE_ENV === 'production') {
|
||||||
register('/service-worker.js', {
|
register('/service-worker.js', {
|
||||||
ready (registration) {
|
ready(registration) {
|
||||||
console.log('Service worker is active.')
|
console.log('Service worker is active.');
|
||||||
},
|
},
|
||||||
registered (registration) {
|
registered(registration) {
|
||||||
console.log('Service worker has been registered.')
|
console.log('Service worker has been registered.');
|
||||||
},
|
},
|
||||||
cached (registration) {
|
cached(registration) {
|
||||||
console.log('Content has been cached for offline use.')
|
console.log('Content has been cached for offline use.');
|
||||||
},
|
},
|
||||||
updatefound (registration) {
|
updatefound(registration) {
|
||||||
console.log('New content is downloading.')
|
console.log('New content is downloading.');
|
||||||
},
|
},
|
||||||
updated (registration) {
|
updated(registration) {
|
||||||
self.setState({ appCacheUpdate: true });
|
self.setState({ appCacheUpdate: true });
|
||||||
console.log('New content is available; please refresh.')
|
console.log('New content is available; please refresh.');
|
||||||
},
|
},
|
||||||
offline () {
|
offline() {
|
||||||
console.log('No internet connection found. App is running in offline mode.')
|
console.log('No internet connection found. App is running in offline mode.');
|
||||||
},
|
},
|
||||||
error (error) {
|
error(error) {
|
||||||
console.error('Error during service worker registration:', error)
|
console.error('Error during service worker registration:', error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -394,21 +396,24 @@ export default class Coriolis extends React.Component {
|
|||||||
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} currentMenu={currentMenu} />
|
<Header announcements={this.state.announcements} appCacheUpdate={this.state.appCacheUpdate}
|
||||||
<div className="announcement-container">{this.state.announcements.map(a => <Announcement text={a.message}/>)}</div>
|
currentMenu={currentMenu}/>
|
||||||
|
<div className="announcement-container">{this.state.announcements.map(a => <Announcement
|
||||||
|
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>
|
||||||
<br/>
|
<br/>
|
||||||
<a
|
<a
|
||||||
href={'https://github.com/EDCD/coriolis/compare/edcd:develop@{' + window.CORIOLIS_DATE + '}...edcd:develop'}
|
href={'https://github.com/EDCD/coriolis/compare/edcd:develop@{' + window.CORIOLIS_DATE + '}...edcd:develop'}
|
||||||
target="_blank" rel="noopener noreferrer" title={'Coriolis Commits since' + window.CORIOLIS_DATE}>Commits since last release
|
target="_blank" rel="noopener noreferrer" title={'Coriolis Commits since' + window.CORIOLIS_DATE}>Commits
|
||||||
|
since last release
|
||||||
({window.CORIOLIS_DATE})</a>
|
({window.CORIOLIS_DATE})</a>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -259,16 +257,8 @@ 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 match = path.match(/\/outfit\/(.*)(\?code=.*)/);
|
const _paq = window._paq || [];
|
||||||
if (match) {
|
_paq.push(['trackPageView']);
|
||||||
if (match[1]) {
|
|
||||||
ReactGA.ga('set', 'contentGroup1', match[1]);
|
|
||||||
}
|
|
||||||
if (match[2]) {
|
|
||||||
ReactGA.ga('set', 'contentGroup2', match[2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ReactGA.pageview(path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -73,7 +73,16 @@ const GRPCAT = {
|
|||||||
'gfsb': 'guardian',
|
'gfsb': 'guardian',
|
||||||
'gmrp': 'guardian',
|
'gmrp': 'guardian',
|
||||||
'gsc': 'guardian',
|
'gsc': 'guardian',
|
||||||
'ghrp': 'guardian'
|
'ghrp': 'guardian',
|
||||||
|
|
||||||
|
// Mining
|
||||||
|
'scl': 'mining',
|
||||||
|
'pwa': 'mining',
|
||||||
|
'sdm': 'mining',
|
||||||
|
|
||||||
|
// Assists
|
||||||
|
'dc': 'flight assists',
|
||||||
|
'sua': 'flight assists',
|
||||||
};
|
};
|
||||||
// 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 = {
|
||||||
@@ -88,9 +97,10 @@ const CATEGORIES = {
|
|||||||
'rf': ['rf'],
|
'rf': ['rf'],
|
||||||
'shields': ['sg', 'bsg', 'psg', 'scb'],
|
'shields': ['sg', 'bsg', 'psg', 'scb'],
|
||||||
'structural reinforcement': ['hr', 'mrp'],
|
'structural reinforcement': ['hr', 'mrp'],
|
||||||
'dc': ['dc'],
|
'flight assists': ['dc', 'sua'],
|
||||||
|
|
||||||
// Hardpoints
|
// Hardpoints
|
||||||
'lasers': ['pl', 'ul', 'bl', 'ml'],
|
'lasers': ['pl', 'ul', 'bl'],
|
||||||
'projectiles': ['mc', 'c', 'fc', 'pa', 'rg'],
|
'projectiles': ['mc', 'c', 'fc', 'pa', 'rg'],
|
||||||
'ordnance': ['mr', 'tp', 'nl'],
|
'ordnance': ['mr', 'tp', 'nl'],
|
||||||
// Utilities
|
// Utilities
|
||||||
@@ -102,7 +112,9 @@ const CATEGORIES = {
|
|||||||
'experimental': ['axmc', 'axmr', 'rfl', 'tbrfl', 'tbsc', 'tbem', 'xs', 'sfn', 'rcpl', 'dtl', 'rsl', 'mahr',],
|
'experimental': ['axmc', 'axmr', 'rfl', 'tbrfl', 'tbsc', 'tbem', 'xs', 'sfn', 'rcpl', 'dtl', 'rsl', 'mahr',],
|
||||||
|
|
||||||
// Guardian
|
// Guardian
|
||||||
'guardian': ['gpp', 'gpd', 'gpc', 'ggc', 'gsrp', 'gfsb', 'ghrp', 'gmrp', 'gsc']
|
'guardian': ['gpp', 'gpd', 'gpc', 'ggc', 'gsrp', 'gfsb', 'ghrp', 'gmrp', 'gsc'],
|
||||||
|
|
||||||
|
'mining': ['ml', 'scl', 'pwa', 'sdm', 'abl'],
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -114,7 +126,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,
|
||||||
shipMass: PropTypes.number,
|
ship: PropTypes.object.isRequired,
|
||||||
warning: PropTypes.func,
|
warning: PropTypes.func,
|
||||||
firstSlotId: PropTypes.string,
|
firstSlotId: PropTypes.string,
|
||||||
lastSlotId: PropTypes.string,
|
lastSlotId: PropTypes.string,
|
||||||
@@ -122,10 +134,6 @@ 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
|
||||||
@@ -147,15 +155,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, shipMass, onSelect, modules, firstSlotId, lastSlotId } = props;
|
let { m, warning, onSelect, modules, ship } = 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);
|
||||||
@@ -221,7 +229,16 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
}
|
}
|
||||||
list.push(buildGroup(grp, modules[grp]));
|
list.push(buildGroup(grp, modules[grp]));
|
||||||
for (const i of modules[grp]) {
|
for (const i of modules[grp]) {
|
||||||
fuzzy.push({ grp, m: i, name: `${i.class}${i.rating} ${translate(grp)} ${i.mount ? i.mount : ''}` });
|
let mount = '';
|
||||||
|
if (i.mount === 'F') {
|
||||||
|
mount = 'Fixed';
|
||||||
|
} else if (i.mount === 'G') {
|
||||||
|
mount = 'Gimballed';
|
||||||
|
} else if (i.mount === 'T') {
|
||||||
|
mount = 'Turreted';
|
||||||
|
}
|
||||||
|
const fuzz = { grp, m: i, name: `${i.class}${i.rating}${mount ? ' ' + mount : ''} ${translate(grp)}` };
|
||||||
|
fuzzy.push(fuzz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -234,18 +251,16 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 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(translate, mountedModule, warningFunc, mass, onSelect, grp, modules, firstSlotId, lastSlotId) {
|
_buildGroup(ship, translate, mountedModule, warningFunc, onSelect, grp, modules) {
|
||||||
let prevClass = null, prevRating = null, prevName;
|
let prevClass = null, prevRating = null, prevName;
|
||||||
let elems = [];
|
let elems = [];
|
||||||
|
|
||||||
@@ -266,10 +281,11 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
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 = mass > m.maxmass;
|
disabled = ship.hullMass > m.maxmass;
|
||||||
} else if (m.maxmass) {
|
// If the mounted module is experimental as well, we can replace it so
|
||||||
// Thrusters care about total mass
|
// the maximum does not apply
|
||||||
disabled = mass + m.mass > m.maxmass;
|
} else if (m.experimental && (!mountedModule || !mountedModule.experimental)) {
|
||||||
|
disabled = 4 <= ship.hardpoints.filter(o => o.m && o.m.experimental).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', {
|
||||||
@@ -363,10 +379,14 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
* mounted module and the hovered modules
|
* mounted module and the hovered modules
|
||||||
*/
|
*/
|
||||||
_showSearch() {
|
_showSearch() {
|
||||||
|
if (this.props.modules instanceof Array) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<FuzzySearch
|
<FuzzySearch
|
||||||
list={this.state.fuzzy}
|
list={this.state.fuzzy}
|
||||||
keys={['grp', 'name']}
|
keys={['grp', 'name']}
|
||||||
|
tokenize={true}
|
||||||
className={'input'}
|
className={'input'}
|
||||||
width={'100%'}
|
width={'100%'}
|
||||||
style={{ padding: 0 }}
|
style={{ padding: 0 }}
|
||||||
|
|||||||
@@ -52,12 +52,12 @@ export default class Defence extends TranslatedComponent {
|
|||||||
* @return {React.Component} contents
|
* @return {React.Component} contents
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
const { ship, sys, opponentWep } = this.props;
|
const { opponent, 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 = ship.standard[4].m;
|
const pd = opponent.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.getClip() * m.getEps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload()))}{u.MW})</span> : null}</div> : null}
|
<span>({formats.round1(m.getEps() * m.getSustainedFactor())}{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.getClip() * m.getHps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload()))})</span> : null}</div> : null}
|
<span>({formats.round1(m.getHps() * m.getSustainedFactor())})</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,11 +121,14 @@ 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('reload')}: {formats.round(m.getReload())}{u.s}</div> : null}
|
{m.getReload() ? <div className={'l'}>{translate('wep_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}
|
||||||
{m.getJitter() ? <div className={'l'}>{translate('jitter')}: {formats.f2(m.getJitter())}°</div> : null}
|
{m.getJitter() ? <div className={'l'}>{translate('jitter')}: {formats.f2(m.getJitter())}°</div> : null}
|
||||||
|
{m.getScanAngle() ? <div className={'l'}>{translate('scan angle')}: {formats.f2(m.getScanAngle())}°</div> : null}
|
||||||
|
{m.getScanRange() ? <div className={'l'}>{translate('scan range')}: {formats.int(m.getScanRange())}{u.m}</div> : null}
|
||||||
|
{m.getMaxAngle() ? <div className={'l'}>{translate('max angle')}: {formats.f2(m.getMaxAngle())}°</div> : null}
|
||||||
{showModuleResistances && m.getExplosiveResistance() ? <div
|
{showModuleResistances && m.getExplosiveResistance() ? <div
|
||||||
className='l'>{translate('explres')}: {formats.pct(m.getExplosiveResistance())}</div> : null}
|
className='l'>{translate('explres')}: {formats.pct(m.getExplosiveResistance())}</div> : null}
|
||||||
{showModuleResistances && m.getKineticResistance() ? <div
|
{showModuleResistances && m.getKineticResistance() ? <div
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -349,7 +349,7 @@ export default class Header extends TranslatedComponent {
|
|||||||
_getShipsMenu() {
|
_getShipsMenu() {
|
||||||
let shipList = [];
|
let shipList = [];
|
||||||
|
|
||||||
for (let s in Ships) {
|
for (let s of this.shipOrder) {
|
||||||
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>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,7 +78,6 @@ 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 }
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import { Download } from './SvgIcons';
|
|||||||
import { outfitURL } from '../utils/UrlGenerators';
|
import { outfitURL } from '../utils/UrlGenerators';
|
||||||
import * as CompanionApiUtils from '../utils/CompanionApiUtils';
|
import * as CompanionApiUtils from '../utils/CompanionApiUtils';
|
||||||
|
|
||||||
|
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\\- ]+)');
|
||||||
const mountMap = { 'H': 4, 'L': 3, 'M': 2, 'S': 1, 'U': 0 };
|
const mountMap = { 'H': 4, 'L': 3, 'M': 2, 'S': 1, 'U': 0 };
|
||||||
@@ -99,6 +101,7 @@ 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,
|
||||||
@@ -111,12 +114,28 @@ 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
|
||||||
@@ -159,7 +178,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({ shipDiscount: importData.moduleDiscount * 1 });
|
this.setState({ moduleDiscount: importData.moduleDiscount * 1 });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof importData.insurance == 'string') {
|
if (typeof importData.insurance == 'string') {
|
||||||
@@ -345,12 +364,14 @@ 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.stack);
|
console.log(e);
|
||||||
this.setState({ errorMsg: (typeof e == 'string') ? e : 'Cannot Parse the data!' });
|
this.setState({ errorMsg: (typeof e == 'string') ? e : 'Cannot Parse the data!' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -364,6 +385,10 @@ 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;
|
||||||
@@ -480,7 +505,7 @@ export default class ModalImport extends TranslatedComponent {
|
|||||||
if (!state.processed) {
|
if (!state.processed) {
|
||||||
importStage = (
|
importStage = (
|
||||||
<div>
|
<div>
|
||||||
<textarea className='cb json' ref={node => this.importField = node} onChange={this._validateImport} defaultValue={this.state.importString} placeholder={translate('PHRASE_IMPORT')} />
|
<textarea spellCheck={false} 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>
|
||||||
|
|||||||
@@ -109,17 +109,18 @@ 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 = 'No modded components.';
|
target.innerText = translate('No modded components.');
|
||||||
target.disabled = true;
|
target.disabled = true;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
target.innerText = 'Send to EDEngineer';
|
target.innerText = translate('Send to EDEngineer');
|
||||||
target.disabled = false;
|
target.disabled = false;
|
||||||
}, 3000);
|
}, 3000);
|
||||||
} else {
|
} else {
|
||||||
target.innerText = 'Sending...';
|
target.innerText = translate('Sending...');
|
||||||
}
|
}
|
||||||
let countSent = 0;
|
let countSent = 0;
|
||||||
let countTotal = this.state.blueprints.length;
|
let countTotal = this.state.blueprints.length;
|
||||||
@@ -139,7 +140,7 @@ export default class ModalShoppingList extends TranslatedComponent {
|
|||||||
countSent++;
|
countSent++;
|
||||||
if (countSent === countTotal) {
|
if (countSent === countTotal) {
|
||||||
target.disabled = false;
|
target.disabled = false;
|
||||||
target.innerText = 'Send to EDEngineer';
|
target.innerText = translate('Send to EDEngineer');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -230,32 +231,32 @@ export default class ModalShoppingList extends TranslatedComponent {
|
|||||||
this.sendToEDEng = this.sendToEDEng.bind(this);
|
this.sendToEDEng = this.sendToEDEng.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>Grade 1 rolls </label>
|
<label>{translate('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>Grade 2 rolls </label>
|
<label>{translate('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>Grade 3 rolls </label>
|
<label>{translate('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>Grade 4 rolls </label>
|
<label>{translate('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>Grade 5 rolls </label>
|
<label>{translate('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'}>CMDR Name </label>
|
<label hidden={!compatible} className={'l cap'}>{translate('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'}>Failed to send to EDEngineer (Launch EDEngineer and make sure the API is started then refresh the page.)</p>
|
<p hidden={!this.state.failed} id={'failed'} className={'l'}>{translate('PHRASE_FAIL_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>
|
<p hidden={compatible} id={'browserbad'} className={'l'}>{translate('PHRASE_FIREFOX_EDENGINEER')}</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 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,7 +3,8 @@ 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 { isValueBeneficial } from '../utils/BlueprintFunctions';
|
import { isChangeValueBeneficial } from '../utils/BlueprintFunctions';
|
||||||
|
import { Modifications } from 'coriolis-data/dist';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modification
|
* Modification
|
||||||
@@ -79,6 +80,7 @@ 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
|
||||||
@@ -117,10 +119,10 @@ export default class Modification extends TranslatedComponent {
|
|||||||
</td>
|
</td>
|
||||||
<td style={{ textAlign: 'center' }} className={
|
<td style={{ textAlign: 'center' }} className={
|
||||||
modValue ?
|
modValue ?
|
||||||
isValueBeneficial(name, modValue) ? 'secondary' : 'warning' :
|
isChangeValueBeneficial(name, modValue) ? 'secondary' : 'warning' :
|
||||||
''
|
''
|
||||||
}>
|
}>
|
||||||
{formats.f2(modValue / 100) || 0}%
|
{formats.f2(modValue / 100) || 0}{isOverwrite ? '' : '%'}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ export default class ModificationsMenu extends TranslatedComponent {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const classes = cn('button-inline-menu', {
|
const classes = cn('button-inline-menu', {
|
||||||
active: m.blueprint && m.blueprint.special && m.blueprint.special.edname == specialName
|
active: m.blueprint && m.blueprint.special && m.blueprint.special.key == specialName
|
||||||
});
|
});
|
||||||
if (classes.indexOf('active') >= 0) this.selectedSpecialId = specialName;
|
if (classes.indexOf('active') >= 0) this.selectedSpecialId = specialName;
|
||||||
const close = this._specialSelected.bind(this, specialName);
|
const close = this._specialSelected.bind(this, specialName);
|
||||||
@@ -437,7 +437,7 @@ export default class ModificationsMenu extends TranslatedComponent {
|
|||||||
let specialTt;
|
let specialTt;
|
||||||
if (m.blueprint && m.blueprint.special) {
|
if (m.blueprint && m.blueprint.special) {
|
||||||
specialLabel = 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.key);
|
||||||
} 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('roll') }: </td>
|
<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: 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>
|
||||||
|
|||||||
@@ -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('defence')}</th>
|
<th style={{ width:'25%' }} className={cn({ active: tab == 'defence' })} onClick={this._showTab.bind(this, 'defence')} >{translate('tab_defence')}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ 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);
|
||||||
@@ -71,7 +72,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}>{translate('jump range')}</th>
|
<th colSpan={5} className={ cn({ 'bg-warning-disabled': !canJump }) }>{translate('jump range')}</th>
|
||||||
<th rowSpan={2}>{translate('shield')}</th>
|
<th rowSpan={2}>{translate('shield')}</th>
|
||||||
<th rowSpan={2}>{translate('integrity')}</th>
|
<th rowSpan={2}>{translate('integrity')}</th>
|
||||||
<th rowSpan={2}>{translate('DPS')}</th>
|
<th rowSpan={2}>{translate('DPS')}</th>
|
||||||
@@ -85,15 +86,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_TIME', { cap: 0 })} onMouseLeave={hide} rowSpan={2}>{translate('boost time')}</th>
|
<th onMouseEnter={termtip.bind(null, 'TT_SUMMARY_BOOST_INTERVAL', { cap: 0 })} onMouseLeave={hide} rowSpan={2}>{translate('boost interval')}</th>
|
||||||
<th rowSpan={2}>{translate('resting heat (Beta)')}</th>
|
<th rowSpan={2}>{translate('resting heat (Beta)')}</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th className='lft'>{translate('max')}</th>
|
<th className={ cn({ 'lft': true, 'bg-warning-disabled': !canJump }) }>{translate('max')}</th>
|
||||||
<th>{translate('unladen')}</th>
|
<th className={ cn({ 'bg-warning-disabled': !canJump }) }>{translate('unladen')}</th>
|
||||||
<th>{translate('laden')}</th>
|
<th className={ cn({ 'bg-warning-disabled': !canJump }) }>{translate('laden')}</th>
|
||||||
<th>{translate('total unladen')}</th>
|
<th className={ cn({ 'bg-warning-disabled': !canJump }) }>{translate('total unladen')}</th>
|
||||||
<th>{translate('total laden')}</th>
|
<th className={ cn({ 'bg-warning-disabled': !canJump }) }>{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>
|
||||||
@@ -103,11 +104,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><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_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_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_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_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_LADEN_SINGLE_JUMP', { cap: 0 })} onMouseLeave={hide}>{ canJump ? <span>{f2(Calc.jumpRange(ship.unladenMass + ship.fuelCapacity + ship.cargoCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}</span> : <span className='warning'>0 <Warning/></span> }</td>
|
||||||
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_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_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_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 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 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>
|
||||||
@@ -159,10 +160,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 && ship.shield > 0 ? ship.shield : 0)}{u.MJ}</td>
|
<td>{int(ship && sgMetrics.summary > 0 ? sgMetrics.summary : 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 > 0 ? sgMetrics.summary / sgMetrics.explosive.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.kinetic.base : 0)}{u.MJ}</td>
|
||||||
<td>{int(ship && ship.shield > 0 ? ship.shield * ((1 / (1 - (ship.shieldThermRes)))) : 0)}{u.MJ}</td>
|
<td>{int(ship && sgMetrics.summary ? sgMetrics.summary / sgMetrics.thermal.base : 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>
|
||||||
@@ -197,11 +198,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(ship.armour)}</td>
|
<td>{int(armourMetrics.total)}</td>
|
||||||
<td>{int(ship.armour * ((1 / (1 - (ship.hullExplRes)))))}</td>
|
<td>{int(armourMetrics.total / armourMetrics.explosive.total)}</td>
|
||||||
<td>{int(ship.armour * ((1 / (1 - (ship.hullKinRes)))))}</td>
|
<td>{int(armourMetrics.total/ armourMetrics.kinetic.total)}</td>
|
||||||
<td>{int(ship.armour * ((1 / (1 - (ship.hullThermRes)))))}</td>
|
<td>{int(armourMetrics.total / armourMetrics.thermal.total)}</td>
|
||||||
<td>{int(ship.armour * ((1 / (1 - (ship.hullCausRes)))))}</td>
|
<td>{int(armourMetrics.total/ armourMetrics.caustic.total)}</td>
|
||||||
<td>{int(armourMetrics.modulearmour)}</td>
|
<td>{int(armourMetrics.modulearmour)}</td>
|
||||||
<td>{int(armourMetrics.moduleprotection * 100) + '%'}</td>
|
<td>{int(armourMetrics.moduleprotection * 100) + '%'}</td>
|
||||||
|
|
||||||
|
|||||||
@@ -127,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)}
|
||||||
|
|||||||
@@ -195,6 +195,15 @@ 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;
|
||||||
|
|||||||
@@ -109,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)}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ 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 d3 from 'd3';
|
import * as d3 from 'd3';
|
||||||
|
|
||||||
let fallbackTerms = EN.terms;
|
let fallbackTerms = EN.terms;
|
||||||
@@ -27,6 +28,7 @@ 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;
|
||||||
default:
|
default:
|
||||||
lang = EN;
|
lang = EN;
|
||||||
}
|
}
|
||||||
@@ -94,5 +96,6 @@ export const Languages = {
|
|||||||
fr: 'Français',
|
fr: 'Français',
|
||||||
ru: 'ру́сский',
|
ru: 'ру́сский',
|
||||||
pl: 'polski',
|
pl: 'polski',
|
||||||
pt: 'português'
|
pt: 'português',
|
||||||
|
cn: '中文'
|
||||||
};
|
};
|
||||||
|
|||||||
16
src/app/i18n/cn.js
Normal file
16
src/app/i18n/cn.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
export const formats = {
|
||||||
|
decimal: '.',
|
||||||
|
thousands: ',',
|
||||||
|
grouping: [3],
|
||||||
|
currency: ['¥', ''],
|
||||||
|
dateTime: '%a %b %e %X %Y',
|
||||||
|
date: '%Y年%m月%d日',
|
||||||
|
time: '%H:%M:%S',
|
||||||
|
periods: ['AM', 'PM'],
|
||||||
|
days: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],
|
||||||
|
shortDays: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'],
|
||||||
|
months: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
|
||||||
|
shortMonths: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月']
|
||||||
|
};
|
||||||
|
|
||||||
|
export { default as terms } from './cn.json';
|
||||||
405
src/app/i18n/cn.json
Normal file
405
src/app/i18n/cn.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -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_TIME": "Time between each boost with 4 pips to ENG",
|
"TT_SUMMARY_BOOST_INTERVAL": "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,6 +81,8 @@
|
|||||||
"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.",
|
||||||
"am": "Auto Field-Maintenance Unit",
|
"am": "Auto Field-Maintenance Unit",
|
||||||
"bh": "Bulkheads",
|
"bh": "Bulkheads",
|
||||||
"bl": "Beam Laser",
|
"bl": "Beam Laser",
|
||||||
@@ -132,6 +134,10 @@
|
|||||||
"gfsb": "Guardian Frame Shift Drive Booster",
|
"gfsb": "Guardian Frame Shift Drive Booster",
|
||||||
"ghrp": "Guardian Hull Reinforcement Package",
|
"ghrp": "Guardian Hull Reinforcement Package",
|
||||||
"gmrp": "Guardian Module Reinforcement Package",
|
"gmrp": "Guardian Module Reinforcement Package",
|
||||||
|
"pwa": "Pulse Wave Analyser",
|
||||||
|
"abl": "Abrasion Blaster",
|
||||||
|
"scl": "Seismic Charge Launcher",
|
||||||
|
"sdm": "Sub-Surface Displacement Missile",
|
||||||
"tbsc": "Shock Cannon",
|
"tbsc": "Shock Cannon",
|
||||||
"gsc": "Guardian Shard Cannon",
|
"gsc": "Guardian Shard Cannon",
|
||||||
"psg": "Prismatic Shield Generator",
|
"psg": "Prismatic Shield Generator",
|
||||||
@@ -147,6 +153,7 @@
|
|||||||
"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",
|
||||||
"ul": "Burst Laser",
|
"ul": "Burst Laser",
|
||||||
@@ -168,6 +175,7 @@
|
|||||||
"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",
|
||||||
@@ -197,7 +205,7 @@
|
|||||||
"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 time": "Boost time",
|
"boost interval": "Boost intervall",
|
||||||
"total": "Total",
|
"total": "Total",
|
||||||
"ammo": "Ammunition maximum",
|
"ammo": "Ammunition maximum",
|
||||||
"boot": "Boot time",
|
"boot": "Boot time",
|
||||||
@@ -234,6 +242,7 @@
|
|||||||
"rof": "Rate of fire",
|
"rof": "Rate of fire",
|
||||||
"angle": "Scan angle",
|
"angle": "Scan angle",
|
||||||
"scanrate": "Scan rate",
|
"scanrate": "Scan rate",
|
||||||
|
"proberadius": "Probe Radius",
|
||||||
"scantime": "Scan time",
|
"scantime": "Scan time",
|
||||||
"shield": "Shield",
|
"shield": "Shield",
|
||||||
"armour": "Armour",
|
"armour": "Armour",
|
||||||
@@ -315,6 +324,7 @@
|
|||||||
"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",
|
||||||
"fastest range": "gamme la plus rapide",
|
"farthest 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",
|
||||||
|
|||||||
@@ -299,7 +299,7 @@
|
|||||||
"edit data": "Редактирование",
|
"edit data": "Редактирование",
|
||||||
"empty all": "пусто все",
|
"empty all": "пусто все",
|
||||||
"Enter Name": "Введите имя",
|
"Enter Name": "Введите имя",
|
||||||
"fastest range": "быстрый диапазон",
|
"farthest range": "быстрый диапазон",
|
||||||
"fuel level": "уровень топлива",
|
"fuel level": "уровень топлива",
|
||||||
"full tank": "Полный бак",
|
"full tank": "Полный бак",
|
||||||
"internal compartments": "внутренние отсеки",
|
"internal compartments": "внутренние отсеки",
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ export default class AboutPage extends Page {
|
|||||||
patreon.com/coriolis_elite
|
patreon.com/coriolis_elite
|
||||||
</a>
|
</a>
|
||||||
, which will be used to keep Coriolis up to date and the servers
|
, which will be used to keep Coriolis up to date and the servers
|
||||||
running. I also run ads, which are also used for development and hosting.
|
running.
|
||||||
</p>
|
</p>
|
||||||
<form
|
<form
|
||||||
action="https://www.paypal.com/cgi-bin/webscr"
|
action="https://www.paypal.com/cgi-bin/webscr"
|
||||||
|
|||||||
@@ -224,9 +224,12 @@ export default class OutfittingPage extends Page {
|
|||||||
const control = LZString.decompressFromBase64(
|
const control = LZString.decompressFromBase64(
|
||||||
Utils.fromUrlSafe(parts[4])
|
Utils.fromUrlSafe(parts[4])
|
||||||
).split('/');
|
).split('/');
|
||||||
sys = parseFloat(control[0]) || sys;
|
sys = parseFloat(control[0]);
|
||||||
eng = parseFloat(control[1]) || eng;
|
eng = parseFloat(control[1]);
|
||||||
wep = parseFloat(control[2]) || wep;
|
wep = parseFloat(control[2]);
|
||||||
|
if (sys + eng + wep > 6) {
|
||||||
|
sys = eng = wep = 2;
|
||||||
|
}
|
||||||
boost = control[3] == 1 ? true : false;
|
boost = control[3] == 1 ? true : false;
|
||||||
fuel = parseFloat(control[4]) || fuel;
|
fuel = parseFloat(control[4]) || fuel;
|
||||||
cargo = parseInt(control[5]) || cargo;
|
cargo = parseInt(control[5]) || cargo;
|
||||||
|
|||||||
@@ -51,22 +51,16 @@ export default class Page extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pages are 'pure' components that only render when props, state, or context changes.
|
* Update the window title upon mount
|
||||||
* 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) {
|
componentWillMount() {
|
||||||
return !shallowEqual(this.props, np) || !shallowEqual(this.state, ns) || !shallowEqual(this.context, nc);
|
document.title = this.state.title || 'Coriolis';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the window title upon mount
|
* Update the window title upon mount
|
||||||
*/
|
*/
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
document.title = this.state.title || 'Coriolis';
|
document.title = this.state.title || 'Coriolis';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -126,12 +126,14 @@ 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
|
* Higlight the current ship in the table on mouse over
|
||||||
* @param {String} shipId Ship Id
|
* @param {String} shipId Ship Id
|
||||||
* @param {SyntheticEvent} event Event
|
* @param {SyntheticEvent} event Event
|
||||||
*/
|
*/
|
||||||
@@ -140,6 +142,24 @@ 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
|
||||||
@@ -169,10 +189,9 @@ export default class ShipyardPage extends Page {
|
|||||||
* @param {Object} u Localized unit map
|
* @param {Object} u Localized unit map
|
||||||
* @param {Function} fInt Localized integer formatter
|
* @param {Function} fInt Localized integer formatter
|
||||||
* @param {Function} fRound Localized round formatter
|
* @param {Function} fRound Localized round formatter
|
||||||
* @param {Boolean} highlight Should this row be highlighted
|
|
||||||
* @return {React.Component} Table Row
|
* @return {React.Component} Table Row
|
||||||
*/
|
*/
|
||||||
_shipRowElement(s, translate, u, fInt, fRound, highlight) {
|
_shipRowElement(s, translate, u, fInt, fRound) {
|
||||||
let noTouch = this.context.noTouch;
|
let noTouch = this.context.noTouch;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -181,9 +200,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,
|
||||||
alt: highlight
|
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">{s.manufacturer}</td>
|
||||||
<td className="ri">{fInt(s.retailCost)}</td>
|
<td className="ri">{fInt(s.retailCost)}</td>
|
||||||
@@ -236,7 +256,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 } = this.state;
|
let { shipSummaries, shipPredicate, shipPredicateIndex, compare, groupCompared } = this.state;
|
||||||
let sortShips = (predicate, index) =>
|
let sortShips = (predicate, index) =>
|
||||||
this._sortShips.bind(this, predicate, index);
|
this._sortShips.bind(this, predicate, index);
|
||||||
|
|
||||||
@@ -269,6 +289,15 @@ 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;
|
||||||
@@ -286,27 +315,13 @@ export default class ShipyardPage extends Page {
|
|||||||
let shipRows = new Array(shipSummaries.length);
|
let shipRows = new Array(shipSummaries.length);
|
||||||
let detailRows = new Array(shipSummaries.length);
|
let detailRows = new Array(shipSummaries.length);
|
||||||
|
|
||||||
let lastShipSortValue = null;
|
|
||||||
let backgroundHighlight = false;
|
|
||||||
|
|
||||||
for (let s of shipSummaries) {
|
for (let s of shipSummaries) {
|
||||||
let shipSortValue = s[shipPredicate];
|
|
||||||
if (shipPredicateIndex != undefined) {
|
|
||||||
shipSortValue = shipSortValue[shipPredicateIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shipSortValue != lastShipSortValue) {
|
|
||||||
backgroundHighlight = !backgroundHighlight;
|
|
||||||
lastShipSortValue = shipSortValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
detailRows[i] = this._shipRowElement(
|
detailRows[i] = this._shipRowElement(
|
||||||
s,
|
s,
|
||||||
translate,
|
translate,
|
||||||
units,
|
units,
|
||||||
fInt,
|
fInt,
|
||||||
formats.f1,
|
formats.f1,
|
||||||
backgroundHighlight
|
|
||||||
);
|
);
|
||||||
shipRows[i] = (
|
shipRows[i] = (
|
||||||
<tr
|
<tr
|
||||||
@@ -314,9 +329,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,
|
||||||
alt: backgroundHighlight
|
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>
|
||||||
@@ -327,18 +343,10 @@ export default class ShipyardPage extends Page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="page" style={{ fontSize: sizeRatio + 'em' }}>
|
<div className="page" style={{fontSize: sizeRatio + 'em'}}>
|
||||||
<div
|
<div className="content-wrapper">
|
||||||
style={{
|
<div className="shipyard-table-wrapper">
|
||||||
whiteSpace: 'nowrap',
|
<table style={{width: '12em', position: 'absolute', zIndex: 1}} className="shipyard-table">
|
||||||
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>
|
||||||
@@ -356,8 +364,8 @@ export default class ShipyardPage extends Page {
|
|||||||
{shipRows}
|
{shipRows}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div style={{ overflowX: 'scroll', maxWidth: '100%' }}>
|
<div style={{ overflowX: 'auto', maxWidth: '100%' }}>
|
||||||
<table style={{ marginLeft: 'calc(12em - 1px)', zIndex: 0 }}>
|
<table style={{ marginLeft: 'calc(12em - 1px)', zIndex: 0 }} className="shipyard-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr className="main">
|
<tr className="main">
|
||||||
<th
|
<th
|
||||||
@@ -614,6 +622,10 @@ 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()}/>Group highlighted ships</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export function jumpRange(mass, fsd, fuel, ship) {
|
|||||||
let jumpAddition = 0;
|
let jumpAddition = 0;
|
||||||
if (ship) {
|
if (ship) {
|
||||||
for (const module of ship.internal) {
|
for (const module of ship.internal) {
|
||||||
if (module && module.m && module.m.grp === 'gfsb') {
|
if (module && module.m && module.m.grp === 'gfsb' && ship.getSlotStatus(module) == 3) {
|
||||||
jumpAddition += module.m.getJumpBoost();
|
jumpAddition += module.m.getJumpBoost();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -400,7 +400,7 @@ export function shieldMetrics(ship, sys) {
|
|||||||
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') {
|
if (module && module.m && module.m.grp === 'gsrp' && module.enabled) {
|
||||||
shieldAddition += module.m.getShieldAddition();
|
shieldAddition += module.m.getShieldAddition();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -465,6 +465,7 @@ 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,
|
||||||
@@ -573,7 +574,7 @@ export function armourMetrics(ship) {
|
|||||||
// };
|
// };
|
||||||
// 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.m.grp === 'hr' || slot.m.grp === 'ghrp' || slot.m.grp == 'mahr')) {
|
if (slot.m && slot.enabled && (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;
|
||||||
@@ -585,7 +586,7 @@ export function armourMetrics(ship) {
|
|||||||
hullThermDmg = hullThermDmg * (1 - slot.m.getThermalResistance());
|
hullThermDmg = hullThermDmg * (1 - slot.m.getThermalResistance());
|
||||||
hullCausDmg = hullCausDmg * (1 - slot.m.getCausticResistance());
|
hullCausDmg = hullCausDmg * (1 - slot.m.getCausticResistance());
|
||||||
}
|
}
|
||||||
if (slot.m && (slot.m.grp == 'mrp' || slot.m.grp == 'gmrp')) {
|
if (slot.m && slot.enabled && (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());
|
||||||
}
|
}
|
||||||
@@ -1014,7 +1015,10 @@ 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 (drainPerSecond <= 0) {
|
// If there is nothing to remove, we're don instantly
|
||||||
|
if (!amount) {
|
||||||
|
return 0;
|
||||||
|
} if (drainPerSecond <= 0) {
|
||||||
// Simple result
|
// Simple result
|
||||||
return amount / dps;
|
return amount / dps;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ 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',
|
||||||
|
|
||||||
// Hard Points
|
// Hard Points
|
||||||
bl: 'Beam Laser',
|
bl: 'Beam Laser',
|
||||||
@@ -94,6 +95,10 @@ export const ModuleGroupToName = {
|
|||||||
gsc: 'Guardian Shard Cannon',
|
gsc: 'Guardian Shard Cannon',
|
||||||
tbem: 'Enzyme Missile Rack',
|
tbem: 'Enzyme Missile Rack',
|
||||||
tbrfl: 'Remote Release Flechette Launcher',
|
tbrfl: 'Remote Release Flechette Launcher',
|
||||||
|
pwa: 'Pulse Wave Analyser',
|
||||||
|
abl: 'Abrasion Blaster',
|
||||||
|
scl: 'Seismic Charge Launcher',
|
||||||
|
sdm: 'Sub-Surface Displacement Missile',
|
||||||
};
|
};
|
||||||
|
|
||||||
let GrpNameToCodeMap = {};
|
let GrpNameToCodeMap = {};
|
||||||
@@ -202,7 +207,7 @@ export const ShipFacets = [
|
|||||||
i: 9
|
i: 9
|
||||||
},
|
},
|
||||||
{ // 10
|
{ // 10
|
||||||
title: 'fastest range',
|
title: 'farthest range',
|
||||||
props: ['unladenFastestRange', 'ladenFastestRange'],
|
props: ['unladenFastestRange', 'ladenFastestRange'],
|
||||||
lbls: ['unladen', 'laden'],
|
lbls: ['unladen', 'laden'],
|
||||||
unit: 'LY',
|
unit: 'LY',
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export default class Module {
|
|||||||
|
|
||||||
if ((!raw) && this.blueprint && this.blueprint.special) {
|
if ((!raw) && this.blueprint && this.blueprint.special) {
|
||||||
// This module has a special effect, see if we need to alter our returned value
|
// This module has a special effect, see if we need to alter our returned value
|
||||||
const modifierActions = Modifications.modifierActions[this.blueprint.special.edname];
|
const modifierActions = Modifications.modifierActions[this.blueprint.special.key];
|
||||||
if (modifierActions && modifierActions[name]) {
|
if (modifierActions && modifierActions[name]) {
|
||||||
// this special effect modifies our returned value
|
// this special effect modifies our returned value
|
||||||
const modification = Modifications.modifications[name];
|
const modification = Modifications.modifications[name];
|
||||||
@@ -59,14 +59,7 @@ export default class Module {
|
|||||||
} else if (modification.method === 'overwrite') {
|
} else if (modification.method === 'overwrite') {
|
||||||
result = modifierActions[name];
|
result = modifierActions[name];
|
||||||
} else {
|
} else {
|
||||||
// rate of fire is special, as it's really burst interval. Handle that here
|
result = (((1 + result / multiplier) * (1 + modifierActions[name])) - 1) * multiplier;
|
||||||
let mod = null;
|
|
||||||
if (name === 'rof') {
|
|
||||||
mod = 1 / (1 + modifierActions[name]) - 1;
|
|
||||||
} else {
|
|
||||||
mod = modifierActions[name];
|
|
||||||
}
|
|
||||||
result = (((1 + result / multiplier) * (1 + mod)) - 1) * multiplier;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,7 +83,7 @@ export default class Module {
|
|||||||
}
|
}
|
||||||
if (valueiswithspecial && this.blueprint && this.blueprint.special) {
|
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.key];
|
||||||
if (modifierActions && modifierActions[name]) {
|
if (modifierActions && modifierActions[name]) {
|
||||||
// This special effect modifies the value being set, so we need to revert it prior to storing the value
|
// This special effect modifies the value being set, so we need to revert it prior to storing the value
|
||||||
const modification = Modifications.modifications[name];
|
const modification = Modifications.modifications[name];
|
||||||
@@ -105,14 +98,7 @@ export default class Module {
|
|||||||
} else if (modification.method === 'overwrite') {
|
} else if (modification.method === 'overwrite') {
|
||||||
value = null;
|
value = null;
|
||||||
} else {
|
} else {
|
||||||
// rate of fire is special, as it's really burst interval. Handle that here
|
value = ((value / 10000 + 1) / (1 + modifierActions[name]) - 1) * 10000;
|
||||||
let mod = null;
|
|
||||||
if (name === 'rof') {
|
|
||||||
mod = 1 / (1 + modifierActions[name]) - 1;
|
|
||||||
} else {
|
|
||||||
mod = modifierActions[name];
|
|
||||||
}
|
|
||||||
value = ((value / 10000 + 1) / (1 + mod) - 1) * 10000;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,6 +117,13 @@ export default class Module {
|
|||||||
* @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);
|
||||||
@@ -166,14 +159,20 @@ 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 = value / baseValue - 1;
|
modValue = baseValue == 0 ? 0 : value / baseValue - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modification.type === 'percentage') {
|
if (modification.type === 'percentage') {
|
||||||
modValue = modValue * 10000;
|
modValue = modValue * 10000;
|
||||||
} else if (modification.type === 'numeric' && name !== 'burst' &&
|
} else if (modification.type === 'numeric') {
|
||||||
name !== 'burstrof') {
|
|
||||||
modValue = modValue * 100;
|
modValue = modValue * 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,7 +190,14 @@ 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 = this.get(name, modified) || 0;
|
let val;
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
@@ -250,12 +256,17 @@ 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') {
|
} else if (name === 'burstrof' || name === 'burst') {
|
||||||
// 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 / 100;
|
result = modValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -277,11 +288,7 @@ 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) {
|
||||||
if (formattingOptions && formattingOptions.synthetic) {
|
val = this.getPretty(name, true);
|
||||||
val = (this[formattingOptions.synthetic]).call(this, true);
|
|
||||||
} else {
|
|
||||||
val = this._getModifiedValue(name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val = val || 0;
|
val = val || 0;
|
||||||
@@ -351,14 +358,18 @@ export default class Module {
|
|||||||
|
|
||||||
if (formattingOptions && formattingOptions.change) {
|
if (formattingOptions && formattingOptions.change) {
|
||||||
let changeFormatting = formattingOptions.change;
|
let changeFormatting = formattingOptions.change;
|
||||||
let baseVal = this[name];
|
let baseVal = this[name] || 0;
|
||||||
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;
|
||||||
}
|
}
|
||||||
val *= 10000;
|
if (Modifications.modifications[name].method === 'overwrite') {
|
||||||
|
val *= 100;
|
||||||
|
} else {
|
||||||
|
val *= 10000;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
@@ -572,20 +583,9 @@ 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 (this.mods && this.mods['fallofffromrange']) {
|
if (modified && 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();
|
||||||
@@ -639,15 +639,6 @@ 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
|
||||||
@@ -703,8 +694,7 @@ export default class Module {
|
|||||||
let result = 0;
|
let result = 0;
|
||||||
if (this['maxmass']) {
|
if (this['maxmass']) {
|
||||||
result = this['maxmass'];
|
result = this['maxmass'];
|
||||||
// max mass is only modified for non-shield boosters
|
if (result && modified) {
|
||||||
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); }
|
||||||
}
|
}
|
||||||
@@ -793,24 +783,6 @@ 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
|
||||||
@@ -834,25 +806,39 @@ 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.key === '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) {
|
||||||
let dps = this.getDps(modified);
|
return this.getDps(modified) * this.getSustainedFactor(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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -876,7 +862,7 @@ export default class Module {
|
|||||||
*/
|
*/
|
||||||
getHps(modified = true) {
|
getHps(modified = true) {
|
||||||
// HPS is a synthetic value
|
// HPS is a synthetic value
|
||||||
let heat = this.getThermalLoad(modified);
|
let heat = this.get('thermload', 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;
|
||||||
|
|
||||||
@@ -913,24 +899,6 @@ 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
|
||||||
@@ -941,8 +909,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.getBurst(modified) || 1;
|
const burst = this.get('burst', modified) || 1;
|
||||||
const burstRoF = this.getBurstRoF(modified) || 1;
|
const burstRoF = this.get('burstrof', 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);
|
||||||
@@ -1073,4 +1041,31 @@ export default class Module {
|
|||||||
getHackTime(modified = true) {
|
getHackTime(modified = true) {
|
||||||
return this.get('hacktime', modified);
|
return this.get('hacktime', modified);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the scan range for this module
|
||||||
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
||||||
|
* @return {string} the time for this module
|
||||||
|
*/
|
||||||
|
getScanRange(modified = true) {
|
||||||
|
return this.get('scanrange', modified);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the scan angle for this module
|
||||||
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
||||||
|
* @return {string} the time for this module
|
||||||
|
*/
|
||||||
|
getScanAngle(modified = true) {
|
||||||
|
return this.get('scanangle', modified);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the max angle for this module
|
||||||
|
* @param {Boolean} [modified=true] Whether to take modifications into account
|
||||||
|
* @return {string} the time for this module
|
||||||
|
*/
|
||||||
|
getMaxAngle(modified = true) {
|
||||||
|
return this.get('maxangle', modified);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,12 +85,12 @@ export function toDetailedBuild(buildName, ship) {
|
|||||||
code = ship.toString();
|
code = ship.toString();
|
||||||
|
|
||||||
let data = {
|
let data = {
|
||||||
$schema: 'https://coriolis.edcd.io/schemas/ship-loadout/4.json#',
|
$schema: 'https://coriolis.io/schemas/ship-loadout/4.json#',
|
||||||
name: buildName,
|
name: buildName,
|
||||||
ship: ship.name,
|
ship: ship.name,
|
||||||
references: [{
|
references: [{
|
||||||
name: 'Coriolis.io',
|
name: 'Coriolis.io',
|
||||||
url: 'https://coriolis.edcd.io' + outfitURL(ship.id, code, buildName),
|
url: 'https://coriolis.io' + outfitURL(ship.id, code, buildName),
|
||||||
code,
|
code,
|
||||||
shipId: ship.id
|
shipId: ship.id
|
||||||
}],
|
}],
|
||||||
|
|||||||
@@ -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'];
|
const UNIQUE_MODULES = ['psg', 'sg', 'bsg', 'rf', 'fs', 'fh', 'gfsb', 'dc'];
|
||||||
|
|
||||||
// Constants for modifications struct
|
// Constants for modifications struct
|
||||||
const SLOT_ID_DONE = -1;
|
const SLOT_ID_DONE = -1;
|
||||||
@@ -1308,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, this); // Full Tank
|
this.fullTankRange = Calc.jumpRange(unladenMass + fuelCapacity, fsd, fuelCapacity, 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);
|
||||||
|
|||||||
@@ -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' },
|
'burst': { 'format': 'int', 'change': 'additive' },
|
||||||
'burstrof': { 'format': 'round1', 'unit': 'ps' },
|
'burstrof': { 'format': 'round1', 'unit': 'ps', 'change': 'additive' },
|
||||||
'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' },
|
'rof': { 'format': 'round1', 'unit': 'ps', 'synthetic': 'getRoF', 'higherbetter': true },
|
||||||
'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' },
|
||||||
@@ -78,5 +78,6 @@ export const STATS_FORMATTING = {
|
|||||||
'thermres': { 'format': 'pct' },
|
'thermres': { 'format': 'pct' },
|
||||||
'wepcap': { 'format': 'round1', 'unit': 'MJ' },
|
'wepcap': { 'format': 'round1', 'unit': 'MJ' },
|
||||||
'weprate': { 'format': 'round1', 'unit': 'MW' },
|
'weprate': { 'format': 'round1', 'unit': 'MW' },
|
||||||
'jumpboost': { 'format': 'round1', 'unit': 'LY' }
|
'jumpboost': { 'format': 'round1', 'unit': 'LY' },
|
||||||
|
'proberadius': { 'format': 'pct1', 'unit': 'pct' },
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
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
|
||||||
@@ -155,7 +156,7 @@ export function blueprintTooltip(translate, blueprint, engineers, grp, m) {
|
|||||||
|
|
||||||
// We also add in any benefits from specials that aren't covered above
|
// We also add in any benefits from specials that aren't covered above
|
||||||
if (m.blueprint && m.blueprint.special) {
|
if (m.blueprint && m.blueprint.special) {
|
||||||
for (const feature in Modifications.modifierActions[m.blueprint.special.edname]) {
|
for (const feature in Modifications.modifierActions[m.blueprint.special.key]) {
|
||||||
if (!blueprint.features[feature] && !m.mods.feature) {
|
if (!blueprint.features[feature] && !m.mods.feature) {
|
||||||
const featureDef = Modifications.modifications[feature];
|
const featureDef = Modifications.modifications[feature];
|
||||||
if (featureDef && !featureDef.hidden) {
|
if (featureDef && !featureDef.hidden) {
|
||||||
@@ -280,6 +281,25 @@ 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
|
||||||
@@ -372,9 +392,7 @@ export function getPercent(m) {
|
|||||||
|
|
||||||
let value = _getValue(m, featureName);
|
let value = _getValue(m, featureName);
|
||||||
let mult;
|
let mult;
|
||||||
if (featureName == 'shieldboost') {
|
if (Modifications.modifications[featureName].higherbetter) {
|
||||||
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);
|
||||||
|
|||||||
@@ -249,6 +249,13 @@ function _addModifications(module, modifiers, blueprint, grade, specialModificat
|
|||||||
if (!modifiers) return;
|
if (!modifiers) return;
|
||||||
let special;
|
let special;
|
||||||
if (specialModifications) {
|
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];
|
special = Modifications.specials[specialModifications];
|
||||||
}
|
}
|
||||||
// Add the blueprint definition, grade and special
|
// Add the blueprint definition, grade and special
|
||||||
@@ -274,6 +281,9 @@ function _addModifications(module, modifiers, blueprint, grade, specialModificat
|
|||||||
if (value === Infinity) {
|
if (value === Infinity) {
|
||||||
value = modifiers[i].Value * 100;
|
value = modifiers[i].Value * 100;
|
||||||
}
|
}
|
||||||
|
if (modifiers[i].Label.search('DamageFalloffRange') >= 0) {
|
||||||
|
value = (modifiers[i].Value / module.range - 1) * 100;
|
||||||
|
}
|
||||||
if (modifiers[i].Label.search('Resistance') >= 0) {
|
if (modifiers[i].Label.search('Resistance') >= 0) {
|
||||||
value = (modifiers[i].Value * 100) - (modifiers[i].OriginalValue * 100);
|
value = (modifiers[i].Value * 100) - (modifiers[i].OriginalValue * 100);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
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
|
||||||
@@ -139,20 +140,21 @@ 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.pgen || 0;
|
let mPowerGeneration = m.getPowerGeneration() || 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.MJ}</span></div>);
|
if (mPowerGeneration != mmPowerGeneration) propDiffs.push(<div key='pgen'>{translate('pgen')}: <span className={diffClass(mPowerGeneration, mmPowerGeneration)}>{diff(formats.round, mPowerGeneration, mmPowerGeneration)}{units.MW}</span></div>);
|
||||||
} else {
|
} else {
|
||||||
let mPowerUsage = m.power || 0;
|
let mPowerUsage = m.getPowerUsage() || 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.MJ}</span></div>);
|
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>);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mDps = m.damage * (m.rpshot || 1) * (m.rof || 1);
|
let mDps = m.getDps() || 0;
|
||||||
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>);
|
||||||
|
|
||||||
@@ -164,7 +166,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.shieldboost - (mm ? mm.getShieldBoost() || 0 : 0));
|
newShield = this.calcShieldStrengthWith(null, m.getShieldBoost() - (mm ? mm.getShieldBoost() || 0 : 0));
|
||||||
} else {
|
} else {
|
||||||
newShield = this.calcShieldStrengthWith(m);
|
newShield = this.calcShieldStrengthWith(m);
|
||||||
}
|
}
|
||||||
@@ -179,7 +181,7 @@ export function diffDetails(language, m, mm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m.grp === 'mrp') {
|
if (m.grp === 'mrp') {
|
||||||
let mProtection = m.protection;
|
let mProtection = m.getProtection();
|
||||||
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>);
|
||||||
@@ -187,7 +189,7 @@ export function diffDetails(language, m, mm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m.grp === 'hr') {
|
if (m.grp === 'hr') {
|
||||||
let mHullReinforcement = m.hullreinforcement;
|
let mHullReinforcement = m.getHullReinforcement();
|
||||||
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>);
|
||||||
}
|
}
|
||||||
@@ -219,7 +221,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.mass || 0;
|
let mMass = m.getMass() || 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>);
|
||||||
|
|
||||||
@@ -240,7 +242,7 @@ export function diffDetails(language, m, mm) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mIntegrity = m.integrity || 0;
|
let mIntegrity = m.getIntegrity() || 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>);
|
||||||
|
|||||||
@@ -32,33 +32,19 @@
|
|||||||
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>
|
||||||
<% if (htmlWebpackPlugin.options.uaTracking) { %>
|
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||||
<script>
|
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-55840909-18"></script>
|
||||||
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
|
<script>
|
||||||
ga('create', '<%- htmlWebpackPlugin.options.uaTracking %>', 'auto');
|
window.dataLayer = window.dataLayer || [];
|
||||||
ga('send', 'pageview');
|
function gtag(){dataLayer.push(arguments);}
|
||||||
|
gtag('js', new Date());
|
||||||
|
|
||||||
|
gtag('config', 'UA-55840909-18');
|
||||||
</script>
|
</script>
|
||||||
<script async src='https://www.google-analytics.com/analytics.js'></script>
|
|
||||||
<% } %>
|
|
||||||
|
|
||||||
<!-- Piwik -->
|
|
||||||
<!-- <script type="text/javascript">
|
|
||||||
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 -->
|
|
||||||
|
<!-- Bugsnag -->
|
||||||
<script src="https://d2wy8f7a9ursnm.cloudfront.net/v5.0.0/bugsnag.min.js"></script>
|
<script src="https://d2wy8f7a9ursnm.cloudfront.net/v5.0.0/bugsnag.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
window.bugsnagClient = bugsnag('ba9fae819372850fb660755341fa6ef5', {appVersion: window.BUGSNAG_VERSION || undefined})
|
window.bugsnagClient = bugsnag('ba9fae819372850fb660755341fa6ef5', {appVersion: window.BUGSNAG_VERSION || undefined})
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
@bgDarken: 40%;
|
@bgDarken: 40%;
|
||||||
@disabledDarken: 15%;
|
@disabledDarken: 15%;
|
||||||
@bgTransparency: 10%;
|
@bgTransparency: 10%;
|
||||||
|
@bgHighlight: 5%;
|
||||||
|
@fgHighlight: 10%;
|
||||||
|
|
||||||
// Foreground colors
|
// Foreground colors
|
||||||
@fg: #CCC;
|
@fg: #CCC;
|
||||||
@@ -21,9 +23,14 @@
|
|||||||
@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); // Brown background
|
@secondary-bg: fadeout(darken(@secondary, @bgDarken), @bgTransparency); // Blue 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: auto;
|
user-select: text;
|
||||||
margin:2em 0;
|
margin:2em 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,4 +49,45 @@ 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,10 +52,10 @@ tbody tr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.no-touch &.highlight:hover, .no-touch &.highlighted {
|
.no-touch &.highlight:hover, .no-touch &.highlighted {
|
||||||
background-color: @warning-bg;
|
background-color: @alt-primary-bg-highlighted; //@warning-bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.alt {
|
&:nth-child(odd){
|
||||||
background-color: @alt-primary-bg;
|
background-color: @alt-primary-bg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -84,3 +84,5 @@ td {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
"id": "https://coriolis.edcd.io/schemas/ship-loadout/1.json#",
|
"id": "https://coriolis.io/schemas/ship-loadout/1.json#",
|
||||||
"title": "Ship Loadout",
|
"title": "Ship Loadout",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "The details for a specific ship build/loadout. DEPRECATED in favor of Version 3",
|
"description": "The details for a specific ship build/loadout. DEPRECATED in favor of Version 3",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
"id": "https://coriolis.edcd.io/schemas/ship-loadout/2.json#",
|
"id": "https://coriolis.io/schemas/ship-loadout/2.json#",
|
||||||
"title": "Ship Loadout",
|
"title": "Ship Loadout",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "The details for a specific ship build/loadout. DEPRECATED in favor of Version 3",
|
"description": "The details for a specific ship build/loadout. DEPRECATED in favor of Version 3",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
"id": "https://coriolis.edcd.io/schemas/ship-loadout/3.json#",
|
"id": "https://coriolis.io/schemas/ship-loadout/3.json#",
|
||||||
"title": "Ship Loadout",
|
"title": "Ship Loadout",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "The details for a specific ship build/loadout",
|
"description": "The details for a specific ship build/loadout",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
"id": "https://coriolis.edcd.io/schemas/ship-loadout/4.json#",
|
"id": "https://coriolis.io/schemas/ship-loadout/4.json#",
|
||||||
"title": "Ship Loadout",
|
"title": "Ship Loadout",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "The details for a specific ship build/loadout",
|
"description": "The details for a specific ship build/loadout",
|
||||||
|
|||||||
25
src/sw.js
25
src/sw.js
@@ -7,13 +7,26 @@ if (workbox) {
|
|||||||
workbox.routing.registerNavigationRoute('/index.html');
|
workbox.routing.registerNavigationRoute('/index.html');
|
||||||
|
|
||||||
workbox.routing.registerRoute(
|
workbox.routing.registerRoute(
|
||||||
new RegExp('/(.*?)'),
|
/\.(?:png|jpg|jpeg|svg|gif)$/,
|
||||||
workbox.strategies.staleWhileRevalidate()
|
new workbox.strategies.CacheFirst({
|
||||||
|
plugins: [
|
||||||
|
new workbox.cacheableResponse.Plugin({
|
||||||
|
statuses: [0, 200]
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
workbox.routing.registerRoute(
|
||||||
|
/\.(?:js|css)$/,
|
||||||
|
new workbox.strategies.StaleWhileRevalidate({
|
||||||
|
cacheName: 'static-resources',
|
||||||
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
workbox.routing.registerRoute(
|
workbox.routing.registerRoute(
|
||||||
new RegExp('https://fonts.(?:googleapis|gstatic).com/(.*)'),
|
new RegExp('https://fonts.(?:googleapis|gstatic).com/(.*)'),
|
||||||
workbox.strategies.cacheFirst({
|
new workbox.strategies.CacheFirst({
|
||||||
cacheName: 'google-fonts',
|
cacheName: 'google-fonts',
|
||||||
plugins: [
|
plugins: [
|
||||||
new workbox.expiration.Plugin({
|
new workbox.expiration.Plugin({
|
||||||
@@ -25,12 +38,6 @@ if (workbox) {
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
|
||||||
workbox.googleAnalytics.initialize();
|
|
||||||
} catch (e) {
|
|
||||||
console.log('Probably an ad-blocker');
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
console.log('Boo! Workbox didn\'t load 😬');
|
console.log('Boo! Workbox didn\'t load 😬');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
mode: 'development',
|
mode: 'development',
|
||||||
entry: {
|
entry: {
|
||||||
main: './src/app/index.js'
|
main: './src/app/index.js',
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
// When requiring, you don't need to add these extensions
|
// When requiring, you don't need to add these extensions
|
||||||
@@ -22,13 +22,11 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
optimization: {
|
optimization: {
|
||||||
minimize: false,
|
minimize: false,
|
||||||
splitChunks: {
|
usedExports: true
|
||||||
chunks: 'all'
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
path: path.join(__dirname, 'build'),
|
path: path.join(__dirname, 'build'),
|
||||||
filename: 'app.js',
|
chunkFilename: '[name].bundle.js',
|
||||||
publicPath: '/'
|
publicPath: '/'
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
@@ -56,7 +54,10 @@ module.exports = {
|
|||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{ test: /\.css$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader' }) },
|
{ 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: /\.less$/,
|
||||||
|
loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader!less-loader' })
|
||||||
|
},
|
||||||
{ test: /\.(js|jsx)$/, loaders: ['babel-loader'], include: path.join(__dirname, 'src') },
|
{ 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: /\.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: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff' },
|
||||||
|
|||||||
@@ -11,26 +11,28 @@ const buildDate = new Date();
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
devtool: 'source-map',
|
devtool: 'source-map',
|
||||||
entry: {
|
entry: {
|
||||||
main: ['./src/app/index.js']
|
main: './src/app/index.js'
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.js', '.jsx', '.json', '.less']
|
extensions: ['.js', '.jsx', '.json', '.less']
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
path: path.join(__dirname, 'build'),
|
path: path.join(__dirname, 'build'),
|
||||||
filename: '[name].[hash].js',
|
chunkFilename: '[name].bundle.js',
|
||||||
publicPath: '/',
|
publicPath: '/',
|
||||||
globalObject: 'this'
|
globalObject: 'this'
|
||||||
},
|
},
|
||||||
mode: 'production',
|
mode: 'production',
|
||||||
optimization: {
|
optimization: {
|
||||||
minimize: true,
|
minimize: true,
|
||||||
splitChunks: {
|
usedExports: true
|
||||||
chunks: 'all'
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new CopyWebpackPlugin(['src/.htaccess', { from: 'src/schemas', to: 'schemas' }, {from: 'src/images/logo/*', flatten: true, to: ''}, 'src/iframe.html', 'src/xdLocalStoragePostMessageApi.min.js']),
|
new CopyWebpackPlugin(['src/.htaccess', { from: 'src/schemas', to: 'schemas' }, {
|
||||||
|
from: 'src/images/logo/*',
|
||||||
|
flatten: true,
|
||||||
|
to: ''
|
||||||
|
}, 'src/iframe.html', 'src/xdLocalStoragePostMessageApi.min.js']),
|
||||||
// new webpack.optimize.CommonsChunkPlugin({
|
// new webpack.optimize.CommonsChunkPlugin({
|
||||||
// name: 'lib',
|
// name: 'lib',
|
||||||
// filename: 'lib.[chunkhash:6].js'
|
// filename: 'lib.[chunkhash:6].js'
|
||||||
@@ -48,15 +50,15 @@ module.exports = {
|
|||||||
disable: false,
|
disable: false,
|
||||||
allChunks: true
|
allChunks: true
|
||||||
}),
|
}),
|
||||||
new BugsnagBuildReporterPlugin({
|
// new BugsnagBuildReporterPlugin({
|
||||||
apiKey: 'ba9fae819372850fb660755341fa6ef5',
|
// apiKey: 'ba9fae819372850fb660755341fa6ef5',
|
||||||
appVersion: `${pkgJson.version}-${buildDate.toISOString()}`
|
// appVersion: `${pkgJson.version}-${buildDate.toISOString()}`
|
||||||
}, { /* opts */ }),
|
// }, { /* opts */ }),
|
||||||
new BugsnagSourceMapUploaderPlugin({
|
// new BugsnagSourceMapUploaderPlugin({
|
||||||
apiKey: 'ba9fae819372850fb660755341fa6ef5',
|
// apiKey: 'ba9fae819372850fb660755341fa6ef5',
|
||||||
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',
|
importWorkboxFrom: 'cdn',
|
||||||
@@ -66,7 +68,10 @@ module.exports = {
|
|||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{ test: /\.css$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader' }) },
|
{ 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: /\.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: /\.(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: /\.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: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff' },
|
||||||
|
|||||||
Reference in New Issue
Block a user