mirror of
https://github.com/EDCD/coriolis.git
synced 2025-12-10 15:15:34 +00:00
Compare commits
132 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9abb4f6d05 | ||
|
|
4b854b8305 | ||
|
|
b400db8216 | ||
|
|
deeb525433 | ||
|
|
a181791500 | ||
|
|
48092d4395 | ||
|
|
593f069806 | ||
|
|
a073692632 | ||
|
|
7752d5c9db | ||
|
|
98782da200 | ||
|
|
2936364934 | ||
|
|
f85a03a9ae | ||
|
|
2703c2aa23 | ||
|
|
954921c231 | ||
|
|
ee3c50e27d | ||
|
|
03020743b3 | ||
|
|
001fed67b7 | ||
|
|
3894915740 | ||
|
|
68fd13e8dc | ||
|
|
fdf16cd959 | ||
|
|
d916c67fe0 | ||
|
|
d8a8e224f4 | ||
|
|
e1c115747c | ||
|
|
e9b6d71606 | ||
|
|
e03e249d2f | ||
|
|
0cfb0b6878 | ||
|
|
600df162aa | ||
|
|
94141aa3c5 | ||
|
|
aca90d7077 | ||
|
|
194db07057 | ||
|
|
38038fcc32 | ||
|
|
9fa740f54e | ||
|
|
d37d69c3a7 | ||
|
|
78d8779641 | ||
|
|
352023f0fb | ||
|
|
3ea194d43e | ||
|
|
bbba048129 | ||
|
|
c6269192f0 | ||
|
|
841e6c3348 | ||
|
|
0febc581d1 | ||
|
|
dc6e398526 | ||
|
|
cb24c1fc69 | ||
|
|
90ad9de831 | ||
|
|
9360b1d574 | ||
|
|
08d2573d1f | ||
|
|
427b9af7de | ||
|
|
222173b388 | ||
|
|
ec0d05e081 | ||
|
|
b3be0bd639 | ||
|
|
529d80682c | ||
|
|
934de01803 | ||
|
|
3367580d78 | ||
|
|
fbf59219d0 | ||
|
|
318d06d9f9 | ||
|
|
1f3c3726f2 | ||
|
|
71beda3a6c | ||
|
|
1d6644b531 | ||
|
|
77401a3b3f | ||
|
|
7c587c29aa | ||
|
|
2295dccd82 | ||
|
|
cc4ad6d132 | ||
|
|
8a2d27290a | ||
|
|
eda61a8e06 | ||
|
|
71b90eb6f4 | ||
|
|
4e891f382c | ||
|
|
3d3f9e44b5 | ||
|
|
dd7a133caa | ||
|
|
ae247c4812 | ||
|
|
6c932f96a6 | ||
|
|
0ea25692d3 | ||
|
|
8e5dd9fb8d | ||
|
|
97ce2828e0 | ||
|
|
6e79ced51e | ||
|
|
0b10cac85c | ||
|
|
34c04a6354 | ||
|
|
4e337c4ca1 | ||
|
|
5048b7e094 | ||
|
|
27fbc1ad66 | ||
|
|
dfffc3a268 | ||
|
|
b59fa15e00 | ||
|
|
12bca4c44e | ||
|
|
7d99471f89 | ||
|
|
a2ab708ac9 | ||
|
|
a34a9c355f | ||
|
|
557c0afd9b | ||
|
|
d52365a204 | ||
|
|
14b2a14e58 | ||
|
|
7f24904f77 | ||
|
|
da07790594 | ||
|
|
5008c7cd74 | ||
|
|
a778b1b6e1 | ||
|
|
bd9771f9ba | ||
|
|
600c244f9b | ||
|
|
a599b1a076 | ||
|
|
3e0a5e22b1 | ||
|
|
3a6ac818c2 | ||
|
|
6f077d4c41 | ||
|
|
9c767c928c | ||
|
|
515f4ad3da | ||
|
|
4fcf074595 | ||
|
|
e5f8153a34 | ||
|
|
571854a11c | ||
|
|
1f22f249a1 | ||
|
|
718ac0a514 | ||
|
|
8f089cb1ee | ||
|
|
d19a7276dd | ||
|
|
10fffe67fc | ||
|
|
f0bf8e8ce2 | ||
|
|
598cf8d677 | ||
|
|
90f03de3fe | ||
|
|
e0766f4424 | ||
|
|
28a90768e4 | ||
|
|
f3d917ccbe | ||
|
|
7e5d52385d | ||
|
|
4368015dc0 | ||
|
|
1201da1811 | ||
|
|
d195b568b0 | ||
|
|
c9866c146b | ||
|
|
5d52809d0d | ||
|
|
8f0cca4fd9 | ||
|
|
e46bb425fe | ||
|
|
06dc110025 | ||
|
|
e9c34c636a | ||
|
|
59d38cbd33 | ||
|
|
51f5188efc | ||
|
|
be8934da80 | ||
|
|
18d78b3089 | ||
|
|
b1ff4e84f7 | ||
|
|
bed2ede701 | ||
|
|
124bd62d2c | ||
|
|
975846f4ab | ||
|
|
3f73f9be10 |
33
.babelrc
33
.babelrc
@@ -1,3 +1,34 @@
|
|||||||
{
|
{
|
||||||
"presets": ["env", "react", "stage-0"]
|
"presets": [
|
||||||
|
["@babel/preset-env", {"modules": "commonjs"}],
|
||||||
|
"@babel/preset-react"
|
||||||
|
],
|
||||||
|
"plugins": [
|
||||||
|
"@babel/plugin-syntax-dynamic-import",
|
||||||
|
"@babel/plugin-syntax-import-meta",
|
||||||
|
["@babel/plugin-proposal-class-properties", { "loose": true }],
|
||||||
|
"@babel/plugin-proposal-json-strings",
|
||||||
|
[
|
||||||
|
"@babel/plugin-proposal-decorators",
|
||||||
|
{
|
||||||
|
"legacy": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"@babel/plugin-proposal-function-sent",
|
||||||
|
"@babel/plugin-proposal-export-namespace-from",
|
||||||
|
"@babel/plugin-proposal-numeric-separator",
|
||||||
|
"@babel/plugin-proposal-throw-expressions",
|
||||||
|
"@babel/plugin-proposal-export-default-from",
|
||||||
|
"@babel/plugin-proposal-logical-assignment-operators",
|
||||||
|
"@babel/plugin-proposal-optional-chaining",
|
||||||
|
[
|
||||||
|
"@babel/plugin-proposal-pipeline-operator",
|
||||||
|
{
|
||||||
|
"proposal": "minimal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"@babel/plugin-proposal-nullish-coalescing-operator",
|
||||||
|
"@babel/plugin-proposal-do-expressions",
|
||||||
|
"@babel/plugin-proposal-function-bind"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,31 +6,28 @@ 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 reset --hard origin/$BRANCH
|
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 reset --hard origin/$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
|
||||||
11
d3-funcs.js
vendored
11
d3-funcs.js
vendored
@@ -1,11 +0,0 @@
|
|||||||
export {
|
|
||||||
axisBottom,
|
|
||||||
axisLeft,
|
|
||||||
axisTop,
|
|
||||||
formatLocale,
|
|
||||||
line,
|
|
||||||
scaleBand,
|
|
||||||
scaleLinear,
|
|
||||||
scaleOrdinal,
|
|
||||||
select
|
|
||||||
} from 'd3';
|
|
||||||
@@ -29,6 +29,23 @@ services:
|
|||||||
- "traefik.basic.port=80"
|
- "traefik.basic.port=80"
|
||||||
- "traefik.basic.protocol=http"
|
- "traefik.basic.protocol=http"
|
||||||
|
|
||||||
|
coriolis_dw2:
|
||||||
|
image: edcd/coriolis:dw2
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- ./nginx.conf:/etc/nginx/nginx.conf
|
||||||
|
networks:
|
||||||
|
- web
|
||||||
|
labels:
|
||||||
|
- "traefik.docker.network=web"
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.basic.frontend.rule=Host:dw2.coriolis.io"
|
||||||
|
- "traefik.basic.port=80"
|
||||||
|
- "traefik.basic.protocol=http"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
web:
|
web:
|
||||||
external: true
|
external: true
|
||||||
127
nginx.conf
127
nginx.conf
@@ -1,59 +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 {
|
||||||
}
|
try_files $uri $uri/ /iframe.html =404;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
271
package.json
271
package.json
@@ -1,125 +1,146 @@
|
|||||||
{
|
{
|
||||||
"name": "coriolis_shipyard",
|
"name": "coriolis_shipyard",
|
||||||
"version": "2.9.18",
|
"version": "3.0.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/EDCD/coriolis"
|
"url": "https://github.com/EDCD/coriolis"
|
||||||
},
|
},
|
||||||
"homepage": "https://coriolis.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",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepublish": "rollup -c && uglifyjs d3.js -c -m -o d3.min.js",
|
"extract-translations": "grep -hroE \"(translate\\('[^']+'\\))|(tip.bind\\(null, '[^']+')\" src/* | grep -oE \"'[^']+'\" | grep -oE \"[^']+\" | sort -u -f",
|
||||||
"extract-translations": "grep -hroE \"(translate\\('[^']+'\\))|(tip.bind\\(null, '[^']+')\" src/* | grep -oE \"'[^']+'\" | grep -oE \"[^']+\" | sort -u -f",
|
"clean": "rimraf build",
|
||||||
"clean": "rimraf build",
|
"start": "node devServer.js",
|
||||||
"start": "node devServer.js",
|
"lint": "eslint --ext .js,.jsx src",
|
||||||
"lint": "eslint --ext .js,.jsx src",
|
"test": "jest",
|
||||||
"test": "jest",
|
"prod-serve": "nginx -p $(pwd) -c nginx.conf",
|
||||||
"prod-serve": "nginx -p $(pwd) -c nginx.conf",
|
"prod-stop": "kill -QUIT $(cat nginx.pid)",
|
||||||
"prod-stop": "kill -QUIT $(cat nginx.pid)",
|
"build": "npm run clean && cross-env NODE_ENV=production webpack -p --config webpack.config.prod.js",
|
||||||
"build": "npm run clean && cross-env NODE_ENV=production webpack -p --config webpack.config.prod.js",
|
"rsync": "rsync -ae \"ssh -i $CORIOLIS_PEM\" --delete build/ $CORIOLIS_USER@$CORIOLIS_HOST:~/wwws",
|
||||||
"rsync": "rsync -ae \"ssh -i $CORIOLIS_PEM\" --delete build/ $CORIOLIS_USER@$CORIOLIS_HOST:~/wwws",
|
"deploy": "npm run lint && npm test && npm run build && npm run rsync"
|
||||||
"deploy": "npm run lint && npm test && npm run build && npm run rsync"
|
},
|
||||||
},
|
"jest": {
|
||||||
"jest": {
|
"transform": {
|
||||||
"transform": {
|
".*": "<rootDir>/node_modules/babel-jest"
|
||||||
".*": "<rootDir>/node_modules/babel-jest"
|
},
|
||||||
},
|
"testRegex": "(/__tests__/test-.*|\\.(test|spec))\\.js$",
|
||||||
"testRegex": "(/__tests__/test-.*|\\.(test|spec))\\.js$",
|
"moduleFileExtensions": [
|
||||||
"moduleFileExtensions": [
|
"js",
|
||||||
"js",
|
"json",
|
||||||
"json",
|
"jsx"
|
||||||
"jsx"
|
],
|
||||||
],
|
"automock": true,
|
||||||
"automock": true,
|
"bail": false,
|
||||||
"bail": false,
|
"unmockedModulePathPatterns": [
|
||||||
"unmockedModulePathPatterns": [
|
"<rootDir>/node_modules/lodash",
|
||||||
"<rootDir>/node_modules/lodash",
|
"<rootDir>/node_modules/react",
|
||||||
"<rootDir>/node_modules/react",
|
"<rootDir>/node_modules/react-dom",
|
||||||
"<rootDir>/node_modules/react-dom",
|
"<rootDir>/node_modules/react-transition-group",
|
||||||
"<rootDir>/node_modules/react-transition-group",
|
"<rootDir>/node_modules/react-testutils-additions",
|
||||||
"<rootDir>/node_modules/react-testutils-additions",
|
"<rootDir>/node_modules/fbjs",
|
||||||
"<rootDir>/node_modules/fbjs",
|
"<rootDir>/node_modules/fbemitter",
|
||||||
"<rootDir>/node_modules/fbemitter",
|
"<rootDir>/node_modules/classnames",
|
||||||
"<rootDir>/node_modules/classnames",
|
"<rootDir>/node_modules/d3",
|
||||||
"<rootDir>/node_modules/d3",
|
"<rootDir>/node_modules/lz-string",
|
||||||
"<rootDir>/node_modules/lz-string",
|
"<rootDir>/node_modules/jsen",
|
||||||
"<rootDir>/node_modules/jsen",
|
"coriolis-data",
|
||||||
"coriolis-data",
|
"<rootDir>/src/app/shipyard",
|
||||||
"<rootDir>/src/app/shipyard",
|
"<rootDir>/src/app/i18n",
|
||||||
"<rootDir>/src/app/i18n",
|
"<rootDir>/src/app/utils",
|
||||||
"<rootDir>/src/app/utils",
|
"<rootDir>/src/schemas",
|
||||||
"<rootDir>/src/schemas",
|
"<rootDir>/__tests__"
|
||||||
"<rootDir>/__tests__"
|
]
|
||||||
]
|
},
|
||||||
},
|
"devDependencies": {
|
||||||
"devDependencies": {
|
"@babel/core": "^7.0.0",
|
||||||
"appcache-webpack-plugin": "^1.3.0",
|
"@babel/plugin-proposal-class-properties": "^7.0.0",
|
||||||
"babel-core": "*",
|
"@babel/plugin-proposal-decorators": "^7.0.0",
|
||||||
"babel-eslint": "*",
|
"@babel/plugin-proposal-do-expressions": "^7.0.0",
|
||||||
"babel-jest": "*",
|
"@babel/plugin-proposal-export-default-from": "^7.0.0",
|
||||||
"babel-loader": "*",
|
"@babel/plugin-proposal-export-namespace-from": "^7.0.0",
|
||||||
"babel-preset-env": "*",
|
"@babel/plugin-proposal-function-bind": "^7.0.0",
|
||||||
"babel-preset-react": "*",
|
"@babel/plugin-proposal-function-sent": "^7.0.0",
|
||||||
"babel-preset-stage-0": "*",
|
"@babel/plugin-proposal-json-strings": "^7.0.0",
|
||||||
"create-react-class": "^15.6.2",
|
"@babel/plugin-proposal-logical-assignment-operators": "^7.0.0",
|
||||||
"cross-env": "^5.1.4",
|
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.0.0",
|
||||||
"css-loader": "^0.28.0",
|
"@babel/plugin-proposal-numeric-separator": "^7.0.0",
|
||||||
"d3-selection": "1",
|
"@babel/plugin-proposal-optional-chaining": "^7.0.0",
|
||||||
"esdoc": "^1.1.0",
|
"@babel/plugin-proposal-pipeline-operator": "^7.0.0",
|
||||||
"esdoc-custom-theme": "^1.4.2",
|
"@babel/plugin-proposal-throw-expressions": "^7.0.0",
|
||||||
"esdoc-ecmascript-proposal-plugin": "^1.0.0",
|
"@babel/plugin-syntax-dynamic-import": "^7.0.0",
|
||||||
"esdoc-jsx-plugin": "^1.0.0",
|
"@babel/plugin-syntax-import-meta": "^7.0.0",
|
||||||
"esdoc-publish-html-plugin": "^1.1.2",
|
"@babel/preset-env": "^7.0.0",
|
||||||
"esdoc-react-plugin": "^1.0.1",
|
"@babel/preset-react": "^7.0.0",
|
||||||
"esdoc-standard-plugin": "^1.0.0",
|
"appcache-webpack-plugin": "^1.4.0",
|
||||||
"eslint": "3.19.0",
|
"babel-core": "^7.0.0-bridge.0",
|
||||||
"eslint-plugin-react": "^6.10.3",
|
"babel-eslint": "^10.0.1",
|
||||||
"expose-loader": "^0.7.3",
|
"babel-jest": "^23.6.0",
|
||||||
"express": "^4.15.2",
|
"babel-loader": "^8.0.0",
|
||||||
"extract-text-webpack-plugin": "2.1.0",
|
"copy-webpack-plugin": "^4.5.2",
|
||||||
"file-loader": "^0.11.1",
|
"create-react-class": "^15.6.3",
|
||||||
"html-webpack-plugin": "^2.28.0",
|
"cross-env": "^5.2.0",
|
||||||
"jest-cli": "^21.2.1",
|
"css-loader": "^1.0.0",
|
||||||
"jsen": "^0.6.4",
|
"d3-selection": "^1.3.2",
|
||||||
"json-loader": "^0.5.4",
|
"esdoc": "^1.1.0",
|
||||||
"less": "^2.7.2",
|
"esdoc-custom-theme": "^1.4.2",
|
||||||
"less-loader": "^4.0.3",
|
"esdoc-ecmascript-proposal-plugin": "^1.0.0",
|
||||||
"react-addons-perf": "^15.4.2",
|
"esdoc-jsx-plugin": "^1.0.0",
|
||||||
"react-container-dimensions": "^1.4.1",
|
"esdoc-publish-html-plugin": "^1.1.2",
|
||||||
"react-testutils-additions": "^15.2.0",
|
"esdoc-react-plugin": "^1.0.1",
|
||||||
"react-transition-group": "^1.1.2",
|
"esdoc-standard-plugin": "^1.0.0",
|
||||||
"rimraf": "^2.6.1",
|
"eslint": "^5.6.0",
|
||||||
"rollup": "0.41",
|
"eslint-plugin-react": "^7.11.1",
|
||||||
"rollup-plugin-node-resolve": "3",
|
"expose-loader": "^0.7.5",
|
||||||
"style-loader": "^0.16.1",
|
"express": "^4.16.3",
|
||||||
"uglify-js": "^2.4.11",
|
"extract-text-webpack-plugin": "^4.0.0-beta.0",
|
||||||
"url-loader": "^0.5.8",
|
"file-loader": "^2.0.0",
|
||||||
"webpack": "^2.4.1",
|
"html-webpack-plugin": "^3.0.7",
|
||||||
"webpack-bugsnag-plugins": "^1.1.1",
|
"jest-cli": "^23.6.0",
|
||||||
"webpack-dev-server": "^2.4.4",
|
"jsen": "^0.6.4",
|
||||||
"webpack-notifier": "^1.6.0",
|
"json-loader": "^0.5.4",
|
||||||
"workbox-webpack-plugin": "^3.4.1"
|
"less": "^3.8.1",
|
||||||
},
|
"less-loader": "^4.1.0",
|
||||||
"dependencies": {
|
"react-addons-perf": "^15.4.2",
|
||||||
"babel-polyfill": "*",
|
"react-container-dimensions": "^1.4.1",
|
||||||
"browserify-zlib-next": "^1.0.1",
|
"react-testutils-additions": "^16.0.0",
|
||||||
"classnames": "^2.2.5",
|
"react-transition-group": "^2.5.0",
|
||||||
"coriolis-data": "../coriolis-data",
|
"rimraf": "^2.6.1",
|
||||||
"d3": "4.8.0",
|
"rollup": "^0.66.2",
|
||||||
"detect-browser": "^1.7.0",
|
"rollup-plugin-node-resolve": "^3.4.0",
|
||||||
"fbemitter": "^2.1.1",
|
"style-loader": "^0.23.0",
|
||||||
"lodash": "^4.17.10",
|
"uglify-js": "^3.4.9",
|
||||||
"lz-string": "^1.4.4",
|
"url-loader": "^1.1.1",
|
||||||
"pako": "^1.0.6",
|
"webpack": "^4.20.2",
|
||||||
"prop-types": "^15.5.8",
|
"webpack-bugsnag-plugins": "^1.2.2",
|
||||||
"react": "^15.5.4",
|
"webpack-cli": "^3.1.1",
|
||||||
"react-dom": "^15.5.4",
|
"webpack-dev-server": "^3.1.9",
|
||||||
"react-ga": "^2.5.3",
|
"webpack-notifier": "^1.6.0",
|
||||||
"react-number-editor": "Athanasius/react-number-editor.git#miggy",
|
"workbox-webpack-plugin": "^3.6.1"
|
||||||
"recharts": "^0.22.3",
|
},
|
||||||
"superagent": "^3.5.2"
|
"sideEffects": false,
|
||||||
}
|
"dependencies": {
|
||||||
}
|
"@babel/polyfill": "^7.0.0",
|
||||||
|
"browserify-zlib-next": "^1.0.1",
|
||||||
|
"classnames": "^2.2.6",
|
||||||
|
"coriolis-data": "../coriolis-data",
|
||||||
|
"d3": "^5.7.0",
|
||||||
|
"detect-browser": "^3.0.1",
|
||||||
|
"fbemitter": "^2.1.1",
|
||||||
|
"lodash": "^4.17.11",
|
||||||
|
"lz-string": "^1.4.4",
|
||||||
|
"pako": "^1.0.6",
|
||||||
|
"prop-types": "^15.6.2",
|
||||||
|
"react": "^15.5.4",
|
||||||
|
"react-dom": "^15.5.4",
|
||||||
|
"react-extras": "^0.7.1",
|
||||||
|
"react-fuzzy": "^0.5.2",
|
||||||
|
"react-ga": "^2.5.3",
|
||||||
|
"react-number-editor": "Athanasius/react-number-editor.git#miggy",
|
||||||
|
"recharts": "^1.2.0",
|
||||||
|
"register-service-worker": "^1.5.2",
|
||||||
|
"superagent": "^3.8.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
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 { 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';
|
||||||
|
|
||||||
|
import Announcement from './components/Announcement';
|
||||||
import Header from './components/Header';
|
import Header from './components/Header';
|
||||||
import Tooltip from './components/Tooltip';
|
import Tooltip from './components/Tooltip';
|
||||||
import ModalExport from './components/ModalExport';
|
import ModalExport from './components/ModalExport';
|
||||||
@@ -13,7 +15,6 @@ import ModalImport from './components/ModalImport';
|
|||||||
import ModalPermalink from './components/ModalPermalink';
|
import ModalPermalink from './components/ModalPermalink';
|
||||||
import * as CompanionApiUtils from './utils/CompanionApiUtils';
|
import * as CompanionApiUtils from './utils/CompanionApiUtils';
|
||||||
import * as JournalUtils from './utils/JournalUtils';
|
import * as JournalUtils from './utils/JournalUtils';
|
||||||
|
|
||||||
import AboutPage from './pages/AboutPage';
|
import AboutPage from './pages/AboutPage';
|
||||||
import NotFoundPage from './pages/NotFoundPage';
|
import NotFoundPage from './pages/NotFoundPage';
|
||||||
import OutfittingPage from './pages/OutfittingPage';
|
import OutfittingPage from './pages/OutfittingPage';
|
||||||
@@ -22,12 +23,12 @@ import ShipyardPage from './pages/ShipyardPage';
|
|||||||
import ErrorDetails from './pages/ErrorDetails';
|
import ErrorDetails from './pages/ErrorDetails';
|
||||||
|
|
||||||
const zlib = require('pako');
|
const zlib = require('pako');
|
||||||
|
const request = require('superagent');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Coriolis App
|
* Coriolis App
|
||||||
*/
|
*/
|
||||||
export default class Coriolis extends React.Component {
|
export default class Coriolis extends React.Component {
|
||||||
|
|
||||||
static childContextTypes = {
|
static childContextTypes = {
|
||||||
closeMenu: PropTypes.func.isRequired,
|
closeMenu: PropTypes.func.isRequired,
|
||||||
hideModal: PropTypes.func.isRequired,
|
hideModal: PropTypes.func.isRequired,
|
||||||
@@ -66,11 +67,12 @@ export default class Coriolis extends React.Component {
|
|||||||
this.state = {
|
this.state = {
|
||||||
noTouch: !('ontouchstart' in window || navigator.msMaxTouchPoints || navigator.maxTouchPoints),
|
noTouch: !('ontouchstart' in window || navigator.msMaxTouchPoints || navigator.maxTouchPoints),
|
||||||
page: null,
|
page: null,
|
||||||
|
announcements: [],
|
||||||
language: getLanguage(Persist.getLangCode()),
|
language: getLanguage(Persist.getLangCode()),
|
||||||
route: {},
|
route: {},
|
||||||
sizeRatio: Persist.getSizeRatio()
|
sizeRatio: Persist.getSizeRatio()
|
||||||
};
|
};
|
||||||
|
this._getAnnouncements();
|
||||||
Router('', (r) => this._setPage(ShipyardPage, r));
|
Router('', (r) => this._setPage(ShipyardPage, r));
|
||||||
Router('/import?', (r) => this._importBuild(r));
|
Router('/import?', (r) => this._importBuild(r));
|
||||||
Router('/import/:data', (r) => this._importBuild(r));
|
Router('/import/:data', (r) => this._importBuild(r));
|
||||||
@@ -103,12 +105,22 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _getAnnouncements() {
|
||||||
|
try {
|
||||||
|
const announces = await request.get('https://orbis.zone/api/announcement')
|
||||||
|
.query({ showInCoriolis: true });
|
||||||
|
this.setState({ announcements: announces.body });
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates / Sets the page and route context
|
* Updates / Sets the page and route context
|
||||||
* @param {[type]} page The page to be shown
|
* @param {[type]} page The page to be shown
|
||||||
@@ -334,47 +346,37 @@ export default class Coriolis extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if ('serviceWorker' in navigator) {
|
if ('serviceWorker' in navigator) {
|
||||||
window.addEventListener('load', () => {
|
// Your service-worker.js *must* be located at the top-level directory relative to your site.
|
||||||
// Your service-worker.js *must* be located at the top-level directory relative to your site.
|
// It won't be able to control pages unless it's located at the same level or higher than them.
|
||||||
// It won't be able to control pages unless it's located at the same level or higher than them.
|
// *Don't* register service worker file in, e.g., a scripts/ sub-directory!
|
||||||
// *Don't* register service worker file in, e.g., a scripts/ sub-directory!
|
// See https://github.com/slightlyoff/ServiceWorker/issues/468
|
||||||
// See https://github.com/slightlyoff/ServiceWorker/issues/468
|
const self = this;
|
||||||
const self = this;
|
if (process.env.NODE_ENV === 'production') {
|
||||||
navigator.serviceWorker.register('/service-worker.js').then(function(reg) {
|
register('/service-worker.js', {
|
||||||
// updatefound is fired if service-worker.js changes.
|
ready(registration) {
|
||||||
reg.onupdatefound = function() {
|
console.log('Service worker is active.');
|
||||||
// The updatefound event implies that reg.installing is set; see
|
},
|
||||||
// https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#service-worker-container-updatefound-event
|
registered(registration) {
|
||||||
var installingWorker = reg.installing;
|
console.log('Service worker has been registered.');
|
||||||
|
},
|
||||||
installingWorker.onstatechange = function() {
|
cached(registration) {
|
||||||
switch (installingWorker.state) {
|
console.log('Content has been cached for offline use.');
|
||||||
case 'installed':
|
},
|
||||||
if (navigator.serviceWorker.controller) {
|
updatefound(registration) {
|
||||||
// At this point, the old content will have been purged and the fresh content will
|
console.log('New content is downloading.');
|
||||||
// have been added to the cache.
|
},
|
||||||
// It's the perfect time to display a "New content is available; please refresh."
|
updated(registration) {
|
||||||
// message in the page's interface.
|
self.setState({ appCacheUpdate: true });
|
||||||
console.log('New or updated content is available.');
|
console.log('New content is available; please refresh.');
|
||||||
self.setState({ appCacheUpdate: true }); // Browser downloaded a new app cache.
|
},
|
||||||
} else {
|
offline() {
|
||||||
// At this point, everything has been precached.
|
console.log('No internet connection found. App is running in offline mode.');
|
||||||
// It's the perfect time to display a "Content is cached for offline use." message.
|
},
|
||||||
console.log('Content is now available offline!');
|
error(error) {
|
||||||
self.setState({ appCacheUpdate: true }); // Browser downloaded a new app cache.
|
console.error('Error during service worker registration:', error);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case 'redundant':
|
|
||||||
console.error('The installing service worker became redundant.');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}).catch(function(e) {
|
|
||||||
console.error('Error during service worker registration:', e);
|
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
window.onerror = this._onError.bind(this);
|
window.onerror = this._onError.bind(this);
|
||||||
window.addEventListener('resize', () => this.emitter.emit('windowResize'));
|
window.addEventListener('resize', () => this.emitter.emit('windowResize'));
|
||||||
@@ -395,19 +397,23 @@ export default class Coriolis extends React.Component {
|
|||||||
|
|
||||||
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 appCacheUpdate={this.state.appCacheUpdate} currentMenu={currentMenu}/>
|
<Header announcements={this.state.announcements} appCacheUpdate={this.state.appCacheUpdate}
|
||||||
|
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"
|
<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" 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,5 +1,6 @@
|
|||||||
import Persist from './stores/Persist';
|
import Persist from './stores/Persist';
|
||||||
import ReactGA from 'react-ga';
|
import ReactGA from 'react-ga';
|
||||||
|
|
||||||
ReactGA.initialize('UA-55840909-18');
|
ReactGA.initialize('UA-55840909-18');
|
||||||
let standalone = undefined;
|
let standalone = undefined;
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ function isActive(href) {
|
|||||||
* Active Link - Highlighted when URL matches window location
|
* Active Link - Highlighted when URL matches window location
|
||||||
*/
|
*/
|
||||||
export default class ActiveLink extends Link {
|
export default class ActiveLink extends Link {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the component
|
* Renders the component
|
||||||
* @return {React.Component} The active link
|
* @return {React.Component} The active link
|
||||||
@@ -29,5 +28,4 @@ export default class ActiveLink extends Link {
|
|||||||
|
|
||||||
return <a {...this.props} className={className} onClick={this.handler}>{this.props.children}</a>;
|
return <a {...this.props} className={className} onClick={this.handler}>{this.props.children}</a>;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|||||||
31
src/app/components/Announcement.jsx
Normal file
31
src/app/components/Announcement.jsx
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { autoBind } from 'react-extras';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Announcement component
|
||||||
|
*/
|
||||||
|
export default class Announcement extends React.Component {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
text: PropTypes.string
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param {Object} props React Component properties
|
||||||
|
*/
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
autoBind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the announcement
|
||||||
|
* @return {React.Component} A href element
|
||||||
|
*/
|
||||||
|
render() {
|
||||||
|
return <div className="announcement" >{this.props.text}</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import TranslatedComponent from './TranslatedComponent';
|
|||||||
import { stopCtxPropagation } from '../utils/UtilityFunctions';
|
import { stopCtxPropagation } from '../utils/UtilityFunctions';
|
||||||
import cn from 'classnames';
|
import cn from 'classnames';
|
||||||
import { MountFixed, MountGimballed, MountTurret } from './SvgIcons';
|
import { MountFixed, MountGimballed, MountTurret } from './SvgIcons';
|
||||||
|
import FuzzySearch from 'react-fuzzy';
|
||||||
|
|
||||||
const PRESS_THRESHOLD = 500; // mouse/touch down threshold
|
const PRESS_THRESHOLD = 500; // mouse/touch down threshold
|
||||||
|
|
||||||
@@ -39,7 +40,7 @@ const GRPCAT = {
|
|||||||
'mc': 'projectiles',
|
'mc': 'projectiles',
|
||||||
'axmc': 'experimental',
|
'axmc': 'experimental',
|
||||||
'fc': 'projectiles',
|
'fc': 'projectiles',
|
||||||
'rfl': 'experimental',
|
'rfl': 'experimental',
|
||||||
'pa': 'projectiles',
|
'pa': 'projectiles',
|
||||||
'rg': 'projectiles',
|
'rg': 'projectiles',
|
||||||
'mr': 'ordnance',
|
'mr': 'ordnance',
|
||||||
@@ -72,7 +73,12 @@ 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'
|
||||||
};
|
};
|
||||||
// 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 = {
|
||||||
@@ -89,7 +95,7 @@ const CATEGORIES = {
|
|||||||
'structural reinforcement': ['hr', 'mrp'],
|
'structural reinforcement': ['hr', 'mrp'],
|
||||||
'dc': ['dc'],
|
'dc': ['dc'],
|
||||||
// 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
|
||||||
@@ -98,17 +104,18 @@ const CATEGORIES = {
|
|||||||
'defence': ['ch', 'po', 'ec'],
|
'defence': ['ch', 'po', 'ec'],
|
||||||
'scanners': ['sc', 'ss', 'cs', 'kw', 'ws'], // Overloaded with internal scanners
|
'scanners': ['sc', 'ss', 'cs', 'kw', 'ws'], // Overloaded with internal scanners
|
||||||
// Experimental
|
// Experimental
|
||||||
'experimental': ['axmc', 'axmr', 'rfl', 'tbrfl', 'tbsc', 'tbem', 'xs', 'sfn', 'rcpl', 'dtl', 'rsl', 'mahr', ],
|
'experimental': ['axmc', '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'],
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Available modules menu
|
* Available modules menu
|
||||||
*/
|
*/
|
||||||
export default class AvailableModulesMenu extends TranslatedComponent {
|
export default class AvailableModulesMenu extends TranslatedComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
modules: PropTypes.oneOfType([PropTypes.object, PropTypes.array]).isRequired,
|
modules: PropTypes.oneOfType([PropTypes.object, PropTypes.array]).isRequired,
|
||||||
onSelect: PropTypes.func.isRequired,
|
onSelect: PropTypes.func.isRequired,
|
||||||
@@ -134,6 +141,7 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props);
|
super(props);
|
||||||
this._hideDiff = this._hideDiff.bind(this);
|
this._hideDiff = this._hideDiff.bind(this);
|
||||||
|
this._showSearch = this._showSearch.bind(this);
|
||||||
this.state = this._initState(props, context);
|
this.state = this._initState(props, context);
|
||||||
this.slotItems = [];// Array to hold <li> refs.
|
this.slotItems = [];// Array to hold <li> refs.
|
||||||
}
|
}
|
||||||
@@ -159,8 +167,8 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
this._hideDiff(event);
|
this._hideDiff(event);
|
||||||
onSelect(m);
|
onSelect(m);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
let fuzzy = [];
|
||||||
if (modules instanceof Array) {
|
if (modules instanceof Array) {
|
||||||
list = buildGroup(modules[0].grp, modules);
|
list = buildGroup(modules[0].grp, modules);
|
||||||
} else {
|
} else {
|
||||||
@@ -168,9 +176,11 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
// At present time slots with grouped options (Hardpoints and Internal) can be empty
|
// At present time slots with grouped options (Hardpoints and Internal) can be empty
|
||||||
if (m) {
|
if (m) {
|
||||||
let emptyId = 'empty';
|
let emptyId = 'empty';
|
||||||
if(this.firstSlotId == null) this.firstSlotId = emptyId;
|
if (this.firstSlotId == null) this.firstSlotId = emptyId;
|
||||||
let keyDown = this._keyDown.bind(this, onSelect);
|
let keyDown = this._keyDown.bind(this, onSelect);
|
||||||
list.push(<div className='empty-c upp' key={emptyId} data-id={emptyId} onClick={onSelect.bind(null, null)} onKeyDown={keyDown} tabIndex="0" ref={slotItem => this.slotItems[emptyId] = slotItem} >{translate('empty')}</div>);
|
list.push(<div className='empty-c upp' key={emptyId} data-id={emptyId} onClick={onSelect.bind(null, null)}
|
||||||
|
onKeyDown={keyDown} tabIndex="0"
|
||||||
|
ref={slotItem => this.slotItems[emptyId] = slotItem}>{translate('empty')}</div>);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to regroup the modules by our own categorisation
|
// Need to regroup the modules by our own categorisation
|
||||||
@@ -198,7 +208,8 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
if (categories.length === 1) {
|
if (categories.length === 1) {
|
||||||
// Show category header instead of group header
|
// Show category header instead of group header
|
||||||
if (m && grp == m.grp) {
|
if (m && grp == m.grp) {
|
||||||
list.push(<div ref={(elem) => this.groupElem = elem} key={category} className={'select-category upp'}>{translate(category)}</div>);
|
list.push(<div ref={(elem) => this.groupElem = elem} key={category}
|
||||||
|
className={'select-category upp'}>{translate(category)}</div>);
|
||||||
} else {
|
} else {
|
||||||
list.push(<div key={category} className={'select-category upp'}>{translate(category)}</div>);
|
list.push(<div key={category} className={'select-category upp'}>{translate(category)}</div>);
|
||||||
}
|
}
|
||||||
@@ -209,19 +220,32 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
categoryHeader = true;
|
categoryHeader = true;
|
||||||
}
|
}
|
||||||
if (m && grp == m.grp) {
|
if (m && grp == m.grp) {
|
||||||
list.push(<div ref={(elem) => this.groupElem = elem} key={grp} className={'select-group cap'}>{translate(grp)}</div>);
|
list.push(<div ref={(elem) => this.groupElem = elem} key={grp}
|
||||||
|
className={'select-group cap'}>{translate(grp)}</div>);
|
||||||
} else {
|
} else {
|
||||||
list.push(<div key={grp} className={'select-group cap'}>{translate(grp)}</div>);
|
list.push(<div key={grp} className={'select-group cap'}>{translate(grp)}</div>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
list.push(buildGroup(grp, modules[grp]));
|
list.push(buildGroup(grp, modules[grp]));
|
||||||
|
for (const i of modules[grp]) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let trackingFocus = false;
|
let trackingFocus = false;
|
||||||
return { list, currentGroup, trackingFocus };
|
return { list, currentGroup, fuzzy, trackingFocus };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -243,9 +267,11 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
|
|
||||||
const sortedModules = modules.sort(this._moduleOrder);
|
const sortedModules = modules.sort(this._moduleOrder);
|
||||||
|
|
||||||
|
|
||||||
// Calculate the number of items per class. Used so we don't have long lists with only a few items in each row
|
// Calculate the number of items per class. Used so we don't have long lists with only a few items in each row
|
||||||
const tmp = sortedModules.map((v, i) => v['class']).reduce((count, cls) => { count[cls] = ++count[cls] || 1; return count; }, {});
|
const tmp = sortedModules.map((v, i) => v['class']).reduce((count, cls) => {
|
||||||
|
count[cls] = ++count[cls] || 1;
|
||||||
|
return count;
|
||||||
|
}, {});
|
||||||
const itemsPerClass = Math.max.apply(null, Object.keys(tmp).map(key => tmp[key]));
|
const itemsPerClass = Math.max.apply(null, Object.keys(tmp).map(key => tmp[key]));
|
||||||
|
|
||||||
let itemsOnThisRow = 0;
|
let itemsOnThisRow = 0;
|
||||||
@@ -298,22 +324,29 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(m.mount) {
|
switch (m.mount) {
|
||||||
case 'F': mount = <MountFixed className={'lg'} />; break;
|
case 'F':
|
||||||
case 'G': mount = <MountGimballed className={'lg'}/>; break;
|
mount = <MountFixed className={'lg'}/>;
|
||||||
case 'T': mount = <MountTurret className={'lg'}/>; break;
|
break;
|
||||||
|
case 'G':
|
||||||
|
mount = <MountGimballed className={'lg'}/>;
|
||||||
|
break;
|
||||||
|
case 'T':
|
||||||
|
mount = <MountTurret className={'lg'}/>;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (m.name && m.name === prevName) {
|
if (m.name && m.name === prevName) {
|
||||||
// elems.push(<br key={'b' + m.grp + i} />);
|
// elems.push(<br key={'b' + m.grp + i} />);
|
||||||
itemsOnThisRow = 0;
|
itemsOnThisRow = 0;
|
||||||
}
|
}
|
||||||
if (itemsOnThisRow == 6 || i > 0 && sortedModules.length > 3 && itemsPerClass > 2 && m.class != prevClass && (m.rating != prevRating || m.mount)) {
|
if (itemsOnThisRow == 6 || i > 0 && sortedModules.length > 3 && itemsPerClass > 2 && m.class != prevClass && (m.rating != prevRating || m.mount)) {
|
||||||
elems.push(<br key={'b' + m.grp + i} />);
|
elems.push(<br key={'b' + m.grp + i}/>);
|
||||||
itemsOnThisRow = 0;
|
itemsOnThisRow = 0;
|
||||||
}
|
}
|
||||||
let tbIdx = (classes.indexOf('disabled') < 0) ? 0 : undefined;
|
let tbIdx = (classes.indexOf('disabled') < 0) ? 0 : undefined;
|
||||||
elems.push(
|
elems.push(
|
||||||
<li key={m.id} data-id={m.id} className={classes} {...eventHandlers} tabIndex={tbIdx} ref={slotItem => this.slotItems[m.id] = slotItem}>
|
<li key={m.id} data-id={m.id} className={classes} {...eventHandlers} tabIndex={tbIdx}
|
||||||
|
ref={slotItem => this.slotItems[m.id] = slotItem}>
|
||||||
{mount}
|
{mount}
|
||||||
{(mount ? ' ' : '') + m.class + m.rating + (m.missile ? '/' + m.missile : '') + (m.name ? ' ' + translate(m.name) : '')}
|
{(mount ? ' ' : '') + m.class + m.rating + (m.missile ? '/' + m.missile : '') + (m.name ? ' ' + translate(m.name) : '')}
|
||||||
</li>
|
</li>
|
||||||
@@ -341,6 +374,40 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate tooltip content for the difference between the
|
||||||
|
* mounted module and the hovered modules
|
||||||
|
*/
|
||||||
|
_showSearch() {
|
||||||
|
if (this.props.modules instanceof Array) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<FuzzySearch
|
||||||
|
list={this.state.fuzzy}
|
||||||
|
keys={['grp', 'name']}
|
||||||
|
tokenize={true}
|
||||||
|
className={'input'}
|
||||||
|
width={'100%'}
|
||||||
|
style={{ padding: 0 }}
|
||||||
|
onSelect={e => this.props.onSelect.bind(null, e.m)()}
|
||||||
|
resultsTemplate={(props, state, styles, clickHandler) => {
|
||||||
|
return state.results.map((val, i) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
className={'lc'}
|
||||||
|
onClick={() => clickHandler(i)}
|
||||||
|
>
|
||||||
|
{val.name}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mouse over diff handler
|
* Mouse over diff handler
|
||||||
* @param {Function} showDiff diff tooltip callback
|
* @param {Function} showDiff diff tooltip callback
|
||||||
@@ -406,7 +473,7 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
* @param {Function} select Select module callback
|
* @param {Function} select Select module callback
|
||||||
* @param {SytheticEvent} event Event
|
* @param {SytheticEvent} event Event
|
||||||
*/
|
*/
|
||||||
_keyUp(select,event) {
|
_keyUp(select, event) {
|
||||||
// nothing here yet
|
// nothing here yet
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -476,12 +543,13 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
this.slotItems[this.firstSlotId].focus();
|
this.slotItems[this.firstSlotId].focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle focus if the component updates
|
* Handle focus if the component updates
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
if(this.props.slotDiv) {
|
if (this.props.slotDiv) {
|
||||||
this.props.slotDiv.focus();
|
this.props.slotDiv.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -502,14 +570,14 @@ export default class AvailableModulesMenu extends TranslatedComponent {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div ref={node => this.node = node}
|
<div ref={node => this.node = node}
|
||||||
className={cn('select', this.props.className)}
|
className={cn('select', this.props.className)}
|
||||||
onScroll={this._hideDiff}
|
onScroll={this._hideDiff}
|
||||||
onClick={(e) => e.stopPropagation() }
|
onClick={(e) => e.stopPropagation()}
|
||||||
onContextMenu={stopCtxPropagation}
|
onContextMenu={stopCtxPropagation}
|
||||||
>
|
>
|
||||||
|
{this._showSearch()}
|
||||||
{this.state.list}
|
{this.state.list}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ function insertLinebreaks(d) {
|
|||||||
* Bar Chart
|
* Bar Chart
|
||||||
*/
|
*/
|
||||||
export default class BarChart extends TranslatedComponent {
|
export default class BarChart extends TranslatedComponent {
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
colors: ['#7b6888', '#6b486b', '#3182bd', '#a05d56', '#d0743c'],
|
colors: ['#7b6888', '#6b486b', '#3182bd', '#a05d56', '#d0743c'],
|
||||||
labels: null,
|
labels: null,
|
||||||
|
|||||||
@@ -1,13 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import TranslatedComponent from './TranslatedComponent';
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
import { Ships } from 'coriolis-data/dist';
|
|
||||||
import { nameComparator } from '../utils/SlotFunctions';
|
|
||||||
import { Pip } from './SvgIcons';
|
|
||||||
import LineChart from '../components/LineChart';
|
|
||||||
import Slider from '../components/Slider';
|
|
||||||
import * as ModuleUtils from '../shipyard/ModuleUtils';
|
|
||||||
import Module from '../shipyard/Module';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Boost displays a boost button that toggles bosot
|
* Boost displays a boost button that toggles bosot
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import TranslatedComponent from './TranslatedComponent';
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
import { Ships } from 'coriolis-data/dist';
|
|
||||||
import Slider from '../components/Slider';
|
import Slider from '../components/Slider';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import { outfitURL } from '../utils/UrlGenerators';
|
|||||||
* Comparison Table
|
* Comparison Table
|
||||||
*/
|
*/
|
||||||
export default class ComparisonTable extends TranslatedComponent {
|
export default class ComparisonTable extends TranslatedComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
facets: PropTypes.array.isRequired,
|
facets: PropTypes.array.isRequired,
|
||||||
builds: PropTypes.array.isRequired,
|
builds: PropTypes.array.isRequired,
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import { ShoppingIcon } from '../components/SvgIcons';
|
|||||||
* Cost Section
|
* Cost Section
|
||||||
*/
|
*/
|
||||||
export default class CostSection extends TranslatedComponent {
|
export default class CostSection extends TranslatedComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
ship: PropTypes.object.isRequired,
|
ship: PropTypes.object.isRequired,
|
||||||
code: PropTypes.string.isRequired,
|
code: PropTypes.string.isRequired,
|
||||||
@@ -361,11 +360,11 @@ export default class CostSection extends TranslatedComponent {
|
|||||||
for (let i = 0, l = retrofitCosts.length; i < l; i++) {
|
for (let i = 0, l = retrofitCosts.length; i < l; i++) {
|
||||||
let item = retrofitCosts[i];
|
let item = retrofitCosts[i];
|
||||||
rows.push(<tr key={i} className={cn('highlight', { disabled: !item.retroItem.incCost })} onClick={this._toggleRetrofitCost.bind(this, item)}>
|
rows.push(<tr key={i} className={cn('highlight', { disabled: !item.retroItem.incCost })} onClick={this._toggleRetrofitCost.bind(this, item)}>
|
||||||
<td className='ptr' style={{ width: '1em' }}>{item.sellClassRating}</td>
|
<td className='ptr' style={{ width: '1em' }}>{item.sellClassRating}</td>
|
||||||
<td className='le ptr shorten cap'>{translate(item.sellName)}</td>
|
<td className='le ptr shorten cap'>{translate(item.sellName)}</td>
|
||||||
<td className='ptr' style={{ width: '1em' }}>{item.buyClassRating}</td>
|
<td className='ptr' style={{ width: '1em' }}>{item.buyClassRating}</td>
|
||||||
<td className='le ptr shorten cap'>{translate(item.buyName)}</td>
|
<td className='le ptr shorten cap'>{translate(item.buyName)}</td>
|
||||||
<td colSpan='2' className={cn('ri ptr', item.retroItem.incCost ? item.netCost > 0 ? 'warning' : 'secondary-disabled' : 'disabled')}>{int(item.netCost)}{units.CR}</td>
|
<td colSpan='2' className={cn('ri ptr', item.retroItem.incCost ? item.netCost > 0 ? 'warning' : 'secondary-disabled' : 'disabled')}>{int(item.netCost)}{units.CR}</td>
|
||||||
</tr>);
|
</tr>);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -226,26 +226,26 @@ export default class Defence extends TranslatedComponent {
|
|||||||
return (
|
return (
|
||||||
<span id='defence'>
|
<span id='defence'>
|
||||||
{shield.total ? <span>
|
{shield.total ? <span>
|
||||||
<div className='group quarter'>
|
<div className='group quarter'>
|
||||||
<h2>{translate('shield metrics')}</h2>
|
<h2>{translate('shield metrics')}</h2>
|
||||||
<br/>
|
<br/>
|
||||||
<h2 onMouseOver={termtip.bind(null, <div>{shieldSourcesTt}</div>)} onMouseOut={tooltip.bind(null, null)} className='summary'>{translate('raw shield strength')}<br/>{formats.int(shield.total)}{units.MJ}</h2>
|
<h2 onMouseOver={termtip.bind(null, <div>{shieldSourcesTt}</div>)} onMouseOut={tooltip.bind(null, null)} className='summary'>{translate('raw shield strength')}<br/>{formats.int(shield.total)}{units.MJ}</h2>
|
||||||
<h2 onMouseOver={termtip.bind(null, translate('TT_TIME_TO_LOSE_SHIELDS'))} onMouseOut={tooltip.bind(null, null)}>{translate('PHRASE_TIME_TO_LOSE_SHIELDS')}<br/>{shielddamage.totalsdps == 0 ? translate('ever') : formats.time(Calc.timeToDeplete(shield.total, shielddamage.totalsdps, shielddamage.totalseps, pd.getWeaponsCapacity(), pd.getWeaponsRechargeRate() * opponentWep / 4))}</h2>
|
<h2 onMouseOver={termtip.bind(null, translate('TT_TIME_TO_LOSE_SHIELDS'))} onMouseOut={tooltip.bind(null, null)}>{translate('PHRASE_TIME_TO_LOSE_SHIELDS')}<br/>{shielddamage.totalsdps == 0 ? translate('ever') : formats.time(Calc.timeToDeplete(shield.total, shielddamage.totalsdps, shielddamage.totalseps, pd.getWeaponsCapacity(), pd.getWeaponsRechargeRate() * opponentWep / 4))}</h2>
|
||||||
<h2 onMouseOver={termtip.bind(null, translate('PHRASE_SG_RECOVER'))} onMouseOut={tooltip.bind(null, null)}>{translate('PHRASE_TIME_TO_RECOVER_SHIELDS')}<br/>{shield.recover === Math.Inf ? translate('never') : formats.time(shield.recover)}</h2>
|
<h2 onMouseOver={termtip.bind(null, translate('PHRASE_SG_RECOVER'))} onMouseOut={tooltip.bind(null, null)}>{translate('PHRASE_TIME_TO_RECOVER_SHIELDS')}<br/>{shield.recover === Math.Inf ? translate('never') : formats.time(shield.recover)}</h2>
|
||||||
<h2 onMouseOver={termtip.bind(null, translate('PHRASE_SG_RECHARGE'))} onMouseOut={tooltip.bind(null, null)}>{translate('PHRASE_TIME_TO_RECHARGE_SHIELDS')}<br/>{shield.recharge === Math.Inf ? translate('never') : formats.time(shield.recharge)}</h2>
|
<h2 onMouseOver={termtip.bind(null, translate('PHRASE_SG_RECHARGE'))} onMouseOut={tooltip.bind(null, null)}>{translate('PHRASE_TIME_TO_RECHARGE_SHIELDS')}<br/>{shield.recharge === Math.Inf ? translate('never') : formats.time(shield.recharge)}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className='group quarter'>
|
<div className='group quarter'>
|
||||||
<h2 onMouseOver={termtip.bind(null, translate('PHRASE_SHIELD_SOURCES'))} onMouseOut={tooltip.bind(null, null)}>{translate('shield sources')}</h2>
|
<h2 onMouseOver={termtip.bind(null, translate('PHRASE_SHIELD_SOURCES'))} onMouseOut={tooltip.bind(null, null)}>{translate('shield sources')}</h2>
|
||||||
<PieChart data={shieldSourcesData} />
|
<PieChart data={shieldSourcesData} />
|
||||||
</div>
|
</div>
|
||||||
<div className='group quarter'>
|
<div className='group quarter'>
|
||||||
<h2 onMouseOver={termtip.bind(null, translate('PHRASE_DAMAGE_TAKEN'))} onMouseOut={tooltip.bind(null, null)}>{translate('damage taken')}(%)</h2>
|
<h2 onMouseOver={termtip.bind(null, translate('PHRASE_DAMAGE_TAKEN'))} onMouseOut={tooltip.bind(null, null)}>{translate('damage taken')}(%)</h2>
|
||||||
<VerticalBarChart data={shieldDamageTakenData} yMax={140} />
|
<VerticalBarChart data={shieldDamageTakenData} yMax={140} />
|
||||||
</div>
|
</div>
|
||||||
<div className='group quarter'>
|
<div className='group quarter'>
|
||||||
<h2 onMouseOver={termtip.bind(null, translate('PHRASE_EFFECTIVE_SHIELD'))} onMouseOut={tooltip.bind(null, null)}>{translate('effective shield')}(MJ)</h2>
|
<h2 onMouseOver={termtip.bind(null, translate('PHRASE_EFFECTIVE_SHIELD'))} onMouseOut={tooltip.bind(null, null)}>{translate('effective shield')}(MJ)</h2>
|
||||||
<VerticalBarChart data={effectiveShieldData} yMax={maxEffectiveShield}/>
|
<VerticalBarChart data={effectiveShieldData} yMax={maxEffectiveShield}/>
|
||||||
</div>
|
</div>
|
||||||
</span> : null }
|
</span> : null }
|
||||||
|
|
||||||
<div className='group quarter'>
|
<div className='group quarter'>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import TranslatedComponent from './TranslatedComponent';
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
import { Ships } from 'coriolis-data/dist';
|
|
||||||
import Slider from '../components/Slider';
|
import Slider from '../components/Slider';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,12 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import TranslatedComponent from './TranslatedComponent';
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
import { Ships } from 'coriolis-data/dist';
|
|
||||||
import { nameComparator } from '../utils/SlotFunctions';
|
|
||||||
import LineChart from '../components/LineChart';
|
import LineChart from '../components/LineChart';
|
||||||
import Slider from '../components/Slider';
|
|
||||||
import * as ModuleUtils from '../shipyard/ModuleUtils';
|
|
||||||
import Module from '../shipyard/Module';
|
|
||||||
import * as Calc from '../shipyard/Calculations';
|
import * as Calc from '../shipyard/Calculations';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,12 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import TranslatedComponent from './TranslatedComponent';
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
import { Ships } from 'coriolis-data/dist';
|
|
||||||
import { nameComparator } from '../utils/SlotFunctions';
|
|
||||||
import LineChart from '../components/LineChart';
|
import LineChart from '../components/LineChart';
|
||||||
import Slider from '../components/Slider';
|
|
||||||
import * as ModuleUtils from '../shipyard/ModuleUtils';
|
|
||||||
import Module from '../shipyard/Module';
|
|
||||||
import * as Calc from '../shipyard/Calculations';
|
import * as Calc from '../shipyard/Calculations';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,7 +64,7 @@ export default class FSDProfile extends TranslatedComponent {
|
|||||||
const { formats, translate, units } = language;
|
const { formats, translate, units } = language;
|
||||||
const { ship, cargo, fuel } = this.props;
|
const { ship, cargo, fuel } = this.props;
|
||||||
|
|
||||||
|
|
||||||
// Calculate bounds for our line chart - use thruster info for X
|
// Calculate bounds for our line chart - use thruster info for X
|
||||||
const thrusters = ship.standard[1].m;
|
const thrusters = ship.standard[1].m;
|
||||||
const fsd = ship.standard[2].m;
|
const fsd = ship.standard[2].m;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import TranslatedComponent from './TranslatedComponent';
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
import { Ships } from 'coriolis-data/dist';
|
|
||||||
import Slider from '../components/Slider';
|
import Slider from '../components/Slider';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2,12 +2,21 @@ import React from 'react';
|
|||||||
import cn from 'classnames';
|
import cn from 'classnames';
|
||||||
import Slot from './Slot';
|
import Slot from './Slot';
|
||||||
import Persist from '../stores/Persist';
|
import Persist from '../stores/Persist';
|
||||||
import { DamageAbsolute, DamageKinetic, DamageThermal, DamageExplosive, MountFixed, MountGimballed, MountTurret, ListModifications, Modified } from './SvgIcons';
|
import {
|
||||||
|
DamageAbsolute,
|
||||||
|
DamageKinetic,
|
||||||
|
DamageThermal,
|
||||||
|
DamageExplosive,
|
||||||
|
MountFixed,
|
||||||
|
MountGimballed,
|
||||||
|
MountTurret,
|
||||||
|
ListModifications,
|
||||||
|
Modified
|
||||||
|
} from './SvgIcons';
|
||||||
import { Modifications } from 'coriolis-data/dist';
|
import { Modifications } from 'coriolis-data/dist';
|
||||||
import { stopCtxPropagation } from '../utils/UtilityFunctions';
|
import { stopCtxPropagation } from '../utils/UtilityFunctions';
|
||||||
import { blueprintTooltip } from '../utils/BlueprintFunctions';
|
import { blueprintTooltip } from '../utils/BlueprintFunctions';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hardpoint / Utility Slot
|
* Hardpoint / Utility Slot
|
||||||
*/
|
*/
|
||||||
@@ -27,7 +36,7 @@ export default class HardpointSlot extends Slot {
|
|||||||
* @return {string} Label
|
* @return {string} Label
|
||||||
*/
|
*/
|
||||||
_getMaxClassLabel(translate) {
|
_getMaxClassLabel(translate) {
|
||||||
return translate(['U','S','M','L','H'][this.props.maxClass]);
|
return translate(['U', 'S', 'M', 'L', 'H'][this.props.maxClass]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,42 +75,76 @@ export default class HardpointSlot extends Slot {
|
|||||||
return <div className={className} draggable='true' onDragStart={drag} onDragEnd={drop}>
|
return <div className={className} draggable='true' onDragStart={drag} onDragEnd={drop}>
|
||||||
<div className={'cb'}>
|
<div className={'cb'}>
|
||||||
<div className={'l'}>
|
<div className={'l'}>
|
||||||
{m.mount && m.mount == 'F' ? <span onMouseOver={termtip.bind(null, 'fixed')} onMouseOut={tooltip.bind(null, null)}><MountFixed /></span> : ''}
|
{m.mount && m.mount == 'F' ? <span onMouseOver={termtip.bind(null, 'fixed')}
|
||||||
{m.mount && m.mount == 'G' ? <span onMouseOver={termtip.bind(null, 'gimballed')} onMouseOut={tooltip.bind(null, null)}><MountGimballed /></span> : ''}
|
onMouseOut={tooltip.bind(null, null)}><MountFixed/></span> : ''}
|
||||||
{m.mount && m.mount == 'T' ? <span onMouseOver={termtip.bind(null, 'turreted')} onMouseOut={tooltip.bind(null, null)}><MountTurret /></span> : ''}
|
{m.mount && m.mount == 'G' ? <span onMouseOver={termtip.bind(null, 'gimballed')}
|
||||||
{m.getDamageDist() && m.getDamageDist().K ? <span onMouseOver={termtip.bind(null, 'kinetic')} onMouseOut={tooltip.bind(null, null)}><DamageKinetic /></span> : ''}
|
onMouseOut={tooltip.bind(null, null)}><MountGimballed/></span> : ''}
|
||||||
{m.getDamageDist() && m.getDamageDist().T ? <span onMouseOver={termtip.bind(null, 'thermal')} onMouseOut={tooltip.bind(null, null)}><DamageThermal /></span> : ''}
|
{m.mount && m.mount == 'T' ? <span onMouseOver={termtip.bind(null, 'turreted')}
|
||||||
{m.getDamageDist() && m.getDamageDist().E ? <span onMouseOver={termtip.bind(null, 'explosive')} onMouseOut={tooltip.bind(null, null)}><DamageExplosive /></span> : ''}
|
onMouseOut={tooltip.bind(null, null)}><MountTurret/></span> : ''}
|
||||||
{m.getDamageDist() && m.getDamageDist().A ? <span onMouseOver={termtip.bind(null, 'absolute')} onMouseOut={tooltip.bind(null, null)}><DamageAbsolute /></span> : ''}
|
{m.getDamageDist() && m.getDamageDist().K ? <span onMouseOver={termtip.bind(null, 'kinetic')}
|
||||||
{classRating} {translate(m.name || m.grp)}{ m.mods && Object.keys(m.mods).length > 0 ? <span className='r' onMouseOver={termtip.bind(null, modTT)} onMouseOut={tooltip.bind(null, null)}><Modified /></span> : null }
|
onMouseOut={tooltip.bind(null, null)}><DamageKinetic/></span> : ''}
|
||||||
|
{m.getDamageDist() && m.getDamageDist().T ? <span onMouseOver={termtip.bind(null, 'thermal')}
|
||||||
|
onMouseOut={tooltip.bind(null, null)}><DamageThermal/></span> : ''}
|
||||||
|
{m.getDamageDist() && m.getDamageDist().E ? <span onMouseOver={termtip.bind(null, 'explosive')}
|
||||||
|
onMouseOut={tooltip.bind(null, null)}><DamageExplosive/></span> : ''}
|
||||||
|
{m.getDamageDist() && m.getDamageDist().A ? <span onMouseOver={termtip.bind(null, 'absolute')}
|
||||||
|
onMouseOut={tooltip.bind(null, null)}><DamageAbsolute/></span> : ''}
|
||||||
|
{classRating} {translate(m.name || m.grp)}{m.mods && Object.keys(m.mods).length > 0 ? <span className='r'
|
||||||
|
onMouseOver={termtip.bind(null, modTT)}
|
||||||
|
onMouseOut={tooltip.bind(null, null)}><Modified/></span> : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={'r'}>{formats.round(m.getMass())}{u.T}</div>
|
<div className={'r'}>{formats.round(m.getMass())}{u.T}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={'cb'}>
|
<div className={'cb'}>
|
||||||
{ m.getDps() ? <div className={'l'} onMouseOver={termtip.bind(null, m.getClip() ? 'dpssdps' : 'dps')} onMouseOut={tooltip.bind(null, null)}>{translate('DPS')}: {formats.round1(m.getDps())} { m.getClip() ? <span>({formats.round1(m.getSDps()) })</span> : null }</div> : null }
|
{m.getDps() ? <div className={'l'} onMouseOver={termtip.bind(null, m.getClip() ? 'dpssdps' : 'dps')}
|
||||||
{ 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() ? <span>({formats.round1((m.getClip() * m.getEps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload())) }{u.MW})</span> : null }</div> : null }
|
onMouseOut={tooltip.bind(null, null)}>{translate('DPS')}: {formats.round1(m.getDps())} {m.getClip() ?
|
||||||
{ 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() ? <span>({formats.round1((m.getClip() * m.getHps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload())) })</span> : null }</div> : null }
|
<span>({formats.round1(m.getSDps())})</span> : null}</div> : null}
|
||||||
{ 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 }
|
{m.getDamage() ? <div className={'l'} onMouseOver={termtip.bind(null, m.getDamage() ? 'shotdmg' : 'shotdmg')}
|
||||||
{ m.getRoF() ? <div className={'l'} onMouseOver={termtip.bind(null, 'rof')} onMouseOut={tooltip.bind(null, null)}>{translate('ROF')}: {formats.f1(m.getRoF())}{u.ps}</div> : null }
|
onMouseOut={tooltip.bind(null, null)}>{translate('shotdmg')}: {formats.round1(m.getDamage())}</div> : null}
|
||||||
{ m.getRange() ? <div className={'l'}>{translate('range', m.grp)} {formats.f1(m.getRange() / 1000)}{u.km}</div> : null }
|
{m.getEps() ? <div className={'l'} onMouseOver={termtip.bind(null, m.getClip() ? 'epsseps' : 'eps')}
|
||||||
{ m.getScanTime() ? <div className={'l'}>{translate('scantime')} {formats.f1(m.getScanTime())}{u.s}</div> : null }
|
onMouseOut={tooltip.bind(null, null)}>{translate('EPS')}: {formats.round1(m.getEps())}{u.MW} {m.getClip() ?
|
||||||
{ m.getFalloff() ? <div className={'l'}>{translate('falloff')} {formats.round(m.getFalloff() / 1000)}{u.km}</div> : null }
|
<span>({formats.round1((m.getClip() * m.getEps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload()))}{u.MW})</span> : null}</div> : null}
|
||||||
{ m.getShieldBoost() ? <div className={'l'}>+{formats.pct1(m.getShieldBoost())}</div> : null }
|
{m.getHps() ? <div className={'l'} onMouseOver={termtip.bind(null, m.getClip() ? 'hpsshps' : 'hps')}
|
||||||
{ m.getAmmo() ? <div className={'l'}>{translate('ammunition')}: {formats.int(m.getClip())}/{formats.int(m.getAmmo())}</div> : null }
|
onMouseOut={tooltip.bind(null, null)}>{translate('HPS')}: {formats.round1(m.getHps())} {m.getClip() ?
|
||||||
{ m.getReload() ? <div className={'l'}>{translate('reload')}: {formats.round(m.getReload())}{u.s}</div> : null }
|
<span>({formats.round1((m.getClip() * m.getHps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload()))})</span> : null}</div> : null}
|
||||||
{ m.getShotSpeed() ? <div className={'l'}>{translate('shotspeed')}: {formats.int(m.getShotSpeed())}{u.mps}</div> : null }
|
{m.getDps() && m.getEps() ? <div className={'l'} onMouseOver={termtip.bind(null, 'dpe')}
|
||||||
{ m.getPiercing() ? <div className={'l'}>{translate('piercing')}: {formats.int(m.getPiercing())}</div> : null }
|
onMouseOut={tooltip.bind(null, null)}>{translate('DPE')}: {formats.f1(m.getDps() / m.getEps())}</div> : null}
|
||||||
{ m.getJitter() ? <div className={'l'}>{translate('jitter')}: {formats.f2(m.getJitter())}°</div> : null }
|
{m.getRoF() ? <div className={'l'} onMouseOver={termtip.bind(null, 'rof')}
|
||||||
{ showModuleResistances && m.getExplosiveResistance() ? <div className='l'>{translate('explres')}: {formats.pct(m.getExplosiveResistance())}</div> : null }
|
onMouseOut={tooltip.bind(null, null)}>{translate('ROF')}: {formats.f1(m.getRoF())}{u.ps}</div> : null}
|
||||||
{ showModuleResistances && m.getKineticResistance() ? <div className='l'>{translate('kinres')}: {formats.pct(m.getKineticResistance())}</div> : null }
|
{m.getRange() ? <div
|
||||||
{ showModuleResistances && m.getThermalResistance() ? <div className='l'>{translate('thermres')}: {formats.pct(m.getThermalResistance())}</div> : null }
|
className={'l'}>{translate('range', m.grp)} {formats.f1(m.getRange() / 1000)}{u.km}</div> : null}
|
||||||
{ m.getIntegrity() ? <div className='l'>{translate('integrity')}: {formats.int(m.getIntegrity())}</div> : null }
|
{m.getScanTime() ? <div
|
||||||
{ m && validMods.length > 0 ? <div className='r' tabIndex="0" ref={ modButton => this.modButton = modButton }><button tabIndex="-1" onClick={this._toggleModifications.bind(this)} onContextMenu={stopCtxPropagation} onMouseOver={termtip.bind(null, 'modifications')} onMouseOut={tooltip.bind(null, null)}><ListModifications /></button></div> : null }
|
className={'l'}>{translate('scantime')} {formats.f1(m.getScanTime())}{u.s}</div> : null}
|
||||||
|
{m.getFalloff() ? <div
|
||||||
|
className={'l'}>{translate('falloff')} {formats.round(m.getFalloff() / 1000)}{u.km}</div> : null}
|
||||||
|
{m.getShieldBoost() ? <div className={'l'}>+{formats.pct1(m.getShieldBoost())}</div> : null}
|
||||||
|
{m.getAmmo() ? <div
|
||||||
|
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.getShotSpeed() ? <div
|
||||||
|
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.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
|
||||||
|
className='l'>{translate('explres')}: {formats.pct(m.getExplosiveResistance())}</div> : null}
|
||||||
|
{showModuleResistances && m.getKineticResistance() ? <div
|
||||||
|
className='l'>{translate('kinres')}: {formats.pct(m.getKineticResistance())}</div> : null}
|
||||||
|
{showModuleResistances && m.getThermalResistance() ? <div
|
||||||
|
className='l'>{translate('thermres')}: {formats.pct(m.getThermalResistance())}</div> : null}
|
||||||
|
{m.getIntegrity() ? <div className='l'>{translate('integrity')}: {formats.int(m.getIntegrity())}</div> : null}
|
||||||
|
{m && validMods.length > 0 ? <div className='r' tabIndex="0" ref={modButton => this.modButton = modButton}>
|
||||||
|
<button tabIndex="-1" onClick={this._toggleModifications.bind(this)} onContextMenu={stopCtxPropagation}
|
||||||
|
onMouseOver={termtip.bind(null, 'modifications')} onMouseOut={tooltip.bind(null, null)}>
|
||||||
|
<ListModifications/></button>
|
||||||
|
</div> : null}
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
} else {
|
} else {
|
||||||
return <div className={'empty'}>{translate('empty')}</div>;
|
return <div className={'empty'}>{translate('empty')}</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import SlotSection from './SlotSection';
|
import SlotSection from './SlotSection';
|
||||||
import HardpointSlot from './HardpointSlot';
|
import HardpointSlot from './HardpointSlot';
|
||||||
import cn from 'classnames';
|
|
||||||
import { MountFixed, MountGimballed, MountTurret } from '../components/SvgIcons';
|
import { MountFixed, MountGimballed, MountTurret } from '../components/SvgIcons';
|
||||||
import { stopCtxPropagation } from '../utils/UtilityFunctions';
|
import { stopCtxPropagation } from '../utils/UtilityFunctions';
|
||||||
|
|
||||||
@@ -154,6 +153,15 @@ export default class HardpointSlotSection extends SlotSection {
|
|||||||
<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>
|
||||||
|
<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', 'T')} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['rfl-T'] = smRef}><MountTurret className='lg'/></li>
|
||||||
|
</ul>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import ModalExport from './ModalExport';
|
|||||||
import ModalHelp from './ModalHelp';
|
import ModalHelp from './ModalHelp';
|
||||||
import ModalImport from './ModalImport';
|
import ModalImport from './ModalImport';
|
||||||
import Slider from './Slider';
|
import Slider from './Slider';
|
||||||
|
import Announcement from './Announcement';
|
||||||
import { outfitURL } from '../utils/UrlGenerators';
|
import { outfitURL } from '../utils/UrlGenerators';
|
||||||
|
|
||||||
const SIZE_MIN = 0.65;
|
const SIZE_MIN = 0.65;
|
||||||
@@ -76,8 +77,11 @@ export default class Header extends TranslatedComponent {
|
|||||||
this._openShips = this._openMenu.bind(this, 's');
|
this._openShips = this._openMenu.bind(this, 's');
|
||||||
this._openBuilds = this._openMenu.bind(this, 'b');
|
this._openBuilds = this._openMenu.bind(this, 'b');
|
||||||
this._openComp = this._openMenu.bind(this, 'comp');
|
this._openComp = this._openMenu.bind(this, 'comp');
|
||||||
|
this._openAnnounce = this._openMenu.bind(this, 'announce');
|
||||||
|
this._getAnnouncementsMenu = this._getAnnouncementsMenu.bind(this);
|
||||||
this._openSettings = this._openMenu.bind(this, 'settings');
|
this._openSettings = this._openMenu.bind(this, 'settings');
|
||||||
this._showHelp = this._showHelp.bind(this);
|
this._showHelp = this._showHelp.bind(this);
|
||||||
|
this.update = this.update.bind(this);
|
||||||
this.languageOptions = [];
|
this.languageOptions = [];
|
||||||
this.insuranceOptions = [];
|
this.insuranceOptions = [];
|
||||||
this.state = {
|
this.state = {
|
||||||
@@ -411,6 +415,29 @@ export default class Header extends TranslatedComponent {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the announcement menu
|
||||||
|
* @return {React.Component} Menu
|
||||||
|
*/
|
||||||
|
_getAnnouncementsMenu() {
|
||||||
|
let announcements;
|
||||||
|
let translate = this.context.language.translate;
|
||||||
|
|
||||||
|
if (this.props.announcements) {
|
||||||
|
announcements = [];
|
||||||
|
for (let announce of this.props.announcements) {
|
||||||
|
announcements.push(<Announcement text={announce.message} />);
|
||||||
|
announcements.push(<hr/>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className='menu-list' onClick={ (e) => e.stopPropagation() } style={{ whiteSpace: 'nowrap' }}>
|
||||||
|
{announcements}
|
||||||
|
<hr />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate the settings menu
|
* Generate the settings menu
|
||||||
* @return {React.Component} Menu
|
* @return {React.Component} Menu
|
||||||
@@ -534,6 +561,15 @@ export default class Header extends TranslatedComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async update() {
|
||||||
|
const reg = await navigator.serviceWorker.getRegistration();
|
||||||
|
if (!reg || !reg.waiting) {
|
||||||
|
return window.location.reload();
|
||||||
|
}
|
||||||
|
reg.waiting.postMessage('skipWaiting');
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the header
|
* Render the header
|
||||||
* @return {React.Component} Header
|
* @return {React.Component} Header
|
||||||
@@ -544,7 +580,7 @@ export default class Header extends TranslatedComponent {
|
|||||||
let hasBuilds = Persist.hasBuilds();
|
let hasBuilds = Persist.hasBuilds();
|
||||||
return (
|
return (
|
||||||
<header>
|
<header>
|
||||||
{this.props.appCacheUpdate && <div id="app-update" onClick={() => window.location.reload() }>{translate('PHRASE_UPDATE_RDY')}</div>}
|
{this.props.appCacheUpdate && <div id="app-update" onClick={this.update}>{translate('PHRASE_UPDATE_RDY')}</div>}
|
||||||
{this.props.appCacheUpdate ? <a className={'view-changes'} href={'https://github.com/EDCD/coriolis/compare/edcd:develop@{' + window.CORIOLIS_DATE + '}...edcd:develop'} target="_blank">
|
{this.props.appCacheUpdate ? <a className={'view-changes'} href={'https://github.com/EDCD/coriolis/compare/edcd:develop@{' + window.CORIOLIS_DATE + '}...edcd:develop'} target="_blank">
|
||||||
{'View Release Changes'}
|
{'View Release Changes'}
|
||||||
</a> : null}
|
</a> : null}
|
||||||
@@ -571,6 +607,13 @@ export default class Header extends TranslatedComponent {
|
|||||||
{openedMenu == 'comp' ? this._getComparisonsMenu() : null}
|
{openedMenu == 'comp' ? this._getComparisonsMenu() : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className='l menu'>
|
||||||
|
<div className={cn('menu-header', { selected: openedMenu == 'announce', disabled: this.props.announcements.length === 0})} onClick={this.props.announcements.length !== 0 && this._openAnnounce}>
|
||||||
|
<span className='menu-item-label'>{translate('announcements')}</span>
|
||||||
|
</div>
|
||||||
|
{openedMenu == 'announce' ? this._getAnnouncementsMenu() : null}
|
||||||
|
</div>
|
||||||
|
|
||||||
{window.location.origin.search('.edcd.io') >= 0 ?
|
{window.location.origin.search('.edcd.io') >= 0 ?
|
||||||
<div className='l menu'>
|
<div className='l menu'>
|
||||||
<a href="https://youtu.be/4SvnLcefhtI" target="_blank">
|
<a href="https://youtu.be/4SvnLcefhtI" target="_blank">
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import cn from 'classnames';
|
|
||||||
import SlotSection from './SlotSection';
|
import SlotSection from './SlotSection';
|
||||||
import InternalSlot from './InternalSlot';
|
import InternalSlot from './InternalSlot';
|
||||||
import * as ModuleUtils from '../shipyard/ModuleUtils';
|
import * as ModuleUtils from '../shipyard/ModuleUtils';
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import TranslatedComponent from './TranslatedComponent';
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
import { Ships } from 'coriolis-data/dist';
|
|
||||||
import { nameComparator } from '../utils/SlotFunctions';
|
|
||||||
import LineChart from '../components/LineChart';
|
import LineChart from '../components/LineChart';
|
||||||
import Slider from '../components/Slider';
|
import Slider from '../components/Slider';
|
||||||
import * as ModuleUtils from '../shipyard/ModuleUtils';
|
|
||||||
import Module from '../shipyard/Module';
|
|
||||||
import * as Calc from '../shipyard/Calculations';
|
import * as Calc from '../shipyard/Calculations';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import Persist from '../stores/Persist';
|
|||||||
* Delete All saved data modal
|
* Delete All saved data modal
|
||||||
*/
|
*/
|
||||||
export default class ModalDeleteAll extends TranslatedComponent {
|
export default class ModalDeleteAll extends TranslatedComponent {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete everything and hide the modal
|
* Delete everything and hide the modal
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -23,8 +23,10 @@ export default class ModalOrbis extends TranslatedComponent {
|
|||||||
this.state = {
|
this.state = {
|
||||||
orbisCreds: Persist.getOrbisCreds(),
|
orbisCreds: Persist.getOrbisCreds(),
|
||||||
orbisUrl: '...',
|
orbisUrl: '...',
|
||||||
|
ship: this.props.ship,
|
||||||
authenticatedStatus: 'Checking...'
|
authenticatedStatus: 'Checking...'
|
||||||
};
|
};
|
||||||
|
this.orbisCategory = this.orbisCategory.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -88,6 +90,17 @@ export default class ModalOrbis extends TranslatedComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for changing category
|
||||||
|
* @param {SyntheticEvent} e React Event
|
||||||
|
*/
|
||||||
|
orbisCategory(e) {
|
||||||
|
let ship = this.state.ship;
|
||||||
|
let cat = e.target.value;
|
||||||
|
ship.category = cat;
|
||||||
|
this.setState({ship});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the modal
|
* Render the modal
|
||||||
* @return {React.Component} Modal Content
|
* @return {React.Component} Modal Content
|
||||||
@@ -106,6 +119,17 @@ export default class ModalOrbis extends TranslatedComponent {
|
|||||||
<br/><br/>
|
<br/><br/>
|
||||||
<a className='button' href="https://orbis.zone/api/auth">Log in / signup to Orbis</a>
|
<a className='button' href="https://orbis.zone/api/auth">Log in / signup to Orbis</a>
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
<h3>Category</h3>
|
||||||
|
<select onChange={this.orbisCategory}>
|
||||||
|
<option value="">No Category</option>
|
||||||
|
<option>Combat</option>
|
||||||
|
<option>Mining</option>
|
||||||
|
<option>Trading</option>
|
||||||
|
<option>Exploration</option>
|
||||||
|
<option>Passenger Liner</option>
|
||||||
|
<option>PvP</option>
|
||||||
|
</select>
|
||||||
|
<br/><br/>
|
||||||
<h3 >{translate('Orbis link')}</h3>
|
<h3 >{translate('Orbis link')}</h3>
|
||||||
<input value={this.state.orbisUrl} readOnly size={25} onFocus={ (e) => e.target.select() }/>
|
<input value={this.state.orbisUrl} readOnly size={25} onFocus={ (e) => e.target.select() }/>
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import { isValueBeneficial } from '../utils/BlueprintFunctions';
|
|||||||
* Modification
|
* Modification
|
||||||
*/
|
*/
|
||||||
export default class Modification extends TranslatedComponent {
|
export default class Modification extends TranslatedComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
ship: PropTypes.object.isRequired,
|
ship: PropTypes.object.isRequired,
|
||||||
m: PropTypes.object.isRequired,
|
m: PropTypes.object.isRequired,
|
||||||
@@ -39,10 +38,24 @@ export default class Modification extends TranslatedComponent {
|
|||||||
* in a value by hand
|
* in a value by hand
|
||||||
*/
|
*/
|
||||||
_updateValue(value) {
|
_updateValue(value) {
|
||||||
let { m, name, ship } = this.props;
|
|
||||||
value = Math.max(Math.min(value, 50000), -50000);
|
|
||||||
ship.setModification(m, name, value, true, true);
|
|
||||||
this.setState({ value });
|
this.setState({ value });
|
||||||
|
let reCast = String(Number(value));
|
||||||
|
if (reCast.endsWith(value) || reCast.startsWith(value)) {
|
||||||
|
let { m, name, ship } = this.props;
|
||||||
|
value = Math.max(Math.min(value, 50000), -50000);
|
||||||
|
ship.setModification(m, name, value, true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggered when a key is pressed down with focus on the number editor.
|
||||||
|
* @param {SyntheticEvent} event Key down event
|
||||||
|
*/
|
||||||
|
_keyDown(event) {
|
||||||
|
if (event.key == 'Enter') {
|
||||||
|
this._updateFinished();
|
||||||
|
}
|
||||||
|
this.props.onKeyDown(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,6 +85,11 @@ export default class Modification extends TranslatedComponent {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let inputClassNames = {
|
||||||
|
'cb': true,
|
||||||
|
'greyed-out': !this.props.highlight
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div onBlur={this._updateFinished.bind(this)} key={name}
|
<div onBlur={this._updateFinished.bind(this)} key={name}
|
||||||
className={cn('cb', 'modification-container')}
|
className={cn('cb', 'modification-container')}
|
||||||
@@ -84,24 +102,24 @@ export default class Modification extends TranslatedComponent {
|
|||||||
<td className={'input-container'}>
|
<td className={'input-container'}>
|
||||||
<span>
|
<span>
|
||||||
{this.props.editable ?
|
{this.props.editable ?
|
||||||
<NumberEditor className={'cb'} value={this.state.value}
|
<NumberEditor className={cn(inputClassNames)} value={this.state.value}
|
||||||
decimals={2} style={{ textAlign: 'right' }} step={0.01}
|
decimals={2} style={{ textAlign: 'right' }} step={0.01}
|
||||||
stepModifier={1} onKeyDown={ this.props.onKeyDown }
|
stepModifier={1} onKeyDown={this._keyDown.bind(this)}
|
||||||
onValueChange={this._updateValue.bind(this)} /> :
|
onValueChange={this._updateValue.bind(this)} /> :
|
||||||
<input type="text" value={formats.f2(this.state.value)}
|
<input type="text" value={formats.f2(this.state.value)}
|
||||||
disabled className={'number-editor'}
|
disabled className={cn('number-editor', 'greyed-out')}
|
||||||
style={{ textAlign: 'right', cursor: 'inherit' }}/>
|
style={{ textAlign: 'right', cursor: 'inherit' }}/>
|
||||||
}
|
}
|
||||||
<span className={'unit-container'}>
|
<span className={'unit-container'}>
|
||||||
{units[m.getStoredUnitFor(name)]}
|
{units[m.getStoredUnitFor(name)]}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td style={{ textAlign: 'center' }} className={
|
<td style={{ textAlign: 'center' }} className={
|
||||||
modValue ?
|
modValue ?
|
||||||
isValueBeneficial(name, modValue) ? 'secondary': 'warning':
|
isValueBeneficial(name, modValue) ? 'secondary' : 'warning' :
|
||||||
''
|
''
|
||||||
}>
|
}>
|
||||||
{formats.f2(modValue / 100) || 0}%
|
{formats.f2(modValue / 100) || 0}%
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import TranslatedComponent from './TranslatedComponent';
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
import { isEmpty, stopCtxPropagation } from '../utils/UtilityFunctions';
|
import { stopCtxPropagation } from '../utils/UtilityFunctions';
|
||||||
import cn from 'classnames';
|
import cn from 'classnames';
|
||||||
import { Modifications } from 'coriolis-data/dist';
|
import { Modifications } from 'coriolis-data/dist';
|
||||||
import Modification from './Modification';
|
import Modification from './Modification';
|
||||||
@@ -23,7 +23,6 @@ const MODIFICATIONS_COMPARATOR = (mod1, mod2) => {
|
|||||||
* Modifications menu
|
* Modifications menu
|
||||||
*/
|
*/
|
||||||
export default class ModificationsMenu extends TranslatedComponent {
|
export default class ModificationsMenu extends TranslatedComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
ship: PropTypes.object.isRequired,
|
ship: PropTypes.object.isRequired,
|
||||||
m: PropTypes.object.isRequired,
|
m: PropTypes.object.isRequired,
|
||||||
@@ -214,11 +213,11 @@ export default class ModificationsMenu extends TranslatedComponent {
|
|||||||
for (const modName of Modifications.modules[m.grp].modifications) {
|
for (const modName of Modifications.modules[m.grp].modifications) {
|
||||||
if (!Modifications.modifications[modName].hidden) {
|
if (!Modifications.modifications[modName].hidden) {
|
||||||
const key = modName + (m.getModValue(modName) / 100 || 0);
|
const key = modName + (m.getModValue(modName) / 100 || 0);
|
||||||
const editable = modName !== 'fallofffromrange' &&
|
const editable = modName !== 'fallofffromrange';
|
||||||
m.blueprint.grades[m.blueprint.grade].features[modName];
|
const highlight = m.blueprint.grades[m.blueprint.grade].features[modName];
|
||||||
this.lastNeId = modName;
|
this.lastNeId = modName;
|
||||||
(editable ? modifiableModifications : modifications).push(
|
(editable && highlight ? modifiableModifications : modifications).push(
|
||||||
<Modification key={ key } ship={ ship } m={ m }
|
<Modification key={ key } ship={ ship } m={ m } highlight={highlight}
|
||||||
value={m.getPretty(modName) || 0} modItems={this.modItems}
|
value={m.getPretty(modName) || 0} modItems={this.modItems}
|
||||||
onChange={onChange} onKeyDown={this._keyDown} name={modName}
|
onChange={onChange} onKeyDown={this._keyDown} name={modName}
|
||||||
editable={editable} handleModChange = {this._handleModChange} />
|
editable={editable} handleModChange = {this._handleModChange} />
|
||||||
@@ -461,10 +460,10 @@ export default class ModificationsMenu extends TranslatedComponent {
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn('select', this.props.className)}
|
className={cn('select', this.props.className)}
|
||||||
onClick={(e) => e.stopPropagation() }
|
onClick={(e) => e.stopPropagation() }
|
||||||
onContextMenu={stopCtxPropagation}
|
onContextMenu={stopCtxPropagation}
|
||||||
ref={modItem => this.modItems['modMainDiv'] = modItem}
|
ref={modItem => this.modItems['modMainDiv'] = modItem}
|
||||||
>
|
>
|
||||||
{ showBlueprintsMenu | showSpecialsMenu ? '' : haveBlueprint ?
|
{ showBlueprintsMenu | showSpecialsMenu ? '' : haveBlueprint ?
|
||||||
<div tabIndex="0" className={ cn('section-menu button-inline-menu', { selected: blueprintMenuOpened })} style={{ cursor: 'pointer' }} onMouseOver={termtip.bind(null, blueprintTt)} onMouseOut={tooltip.bind(null, null)} onClick={_toggleBlueprintsMenu} onKeyDown={ this._keyDown } ref={modItems => this.modItems[this.firstBPLabel] = modItems}>{blueprintLabel}</div> :
|
<div tabIndex="0" className={ cn('section-menu button-inline-menu', { selected: blueprintMenuOpened })} style={{ cursor: 'pointer' }} onMouseOver={termtip.bind(null, blueprintTt)} onMouseOut={tooltip.bind(null, null)} onClick={_toggleBlueprintsMenu} onKeyDown={ this._keyDown } ref={modItems => this.modItems[this.firstBPLabel] = modItems}>{blueprintLabel}</div> :
|
||||||
@@ -473,11 +472,11 @@ export default class ModificationsMenu extends TranslatedComponent {
|
|||||||
{ showSpecial & !showSpecialsMenu ? <div tabIndex="0" className={ cn('section-menu button-inline-menu', { selected: specialMenuOpened })} style={{ cursor: 'pointer' }} onMouseOver={specialTt ? termtip.bind(null, specialTt) : null} onMouseOut={specialTt ? tooltip.bind(null, null) : null} onClick={_toggleSpecialsMenu} onKeyDown={ this._keyDown }>{specialLabel}</div> : null }
|
{ showSpecial & !showSpecialsMenu ? <div tabIndex="0" className={ cn('section-menu button-inline-menu', { selected: specialMenuOpened })} style={{ cursor: 'pointer' }} onMouseOver={specialTt ? termtip.bind(null, specialTt) : null} onMouseOut={specialTt ? tooltip.bind(null, null) : null} onClick={_toggleSpecialsMenu} onKeyDown={ this._keyDown }>{specialLabel}</div> : null }
|
||||||
{ showSpecialsMenu ? specials : null }
|
{ showSpecialsMenu ? specials : null }
|
||||||
{ showReset ? <div tabIndex="0" className={'section-menu button-inline-menu warning'} style={{ cursor: 'pointer' }} onClick={_reset} onKeyDown={ this._keyDown } onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_RESET')} onMouseOut={tooltip.bind(null, null)}> { translate('reset') } </div> : null }
|
{ showReset ? <div tabIndex="0" className={'section-menu button-inline-menu warning'} style={{ cursor: 'pointer' }} onClick={_reset} onKeyDown={ this._keyDown } onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_RESET')} onMouseOut={tooltip.bind(null, null)}> { translate('reset') } </div> : null }
|
||||||
{ showRolls ?
|
{ showRolls ?
|
||||||
|
|
||||||
<table style={{ width: '100%', backgroundColor: 'transparent' }}>
|
<table style={{ width: '100%', backgroundColor: 'transparent' }}>
|
||||||
<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('roll') }: </td>
|
||||||
<td tabIndex="0" className={ cn('section-menu button-inline-menu', { active: blueprintCv === 0 }) } style={{ cursor: 'pointer' }} onClick={_rollWorst} onKeyDown={ this._keyDown } onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_WORST')} onMouseOut={tooltip.bind(null, null)}> { translate('0%') } </td>
|
<td tabIndex="0" className={ cn('section-menu button-inline-menu', { active: blueprintCv === 0 }) } style={{ cursor: 'pointer' }} onClick={_rollWorst} onKeyDown={ this._keyDown } onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_WORST')} onMouseOut={tooltip.bind(null, null)}> { translate('0%') } </td>
|
||||||
@@ -485,7 +484,7 @@ export default class ModificationsMenu extends TranslatedComponent {
|
|||||||
<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>
|
||||||
<td tabIndex="0" className={ cn('section-menu button-inline-menu', { active: blueprintCv === null || blueprintCv % 50 != 0 })} style={{ cursor: 'pointer' }} onClick={_rollRandom} onKeyDown={ this._keyDown } onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_RANDOM')} onMouseOut={tooltip.bind(null, null)}> { translate('random') } </td>
|
<td tabIndex="0" className={ cn('section-menu button-inline-menu', { active: blueprintCv === null || blueprintCv % 50 != 0 })} style={{ cursor: 'pointer' }} onClick={_rollRandom} onKeyDown={ this._keyDown } onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_RANDOM')} onMouseOut={tooltip.bind(null, null)}> { translate('random') } </td>
|
||||||
</tr> : null }
|
</tr> : null }
|
||||||
</tbody>
|
</tbody>
|
||||||
</table> : null }
|
</table> : null }
|
||||||
{ showMods ? <hr /> : null }
|
{ showMods ? <hr /> : null }
|
||||||
{ showMods ?
|
{ showMods ?
|
||||||
|
|||||||
@@ -35,13 +35,13 @@ export default class Movement extends TranslatedComponent {
|
|||||||
return (
|
return (
|
||||||
<span id='movement'>
|
<span id='movement'>
|
||||||
<svg viewBox='0 0 600 600' fillRule="evenodd" clipRule="evenodd">
|
<svg viewBox='0 0 600 600' fillRule="evenodd" clipRule="evenodd">
|
||||||
// Axes
|
{/* Axes */}
|
||||||
<path d="M150 250v300" strokeWidth='1'/>
|
<path d="M150 250v300" strokeWidth='1'/>
|
||||||
<path d="M150 250l236 236" strokeWidth='1'/>
|
<path d="M150 250l236 236" strokeWidth='1'/>
|
||||||
<path d="M150 250l350 -200" strokeWidth='1'/>
|
<path d="M150 250l350 -200" strokeWidth='1'/>
|
||||||
// End Arrow
|
{/* End Arrow */}
|
||||||
<path d="M508 43.3L487 67l-10-17.3 31-6.4z"/>
|
<path d="M508 43.3L487 67l-10-17.3 31-6.4z"/>
|
||||||
// Axes arcs and arrows
|
{/* Axes arcs and arrows */}
|
||||||
<path d="M71.7 251.7C64.2 259.2 60 269.4 60 280c0 22 18 40 40 40s40-18 40-40c0-10.6-4.2-20.8-11.7-28.3 7.5 7.5 11.7 17.7 11.7 28.3 0 22-18 40-40 40s-40-18-40-40c0-10.6 4.2-20.8 11.7-28.3z" strokeWidth='4' transform="matrix(.6 0 0 .3 87.5 376.3)"/>
|
<path d="M71.7 251.7C64.2 259.2 60 269.4 60 280c0 22 18 40 40 40s40-18 40-40c0-10.6-4.2-20.8-11.7-28.3 7.5 7.5 11.7 17.7 11.7 28.3 0 22-18 40-40 40s-40-18-40-40c0-10.6 4.2-20.8 11.7-28.3z" strokeWidth='4' transform="matrix(.6 0 0 .3 87.5 376.3)"/>
|
||||||
<path d="M142.8 453l-13.2 8.7-2.6-9.7 15.8 1z"/>
|
<path d="M142.8 453l-13.2 8.7-2.6-9.7 15.8 1z"/>
|
||||||
<path d="M144.7 451.6l.5 1.6-16.2 10.6h-.4l-3.5-13 .7-.4 19.3 1.2zm-14.2 7.7l7.7-5-9.2-.7 1.5 5.7zm25.7-6.3l15.8-1-2.6 9.7-13.2-8.8z"/>
|
<path d="M144.7 451.6l.5 1.6-16.2 10.6h-.4l-3.5-13 .7-.4 19.3 1.2zm-14.2 7.7l7.7-5-9.2-.7 1.5 5.7zm25.7-6.3l15.8-1-2.6 9.7-13.2-8.8z"/>
|
||||||
@@ -57,13 +57,13 @@ export default class Movement extends TranslatedComponent {
|
|||||||
<path d="M359.5 422.4l-1.2 19.3-1.6.4-10.7-16 .2-.2 13-3.4.3.4zm-9 5l5.2 7.8.6-9.3-5.7 1.2zm-10.5 24l-13.2 8.6-2.6-9.7 15.8 1z"/>
|
<path d="M359.5 422.4l-1.2 19.3-1.6.4-10.7-16 .2-.2 13-3.4.3.4zm-9 5l5.2 7.8.6-9.3-5.7 1.2zm-10.5 24l-13.2 8.6-2.6-9.7 15.8 1z"/>
|
||||||
<path d="M342 450l.4 1.5-16.2 10.7-.4-.2-3.5-13 .3-.3L342 450zm-14.3 7.6l7.7-5-9.2-.6 1.5 5.6z"/>
|
<path d="M342 450l.4 1.5-16.2 10.7-.4-.2-3.5-13 .3-.3L342 450zm-14.3 7.6l7.7-5-9.2-.6 1.5 5.6z"/>
|
||||||
|
|
||||||
// Speed
|
{/* Speed */}
|
||||||
<text x="470" y="30" strokeWidth='0'>{ship.canThrust(cargo, fuel) ? formats.int(ship.calcSpeed(eng, fuel, cargo, boost)) + 'm/s' : '-'}</text>
|
<text x="470" y="30" strokeWidth='0'>{ship.canThrust(cargo, fuel) ? formats.int(ship.calcSpeed(eng, fuel, cargo, boost)) + 'm/s' : '-'}</text>
|
||||||
// Pitch
|
{/* Pitch */}
|
||||||
<text x="355" y="410" strokeWidth='0'>{ship.canThrust(cargo, fuel) ? formats.int(ship.calcPitch(eng, fuel, cargo, boost)) + '°/s' : '-'}</text>
|
<text x="355" y="410" strokeWidth='0'>{ship.canThrust(cargo, fuel) ? formats.int(ship.calcPitch(eng, fuel, cargo, boost)) + '°/s' : '-'}</text>
|
||||||
// Roll
|
{/* Roll */}
|
||||||
<text x="450" y="110" strokeWidth='0'>{ship.canThrust(cargo, fuel) ? formats.int(ship.calcRoll(eng, fuel, cargo, boost)) + '°/s' : '-'}</text>
|
<text x="450" y="110" strokeWidth='0'>{ship.canThrust(cargo, fuel) ? formats.int(ship.calcRoll(eng, fuel, cargo, boost)) + '°/s' : '-'}</text>
|
||||||
// Yaw
|
{/* Yaw */}
|
||||||
<text x="160" y="430" strokeWidth='0'>{ship.canThrust(cargo, fuel) ? formats.int(ship.calcYaw(eng, fuel, cargo, boost)) + '°/s' : '-'}</text>
|
<text x="160" y="430" strokeWidth='0'>{ship.canThrust(cargo, fuel) ? formats.int(ship.calcYaw(eng, fuel, cargo, boost)) + '°/s' : '-'}</text>
|
||||||
</svg>
|
</svg>
|
||||||
</span>);
|
</span>);
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import * as Calc from '../shipyard/Calculations';
|
|||||||
import PieChart from './PieChart';
|
import PieChart from './PieChart';
|
||||||
import { nameComparator } from '../utils/SlotFunctions';
|
import { nameComparator } from '../utils/SlotFunctions';
|
||||||
import { MountFixed, MountGimballed, MountTurret } from './SvgIcons';
|
import { MountFixed, MountGimballed, MountTurret } from './SvgIcons';
|
||||||
import VerticalBarChart from './VerticalBarChart';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates an internationalization friendly weapon comparator that will
|
* Generates an internationalization friendly weapon comparator that will
|
||||||
@@ -203,9 +202,9 @@ export default class Offence extends TranslatedComponent {
|
|||||||
|
|
||||||
|
|
||||||
let totalSEps = 0;
|
let totalSEps = 0;
|
||||||
let totalSDpsObject = {'absolute': 0, 'explosive': 0, 'kinetic': 0, 'thermal': 0};
|
let totalSDpsObject = { 'absolute': 0, 'explosive': 0, 'kinetic': 0, 'thermal': 0 };
|
||||||
let shieldsSDpsObject = {'absolute': 0, 'explosive': 0, 'kinetic': 0, 'thermal': 0};
|
let shieldsSDpsObject = { 'absolute': 0, 'explosive': 0, 'kinetic': 0, 'thermal': 0 };
|
||||||
let armourSDpsObject = {'absolute': 0, 'explosive': 0, 'kinetic': 0, 'thermal': 0};
|
let armourSDpsObject = { 'absolute': 0, 'explosive': 0, 'kinetic': 0, 'thermal': 0 };
|
||||||
|
|
||||||
const rows = [];
|
const rows = [];
|
||||||
for (let i = 0; i < damage.length; i++) {
|
for (let i = 0; i < damage.length; i++) {
|
||||||
@@ -267,22 +266,22 @@ export default class Offence extends TranslatedComponent {
|
|||||||
return (
|
return (
|
||||||
<span id='offence'>
|
<span id='offence'>
|
||||||
<div className='group full'>
|
<div className='group full'>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr className='main'>
|
<tr className='main'>
|
||||||
<th rowSpan='2' className='sortable' onClick={sortOrder.bind(this, 'n')}>{translate('weapon')}</th>
|
<th rowSpan='2' className='sortable' onClick={sortOrder.bind(this, 'n')}>{translate('weapon')}</th>
|
||||||
<th colSpan='1'>{translate('overall')}</th>
|
<th colSpan='1'>{translate('overall')}</th>
|
||||||
<th colSpan='2'>{translate('opponent\'s shields')}</th>
|
<th colSpan='2'>{translate('opponent\'s shields')}</th>
|
||||||
<th colSpan='2'>{translate('opponent\'s armour')}</th>
|
<th colSpan='2'>{translate('opponent\'s armour')}</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th className='lft sortable' onMouseOver={termtip.bind(null, 'TT_EFFECTIVE_SDPS_SHIELDS')} onMouseOut={tooltip.bind(null, null)} onClick={sortOrder.bind(this, 'esdpss')}>{'sdps'}</th>
|
<th className='lft sortable' onMouseOver={termtip.bind(null, 'TT_EFFECTIVE_SDPS_SHIELDS')} onMouseOut={tooltip.bind(null, null)} onClick={sortOrder.bind(this, 'esdpss')}>{'sdps'}</th>
|
||||||
<th className='lft sortable' onMouseOver={termtip.bind(null, 'TT_EFFECTIVE_SDPS_SHIELDS')} onMouseOut={tooltip.bind(null, null)} onClick={sortOrder.bind(this, 'esdpss')}>{'sdps'}</th>
|
<th className='lft sortable' onMouseOver={termtip.bind(null, 'TT_EFFECTIVE_SDPS_SHIELDS')} onMouseOut={tooltip.bind(null, null)} onClick={sortOrder.bind(this, 'esdpss')}>{'sdps'}</th>
|
||||||
<th className='sortable' onMouseOver={termtip.bind(null, 'TT_EFFECTIVENESS_SHIELDS')} onMouseOut={tooltip.bind(null, null)}onClick={sortOrder.bind(this, 'es')}>{'eft'}</th>
|
<th className='sortable' onMouseOver={termtip.bind(null, 'TT_EFFECTIVENESS_SHIELDS')} onMouseOut={tooltip.bind(null, null)}onClick={sortOrder.bind(this, 'es')}>{'eft'}</th>
|
||||||
<th className='lft sortable' onMouseOver={termtip.bind(null, 'TT_EFFECTIVE_SDPS_ARMOUR')} onMouseOut={tooltip.bind(null, null)}onClick={sortOrder.bind(this, 'esdpsh')}>{'sdps'}</th>
|
<th className='lft sortable' onMouseOver={termtip.bind(null, 'TT_EFFECTIVE_SDPS_ARMOUR')} onMouseOut={tooltip.bind(null, null)}onClick={sortOrder.bind(this, 'esdpsh')}>{'sdps'}</th>
|
||||||
<th className='sortable' onMouseOver={termtip.bind(null, 'TT_EFFECTIVENESS_ARMOUR')} onMouseOut={tooltip.bind(null, null)}onClick={sortOrder.bind(this, 'eh')}>{'eft'}</th>
|
<th className='sortable' onMouseOver={termtip.bind(null, 'TT_EFFECTIVENESS_ARMOUR')} onMouseOut={tooltip.bind(null, null)}onClick={sortOrder.bind(this, 'eh')}>{'eft'}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{rows}
|
{rows}
|
||||||
{rows.length > 0 &&
|
{rows.length > 0 &&
|
||||||
@@ -296,7 +295,7 @@ export default class Offence extends TranslatedComponent {
|
|||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div className='group quarter'>
|
<div className='group quarter'>
|
||||||
<h2>{translate('offence metrics')}</h2>
|
<h2>{translate('offence metrics')}</h2>
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import cn from 'classnames';
|
import cn from 'classnames';
|
||||||
import { Ships } from 'coriolis-data/dist';
|
|
||||||
import Ship from '../shipyard/Ship';
|
|
||||||
import Persist from '../stores/Persist';
|
import Persist from '../stores/Persist';
|
||||||
import TranslatedComponent from './TranslatedComponent';
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
import PowerManagement from './PowerManagement';
|
import PowerManagement from './PowerManagement';
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import TranslatedComponent from './TranslatedComponent';
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
import { Ships } from 'coriolis-data/dist';
|
|
||||||
import { nameComparator } from '../utils/SlotFunctions';
|
|
||||||
import { Pip } from './SvgIcons';
|
import { Pip } from './SvgIcons';
|
||||||
import LineChart from '../components/LineChart';
|
import { autoBind } from 'react-extras';
|
||||||
import Slider from '../components/Slider';
|
|
||||||
import * as ModuleUtils from '../shipyard/ModuleUtils';
|
|
||||||
import Module from '../shipyard/Module';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pips displays SYS/ENG/WEP pips and allows users to change them with key presses by clicking on the relevant area.
|
* Pips displays SYS/ENG/WEP pips and allows users to change them with key presses by clicking on the relevant area.
|
||||||
@@ -18,6 +13,9 @@ export default class Pips extends TranslatedComponent {
|
|||||||
sys: PropTypes.number.isRequired,
|
sys: PropTypes.number.isRequired,
|
||||||
eng: PropTypes.number.isRequired,
|
eng: PropTypes.number.isRequired,
|
||||||
wep: PropTypes.number.isRequired,
|
wep: PropTypes.number.isRequired,
|
||||||
|
mcSys: PropTypes.number.isRequired,
|
||||||
|
mcEng: PropTypes.number.isRequired,
|
||||||
|
mcWep: PropTypes.number.isRequired,
|
||||||
onChange: PropTypes.func.isRequired
|
onChange: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -28,9 +26,7 @@ export default class Pips extends TranslatedComponent {
|
|||||||
*/
|
*/
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props);
|
super(props);
|
||||||
const { sys, eng, wep } = props;
|
autoBind(this);
|
||||||
|
|
||||||
this._keyDown = this._keyDown.bind(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,30 +70,21 @@ export default class Pips extends TranslatedComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle a click
|
|
||||||
* @param {string} which Which item was clicked
|
|
||||||
*/
|
|
||||||
onClick(which) {
|
|
||||||
if (which == 'SYS') {
|
|
||||||
this._incSys();
|
|
||||||
} else if (which == 'ENG') {
|
|
||||||
this._incEng();
|
|
||||||
} else if (which == 'WEP') {
|
|
||||||
this._incWep();
|
|
||||||
} else if (which == 'RST') {
|
|
||||||
this._reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset the capacitor
|
* Reset the capacitor
|
||||||
*/
|
*/
|
||||||
_reset() {
|
_reset(isMc) {
|
||||||
let { sys, eng, wep } = this.props;
|
let { sys, eng, wep, mcSys, mcEng, mcWep } = this.props;
|
||||||
if (sys != 2 || eng != 2 || wep != 2) {
|
if (isMc) {
|
||||||
|
if (mcSys || mcEng || mcWep) {
|
||||||
|
sys -= mcSys;
|
||||||
|
eng -= mcEng;
|
||||||
|
wep -= mcWep;
|
||||||
|
this.props.onChange(sys, eng, wep, 0, 0, 0);
|
||||||
|
}
|
||||||
|
} else if (sys != 2 || eng != 2 || wep != 2) {
|
||||||
sys = eng = wep = 2;
|
sys = eng = wep = 2;
|
||||||
this.props.onChange(sys, eng, wep);
|
this.props.onChange(sys + mcSys, eng + mcEng, wep + mcWep, mcSys, mcEng, mcWep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,151 +92,133 @@ export default class Pips extends TranslatedComponent {
|
|||||||
* Increment the SYS capacitor
|
* Increment the SYS capacitor
|
||||||
*/
|
*/
|
||||||
_incSys() {
|
_incSys() {
|
||||||
let { sys, eng, wep } = this.props;
|
this._inc('sys', false);
|
||||||
|
|
||||||
const required = Math.min(1, 4 - sys);
|
|
||||||
if (required > 0) {
|
|
||||||
if (required == 0.5) {
|
|
||||||
// Take from whichever is larger
|
|
||||||
if (eng > wep) {
|
|
||||||
eng -= 0.5;
|
|
||||||
sys += 0.5;
|
|
||||||
} else {
|
|
||||||
wep -= 0.5;
|
|
||||||
sys += 0.5;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Required is 1 - take from both if possible
|
|
||||||
if (eng == 0) {
|
|
||||||
wep -= 1;
|
|
||||||
sys += 1;
|
|
||||||
} else if (wep == 0) {
|
|
||||||
eng -= 1;
|
|
||||||
sys += 1;
|
|
||||||
} else {
|
|
||||||
eng -= 0.5;
|
|
||||||
wep -= 0.5;
|
|
||||||
sys += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.props.onChange(sys, eng, wep);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increment the ENG capacitor
|
* Increment the ENG capacitor
|
||||||
*/
|
*/
|
||||||
_incEng() {
|
_incEng() {
|
||||||
let { sys, eng, wep } = this.props;
|
this._inc('eng', false);
|
||||||
|
|
||||||
const required = Math.min(1, 4 - eng);
|
|
||||||
if (required > 0) {
|
|
||||||
if (required == 0.5) {
|
|
||||||
// Take from whichever is larger
|
|
||||||
if (sys > wep) {
|
|
||||||
sys -= 0.5;
|
|
||||||
eng += 0.5;
|
|
||||||
} else {
|
|
||||||
wep -= 0.5;
|
|
||||||
eng += 0.5;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Required is 1 - take from both if possible
|
|
||||||
if (sys == 0) {
|
|
||||||
wep -= 1;
|
|
||||||
eng += 1;
|
|
||||||
} else if (wep == 0) {
|
|
||||||
sys -= 1;
|
|
||||||
eng += 1;
|
|
||||||
} else {
|
|
||||||
sys -= 0.5;
|
|
||||||
wep -= 0.5;
|
|
||||||
eng += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.props.onChange(sys, eng, wep);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increment the WEP capacitor
|
* Increment the WEP capacitor
|
||||||
*/
|
*/
|
||||||
_incWep() {
|
_incWep() {
|
||||||
let { sys, eng, wep } = this.props;
|
this._inc('wep', false);
|
||||||
|
}
|
||||||
|
|
||||||
const required = Math.min(1, 4 - wep);
|
_wrapMcClick(key) {
|
||||||
if (required > 0) {
|
return (event) => {
|
||||||
if (required == 0.5) {
|
event.stopPropagation();
|
||||||
// Take from whichever is larger
|
event.preventDefault();
|
||||||
if (sys > eng) {
|
if (key == 'rst') {
|
||||||
sys -= 0.5;
|
this._reset(true);
|
||||||
wep += 0.5;
|
|
||||||
} else {
|
|
||||||
eng -= 0.5;
|
|
||||||
wep += 0.5;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Required is 1 - take from both if possible
|
this._inc(key, true);
|
||||||
if (sys == 0) {
|
}
|
||||||
eng -= 1;
|
};
|
||||||
wep += 1;
|
}
|
||||||
} else if (eng == 0) {
|
|
||||||
sys -= 1;
|
/**
|
||||||
wep += 1;
|
* Increases a given capacitor
|
||||||
|
* @param {String} key Pip name to increase (one of 'sys', 'eng', 'wep')
|
||||||
|
* @param {Boolean} isMc True when increase is by multi crew
|
||||||
|
*/
|
||||||
|
_inc(key, isMc) {
|
||||||
|
if (!['sys', 'eng', 'wep'].includes(key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let { sys, eng, wep, mcSys, mcEng, mcWep } = this.props;
|
||||||
|
let mc = key == 'sys' ? mcSys : (key == 'eng' ? mcEng : mcWep);
|
||||||
|
let pips = this.props[key] - mc;
|
||||||
|
let other1 = key == 'sys' ? eng - mcEng : sys - mcSys;
|
||||||
|
let other2 = key == 'wep' ? eng - mcEng : wep - mcWep;
|
||||||
|
|
||||||
|
const required = Math.min(1, 4 - mc - pips);
|
||||||
|
if (isMc) {
|
||||||
|
// We can only set full pips in multi-crew also we can only set two pips
|
||||||
|
if (required > 0.5 && mcSys + mcEng + mcWep < 2) {
|
||||||
|
if (key == 'sys') {
|
||||||
|
mcSys += 1;
|
||||||
|
} else if (key == 'eng') {
|
||||||
|
mcEng += 1;
|
||||||
} else {
|
} else {
|
||||||
sys -= 0.5;
|
mcWep += 1;
|
||||||
eng -= 0.5;
|
|
||||||
wep += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.props.onChange(sys, eng, wep);
|
} else if (required > 0) {
|
||||||
|
if (required == 0.5) {
|
||||||
|
// Take from whichever is larger
|
||||||
|
if (other1 > other2) {
|
||||||
|
other1 -= 0.5;
|
||||||
|
} else {
|
||||||
|
other2 -= 0.5;
|
||||||
|
}
|
||||||
|
pips += 0.5;
|
||||||
|
} else {
|
||||||
|
// Required is 1 - take from both if possible
|
||||||
|
if (other1 == 0) {
|
||||||
|
other2 -= 1;
|
||||||
|
} else if (other2 == 0) {
|
||||||
|
other1 -= 1;
|
||||||
|
} else {
|
||||||
|
other1 -= 0.5;
|
||||||
|
other2 -= 0.5;
|
||||||
|
}
|
||||||
|
pips += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sys = mcSys + (key == 'sys' ? pips : other1);
|
||||||
|
eng = mcEng + (key == 'eng' ? pips : (key == 'sys' ? other1 : other2));
|
||||||
|
wep = mcWep + (key == 'wep' ? pips : other2);
|
||||||
|
this.props.onChange(sys, eng, wep, mcSys, mcEng, mcWep);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up the rendering for pips
|
* Set up the rendering for pips
|
||||||
* @param {int} sys the SYS pips
|
* @param {Number} sys the SYS pips
|
||||||
* @param {int} eng the ENG pips
|
* @param {Number} eng the ENG pips
|
||||||
* @param {int} wep the WEP pips
|
* @param {Number} wep the WEP pips
|
||||||
|
* @param {Number} mcSys SYS pips from multi-crew
|
||||||
|
* @param {Number} mcEng ENG pips from multi-crew
|
||||||
|
* @param {Number} mcWep WEP pips from multi-crew
|
||||||
* @returns {Object} Object containing the rendering for the pips
|
* @returns {Object} Object containing the rendering for the pips
|
||||||
*/
|
*/
|
||||||
_renderPips(sys, eng, wep) {
|
_renderPips(sys, eng, wep, mcSys, mcEng, mcWep) {
|
||||||
const pipsSvg = {};
|
const pipsSvg = {
|
||||||
|
SYS: [],
|
||||||
|
ENG: [],
|
||||||
|
WEP: [],
|
||||||
|
};
|
||||||
|
|
||||||
// SYS
|
// Multi-crew pipsSettings actually are included in the overall pip count therefore
|
||||||
pipsSvg['SYS'] = [];
|
// we can consider [0, sys - mcSys] as normal pipsSettings whilst [sys - mcSys, sys]
|
||||||
for (let i = 0; i < Math.floor(sys); i++) {
|
// are the multi-crew pipsSettings in what follows.
|
||||||
pipsSvg['SYS'].push(<Pip className='full' key={i} />);
|
|
||||||
}
|
|
||||||
if (sys > Math.floor(sys)) {
|
|
||||||
pipsSvg['SYS'].push(<Pip className='half' key={'half'} />);
|
|
||||||
}
|
|
||||||
for (let i = Math.floor(sys + 0.5); i < 4; i++) {
|
|
||||||
pipsSvg['SYS'].push(<Pip className='empty' key={i} />);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ENG
|
let pipsSettings = {
|
||||||
pipsSvg['ENG'] = [];
|
SYS: [sys, mcSys],
|
||||||
for (let i = 0; i < Math.floor(eng); i++) {
|
ENG: [eng, mcEng],
|
||||||
pipsSvg['ENG'].push(<Pip className='full' key={i} />);
|
WEP: [wep, mcWep],
|
||||||
}
|
};
|
||||||
if (eng > Math.floor(eng)) {
|
|
||||||
pipsSvg['ENG'].push(<Pip className='half' key={'half'} />);
|
|
||||||
}
|
|
||||||
for (let i = Math.floor(eng + 0.5); i < 4; i++) {
|
|
||||||
pipsSvg['ENG'].push(<Pip className='empty' key={i} />);
|
|
||||||
}
|
|
||||||
|
|
||||||
// WEP
|
for (let pipName in pipsSettings) {
|
||||||
pipsSvg['WEP'] = [];
|
let [pips, mcPips] = pipsSettings[pipName];
|
||||||
for (let i = 0; i < Math.floor(wep); i++) {
|
for (let i = 0; i < Math.floor(pips - mcPips); i++) {
|
||||||
pipsSvg['WEP'].push(<Pip className='full' key={i} />);
|
pipsSvg[pipName].push(<Pip key={i} className='full' />);
|
||||||
}
|
}
|
||||||
if (wep > Math.floor(wep)) {
|
if (pips > Math.floor(pips)) {
|
||||||
pipsSvg['WEP'].push(<Pip className='half' key={'half'} />);
|
pipsSvg[pipName].push(<Pip className='half' key={'half'} />);
|
||||||
}
|
}
|
||||||
for (let i = Math.floor(wep + 0.5); i < 4; i++) {
|
for (let i = pips - mcPips; i < Math.floor(pips); i++) {
|
||||||
pipsSvg['WEP'].push(<Pip className='empty' key={i} />);
|
pipsSvg[pipName].push(<Pip key={i} className='mc' />);
|
||||||
|
}
|
||||||
|
for (let i = Math.floor(pips + 0.5); i < 4; i++) {
|
||||||
|
pipsSvg[pipName].push(<Pip className='empty' key={i} />);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pipsSvg;
|
return pipsSvg;
|
||||||
@@ -260,15 +229,11 @@ export default class Pips extends TranslatedComponent {
|
|||||||
* @return {React.Component} contents
|
* @return {React.Component} contents
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
|
const { tooltip, termtip } = this.context;
|
||||||
const { formats, translate, units } = this.context.language;
|
const { formats, translate, units } = this.context.language;
|
||||||
const { sys, eng, wep } = this.props;
|
const { sys, eng, wep, mcSys, mcEng, mcWep } = this.props;
|
||||||
|
|
||||||
const onSysClicked = this.onClick.bind(this, 'SYS');
|
const pipsSvg = this._renderPips(sys, eng, wep, mcSys, mcEng, mcWep);
|
||||||
const onEngClicked = this.onClick.bind(this, 'ENG');
|
|
||||||
const onWepClicked = this.onClick.bind(this, 'WEP');
|
|
||||||
const onRstClicked = this.onClick.bind(this, 'RST');
|
|
||||||
|
|
||||||
const pipsSvg = this._renderPips(sys, eng, wep);
|
|
||||||
return (
|
return (
|
||||||
<span id='pips'>
|
<span id='pips'>
|
||||||
<table>
|
<table>
|
||||||
@@ -276,20 +241,38 @@ export default class Pips extends TranslatedComponent {
|
|||||||
<tr>
|
<tr>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
<td className='clickable' onClick={onEngClicked}>{pipsSvg['ENG']}</td>
|
<td className='clickable' onClick={() => this._inc('eng')}
|
||||||
|
onContextMenu={this._wrapMcClick('eng')}>{pipsSvg['ENG']}</td>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
<td className='clickable' onClick={onSysClicked}>{pipsSvg['SYS']}</td>
|
<td className='clickable' onClick={this._incSys}
|
||||||
<td className='clickable' onClick={onEngClicked}>{translate('ENG')}</td>
|
onContextMenu={this._wrapMcClick('sys')}>{pipsSvg['SYS']}</td>
|
||||||
<td className='clickable' onClick={onWepClicked}>{pipsSvg['WEP']}</td>
|
<td className='clickable' onClick={this._incEng}
|
||||||
|
onContextMenu={this._wrapMcClick('eng')}>{translate('ENG')}</td>
|
||||||
|
<td className='clickable' onClick={this._incWep}
|
||||||
|
onContextMenu={this._wrapMcClick('wep')}>{pipsSvg['WEP']}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
<td className='clickable' onClick={onSysClicked}>{translate('SYS')}</td>
|
<td className='clickable' onClick={this._incSys}
|
||||||
<td className='clickable' onClick={onRstClicked}>{translate('RST')}</td>
|
onContextMenu={this._wrapMcClick('sys')}>{translate('SYS')}</td>
|
||||||
<td className='clickable' onClick={onWepClicked}>{translate('WEP')}</td>
|
<td className='clickable' onClick={this._reset.bind(this, false)}>
|
||||||
|
{translate('RST')}
|
||||||
|
</td>
|
||||||
|
<td className='clickable' onClick={this._incWep}
|
||||||
|
onContextMenu={this._wrapMcClick('wep')}>{translate('WEP')}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td> </td>
|
||||||
|
<td> </td>
|
||||||
|
<td className='clickable secondary' onClick={this._wrapMcClick('rst')}
|
||||||
|
onMouseEnter={termtip.bind(null, 'PHRASE_MULTI_CREW_CAPACITOR_POINTS')}
|
||||||
|
onMouseLeave={tooltip.bind(null, null)}>
|
||||||
|
{translate('RST')}
|
||||||
|
</td>
|
||||||
|
<td> </td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ function bandText(val, index, wattScale) {
|
|||||||
* Renders the SVG to simulate in-game power bands
|
* Renders the SVG to simulate in-game power bands
|
||||||
*/
|
*/
|
||||||
export default class PowerBands extends TranslatedComponent {
|
export default class PowerBands extends TranslatedComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
bands: PropTypes.array.isRequired,
|
bands: PropTypes.array.isRequired,
|
||||||
available: PropTypes.number.isRequired,
|
available: PropTypes.number.isRequired,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import TranslatedComponent from './TranslatedComponent';
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
import Ship from '../shipyard/Ship';
|
|
||||||
import { Ships } from 'coriolis-data/dist';
|
import { Ships } from 'coriolis-data/dist';
|
||||||
import { Rocket } from './SvgIcons';
|
import { Rocket } from './SvgIcons';
|
||||||
import Persist from '../stores/Persist';
|
import Persist from '../stores/Persist';
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ export default class ShipSummaryTable extends TranslatedComponent {
|
|||||||
const boostTooltip = canBoost ? 'TT_SUMMARY_BOOST' : canThrust ? 'TT_SUMMARY_BOOST_NONFUNCTIONAL' : 'TT_SUMMARY_SPEED_NONFUNCTIONAL';
|
const boostTooltip = canBoost ? 'TT_SUMMARY_BOOST' : canThrust ? 'TT_SUMMARY_BOOST_NONFUNCTIONAL' : 'TT_SUMMARY_SPEED_NONFUNCTIONAL';
|
||||||
const 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 armourMetrics = Calc.armourMetrics(ship);
|
const armourMetrics = Calc.armourMetrics(ship);
|
||||||
let shieldColour = 'blue';
|
let shieldColour = 'blue';
|
||||||
if (shieldGenerator && shieldGenerator.m.grp === 'psg') {
|
if (shieldGenerator && shieldGenerator.m.grp === 'psg') {
|
||||||
@@ -78,13 +79,14 @@ export default class ShipSummaryTable extends TranslatedComponent {
|
|||||||
<th rowSpan={2}>{translate('TTD')}</th>
|
<th rowSpan={2}>{translate('TTD')}</th>
|
||||||
{/* <th onMouseEnter={termtip.bind(null, 'heat per second')} onMouseLeave={hide} rowSpan={2}>{translate('HPS')}</th> */}
|
{/* <th onMouseEnter={termtip.bind(null, 'heat per second')} onMouseLeave={hide} rowSpan={2}>{translate('HPS')}</th> */}
|
||||||
<th rowSpan={2}>{translate('cargo')}</th>
|
<th rowSpan={2}>{translate('cargo')}</th>
|
||||||
<th rowSpan={2}>{translate('pax')}</th>
|
<th rowSpan={2} onMouseEnter={termtip.bind(null, 'passenger capacity', { cap: 0 })} onMouseLeave={hide}>{translate('pax')}</th>
|
||||||
<th rowSpan={2}>{translate('fuel')}</th>
|
<th rowSpan={2}>{translate('fuel')}</th>
|
||||||
<th colSpan={3}>{translate('mass')}</th>
|
<th colSpan={3}>{translate('mass')}</th>
|
||||||
<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_TIME', { cap: 0 })} onMouseLeave={hide} rowSpan={2}>{translate('boost time')}</th>
|
||||||
|
<th rowSpan={2}>{translate('resting heat (Beta)')}</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th className='lft'>{translate('max')}</th>
|
<th className='lft'>{translate('max')}</th>
|
||||||
@@ -122,6 +124,7 @@ export default class ShipSummaryTable extends TranslatedComponent {
|
|||||||
<td>{ship.crew}</td>
|
<td>{ship.crew}</td>
|
||||||
<td>{ship.masslock}</td>
|
<td>{ship.masslock}</td>
|
||||||
<td>{shipBoost !== 'No Boost' ? formats.time(shipBoost) : 'No Boost'}</td>
|
<td>{shipBoost !== 'No Boost' ? formats.time(shipBoost) : 'No Boost'}</td>
|
||||||
|
<td>{formats.pct(restingHeat)}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import AvailableModulesMenu from './AvailableModulesMenu';
|
|||||||
import ModificationsMenu from './ModificationsMenu';
|
import ModificationsMenu from './ModificationsMenu';
|
||||||
import { diffDetails } from '../utils/SlotFunctions';
|
import { diffDetails } from '../utils/SlotFunctions';
|
||||||
import { wrapCtxMenu } from '../utils/UtilityFunctions';
|
import { wrapCtxMenu } from '../utils/UtilityFunctions';
|
||||||
import { stopCtxPropagation } from '../utils/UtilityFunctions';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract Slot
|
* Abstract Slot
|
||||||
@@ -88,7 +87,7 @@ export default class Slot extends TranslatedComponent {
|
|||||||
if(event.target.className == 'r') {
|
if(event.target.className == 'r') {
|
||||||
this._toggleModifications();
|
this._toggleModifications();
|
||||||
}
|
}
|
||||||
this.props.onOpen(event);
|
this.props.onOpen(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -20,16 +20,28 @@ export default class StandardSlotSection extends SlotSection {
|
|||||||
super(props, context, 'standard', 'core internal');
|
super(props, context, 'standard', 'core internal');
|
||||||
this._optimizeStandard = this._optimizeStandard.bind(this);
|
this._optimizeStandard = this._optimizeStandard.bind(this);
|
||||||
this._selectBulkhead = this._selectBulkhead.bind(this);
|
this._selectBulkhead = this._selectBulkhead.bind(this);
|
||||||
|
this._showDW2Menu = this._showDW2Menu.bind(this);
|
||||||
|
this._dw2 = this._dw2.bind(this);
|
||||||
this.selectedRefId = null;
|
this.selectedRefId = null;
|
||||||
this.firstRefId = 'maxjump';
|
this.firstRefId = 'maxjump';
|
||||||
this.lastRefId = 'racer';
|
this.lastRefId = 'dw2';
|
||||||
|
this.state = {
|
||||||
|
showDW2: false,
|
||||||
|
DW2Tier: -1,
|
||||||
|
DW2Eng: -1,
|
||||||
|
DW2Role: '',
|
||||||
|
DW2Gfsb: false,
|
||||||
|
DW2Gpp: false,
|
||||||
|
DW2Fighter: false
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle focus if the component updates
|
* Handle focus if the component updates
|
||||||
* @param {Object} prevProps React Component properties
|
* @param {Object} prevProps React Component properties
|
||||||
*/
|
*/
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
this._handleSectionFocus(prevProps,this.firstRefId, this.lastRefId);
|
this._handleSectionFocus(prevProps, this.firstRefId, this.lastRefId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,6 +84,114 @@ export default class StandardSlotSection extends SlotSection {
|
|||||||
this._close();
|
this._close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DW2 Build
|
||||||
|
*/
|
||||||
|
_dw2() {
|
||||||
|
this.selectedRefId = 'dw2';
|
||||||
|
this.setState({ showDW2: false });
|
||||||
|
ShipRoles.dw2Build(this.props.ship, this.state.DW2Tier, this.state.DW2Eng, this.state.DW2Role, this.state.DW2Gfsb, this.state.DW2Gpp, this.state.DW2Fighter);
|
||||||
|
this.props.ship.updateModificationsString();
|
||||||
|
this.props.onChange();
|
||||||
|
this.props.onCargoChange(this.props.ship.cargoCapacity);
|
||||||
|
this.props.onFuelChange(this.props.ship.fuelCapacity);
|
||||||
|
this._close();
|
||||||
|
}
|
||||||
|
|
||||||
|
_showDW2Menu(translate) {
|
||||||
|
return (
|
||||||
|
<div className='select' onClick={(e) => e.stopPropagation()} onContextMenu={stopCtxPropagation}>
|
||||||
|
<div className='select-group cap'>{translate('Tier')}</div>
|
||||||
|
<ul id={'tier'}>
|
||||||
|
<li className={cn({ active: this.state.DW2Tier === 1 }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Tier: 1 })} onKeyDown={this._keyDown}
|
||||||
|
>{translate('1 - Max. Jump Range, Unshielded')}</li>
|
||||||
|
<li className={cn({ active: this.state.DW2Tier === 2 }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Tier: 2 })} onKeyDown={this._keyDown}
|
||||||
|
>{translate('2 - Max. Jump Range, Minimal Shields')}</li>
|
||||||
|
<li className={cn({ active: this.state.DW2Tier === 3 }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Tier: 3 })} onKeyDown={this._keyDown}
|
||||||
|
>{translate('3 - Max. Jump Range, Optimal Shields')}</li>
|
||||||
|
<li className={cn({ active: this.state.DW2Tier === 4 }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Tier: 4 })} onKeyDown={this._keyDown}
|
||||||
|
>{translate('4 - Max. Jump Range, Optimal Shields & Thrusters')}</li>
|
||||||
|
</ul>
|
||||||
|
<hr/>
|
||||||
|
<div className='select-group cap'>{translate('Engineering Level')}</div>
|
||||||
|
<ul id={'engLevel'}>
|
||||||
|
<li className={cn({ active: this.state.DW2Eng === 1 }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Eng: 1 })} onKeyDown={this._keyDown}
|
||||||
|
>{translate('No engineering')}</li>
|
||||||
|
<li className={cn({ active: this.state.DW2Eng === 2 }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Eng: 2 })} onKeyDown={this._keyDown}
|
||||||
|
>{translate('Only Felicity Farseer and Elvira Martuuk')}</li>
|
||||||
|
<li className={cn({ active: this.state.DW2Eng === 3 }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Eng: 3 })} onKeyDown={this._keyDown}
|
||||||
|
>{translate('All exploration engineers')}</li>
|
||||||
|
</ul>
|
||||||
|
<hr/>
|
||||||
|
<div className='select-group cap'>{translate('Role')}</div>
|
||||||
|
<ul id={'role'}>
|
||||||
|
<li className={cn({ active: this.state.DW2Role === 'exploration' }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Role: 'exploration' })}
|
||||||
|
onKeyDown={this._keyDown}
|
||||||
|
>{translate('Space exploration')}</li>
|
||||||
|
<li className={cn({ active: this.state.DW2Role === 'surface' }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Role: 'surface' })}
|
||||||
|
onKeyDown={this._keyDown}
|
||||||
|
>{translate('Surface exploration')}</li>
|
||||||
|
<li className={cn({ active: this.state.DW2Role === 'materialProspector' }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Role: 'materialProspector' })}
|
||||||
|
onKeyDown={this._keyDown}
|
||||||
|
>{translate('Material prospector')}</li>
|
||||||
|
<li className={cn({ active: this.state.DW2Role === 'propectorMining' }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Role: 'propectorMining' })}
|
||||||
|
onKeyDown={this._keyDown}
|
||||||
|
>{translate('Prospector/Sapper Miner')}</li>
|
||||||
|
<li className={cn({ active: this.state.DW2Role === 'bigRigMining' }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Role: 'bigRigMining' })}
|
||||||
|
onKeyDown={this._keyDown}
|
||||||
|
>{translate('Big Rig, full mining')}</li>
|
||||||
|
<li className={cn({ active: this.state.DW2Role === 'fuelRat' }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Role: 'fuelRat' })} onKeyDown={this._keyDown}
|
||||||
|
>{translate('Fuel Rat')}</li>
|
||||||
|
<li className={cn({ active: this.state.DW2Role === 'mechanic' }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Role: 'mechanic' })} onKeyDown={this._keyDown}
|
||||||
|
>{translate('Mechanic')}</li>
|
||||||
|
<li className={cn({ active: this.state.DW2Role === 'trucker' }, 'lc')} tabIndex="0"
|
||||||
|
onClick={() => this.setState({ DW2Role: 'trucker' })} onKeyDown={this._keyDown}
|
||||||
|
>{translate('Trucker')}</li>
|
||||||
|
</ul>
|
||||||
|
<hr/>
|
||||||
|
<ul>
|
||||||
|
<li className={cn({ active: this.state.DW2Gfsb === true }, 'lc')}
|
||||||
|
onClick={() => this.setState({ DW2Gfsb: this.state.DW2Gfsb !== true })}>
|
||||||
|
Add Guardian FSD Booster
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li className={cn({ active: this.state.DW2Gpp === true }, 'lc')}
|
||||||
|
onClick={() => this.setState({ DW2Gpp: this.state.DW2Gpp !== true })}>
|
||||||
|
Add Guardian Power Plant
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li className={cn({ active: this.state.DW2Fighter === true }, 'lc')}
|
||||||
|
onClick={() => this.setState({ DW2Fighter: this.state.DW2Fighter !== true })}>
|
||||||
|
Add Fighter
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<hr/>
|
||||||
|
<ul>
|
||||||
|
<li onClick={this._dw2} className={cn('lc')} tabIndex="0"
|
||||||
|
onKeyDown={this._keyDown}>
|
||||||
|
<button className="button">Apply</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Miner Build
|
* Miner Build
|
||||||
* @param {Boolean} shielded True if shield generator should be included
|
* @param {Boolean} shielded True if shield generator should be included
|
||||||
@@ -177,7 +297,6 @@ export default class StandardSlotSection extends SlotSection {
|
|||||||
warning={m => m instanceof Module ? m.getMaxMass() < (ship.unladenMass + cargo + fuel - st[1].m.mass + m.mass) : m.maxmass < (ship.unladenMass + cargo + fuel - st[1].m.mass + m.mass)}
|
warning={m => m instanceof Module ? m.getMaxMass() < (ship.unladenMass + cargo + fuel - st[1].m.mass + m.mass) : m.maxmass < (ship.unladenMass + cargo + fuel - st[1].m.mass + m.mass)}
|
||||||
/>;
|
/>;
|
||||||
|
|
||||||
|
|
||||||
slots[3] = <StandardSlot
|
slots[3] = <StandardSlot
|
||||||
key='fsd'
|
key='fsd'
|
||||||
slot={st[2]}
|
slot={st[2]}
|
||||||
@@ -232,7 +351,7 @@ export default class StandardSlotSection extends SlotSection {
|
|||||||
selected={currentMenu == st[6]}
|
selected={currentMenu == st[6]}
|
||||||
onChange={this.props.onChange}
|
onChange={this.props.onChange}
|
||||||
ship={ship}
|
ship={ship}
|
||||||
warning= {m => m.fuel < st[2].m.maxfuel} // Show warning when fuel tank is smaller than FSD Max Fuel
|
warning={m => m.fuel < st[2].m.maxfuel} // Show warning when fuel tank is smaller than FSD Max Fuel
|
||||||
/>;
|
/>;
|
||||||
|
|
||||||
return slots;
|
return slots;
|
||||||
@@ -245,19 +364,34 @@ export default class StandardSlotSection extends SlotSection {
|
|||||||
*/
|
*/
|
||||||
_getSectionMenu(translate) {
|
_getSectionMenu(translate) {
|
||||||
let planetaryDisabled = this.props.ship.internal.length < 4;
|
let planetaryDisabled = this.props.ship.internal.length < 4;
|
||||||
|
if (this.state.showDW2 === true) {
|
||||||
|
return this._showDW2Menu(translate);
|
||||||
|
}
|
||||||
return <div className='select' onClick={(e) => e.stopPropagation()} onContextMenu={stopCtxPropagation}>
|
return <div className='select' onClick={(e) => e.stopPropagation()} onContextMenu={stopCtxPropagation}>
|
||||||
<ul>
|
<ul>
|
||||||
<li className='lc' tabIndex="0" onClick={this._optimizeStandard} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['maxjump'] = smRef}>{translate('Maximize Jump Range')}</li>
|
<li className='lc' tabIndex="0" onClick={this._optimizeStandard} onKeyDown={this._keyDown}
|
||||||
|
ref={smRef => this.sectionRefArr['maxjump'] = smRef}>{translate('Maximize Jump Range')}</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div className='select-group cap'>{translate('roles')}</div>
|
<div className='select-group cap'>{translate('roles')}</div>
|
||||||
<ul>
|
<ul>
|
||||||
<li className='lc' tabIndex="0" onClick={this._multiPurpose.bind(this, false, 0)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['multipurpose'] = smRef}>{translate('Multi-purpose')}</li>
|
<li className='lc' tabIndex="0" onClick={this._multiPurpose.bind(this, false, 0)} onKeyDown={this._keyDown}
|
||||||
<li className='lc' tabIndex="0" onClick={this._multiPurpose.bind(this, true, 2)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['combat'] = smRef}>{translate('Combat')}</li>
|
ref={smRef => this.sectionRefArr['multipurpose'] = smRef}>{translate('Multi-purpose')}</li>
|
||||||
<li className='lc' tabIndex="0" onClick={this._optimizeCargo.bind(this, true)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['trader'] = smRef}>{translate('Trader')}</li>
|
<li className='lc' tabIndex="0" onClick={this._multiPurpose.bind(this, true, 2)} onKeyDown={this._keyDown}
|
||||||
<li className='lc' tabIndex="0" onClick={this._optimizeExplorer.bind(this, false)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['explorer'] = smRef}>{translate('Explorer')}</li>
|
ref={smRef => this.sectionRefArr['combat'] = smRef}>{translate('Combat')}</li>
|
||||||
<li className={cn('lc', { disabled: planetaryDisabled })} tabIndex={planetaryDisabled ? '' : '0'} onClick={!planetaryDisabled && this._optimizeExplorer.bind(this, true)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['planetary'] = smRef}>{translate('Planetary Explorer')}</li>
|
<li className='lc' tabIndex="0" onClick={this._optimizeCargo.bind(this, true)} onKeyDown={this._keyDown}
|
||||||
<li className='lc' tabIndex="0" onClick={this._optimizeMiner.bind(this, true)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['miner'] = smRef}>{translate('Miner')}</li>
|
ref={smRef => this.sectionRefArr['trader'] = smRef}>{translate('Trader')}</li>
|
||||||
<li className='lc' tabIndex="0" onClick={this._optimizeRacer.bind(this)} onKeyDown={this._keyDown} ref={smRef => this.sectionRefArr['racer'] = smRef}>{translate('Racer')}</li>
|
<li className='lc' tabIndex="0" onClick={this._optimizeExplorer.bind(this, false)} onKeyDown={this._keyDown}
|
||||||
|
ref={smRef => this.sectionRefArr['explorer'] = smRef}>{translate('Explorer')}</li>
|
||||||
|
<li className={cn('lc', { disabled: planetaryDisabled })} tabIndex={planetaryDisabled ? '' : '0'}
|
||||||
|
onClick={!planetaryDisabled && this._optimizeExplorer.bind(this, true)} onKeyDown={this._keyDown}
|
||||||
|
ref={smRef => this.sectionRefArr['planetary'] = smRef}>{translate('Planetary Explorer')}</li>
|
||||||
|
<li className='lc' tabIndex="0" onClick={this._optimizeMiner.bind(this, true)} onKeyDown={this._keyDown}
|
||||||
|
ref={smRef => this.sectionRefArr['miner'] = smRef}>{translate('Miner')}</li>
|
||||||
|
<li className='lc' tabIndex="0" onClick={this._optimizeRacer.bind(this)} onKeyDown={this._keyDown}
|
||||||
|
ref={smRef => this.sectionRefArr['racer'] = smRef}>{translate('Racer')}</li>
|
||||||
|
<li className='lc' tabIndex="0" onClick={() => this.setState({ showDW2: !this.state.showDW2 })}
|
||||||
|
onKeyDown={this._keyDown}
|
||||||
|
ref={smRef => this.sectionRefArr['dw2'] = smRef}>{translate('DW2')}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import cn from 'classnames';
|
|
||||||
import SlotSection from './SlotSection';
|
import SlotSection from './SlotSection';
|
||||||
import HardpointSlot from './HardpointSlot';
|
import HardpointSlot from './HardpointSlot';
|
||||||
import { stopCtxPropagation } from '../utils/UtilityFunctions';
|
import { stopCtxPropagation } from '../utils/UtilityFunctions';
|
||||||
@@ -8,7 +7,6 @@ import { stopCtxPropagation } from '../utils/UtilityFunctions';
|
|||||||
* Utility Slot Section
|
* Utility Slot Section
|
||||||
*/
|
*/
|
||||||
export default class UtilitySlotSection extends SlotSection {
|
export default class UtilitySlotSection extends SlotSection {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
@@ -133,5 +131,4 @@ export default class UtilitySlotSection extends SlotSection {
|
|||||||
</ul>
|
</ul>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import TranslatedComponent from './TranslatedComponent';
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import ContainerDimensions from 'react-container-dimensions';
|
import ContainerDimensions from 'react-container-dimensions';
|
||||||
import { BarChart, Bar, XAxis, YAxis } from 'recharts';
|
import { BarChart, Bar, XAxis, YAxis, LabelList } from 'recharts';
|
||||||
|
|
||||||
const CORIOLIS_COLOURS = ['#FF8C0D', '#1FB0FF', '#71A052', '#D5D54D'];
|
const CORIOLIS_COLOURS = ['#FF8C0D', '#1FB0FF', '#71A052', '#D5D54D'];
|
||||||
const LABEL_COLOUR = '#000000';
|
const LABEL_COLOUR = '#000000';
|
||||||
@@ -17,7 +17,6 @@ const merge = function(one, two) {
|
|||||||
* A vertical bar chart
|
* A vertical bar chart
|
||||||
*/
|
*/
|
||||||
export default class VerticalBarChart extends TranslatedComponent {
|
export default class VerticalBarChart extends TranslatedComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
data : PropTypes.array.isRequired,
|
data : PropTypes.array.isRequired,
|
||||||
yMax : PropTypes.number
|
yMax : PropTypes.number
|
||||||
@@ -54,7 +53,9 @@ export default class VerticalBarChart extends TranslatedComponent {
|
|||||||
<BarChart width={width} height={width * ASPECT} data={this.props.data} margin={{ top: 5, right: 5, left: 5, bottom: 5 }}>
|
<BarChart width={width} height={width * ASPECT} data={this.props.data} margin={{ top: 5, right: 5, left: 5, bottom: 5 }}>
|
||||||
<XAxis interval={0} fontSize='0.8em' stroke={AXIS_COLOUR} dataKey='label' />
|
<XAxis interval={0} fontSize='0.8em' stroke={AXIS_COLOUR} dataKey='label' />
|
||||||
<YAxis interval={'preserveStart'} tickCount={11} fontSize='0.8em' stroke={AXIS_COLOUR} type='number' domain={[0, localMax]}/>
|
<YAxis interval={'preserveStart'} tickCount={11} fontSize='0.8em' stroke={AXIS_COLOUR} type='number' domain={[0, localMax]}/>
|
||||||
<Bar dataKey='value' label={<ValueLabel />} fill={CORIOLIS_COLOURS[0]} isAnimationActive={false} onMouseOver={this._termtip} onMouseOut={tooltip.bind(null, null)}/>
|
<Bar dataKey='value' fill={CORIOLIS_COLOURS[0]} isAnimationActive={false} onMouseOver={this._termtip} onMouseOut={tooltip.bind(null, null)}>
|
||||||
|
<LabelList dataKey='value' position='insideTop'/>
|
||||||
|
</Bar>
|
||||||
</BarChart>
|
</BarChart>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -77,29 +78,3 @@ export default class VerticalBarChart extends TranslatedComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A label that displays the value within the bar of the chart
|
|
||||||
*/
|
|
||||||
class ValueLabel extends React.Component {
|
|
||||||
static propTypes = {
|
|
||||||
x: PropTypes.number,
|
|
||||||
y: PropTypes.number,
|
|
||||||
payload: PropTypes.object,
|
|
||||||
value: PropTypes.number
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render offence
|
|
||||||
* @return {React.Component} contents
|
|
||||||
*/
|
|
||||||
render() {
|
|
||||||
const { x, y, payload, value } = this.props;
|
|
||||||
|
|
||||||
const em = value < 1000 ? '1em' : value < 1000 ? '0.8em' : '0.7em';
|
|
||||||
|
|
||||||
return (
|
|
||||||
<text x={x} y={y} fill="#000000" textAnchor="middle" dy={20} style={{ fontSize: em }}>{value}</text>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import TranslatedComponent from './TranslatedComponent';
|
import TranslatedComponent from './TranslatedComponent';
|
||||||
import { Ships } from 'coriolis-data/dist';
|
|
||||||
import { nameComparator } from '../utils/SlotFunctions';
|
|
||||||
import { CollapseSection, ExpandSection, MountFixed, MountGimballed, MountTurret } from './SvgIcons';
|
|
||||||
import LineChart from '../components/LineChart';
|
import LineChart from '../components/LineChart';
|
||||||
import Slider from '../components/Slider';
|
|
||||||
import * as Calc from '../shipyard/Calculations';
|
import * as Calc from '../shipyard/Calculations';
|
||||||
import Module from '../shipyard/Module';
|
|
||||||
|
|
||||||
const DAMAGE_DEALT_COLORS = ['#FFFFFF', '#FF0000', '#00FF00', '#7777FF', '#FFFF00', '#FF00FF', '#00FFFF', '#777777'];
|
const DAMAGE_DEALT_COLORS = ['#FFFFFF', '#FF0000', '#00FF00', '#7777FF', '#FFFF00', '#FF00FF', '#00FFFF', '#777777'];
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
|||||||
import 'babel-polyfill';
|
import '@babel/polyfill';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { render } from 'react-dom';
|
import { render } from 'react-dom';
|
||||||
import '../less/app.less';
|
import '../less/app.less';
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import { CoriolisLogo, GitHub } from '../components/SvgIcons';
|
|||||||
* About Page
|
* About Page
|
||||||
*/
|
*/
|
||||||
export default class AboutPage extends Page {
|
export default class AboutPage extends Page {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
@@ -23,33 +22,112 @@ export default class AboutPage extends Page {
|
|||||||
* @return {React.Component} The page contents
|
* @return {React.Component} The page contents
|
||||||
*/
|
*/
|
||||||
renderPage() {
|
renderPage() {
|
||||||
return <div className={'page'} style={{ textAlign: 'left', maxWidth: 800, margin: '0 auto' }}>
|
return (
|
||||||
<h1><CoriolisLogo style={{ marginRight: '0.4em' }} className='xl'/><span className='warning'>Coriolis EDCD Edition</span></h1>
|
<div
|
||||||
|
className={'page'}
|
||||||
|
style={{ textAlign: 'left', maxWidth: 800, margin: '0 auto' }}
|
||||||
|
>
|
||||||
|
<h1>
|
||||||
|
<CoriolisLogo style={{ marginRight: '0.4em' }} className="xl" />
|
||||||
|
<span className="warning">Coriolis EDCD Edition</span>
|
||||||
|
</h1>
|
||||||
|
|
||||||
<p>This is a clone of the Coriolis project, whose original author is currently unable to maintain it. This clone is maintained by the <a href="http://edcd.github.io/">EDCD community</a>.</p>
|
<p>
|
||||||
<p>To recover your builds, go to <a href='https://coriolis.io/' target='_blank'>https://coriolis.io/</a>, backup your builds (Settings / Backup), copy the text, return here and import (Settings / Import).</p>
|
This is a clone of the Coriolis project, whose original author is
|
||||||
<p>The Coriolis project was inspired by <a href='http://www.edshipyard.com/' target='_blank'>E:D Shipyard</a> and, of course, <a href='http://www.elitedangerous.com' target='_blank'>Elite Dangerous</a>. The ultimate goal of Coriolis is to provide rich features to support in-game play and planning while engaging the E:D community to support its development.</p>
|
currently unable to maintain it. This clone is maintained by the{' '}
|
||||||
<p>Coriolis was created using assets and imagery from Elite: Dangerous, with the permission of Frontier Developments plc, for non-commercial purposes. It is not endorsed by nor reflects the views or opinions of Frontier Developments. A number of assets were sourced from <a href='http://edassets.org' target='_blank'>ED Assets</a></p>
|
<a href="http://edcd.github.io/">EDCD community</a>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
To recover your builds, go to{' '}
|
||||||
|
<a href="https://coriolis.io/" target="_blank">
|
||||||
|
https://coriolis.io/
|
||||||
|
</a>
|
||||||
|
, backup your builds (Settings / Backup), copy the text, return here
|
||||||
|
and import (Settings / Import).
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The Coriolis project was inspired by{' '}
|
||||||
|
<a href="http://www.edshipyard.com/" target="_blank">
|
||||||
|
E:D Shipyard
|
||||||
|
</a>{' '}
|
||||||
|
and, of course,{' '}
|
||||||
|
<a href="http://www.elitedangerous.com" target="_blank">
|
||||||
|
Elite Dangerous
|
||||||
|
</a>
|
||||||
|
. The ultimate goal of Coriolis is to provide rich features to support
|
||||||
|
in-game play and planning while engaging the E:D community to support
|
||||||
|
its development.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Coriolis was created using assets and imagery from Elite: Dangerous,
|
||||||
|
with the permission of Frontier Developments plc, for non-commercial
|
||||||
|
purposes. It is not endorsed by nor reflects the views or opinions of
|
||||||
|
Frontier Developments. A number of assets were sourced from{' '}
|
||||||
|
<a href="http://edassets.org" target="_blank">
|
||||||
|
ED Assets
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
<a style={{ display: 'block', textDecoration: 'none' }} href='https://github.com/EDCD/coriolis' target='_blank' title='Coriolis Github Project'>
|
<a
|
||||||
<GitHub style={{ margin: '0.4em' }} className='l fg xl'/>
|
style={{ display: 'block', textDecoration: 'none' }}
|
||||||
<h2 style={{ margin: 0, textDecoration: 'none' }}>Github</h2>
|
href="https://github.com/EDCD/coriolis"
|
||||||
github.com/EDCD/coriolis
|
target="_blank"
|
||||||
</a>
|
title="Coriolis Github Project"
|
||||||
|
>
|
||||||
|
<GitHub style={{ margin: '0.4em' }} className="l fg xl" />
|
||||||
|
<h2 style={{ margin: 0, textDecoration: 'none' }}>Github</h2>
|
||||||
|
github.com/EDCD/coriolis
|
||||||
|
</a>
|
||||||
|
|
||||||
<p>Coriolis is an open source project. Checkout the list of upcoming features and to-do list on github. Any and all contributions and feedback are welcome. If you encounter any bugs please report them and provide as much detail as possible.</p>
|
<p>
|
||||||
|
Coriolis is an open source project. Checkout the list of upcoming
|
||||||
|
features and to-do list on github. Any and all contributions and
|
||||||
|
feedback are welcome. If you encounter any bugs please report them and
|
||||||
|
provide as much detail as possible.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h3>Chat</h3>
|
<h3>Chat</h3>
|
||||||
<p>You can chat to us on our <a href='https://discord.gg/0uwCh6R62aPRjk9w' target='_blank'>EDCD Discord server</a>.</p>
|
<p>
|
||||||
|
You can chat to us on our{' '}
|
||||||
|
<a href="https://discord.gg/0uwCh6R62aPRjk9w" target="_blank">
|
||||||
|
EDCD Discord server
|
||||||
|
</a>
|
||||||
|
.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h3>Supporting Coriolis</h3>
|
<h3>Supporting Coriolis</h3>
|
||||||
<p>Coriolis is an open source project, and I work on it in my free time. I have set up a patreon at <a href='https://www.patreon.com/coriolis_elite'>patreon.com/coriolis_elite</a>, which will be used to keep Coriolis up to date and the servers running.</p>
|
<p>
|
||||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
|
Coriolis is an open source project, and I work on it in my free time.
|
||||||
<input type="hidden" name="cmd" value="_s-xclick"/>
|
I have set up a patreon at{' '}
|
||||||
<input type="hidden" name="hosted_button_id" value="SJBKT2SWEEU68" />
|
<a href="https://www.patreon.com/coriolis_elite">
|
||||||
<input type="image" src="https://www.paypalobjects.com/en_AU/i/btn/btn_donate_SM.gif" border="0" name="submit" alt="PayPal – The safer, easier way to pay online!" />
|
patreon.com/coriolis_elite
|
||||||
<img alt="" border="0" src="https://www.paypalobjects.com/en_AU/i/scr/pixel.gif" width="1" height="1" />
|
</a>
|
||||||
|
, which will be used to keep Coriolis up to date and the servers
|
||||||
|
running.
|
||||||
|
</p>
|
||||||
|
<form
|
||||||
|
action="https://www.paypal.com/cgi-bin/webscr"
|
||||||
|
method="post"
|
||||||
|
target="_top"
|
||||||
|
>
|
||||||
|
<input type="hidden" name="cmd" value="_s-xclick" />
|
||||||
|
<input type="hidden" name="hosted_button_id" value="SJBKT2SWEEU68" />
|
||||||
|
<input
|
||||||
|
type="image"
|
||||||
|
src="https://www.paypalobjects.com/en_AU/i/btn/btn_donate_SM.gif"
|
||||||
|
border="0"
|
||||||
|
name="submit"
|
||||||
|
alt="PayPal – The safer, easier way to pay online!"
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
alt=""
|
||||||
|
border="0"
|
||||||
|
src="https://www.paypalobjects.com/en_AU/i/scr/pixel.gif"
|
||||||
|
width="1"
|
||||||
|
height="1"
|
||||||
|
/>
|
||||||
</form>
|
</form>
|
||||||
</div>;
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,14 @@ import ModalCompare from '../components/ModalCompare';
|
|||||||
import ModalExport from '../components/ModalExport';
|
import ModalExport from '../components/ModalExport';
|
||||||
import ModalPermalink from '../components/ModalPermalink';
|
import ModalPermalink from '../components/ModalPermalink';
|
||||||
import ModalImport from '../components/ModalImport';
|
import ModalImport from '../components/ModalImport';
|
||||||
import { FloppyDisk, Bin, Download, Embed, Rocket, LinkIcon } from '../components/SvgIcons';
|
import {
|
||||||
|
FloppyDisk,
|
||||||
|
Bin,
|
||||||
|
Download,
|
||||||
|
Embed,
|
||||||
|
Rocket,
|
||||||
|
LinkIcon
|
||||||
|
} from '../components/SvgIcons';
|
||||||
import ShortenUrl from '../utils/ShortenUrl';
|
import ShortenUrl from '../utils/ShortenUrl';
|
||||||
import { comparisonBBCode } from '../utils/BBCode';
|
import { comparisonBBCode } from '../utils/BBCode';
|
||||||
const browser = require('detect-browser');
|
const browser = require('detect-browser');
|
||||||
@@ -42,7 +49,6 @@ function sortBy(predicate) {
|
|||||||
* Comparison Page
|
* Comparison Page
|
||||||
*/
|
*/
|
||||||
export default class ComparisonPage extends Page {
|
export default class ComparisonPage extends Page {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
@@ -81,7 +87,13 @@ export default class ComparisonPage extends Page {
|
|||||||
for (let shipId in allBuilds) {
|
for (let shipId in allBuilds) {
|
||||||
for (let buildName in allBuilds[shipId]) {
|
for (let buildName in allBuilds[shipId]) {
|
||||||
if (buildName && allBuilds[shipId][buildName]) {
|
if (buildName && allBuilds[shipId][buildName]) {
|
||||||
builds.push(this._createBuild(shipId, buildName, allBuilds[shipId][buildName]));
|
builds.push(
|
||||||
|
this._createBuild(
|
||||||
|
shipId,
|
||||||
|
buildName,
|
||||||
|
allBuilds[shipId][buildName]
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,7 +101,9 @@ export default class ComparisonPage extends Page {
|
|||||||
let comparisonData = Persist.getComparison(name);
|
let comparisonData = Persist.getComparison(name);
|
||||||
if (comparisonData) {
|
if (comparisonData) {
|
||||||
defaultFacets = comparisonData.facets;
|
defaultFacets = comparisonData.facets;
|
||||||
comparisonData.builds.forEach((b) => builds.push(this._createBuild(b.shipId, b.buildName)));
|
comparisonData.builds.forEach(b =>
|
||||||
|
builds.push(this._createBuild(b.shipId, b.buildName))
|
||||||
|
);
|
||||||
saved = true;
|
saved = true;
|
||||||
newName = name;
|
newName = name;
|
||||||
}
|
}
|
||||||
@@ -101,7 +115,7 @@ export default class ComparisonPage extends Page {
|
|||||||
newName = name = comparisonData.n;
|
newName = name = comparisonData.n;
|
||||||
predicate = comparisonData.p;
|
predicate = comparisonData.p;
|
||||||
desc = comparisonData.d;
|
desc = comparisonData.d;
|
||||||
comparisonData.b.forEach((build) => {
|
comparisonData.b.forEach(build => {
|
||||||
builds.push(this._createBuild(build.s, build.n, build.c));
|
builds.push(this._createBuild(build.s, build.n, build.c));
|
||||||
if (!importObj[build.s]) {
|
if (!importObj[build.s]) {
|
||||||
importObj[build.s] = {};
|
importObj[build.s] = {};
|
||||||
@@ -118,9 +132,9 @@ export default class ComparisonPage extends Page {
|
|||||||
let selectedFacets = new Array(selectedLength);
|
let selectedFacets = new Array(selectedLength);
|
||||||
|
|
||||||
for (let i = 0; i < ShipFacets.length; i++) {
|
for (let i = 0; i < ShipFacets.length; i++) {
|
||||||
let facet = Object.assign({ }, ShipFacets[i]);
|
let facet = Object.assign({}, ShipFacets[i]);
|
||||||
let defaultIndex = defaultFacets.indexOf(facet.i);
|
let defaultIndex = defaultFacets.indexOf(facet.i);
|
||||||
if(defaultIndex == -1) {
|
if (defaultIndex == -1) {
|
||||||
facets.push(facet);
|
facets.push(facet);
|
||||||
} else {
|
} else {
|
||||||
facet.active = true;
|
facet.active = true;
|
||||||
@@ -155,17 +169,18 @@ export default class ComparisonPage extends Page {
|
|||||||
_createBuild(id, name, code) {
|
_createBuild(id, name, code) {
|
||||||
code = code ? code : Persist.getBuild(id, name); // Retrieve build code if not passed
|
code = code ? code : Persist.getBuild(id, name); // Retrieve build code if not passed
|
||||||
|
|
||||||
if (!code) { // No build found
|
if (!code) {
|
||||||
|
// No build found
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = Ships[id]; // Get ship properties
|
let data = Ships[id]; // Get ship properties
|
||||||
let b = new Ship(id, data.properties, data.slots); // Create a new Ship instance
|
let b = new Ship(id, data.properties, data.slots); // Create a new Ship instance
|
||||||
b.buildFrom(code); // Populate components from code
|
b.buildFrom(code); // Populate components from code
|
||||||
b.buildName = name;
|
b.buildName = name;
|
||||||
b.applyDiscounts(Persist.getShipDiscount(), Persist.getModuleDiscount());
|
b.applyDiscounts(Persist.getShipDiscount(), Persist.getModuleDiscount());
|
||||||
return b;
|
return b;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update state with the specified sort predicates
|
* Update state with the specified sort predicates
|
||||||
@@ -184,13 +199,18 @@ export default class ComparisonPage extends Page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.setState({ predicate, desc });
|
this.setState({ predicate, desc });
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show selected builds modal
|
* Show selected builds modal
|
||||||
*/
|
*/
|
||||||
_selectBuilds() {
|
_selectBuilds() {
|
||||||
this.context.showModal(<ModalCompare onSelect={this._buildsSelected} builds={this.state.builds} />);
|
this.context.showModal(
|
||||||
|
<ModalCompare
|
||||||
|
onSelect={this._buildsSelected}
|
||||||
|
builds={this.state.builds}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -224,7 +244,7 @@ export default class ComparisonPage extends Page {
|
|||||||
_facetDrag(e) {
|
_facetDrag(e) {
|
||||||
this.nodeAfter = false;
|
this.nodeAfter = false;
|
||||||
this.dragged = e.currentTarget;
|
this.dragged = e.currentTarget;
|
||||||
let placeholder = this.placeholder = document.createElement('li');
|
let placeholder = (this.placeholder = document.createElement('li'));
|
||||||
placeholder.style.width = Math.round(this.dragged.offsetWidth) + 'px';
|
placeholder.style.width = Math.round(this.dragged.offsetWidth) + 'px';
|
||||||
placeholder.className = 'facet-placeholder';
|
placeholder.className = 'facet-placeholder';
|
||||||
if (!browser || (browser.name !== 'edge' && browser.name !== 'ie')) {
|
if (!browser || (browser.name !== 'edge' && browser.name !== 'ie')) {
|
||||||
@@ -262,7 +282,7 @@ export default class ComparisonPage extends Page {
|
|||||||
_facetDragOver(e) {
|
_facetDragOver(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if(e.target.className == 'facet-placeholder') {
|
if (e.target.className == 'facet-placeholder') {
|
||||||
return;
|
return;
|
||||||
} else if (e.target != e.currentTarget) {
|
} else if (e.target != e.currentTarget) {
|
||||||
this.over = e.target;
|
this.over = e.target;
|
||||||
@@ -272,7 +292,7 @@ export default class ComparisonPage extends Page {
|
|||||||
let parent = e.target.parentNode;
|
let parent = e.target.parentNode;
|
||||||
|
|
||||||
if (parent == e.currentTarget) {
|
if (parent == e.currentTarget) {
|
||||||
if(relX > width && this.dragged != e.target) {
|
if (relX > width && this.dragged != e.target) {
|
||||||
this.nodeAfter = true;
|
this.nodeAfter = true;
|
||||||
parent.insertBefore(this.placeholder, e.target.nextElementSibling);
|
parent.insertBefore(this.placeholder, e.target.nextElementSibling);
|
||||||
} else {
|
} else {
|
||||||
@@ -321,7 +341,7 @@ export default class ComparisonPage extends Page {
|
|||||||
let { newName, builds, facets } = this.state;
|
let { newName, builds, facets } = this.state;
|
||||||
let selectedFacets = [];
|
let selectedFacets = [];
|
||||||
|
|
||||||
facets.forEach((f) => {
|
facets.forEach(f => {
|
||||||
if (f.active) {
|
if (f.active) {
|
||||||
selectedFacets.unshift(f.i);
|
selectedFacets.unshift(f.i);
|
||||||
}
|
}
|
||||||
@@ -348,14 +368,20 @@ export default class ComparisonPage extends Page {
|
|||||||
|
|
||||||
let code = fromComparison(name, builds, selectedFacets, predicate, desc);
|
let code = fromComparison(name, builds, selectedFacets, predicate, desc);
|
||||||
let loc = window.location;
|
let loc = window.location;
|
||||||
return loc.protocol + '//' + loc.host + '/comparison?code=' + encodeURIComponent(code);
|
return (
|
||||||
|
loc.protocol +
|
||||||
|
'//' +
|
||||||
|
loc.host +
|
||||||
|
'/comparison?code=' +
|
||||||
|
encodeURIComponent(code)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the long permalink URL
|
* Generates the long permalink URL
|
||||||
*/
|
*/
|
||||||
_genPermalink() {
|
_genPermalink() {
|
||||||
this.context.showModal(<ModalPermalink url={this._buildUrl()}/>);
|
this.context.showModal(<ModalPermalink url={this._buildUrl()} />);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -365,18 +391,25 @@ export default class ComparisonPage extends Page {
|
|||||||
let { translate, formats } = this.context.language;
|
let { translate, formats } = this.context.language;
|
||||||
let { facets, builds } = this.state;
|
let { facets, builds } = this.state;
|
||||||
|
|
||||||
let generator = (callback) => {
|
let generator = callback => {
|
||||||
let url = this._buildUrl();
|
let url = this._buildUrl();
|
||||||
ShortenUrl(url,
|
ShortenUrl(
|
||||||
(shortenedUrl) => callback(comparisonBBCode(translate, formats, facets, builds, shortenedUrl)),
|
url,
|
||||||
(error) => callback(comparisonBBCode(translate, formats, facets, builds, url))
|
shortenedUrl =>
|
||||||
|
callback(
|
||||||
|
comparisonBBCode(translate, formats, facets, builds, shortenedUrl)
|
||||||
|
),
|
||||||
|
error =>
|
||||||
|
callback(comparisonBBCode(translate, formats, facets, builds, url))
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.context.showModal(<ModalExport
|
this.context.showModal(
|
||||||
title={translate('forum') + ' BBCode'}
|
<ModalExport
|
||||||
generator={generator}
|
title={translate('forum') + ' BBCode'}
|
||||||
/>);
|
generator={generator}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -409,7 +442,8 @@ export default class ComparisonPage extends Page {
|
|||||||
* @param {Object} nextContext Incoming/Next conext
|
* @param {Object} nextContext Incoming/Next conext
|
||||||
*/
|
*/
|
||||||
componentWillReceiveProps(nextProps, nextContext) {
|
componentWillReceiveProps(nextProps, nextContext) {
|
||||||
if (this.context.route !== nextContext.route) { // Only reinit state if the route has changed
|
if (this.context.route !== nextContext.route) {
|
||||||
|
// Only reinit state if the route has changed
|
||||||
this.setState(this._initState(nextContext));
|
this.setState(this._initState(nextContext));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -419,7 +453,10 @@ export default class ComparisonPage extends Page {
|
|||||||
*/
|
*/
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
this.resizeListener = this.context.onWindowResize(this._updateDimensions);
|
this.resizeListener = this.context.onWindowResize(this._updateDimensions);
|
||||||
this.persistListener = Persist.addListener('discounts', this._updateDiscounts);
|
this.persistListener = Persist.addListener(
|
||||||
|
'discounts',
|
||||||
|
this._updateDiscounts
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -444,65 +481,132 @@ export default class ComparisonPage extends Page {
|
|||||||
renderPage() {
|
renderPage() {
|
||||||
let translate = this.context.language.translate;
|
let translate = this.context.language.translate;
|
||||||
let compareHeader;
|
let compareHeader;
|
||||||
let { newName, name, saved, builds, facets, predicate, desc, chartWidth } = this.state;
|
let {
|
||||||
|
newName,
|
||||||
|
name,
|
||||||
|
saved,
|
||||||
|
builds,
|
||||||
|
facets,
|
||||||
|
predicate,
|
||||||
|
desc,
|
||||||
|
chartWidth
|
||||||
|
} = this.state;
|
||||||
|
|
||||||
if (this.state.compareMode) {
|
if (this.state.compareMode) {
|
||||||
compareHeader = <tr>
|
compareHeader = (
|
||||||
<td className='head'>{translate('comparison')}</td>
|
<tr>
|
||||||
<td>
|
<td className="head">{translate('comparison')}</td>
|
||||||
<input value={newName} onChange={this._onNameChange} placeholder={translate('Enter Name')} maxLength='50' />
|
<td>
|
||||||
<button onClick={this._save} disabled={!newName || newName == 'all' || saved}>
|
<input
|
||||||
<FloppyDisk className='lg'/><span className='button-lbl'>{translate('save')}</span>
|
value={newName}
|
||||||
</button>
|
onChange={this._onNameChange}
|
||||||
<button onClick={this._delete} disabled={name == 'all' || !saved}><Bin className='lg warning'/></button>
|
placeholder={translate('Enter Name')}
|
||||||
<button onClick={this._selectBuilds}>
|
maxLength="50"
|
||||||
<Rocket className='lg'/><span className='button-lbl'>{translate('builds')}</span>
|
/>
|
||||||
</button>
|
<button
|
||||||
<button className='r' onClick={this._genPermalink} disabled={builds.length == 0}>
|
onClick={this._save}
|
||||||
<LinkIcon className='lg'/><span className='button-lbl'>{translate('permalink')}</span>
|
disabled={!newName || newName == 'all' || saved}
|
||||||
</button>
|
>
|
||||||
<button className='r' onClick={this._genBBcode} disabled={builds.length == 0}>
|
<FloppyDisk className="lg" />
|
||||||
<Embed className='lg'/><span className='button-lbl'>{translate('forum')}</span>
|
<span className="button-lbl">{translate('save')}</span>
|
||||||
</button>
|
</button>
|
||||||
</td>
|
<button onClick={this._delete} disabled={name == 'all' || !saved}>
|
||||||
</tr>;
|
<Bin className="lg warning" />
|
||||||
|
</button>
|
||||||
|
<button onClick={this._selectBuilds}>
|
||||||
|
<Rocket className="lg" />
|
||||||
|
<span className="button-lbl">{translate('builds')}</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="r"
|
||||||
|
onClick={this._genPermalink}
|
||||||
|
disabled={builds.length == 0}
|
||||||
|
>
|
||||||
|
<LinkIcon className="lg" />
|
||||||
|
<span className="button-lbl">{translate('permalink')}</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="r"
|
||||||
|
onClick={this._genBBcode}
|
||||||
|
disabled={builds.length == 0}
|
||||||
|
>
|
||||||
|
<Embed className="lg" />
|
||||||
|
<span className="button-lbl">{translate('forum')}</span>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
compareHeader = <tr>
|
compareHeader = (
|
||||||
<td className='head'>{translate('comparison')}</td>
|
<tr>
|
||||||
<td>
|
<td className="head">{translate('comparison')}</td>
|
||||||
<h3>{name}</h3>
|
<td>
|
||||||
<button className='r' onClick={this._import}><Download className='lg'/>{translate('import')}</button>
|
<h3>{name}</h3>
|
||||||
</td>
|
<button className="r" onClick={this._import}>
|
||||||
</tr>;
|
<Download className="lg" />
|
||||||
|
{translate('import')}
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'page'} style={{ fontSize: this.context.sizeRatio + 'em' }}>
|
<div
|
||||||
<table id='comparison'>
|
className={'page'}
|
||||||
|
style={{ fontSize: this.context.sizeRatio + 'em' }}
|
||||||
|
>
|
||||||
|
<table id="comparison">
|
||||||
<tbody>
|
<tbody>
|
||||||
{compareHeader}
|
{compareHeader}
|
||||||
<tr key='facets'>
|
<tr key="facets">
|
||||||
<td className='head'>{translate('compare')}</td>
|
<td className="head">{translate('compare')}</td>
|
||||||
<td>
|
<td>
|
||||||
<ul id='facet-container' onDragOver={this._facetDragOver}>
|
<ul id="facet-container" onDragOver={this._facetDragOver}>
|
||||||
{facets.map((f, i) =>
|
{facets.map((f, i) => (
|
||||||
<li key={f.title} data-i={i} draggable='true' onDragStart={this._facetDrag} onDragEnd={this._facetDrop} className={cn('facet', { active: f.active })} onClick={this._toggleFacet.bind(this, f)}>
|
<li
|
||||||
|
key={f.title}
|
||||||
|
data-i={i}
|
||||||
|
draggable="true"
|
||||||
|
onDragStart={this._facetDrag}
|
||||||
|
onDragEnd={this._facetDrop}
|
||||||
|
className={cn('facet', { active: f.active })}
|
||||||
|
onClick={this._toggleFacet.bind(this, f)}
|
||||||
|
>
|
||||||
{'↔ ' + translate(f.title)}
|
{'↔ ' + translate(f.title)}
|
||||||
</li>
|
</li>
|
||||||
)}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<ComparisonTable builds={builds} facets={facets} onSort={this._sortShips} predicate={predicate} desc={desc} />
|
<ComparisonTable
|
||||||
|
builds={builds}
|
||||||
|
facets={facets}
|
||||||
|
onSort={this._sortShips}
|
||||||
|
predicate={predicate}
|
||||||
|
desc={desc}
|
||||||
|
/>
|
||||||
|
|
||||||
{!builds.length ?
|
{!builds.length ? (
|
||||||
<div className='chart' ref={node => this.chartRef = node}>{translate('PHRASE_NO_BUILDS')}</div> :
|
<div className="chart" ref={node => (this.chartRef = node)}>
|
||||||
facets.filter((f) => f.active).map((f, i) =>
|
{translate('PHRASE_NO_BUILDS')}
|
||||||
<div key={f.title} className='chart' ref={ i == 0 ? node => this.chartRef = node : null}>
|
</div>
|
||||||
<h3 className='ptr' onClick={this._sortShips.bind(this, f.props[0])}>{translate(f.title)}</h3>
|
) : (
|
||||||
|
facets.filter(f => f.active).map((f, i) => (
|
||||||
|
<div
|
||||||
|
key={f.title}
|
||||||
|
className="chart"
|
||||||
|
ref={i == 0 ? node => (this.chartRef = node) : null}
|
||||||
|
>
|
||||||
|
<h3
|
||||||
|
className="ptr"
|
||||||
|
onClick={this._sortShips.bind(this, f.props[0])}
|
||||||
|
>
|
||||||
|
{translate(f.title)}
|
||||||
|
</h3>
|
||||||
<BarChart
|
<BarChart
|
||||||
width={chartWidth}
|
width={chartWidth}
|
||||||
data={builds}
|
data={builds}
|
||||||
@@ -515,8 +619,8 @@ export default class ComparisonPage extends Page {
|
|||||||
desc={desc}
|
desc={desc}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
))
|
||||||
)}
|
)}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import Page from './Page';
|
|||||||
* 404 Page
|
* 404 Page
|
||||||
*/
|
*/
|
||||||
export default class NotFoundPage extends Page {
|
export default class NotFoundPage extends Page {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
@@ -22,6 +21,10 @@ export default class NotFoundPage extends Page {
|
|||||||
* @return {React.Component} The page contents
|
* @return {React.Component} The page contents
|
||||||
*/
|
*/
|
||||||
renderPage() {
|
renderPage() {
|
||||||
return <div className='page' style={{ marginTop: 30 }}>Page <small>{this.context.route.path}</small> Not Found</div>;
|
return (
|
||||||
|
<div className="page" style={{ marginTop: 30 }}>
|
||||||
|
Page <small>{this.context.route.path}</small> Not Found
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ function getTitle(shipName, buildName) {
|
|||||||
* The Outfitting Page
|
* The Outfitting Page
|
||||||
*/
|
*/
|
||||||
export default class OutfittingPage extends Page {
|
export default class OutfittingPage extends Page {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param {Object} props React Component properties
|
* @param {Object} props React Component properties
|
||||||
@@ -85,22 +84,38 @@ export default class OutfittingPage extends Page {
|
|||||||
let shipId = params.ship;
|
let shipId = params.ship;
|
||||||
let code = params.code;
|
let code = params.code;
|
||||||
let buildName = params.bn;
|
let buildName = params.bn;
|
||||||
let data = Ships[shipId]; // Retrieve the basic ship properties, slots and defaults
|
let data = Ships[shipId]; // Retrieve the basic ship properties, slots and defaults
|
||||||
let savedCode = Persist.getBuild(shipId, buildName);
|
let savedCode = Persist.getBuild(shipId, buildName);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return { error: { message: 'Ship not found: ' + shipId } };
|
return { error: { message: 'Ship not found: ' + shipId } };
|
||||||
}
|
}
|
||||||
let ship = new Ship(shipId, data.properties, data.slots); // Create a new Ship instance
|
let ship = new Ship(shipId, data.properties, data.slots); // Create a new Ship instance
|
||||||
if (code) {
|
if (code) {
|
||||||
ship.buildFrom(code); // Populate modules from serialized 'code' URL param
|
ship.buildFrom(code); // Populate modules from serialized 'code' URL param
|
||||||
} else {
|
} else {
|
||||||
ship.buildWith(data.defaults); // Populate with default components
|
ship.buildWith(data.defaults); // Populate with default components
|
||||||
}
|
}
|
||||||
|
|
||||||
this._getTitle = getTitle.bind(this, data.properties.name);
|
this._getTitle = getTitle.bind(this, data.properties.name);
|
||||||
|
|
||||||
// Obtain ship control from code
|
// Obtain ship control from code
|
||||||
const { sys, eng, wep, boost, fuel, cargo, opponent, opponentBuild, opponentSys, opponentEng, opponentWep, engagementRange } = this._obtainControlFromCode(ship, code);
|
const {
|
||||||
|
sys,
|
||||||
|
eng,
|
||||||
|
wep,
|
||||||
|
mcSys,
|
||||||
|
mcEng,
|
||||||
|
mcWep,
|
||||||
|
boost,
|
||||||
|
fuel,
|
||||||
|
cargo,
|
||||||
|
opponent,
|
||||||
|
opponentBuild,
|
||||||
|
opponentSys,
|
||||||
|
opponentEng,
|
||||||
|
opponentWep,
|
||||||
|
engagementRange
|
||||||
|
} = this._obtainControlFromCode(ship, code);
|
||||||
return {
|
return {
|
||||||
error: null,
|
error: null,
|
||||||
title: this._getTitle(buildName),
|
title: this._getTitle(buildName),
|
||||||
@@ -114,6 +129,9 @@ export default class OutfittingPage extends Page {
|
|||||||
sys,
|
sys,
|
||||||
eng,
|
eng,
|
||||||
wep,
|
wep,
|
||||||
|
mcSys,
|
||||||
|
mcEng,
|
||||||
|
mcWep,
|
||||||
boost,
|
boost,
|
||||||
fuel,
|
fuel,
|
||||||
cargo,
|
cargo,
|
||||||
@@ -136,7 +154,10 @@ export default class OutfittingPage extends Page {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (Persist.hasBuild(this.state.shipId, stateChanges.newBuildName)) {
|
if (Persist.hasBuild(this.state.shipId, stateChanges.newBuildName)) {
|
||||||
stateChanges.savedCode = Persist.getBuild(this.state.shipId, stateChanges.newBuildName);
|
stateChanges.savedCode = Persist.getBuild(
|
||||||
|
this.state.shipId,
|
||||||
|
stateChanges.newBuildName
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
stateChanges.savedCode = null;
|
stateChanges.savedCode = null;
|
||||||
}
|
}
|
||||||
@@ -162,7 +183,9 @@ export default class OutfittingPage extends Page {
|
|||||||
* @returns {string} the code for this ship
|
* @returns {string} the code for this ship
|
||||||
*/
|
*/
|
||||||
_fullCode(ship, fuel, cargo) {
|
_fullCode(ship, fuel, cargo) {
|
||||||
return `${ship.toString()}.${LZString.compressToBase64(this._controlCode(fuel, cargo))}`;
|
return `${ship.toString()}.${LZString.compressToBase64(
|
||||||
|
this._controlCode(fuel, cargo)
|
||||||
|
)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -176,10 +199,17 @@ export default class OutfittingPage extends Page {
|
|||||||
let sys = 2;
|
let sys = 2;
|
||||||
let eng = 2;
|
let eng = 2;
|
||||||
let wep = 2;
|
let wep = 2;
|
||||||
|
let mcSys = 0;
|
||||||
|
let mcEng = 0;
|
||||||
|
let mcWep = 0;
|
||||||
let boost = false;
|
let boost = false;
|
||||||
let fuel = ship.fuelCapacity;
|
let fuel = ship.fuelCapacity;
|
||||||
let cargo = ship.cargoCapacity;
|
let cargo = ship.cargoCapacity;
|
||||||
let opponent = new Ship('eagle', Ships['eagle'].properties, Ships['eagle'].slots).buildWith(Ships['eagle'].defaults);
|
let opponent = new Ship(
|
||||||
|
'eagle',
|
||||||
|
Ships['eagle'].properties,
|
||||||
|
Ships['eagle'].slots
|
||||||
|
).buildWith(Ships['eagle'].defaults);
|
||||||
let opponentSys = 2;
|
let opponentSys = 2;
|
||||||
let opponentEng = 2;
|
let opponentEng = 2;
|
||||||
let opponentWep = 2;
|
let opponentWep = 2;
|
||||||
@@ -191,16 +221,25 @@ export default class OutfittingPage extends Page {
|
|||||||
const parts = code.split('.');
|
const parts = code.split('.');
|
||||||
if (parts.length >= 5) {
|
if (parts.length >= 5) {
|
||||||
// We have control information in the code
|
// We have control information in the code
|
||||||
const control = LZString.decompressFromBase64(Utils.fromUrlSafe(parts[4])).split('/');
|
const control = LZString.decompressFromBase64(
|
||||||
|
Utils.fromUrlSafe(parts[4])
|
||||||
|
).split('/');
|
||||||
sys = parseFloat(control[0]);
|
sys = parseFloat(control[0]);
|
||||||
eng = parseFloat(control[1]);
|
eng = parseFloat(control[1]);
|
||||||
wep = parseFloat(control[2]);
|
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 = parseFloat(control[4]) || fuel;
|
||||||
cargo = parseInt(control[5]);
|
cargo = parseInt(control[5]) || cargo;
|
||||||
if (control[6]) {
|
if (control[6]) {
|
||||||
const shipId = control[6];
|
const shipId = control[6];
|
||||||
opponent = new Ship(shipId, Ships[shipId].properties, Ships[shipId].slots);
|
opponent = new Ship(
|
||||||
|
shipId,
|
||||||
|
Ships[shipId].properties,
|
||||||
|
Ships[shipId].slots
|
||||||
|
);
|
||||||
if (control[7] && Persist.getBuild(shipId, control[7])) {
|
if (control[7] && Persist.getBuild(shipId, control[7])) {
|
||||||
// Ship is a particular build
|
// Ship is a particular build
|
||||||
const opponentCode = Persist.getBuild(shipId, control[7]);
|
const opponentCode = Persist.getBuild(shipId, control[7]);
|
||||||
@@ -210,10 +249,12 @@ export default class OutfittingPage extends Page {
|
|||||||
// Obtain opponent's sys/eng/wep pips from their code
|
// Obtain opponent's sys/eng/wep pips from their code
|
||||||
const opponentParts = opponentCode.split('.');
|
const opponentParts = opponentCode.split('.');
|
||||||
if (opponentParts.length >= 5) {
|
if (opponentParts.length >= 5) {
|
||||||
const opponentControl = LZString.decompressFromBase64(Utils.fromUrlSafe(opponentParts[4])).split('/');
|
const opponentControl = LZString.decompressFromBase64(
|
||||||
opponentSys = parseFloat(opponentControl[0]);
|
Utils.fromUrlSafe(opponentParts[4])
|
||||||
opponentEng = parseFloat(opponentControl[1]);
|
).split('/');
|
||||||
opponentWep = parseFloat(opponentControl[2]);
|
opponentSys = parseFloat(opponentControl[0]) || opponentSys;
|
||||||
|
opponentEng = parseFloat(opponentControl[1]) || opponentEng;
|
||||||
|
opponentWep = parseFloat(opponentControl[2]) || opponentWep;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -221,21 +262,50 @@ export default class OutfittingPage extends Page {
|
|||||||
opponent.buildWith(Ships[shipId].defaults);
|
opponent.buildWith(Ships[shipId].defaults);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
engagementRange = parseInt(control[8]);
|
engagementRange = parseInt(control[8]) || engagementRange;
|
||||||
|
|
||||||
|
// Multi-crew pips were introduced later on so assign default values
|
||||||
|
// because those values might not be present.
|
||||||
|
mcSys = parseInt(control[9]) || mcSys;
|
||||||
|
mcEng = parseInt(control[10]) || mcEng;
|
||||||
|
mcWep = parseInt(control[11]) || mcWep;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { sys, eng, wep, boost, fuel, cargo, opponent, opponentBuild, opponentSys, opponentEng, opponentWep, engagementRange };
|
return {
|
||||||
|
sys,
|
||||||
|
eng,
|
||||||
|
wep,
|
||||||
|
mcSys,
|
||||||
|
mcEng,
|
||||||
|
mcWep,
|
||||||
|
boost,
|
||||||
|
fuel,
|
||||||
|
cargo,
|
||||||
|
opponent,
|
||||||
|
opponentBuild,
|
||||||
|
opponentSys,
|
||||||
|
opponentEng,
|
||||||
|
opponentWep,
|
||||||
|
engagementRange
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Triggered when pips have been updated
|
* Triggered when pips have been updated. Multi-crew pips are already included
|
||||||
|
* in sys, eng and wep but mcSys, mcEng and mcWep make clear where each pip
|
||||||
|
* comes from.
|
||||||
* @param {number} sys SYS pips
|
* @param {number} sys SYS pips
|
||||||
* @param {number} eng ENG pips
|
* @param {number} eng ENG pips
|
||||||
* @param {number} wep WEP pips
|
* @param {number} wep WEP pips
|
||||||
|
* @param {number} mcSys SYS pips from multi-crew
|
||||||
|
* @param {number} mcEng ENG pips from multi-crew
|
||||||
|
* @param {number} mcWep WEP pips from multi-crew
|
||||||
*/
|
*/
|
||||||
_pipsUpdated(sys, eng, wep) {
|
_pipsUpdated(sys, eng, wep, mcSys, mcEng, mcWep) {
|
||||||
this.setState({ sys, eng, wep }, () => this._updateRouteOnControlChange());
|
this.setState({ sys, eng, wep, mcSys, mcEng, mcWep }, () =>
|
||||||
|
this._updateRouteOnControlChange()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -243,7 +313,7 @@ export default class OutfittingPage extends Page {
|
|||||||
* @param {boolean} boost true if boosting
|
* @param {boolean} boost true if boosting
|
||||||
*/
|
*/
|
||||||
_boostUpdated(boost) {
|
_boostUpdated(boost) {
|
||||||
this.setState({ boost }, () => this._updateRouteOnControlChange());
|
this.setState({ boost }, () => this._updateRouteOnControlChange());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -251,7 +321,7 @@ export default class OutfittingPage extends Page {
|
|||||||
* @param {number} fuel the amount of fuel, in T
|
* @param {number} fuel the amount of fuel, in T
|
||||||
*/
|
*/
|
||||||
_fuelUpdated(fuel) {
|
_fuelUpdated(fuel) {
|
||||||
this.setState({ fuel }, () => this._updateRouteOnControlChange());
|
this.setState({ fuel }, () => this._updateRouteOnControlChange());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -259,7 +329,7 @@ export default class OutfittingPage extends Page {
|
|||||||
* @param {number} cargo the amount of cargo, in T
|
* @param {number} cargo the amount of cargo, in T
|
||||||
*/
|
*/
|
||||||
_cargoUpdated(cargo) {
|
_cargoUpdated(cargo) {
|
||||||
this.setState({ cargo }, () => this._updateRouteOnControlChange());
|
this.setState({ cargo }, () => this._updateRouteOnControlChange());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -267,7 +337,9 @@ export default class OutfittingPage extends Page {
|
|||||||
* @param {number} engagementRange the engagement range, in m
|
* @param {number} engagementRange the engagement range, in m
|
||||||
*/
|
*/
|
||||||
_engagementRangeUpdated(engagementRange) {
|
_engagementRangeUpdated(engagementRange) {
|
||||||
this.setState({ engagementRange }, () => this._updateRouteOnControlChange());
|
this.setState({ engagementRange }, () =>
|
||||||
|
this._updateRouteOnControlChange()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -276,7 +348,11 @@ export default class OutfittingPage extends Page {
|
|||||||
* @param {string} opponentBuild the name of the opponent's build
|
* @param {string} opponentBuild the name of the opponent's build
|
||||||
*/
|
*/
|
||||||
_opponentUpdated(opponent, opponentBuild) {
|
_opponentUpdated(opponent, opponentBuild) {
|
||||||
const opponentShip = new Ship(opponent, Ships[opponent].properties, Ships[opponent].slots);
|
const opponentShip = new Ship(
|
||||||
|
opponent,
|
||||||
|
Ships[opponent].properties,
|
||||||
|
Ships[opponent].slots
|
||||||
|
);
|
||||||
let opponentSys = this.state.opponentSys;
|
let opponentSys = this.state.opponentSys;
|
||||||
let opponentEng = this.state.opponentEng;
|
let opponentEng = this.state.opponentEng;
|
||||||
let opponentWep = this.state.opponentWep;
|
let opponentWep = this.state.opponentWep;
|
||||||
@@ -284,9 +360,13 @@ export default class OutfittingPage extends Page {
|
|||||||
// Ship is a particular build
|
// Ship is a particular build
|
||||||
opponentShip.buildFrom(Persist.getBuild(opponent, opponentBuild));
|
opponentShip.buildFrom(Persist.getBuild(opponent, opponentBuild));
|
||||||
// Set pips for opponent
|
// Set pips for opponent
|
||||||
const opponentParts = Persist.getBuild(opponent, opponentBuild).split('.');
|
const opponentParts = Persist.getBuild(opponent, opponentBuild).split(
|
||||||
|
'.'
|
||||||
|
);
|
||||||
if (opponentParts.length >= 5) {
|
if (opponentParts.length >= 5) {
|
||||||
const opponentControl = LZString.decompressFromBase64(Utils.fromUrlSafe(opponentParts[4])).split('/');
|
const opponentControl = LZString.decompressFromBase64(
|
||||||
|
Utils.fromUrlSafe(opponentParts[4])
|
||||||
|
).split('/');
|
||||||
opponentSys = parseFloat(opponentControl[0]);
|
opponentSys = parseFloat(opponentControl[0]);
|
||||||
opponentEng = parseFloat(opponentControl[1]);
|
opponentEng = parseFloat(opponentControl[1]);
|
||||||
opponentWep = parseFloat(opponentControl[2]);
|
opponentWep = parseFloat(opponentControl[2]);
|
||||||
@@ -299,7 +379,16 @@ export default class OutfittingPage extends Page {
|
|||||||
opponentWep = 2;
|
opponentWep = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({ opponent: opponentShip, opponentBuild, opponentSys, opponentEng, opponentWep }, () => this._updateRouteOnControlChange());
|
this.setState(
|
||||||
|
{
|
||||||
|
opponent: opponentShip,
|
||||||
|
opponentBuild,
|
||||||
|
opponentSys,
|
||||||
|
opponentEng,
|
||||||
|
opponentWep
|
||||||
|
},
|
||||||
|
() => this._updateRouteOnControlChange()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -309,8 +398,22 @@ export default class OutfittingPage extends Page {
|
|||||||
* @returns {string} The control code
|
* @returns {string} The control code
|
||||||
*/
|
*/
|
||||||
_controlCode(fuel, cargo) {
|
_controlCode(fuel, cargo) {
|
||||||
const { sys, eng, wep, boost, opponent, opponentBuild, engagementRange } = this.state;
|
const {
|
||||||
const code = `${sys}/${eng}/${wep}/${boost ? 1 : 0}/${fuel || this.state.fuel}/${cargo || this.state.cargo}/${opponent.id}/${opponentBuild ? opponentBuild : ''}/${engagementRange}`;
|
sys,
|
||||||
|
eng,
|
||||||
|
wep,
|
||||||
|
mcSys,
|
||||||
|
mcEng,
|
||||||
|
mcWep,
|
||||||
|
boost,
|
||||||
|
opponent,
|
||||||
|
opponentBuild,
|
||||||
|
engagementRange
|
||||||
|
} = this.state;
|
||||||
|
const code = `${sys}/${eng}/${wep}/${boost ? 1 : 0}/${fuel ||
|
||||||
|
this.state.fuel}/${cargo || this.state.cargo}/${opponent.id}/${
|
||||||
|
opponentBuild ? opponentBuild : ''
|
||||||
|
}/${engagementRange}/${mcSys}/${mcEng}/${mcWep}`;
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,27 +424,44 @@ export default class OutfittingPage extends Page {
|
|||||||
const { ship, buildName, newBuildName, shipId } = this.state;
|
const { ship, buildName, newBuildName, shipId } = this.state;
|
||||||
|
|
||||||
// If this is a stock ship the code won't be set, so ensure that we have it
|
// If this is a stock ship the code won't be set, so ensure that we have it
|
||||||
const code = this.state.code || ship.toString();
|
const code = this.state.code || ship.toString();
|
||||||
|
|
||||||
Persist.saveBuild(shipId, newBuildName, code);
|
Persist.saveBuild(shipId, newBuildName, code);
|
||||||
this._updateRoute(shipId, newBuildName, code);
|
this._updateRoute(shipId, newBuildName, code);
|
||||||
|
|
||||||
let opponent, opponentBuild, opponentSys, opponentEng, opponentWep;
|
let opponent, opponentBuild, opponentSys, opponentEng, opponentWep;
|
||||||
if (shipId === this.state.opponent.id && buildName === this.state.opponentBuild) {
|
if (
|
||||||
|
shipId === this.state.opponent.id &&
|
||||||
|
buildName === this.state.opponentBuild
|
||||||
|
) {
|
||||||
// This is a save of our current opponent build; update it
|
// This is a save of our current opponent build; update it
|
||||||
opponentBuild = newBuildName;
|
opponentBuild = newBuildName;
|
||||||
opponent = new Ship(shipId, Ships[shipId].properties, Ships[shipId].slots).buildFrom(code);
|
opponent = new Ship(
|
||||||
|
shipId,
|
||||||
|
Ships[shipId].properties,
|
||||||
|
Ships[shipId].slots
|
||||||
|
).buildFrom(code);
|
||||||
opponentSys = this.state.sys;
|
opponentSys = this.state.sys;
|
||||||
opponentEng = this.state.eng;
|
opponentEng = this.state.eng;
|
||||||
opponentWep = this.state.wep;
|
opponentWep = this.state.wep;
|
||||||
} else {
|
} else {
|
||||||
opponentBuild = this.state.opponentBuild;
|
opponentBuild = this.state.opponentBuild;
|
||||||
opponent = this.state.opponent;
|
opponent = this.state.opponent;
|
||||||
opponentSys = this.state.opponentSys;
|
opponentSys = this.state.opponentSys;
|
||||||
opponentEng = this.state.opponentEng;
|
opponentEng = this.state.opponentEng;
|
||||||
opponentWep = this.state.opponentWep;
|
opponentWep = this.state.opponentWep;
|
||||||
}
|
}
|
||||||
this.setState({ buildName: newBuildName, code, savedCode: code, opponent, opponentBuild, opponentSys, opponentEng, opponentWep, title: this._getTitle(newBuildName) });
|
this.setState({
|
||||||
|
buildName: newBuildName,
|
||||||
|
code,
|
||||||
|
savedCode: code,
|
||||||
|
opponent,
|
||||||
|
opponentBuild,
|
||||||
|
opponentSys,
|
||||||
|
opponentEng,
|
||||||
|
opponentWep,
|
||||||
|
title: this._getTitle(newBuildName)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -353,7 +473,12 @@ export default class OutfittingPage extends Page {
|
|||||||
Persist.deleteBuild(shipId, buildName);
|
Persist.deleteBuild(shipId, buildName);
|
||||||
Persist.saveBuild(shipId, newBuildName, code);
|
Persist.saveBuild(shipId, newBuildName, code);
|
||||||
this._updateRoute(shipId, newBuildName, code);
|
this._updateRoute(shipId, newBuildName, code);
|
||||||
this.setState({ buildName: newBuildName, code, savedCode: code, opponentBuild: newBuildName });
|
this.setState({
|
||||||
|
buildName: newBuildName,
|
||||||
|
code,
|
||||||
|
savedCode: code,
|
||||||
|
opponentBuild: newBuildName
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,19 +498,38 @@ export default class OutfittingPage extends Page {
|
|||||||
ship.buildWith(Ships[shipId].defaults);
|
ship.buildWith(Ships[shipId].defaults);
|
||||||
// Reset controls
|
// Reset controls
|
||||||
const code = ship.toString();
|
const code = ship.toString();
|
||||||
const { sys, eng, wep, boost, fuel, cargo, opponent, opponentBuild, engagementRange } = this._obtainControlFromCode(ship, code);
|
const {
|
||||||
// Update state, and refresh the ship
|
|
||||||
this.setState({
|
|
||||||
sys,
|
sys,
|
||||||
eng,
|
eng,
|
||||||
wep,
|
wep,
|
||||||
|
mcSys,
|
||||||
|
mcEng,
|
||||||
|
mcWep,
|
||||||
boost,
|
boost,
|
||||||
fuel,
|
fuel,
|
||||||
cargo,
|
cargo,
|
||||||
opponent,
|
opponent,
|
||||||
opponentBuild,
|
opponentBuild,
|
||||||
engagementRange
|
engagementRange
|
||||||
}, () => this._updateRoute(shipId, buildName, code));
|
} = this._obtainControlFromCode(ship, code);
|
||||||
|
// Update state, and refresh the ship
|
||||||
|
this.setState(
|
||||||
|
{
|
||||||
|
sys,
|
||||||
|
eng,
|
||||||
|
wep,
|
||||||
|
mcSys,
|
||||||
|
mcEng,
|
||||||
|
mcWep,
|
||||||
|
boost,
|
||||||
|
fuel,
|
||||||
|
cargo,
|
||||||
|
opponent,
|
||||||
|
opponentBuild,
|
||||||
|
engagementRange
|
||||||
|
},
|
||||||
|
() => this._updateRoute(shipId, buildName, code)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -396,7 +540,10 @@ export default class OutfittingPage extends Page {
|
|||||||
Persist.deleteBuild(shipId, buildName);
|
Persist.deleteBuild(shipId, buildName);
|
||||||
|
|
||||||
let opponentBuild;
|
let opponentBuild;
|
||||||
if (shipId === this.state.opponent.id && buildName === this.state.opponentBuild) {
|
if (
|
||||||
|
shipId === this.state.opponent.id &&
|
||||||
|
buildName === this.state.opponentBuild
|
||||||
|
) {
|
||||||
// Our current opponent has been deleted; revert to stock
|
// Our current opponent has been deleted; revert to stock
|
||||||
opponentBuild = null;
|
opponentBuild = null;
|
||||||
} else {
|
} else {
|
||||||
@@ -413,11 +560,13 @@ export default class OutfittingPage extends Page {
|
|||||||
_exportBuild() {
|
_exportBuild() {
|
||||||
let translate = this.context.language.translate;
|
let translate = this.context.language.translate;
|
||||||
let { buildName, ship } = this.state;
|
let { buildName, ship } = this.state;
|
||||||
this.context.showModal(<ModalExport
|
this.context.showModal(
|
||||||
title={(buildName || ship.name) + ' ' + translate('export')}
|
<ModalExport
|
||||||
description={translate('PHRASE_EXPORT_DESC')}
|
title={(buildName || ship.name) + ' ' + translate('export')}
|
||||||
data={toDetailedBuild(buildName, ship, ship.toString())}
|
description={translate('PHRASE_EXPORT_DESC')}
|
||||||
/>);
|
data={toDetailedBuild(buildName, ship, ship.toString())}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -430,19 +579,38 @@ export default class OutfittingPage extends Page {
|
|||||||
this.state.ship.buildFrom(code);
|
this.state.ship.buildFrom(code);
|
||||||
|
|
||||||
// Obtain controls from the code
|
// Obtain controls from the code
|
||||||
const { sys, eng, wep, boost, fuel, cargo, opponent, opponentBuild, engagementRange } = this._obtainControlFromCode(ship, code);
|
const {
|
||||||
// Update state, and refresh the route when complete
|
|
||||||
this.setState({
|
|
||||||
sys,
|
sys,
|
||||||
eng,
|
eng,
|
||||||
wep,
|
wep,
|
||||||
|
mcSys,
|
||||||
|
mcEng,
|
||||||
|
mcWep,
|
||||||
boost,
|
boost,
|
||||||
fuel,
|
fuel,
|
||||||
cargo,
|
cargo,
|
||||||
opponent,
|
opponent,
|
||||||
opponentBuild,
|
opponentBuild,
|
||||||
engagementRange
|
engagementRange
|
||||||
}, () => this._updateRoute(shipId, buildName, code));
|
} = this._obtainControlFromCode(ship, code);
|
||||||
|
// Update state, and refresh the route when complete
|
||||||
|
this.setState(
|
||||||
|
{
|
||||||
|
sys,
|
||||||
|
eng,
|
||||||
|
wep,
|
||||||
|
mcSys,
|
||||||
|
mcEng,
|
||||||
|
mcWep,
|
||||||
|
boost,
|
||||||
|
fuel,
|
||||||
|
cargo,
|
||||||
|
opponent,
|
||||||
|
opponentBuild,
|
||||||
|
engagementRange
|
||||||
|
},
|
||||||
|
() => this._updateRoute(shipId, buildName, code)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -458,8 +626,14 @@ export default class OutfittingPage extends Page {
|
|||||||
}
|
}
|
||||||
const code = this._fullCode(ship, fuel, cargo);
|
const code = this._fullCode(ship, fuel, cargo);
|
||||||
// Only update the state if this really has been updated
|
// Only update the state if this really has been updated
|
||||||
if (this.state.code != code || this.state.cargo != cargo || this.state.fuel != fuel) {
|
if (
|
||||||
this.setState({ code, cargo, fuel }, () => this._updateRoute(shipId, buildName, code));
|
this.state.code != code ||
|
||||||
|
this.state.cargo != cargo ||
|
||||||
|
this.state.fuel != fuel
|
||||||
|
) {
|
||||||
|
this.setState({ code, cargo, fuel }, () =>
|
||||||
|
this._updateRoute(shipId, buildName, code)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -479,7 +653,8 @@ export default class OutfittingPage extends Page {
|
|||||||
* @param {Object} nextContext Incoming/Next conext
|
* @param {Object} nextContext Incoming/Next conext
|
||||||
*/
|
*/
|
||||||
componentWillReceiveProps(nextProps, nextContext) {
|
componentWillReceiveProps(nextProps, nextContext) {
|
||||||
if (this.context.route !== nextContext.route) { // Only reinit state if the route has changed
|
if (this.context.route !== nextContext.route) {
|
||||||
|
// Only reinit state if the route has changed
|
||||||
this.setState(this._initState(nextProps, nextContext));
|
this.setState(this._initState(nextProps, nextContext));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -502,7 +677,7 @@ export default class OutfittingPage extends Page {
|
|||||||
* Generates the short URL
|
* Generates the short URL
|
||||||
*/
|
*/
|
||||||
_genShortlink() {
|
_genShortlink() {
|
||||||
this.context.showModal(<ModalPermalink url={window.location.href}/>);
|
this.context.showModal(<ModalPermalink url={window.location.href} />);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -519,7 +694,7 @@ export default class OutfittingPage extends Page {
|
|||||||
data.ShipName = ship.id;
|
data.ShipName = ship.id;
|
||||||
data.Ship = ship.id;
|
data.Ship = ship.id;
|
||||||
console.log(data);
|
console.log(data);
|
||||||
this.context.showModal(<ModalOrbis ship={data}/>);
|
this.context.showModal(<ModalOrbis ship={data} />);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -530,17 +705,23 @@ export default class OutfittingPage extends Page {
|
|||||||
|
|
||||||
const shipId = Ships[ship.id].eddbID;
|
const shipId = Ships[ship.id].eddbID;
|
||||||
// Provide unique list of non-PP module EDDB IDs
|
// Provide unique list of non-PP module EDDB IDs
|
||||||
const modIds = ship.internal.concat(ship.bulkheads, ship.standard, ship.hardpoints).filter(slot => slot !== null && slot.m !== null && !slot.m.pp).map(slot => slot.m.eddbID).filter((v, i, a) => a.indexOf(v) === i);
|
const modIds = ship.internal
|
||||||
|
.concat(ship.bulkheads, ship.standard, ship.hardpoints)
|
||||||
|
.filter(slot => slot !== null && slot.m !== null && !slot.m.pp)
|
||||||
|
.map(slot => slot.m.eddbID)
|
||||||
|
.filter((v, i, a) => a.indexOf(v) === i);
|
||||||
|
|
||||||
// Open up the relevant URL
|
// Open up the relevant URL
|
||||||
window.open('https://eddb.io/station?s=' + shipId + '&m=' + modIds.join(','));
|
window.open(
|
||||||
|
'https://eddb.io/station?s=' + shipId + '&m=' + modIds.join(',')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the shopping list
|
* Generates the shopping list
|
||||||
*/
|
*/
|
||||||
_genShoppingList() {
|
_genShoppingList() {
|
||||||
this.context.showModal(<ModalShoppingList ship={this.state.ship}/>);
|
this.context.showModal(<ModalShoppingList ship={this.state.ship} />);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -550,8 +731,9 @@ export default class OutfittingPage extends Page {
|
|||||||
_keyDown(e) {
|
_keyDown(e) {
|
||||||
// .keyCode will eventually be replaced with .key
|
// .keyCode will eventually be replaced with .key
|
||||||
switch (e.keyCode) {
|
switch (e.keyCode) {
|
||||||
case 69: // 'e'
|
case 69: // 'e'
|
||||||
if (e.ctrlKey || e.metaKey) { // CTRL/CMD + e
|
if (e.ctrlKey || e.metaKey) {
|
||||||
|
// CTRL/CMD + e
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this._exportBuild();
|
this._exportBuild();
|
||||||
}
|
}
|
||||||
@@ -567,7 +749,28 @@ export default class OutfittingPage extends Page {
|
|||||||
let state = this.state,
|
let state = this.state,
|
||||||
{ language, termtip, tooltip, sizeRatio, onWindowResize } = this.context,
|
{ language, termtip, tooltip, sizeRatio, onWindowResize } = this.context,
|
||||||
{ translate, units, formats } = language,
|
{ translate, units, formats } = language,
|
||||||
{ ship, code, savedCode, buildName, newBuildName, sys, eng, wep, boost, fuel, cargo, opponent, opponentBuild, opponentSys, opponentEng, opponentWep, engagementRange } = state,
|
{
|
||||||
|
ship,
|
||||||
|
code,
|
||||||
|
savedCode,
|
||||||
|
buildName,
|
||||||
|
newBuildName,
|
||||||
|
sys,
|
||||||
|
eng,
|
||||||
|
wep,
|
||||||
|
mcSys,
|
||||||
|
mcEng,
|
||||||
|
mcWep,
|
||||||
|
boost,
|
||||||
|
fuel,
|
||||||
|
cargo,
|
||||||
|
opponent,
|
||||||
|
opponentBuild,
|
||||||
|
opponentSys,
|
||||||
|
opponentEng,
|
||||||
|
opponentWep,
|
||||||
|
engagementRange
|
||||||
|
} = state,
|
||||||
hide = tooltip.bind(null, null),
|
hide = tooltip.bind(null, null),
|
||||||
menu = this.props.currentMenu,
|
menu = this.props.currentMenu,
|
||||||
shipUpdated = this._shipUpdated,
|
shipUpdated = this._shipUpdated,
|
||||||
@@ -585,11 +788,15 @@ export default class OutfittingPage extends Page {
|
|||||||
const _pStr = `${ship.getPowerEnabledString()}${ship.getPowerPrioritiesString()}`;
|
const _pStr = `${ship.getPowerEnabledString()}${ship.getPowerPrioritiesString()}`;
|
||||||
const _mStr = ship.getModificationsString();
|
const _mStr = ship.getModificationsString();
|
||||||
|
|
||||||
const standardSlotMarker = `${ship.name}${_sStr}${_pStr}${_mStr}${ship.ladenMass}${cargo}${fuel}`;
|
const standardSlotMarker = `${ship.name}${_sStr}${_pStr}${_mStr}${
|
||||||
|
ship.ladenMass
|
||||||
|
}${cargo}${fuel}`;
|
||||||
const internalSlotMarker = `${ship.name}${_iStr}${_pStr}${_mStr}`;
|
const internalSlotMarker = `${ship.name}${_iStr}${_pStr}${_mStr}`;
|
||||||
const hardpointsSlotMarker = `${ship.name}${_hStr}${_pStr}${_mStr}`;
|
const hardpointsSlotMarker = `${ship.name}${_hStr}${_pStr}${_mStr}`;
|
||||||
const boostMarker = `${ship.canBoost(cargo, fuel)}`;
|
const boostMarker = `${ship.canBoost(cargo, fuel)}`;
|
||||||
const shipSummaryMarker = `${ship.name}${_sStr}${_iStr}${_hStr}${_pStr}${_mStr}${ship.ladenMass}${cargo}${fuel}`;
|
const shipSummaryMarker = `${
|
||||||
|
ship.name
|
||||||
|
}${_sStr}${_iStr}${_hStr}${_pStr}${_mStr}${ship.ladenMass}${cargo}${fuel}`;
|
||||||
|
|
||||||
const requirements = Ships[ship.id].requirements;
|
const requirements = Ships[ship.id].requirements;
|
||||||
let requirementElements = [];
|
let requirementElements = [];
|
||||||
@@ -601,94 +808,275 @@ export default class OutfittingPage extends Page {
|
|||||||
*/
|
*/
|
||||||
function renderRequirement(className, textKey, tooltipTextKey) {
|
function renderRequirement(className, textKey, tooltipTextKey) {
|
||||||
if (textKey.startsWith('empire') || textKey.startsWith('federation')) {
|
if (textKey.startsWith('empire') || textKey.startsWith('federation')) {
|
||||||
requirementElements.push(<div key={textKey} className={className} onMouseEnter={termtip.bind(null, tooltipTextKey)} onMouseLeave={hide}><a href={textKey.startsWith('empire') ? 'http://elite-dangerous.wikia.com/wiki/Empire/Ranks' : 'http://elite-dangerous.wikia.com/wiki/Federation/Ranks'} target="_blank" rel="noopener">{translate(textKey)}</a></div>);
|
requirementElements.push(
|
||||||
|
<div
|
||||||
|
key={textKey}
|
||||||
|
className={className}
|
||||||
|
onMouseEnter={termtip.bind(null, tooltipTextKey)}
|
||||||
|
onMouseLeave={hide}
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href={
|
||||||
|
textKey.startsWith('empire') ?
|
||||||
|
'http://elite-dangerous.wikia.com/wiki/Empire/Ranks' :
|
||||||
|
'http://elite-dangerous.wikia.com/wiki/Federation/Ranks'
|
||||||
|
}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>
|
||||||
|
{translate(textKey)}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
requirementElements.push(<div key={textKey} className={className} onMouseEnter={termtip.bind(null, tooltipTextKey)} onMouseLeave={hide}>{translate(textKey)}</div>);
|
requirementElements.push(
|
||||||
|
<div
|
||||||
|
key={textKey}
|
||||||
|
className={className}
|
||||||
|
onMouseEnter={termtip.bind(null, tooltipTextKey)}
|
||||||
|
onMouseLeave={hide}
|
||||||
|
>
|
||||||
|
{translate(textKey)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (requirements) {
|
if (requirements) {
|
||||||
requirements.federationRank && renderRequirement('federation', 'federation rank ' + requirements.federationRank, 'federation rank required');
|
requirements.federationRank &&
|
||||||
requirements.empireRank && renderRequirement('empire', 'empire rank ' + requirements.empireRank, 'empire rank required');
|
renderRequirement(
|
||||||
requirements.horizons && renderRequirement('horizons', 'horizons', 'horizons required');
|
'federation',
|
||||||
requirements.horizonsEarlyAdoption && renderRequirement('horizons', 'horizons early adoption', 'horizons early adoption required');
|
'federation rank ' + requirements.federationRank,
|
||||||
|
'federation rank required'
|
||||||
|
);
|
||||||
|
requirements.empireRank &&
|
||||||
|
renderRequirement(
|
||||||
|
'empire',
|
||||||
|
'empire rank ' + requirements.empireRank,
|
||||||
|
'empire rank required'
|
||||||
|
);
|
||||||
|
requirements.horizons &&
|
||||||
|
renderRequirement('horizons', 'horizons', 'horizons required');
|
||||||
|
requirements.horizonsEarlyAdoption &&
|
||||||
|
renderRequirement(
|
||||||
|
'horizons',
|
||||||
|
'horizons early adoption',
|
||||||
|
'horizons early adoption required'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id='outfit' className={'page'} style={{ fontSize: (sizeRatio * 0.9) + 'em' }}>
|
<div
|
||||||
<div id='overview'>
|
id="outfit"
|
||||||
|
className={'page'}
|
||||||
|
style={{ fontSize: sizeRatio * 0.9 + 'em' }}
|
||||||
|
>
|
||||||
|
<div id="overview">
|
||||||
<h1>{ship.name}</h1>
|
<h1>{ship.name}</h1>
|
||||||
<div id='requirements'>{requirementElements}</div>
|
<div id="requirements">{requirementElements}</div>
|
||||||
<div id='build'>
|
<div id="build">
|
||||||
<input value={newBuildName || ''} onChange={this._buildNameChange} placeholder={translate('Enter Name')} maxLength={50} />
|
<input
|
||||||
<button onClick={canSave && this._saveBuild} disabled={!canSave} onMouseOver={termtip.bind(null, 'save')} onMouseOut={hide}>
|
value={newBuildName || ''}
|
||||||
<FloppyDisk className='lg' />
|
onChange={this._buildNameChange}
|
||||||
|
placeholder={translate('Enter Name')}
|
||||||
|
maxLength={50}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
onClick={canSave && this._saveBuild}
|
||||||
|
disabled={!canSave}
|
||||||
|
onMouseOver={termtip.bind(null, 'save')}
|
||||||
|
onMouseOut={hide}
|
||||||
|
>
|
||||||
|
<FloppyDisk className="lg" />
|
||||||
</button>
|
</button>
|
||||||
<button onClick={canRename && this._renameBuild} disabled={!canRename} onMouseOver={termtip.bind(null, 'rename')} onMouseOut={hide}>
|
<button
|
||||||
<span style={{ textTransform: 'none', fontSize: '1.8em' }}>a|</span>
|
onClick={canRename && this._renameBuild}
|
||||||
|
disabled={!canRename}
|
||||||
|
onMouseOver={termtip.bind(null, 'rename')}
|
||||||
|
onMouseOut={hide}
|
||||||
|
>
|
||||||
|
<span style={{ textTransform: 'none', fontSize: '1.8em' }}>
|
||||||
|
a|
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<button onClick={canReload && this._reloadBuild} disabled={!canReload} onMouseOver={termtip.bind(null, 'reload')} onMouseOut={hide}>
|
<button
|
||||||
<Reload className='lg'/>
|
onClick={canReload && this._reloadBuild}
|
||||||
|
disabled={!canReload}
|
||||||
|
onMouseOver={termtip.bind(null, 'reload')}
|
||||||
|
onMouseOut={hide}
|
||||||
|
>
|
||||||
|
<Reload className="lg" />
|
||||||
</button>
|
</button>
|
||||||
<button className={'danger'} onClick={savedCode && this._deleteBuild} disabled={!savedCode} onMouseOver={termtip.bind(null, 'delete')} onMouseOut={hide}>
|
<button
|
||||||
<Bin className='lg'/>
|
className={'danger'}
|
||||||
|
onClick={savedCode && this._deleteBuild}
|
||||||
|
disabled={!savedCode}
|
||||||
|
onMouseOver={termtip.bind(null, 'delete')}
|
||||||
|
onMouseOut={hide}
|
||||||
|
>
|
||||||
|
<Bin className="lg" />
|
||||||
</button>
|
</button>
|
||||||
<button onClick={code && this._resetBuild} disabled={!code} onMouseOver={termtip.bind(null, 'reset')} onMouseOut={hide}>
|
<button
|
||||||
<Switch className='lg'/>
|
onClick={code && this._resetBuild}
|
||||||
|
disabled={!code}
|
||||||
|
onMouseOver={termtip.bind(null, 'reset')}
|
||||||
|
onMouseOut={hide}
|
||||||
|
>
|
||||||
|
<Switch className="lg" />
|
||||||
</button>
|
</button>
|
||||||
<button onClick={buildName && this._exportBuild} disabled={!buildName} onMouseOver={termtip.bind(null, 'export')} onMouseOut={hide}>
|
<button
|
||||||
<Download className='lg'/>
|
onClick={buildName && this._exportBuild}
|
||||||
|
disabled={!buildName}
|
||||||
|
onMouseOver={termtip.bind(null, 'export')}
|
||||||
|
onMouseOut={hide}
|
||||||
|
>
|
||||||
|
<Download className="lg" />
|
||||||
</button>
|
</button>
|
||||||
<button onClick={this._eddbShoppingList} onMouseOver={termtip.bind(null, 'PHRASE_SHOPPING_LIST')} onMouseOut={hide}>
|
<button
|
||||||
<ShoppingIcon className='lg' />
|
onClick={this._eddbShoppingList}
|
||||||
|
onMouseOver={termtip.bind(null, 'PHRASE_SHOPPING_LIST')}
|
||||||
|
onMouseOut={hide}
|
||||||
|
>
|
||||||
|
<ShoppingIcon className="lg" />
|
||||||
</button>
|
</button>
|
||||||
<button onClick={this._genShortlink} onMouseOver={termtip.bind(null, 'shortlink')} onMouseOut={hide}>
|
<button
|
||||||
<LinkIcon className='lg' />
|
onClick={this._genShortlink}
|
||||||
|
onMouseOver={termtip.bind(null, 'shortlink')}
|
||||||
|
onMouseOut={hide}
|
||||||
|
>
|
||||||
|
<LinkIcon className="lg" />
|
||||||
</button>
|
</button>
|
||||||
<button onClick={this._genOrbis} onMouseOver={termtip.bind(null, 'PHASE_UPLOAD_ORBIS')} onMouseOut={hide}>
|
<button
|
||||||
<OrbisIcon className='lg' />
|
onClick={this._genOrbis}
|
||||||
|
onMouseOver={termtip.bind(null, 'PHASE_UPLOAD_ORBIS')}
|
||||||
|
onMouseOut={hide}
|
||||||
|
>
|
||||||
|
<OrbisIcon className="lg" />
|
||||||
</button>
|
</button>
|
||||||
<button onClick={this._genShoppingList} onMouseOver={termtip.bind(null, 'PHRASE_SHOPPING_MATS')} onMouseOut={hide}>
|
<button
|
||||||
<MatIcon className='lg' />
|
onClick={this._genShoppingList}
|
||||||
|
onMouseOver={termtip.bind(null, 'PHRASE_SHOPPING_MATS')}
|
||||||
|
onMouseOut={hide}
|
||||||
|
>
|
||||||
|
<MatIcon className="lg" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Main tables */}
|
{/* Main tables */}
|
||||||
<ShipSummaryTable ship={ship} fuel={fuel} cargo={cargo} marker={shipSummaryMarker} pips={{ sys: this.state.sys, wep: this.state.wep, eng: this.state.eng }} />
|
<ShipSummaryTable
|
||||||
<StandardSlotSection ship={ship} fuel={fuel} cargo={cargo} code={standardSlotMarker} onChange={shipUpdated} onCargoChange={this._cargoUpdated} onFuelChange={this._fuelUpdated} currentMenu={menu} sectionMenuRefs={this._sectionMenuRefs}/>
|
ship={ship}
|
||||||
<InternalSlotSection ship={ship} code={internalSlotMarker} onChange={shipUpdated} onCargoChange={this._cargoUpdated} onFuelChange={this._fuelUpdated} currentMenu={menu} sectionMenuRefs={this._sectionMenuRefs}/>
|
fuel={fuel}
|
||||||
<HardpointSlotSection ship={ship} code={hardpointsSlotMarker} onChange={shipUpdated} onCargoChange={this._cargoUpdated} onFuelChange={this._fuelUpdated} currentMenu={menu} sectionMenuRefs={this._sectionMenuRefs}/>
|
cargo={cargo}
|
||||||
<UtilitySlotSection ship={ship} code={hardpointsSlotMarker} onChange={shipUpdated} onCargoChange={this._cargoUpdated} onFuelChange={this._fuelUpdated} currentMenu={menu} sectionMenuRefs={this._sectionMenuRefs}/>
|
marker={shipSummaryMarker}
|
||||||
|
pips={{
|
||||||
|
sys: this.state.sys,
|
||||||
|
wep: this.state.wep,
|
||||||
|
eng: this.state.eng
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<StandardSlotSection
|
||||||
|
ship={ship}
|
||||||
|
fuel={fuel}
|
||||||
|
cargo={cargo}
|
||||||
|
code={standardSlotMarker}
|
||||||
|
onChange={shipUpdated}
|
||||||
|
onCargoChange={this._cargoUpdated}
|
||||||
|
onFuelChange={this._fuelUpdated}
|
||||||
|
currentMenu={menu}
|
||||||
|
sectionMenuRefs={this._sectionMenuRefs}
|
||||||
|
/>
|
||||||
|
<InternalSlotSection
|
||||||
|
ship={ship}
|
||||||
|
code={internalSlotMarker}
|
||||||
|
onChange={shipUpdated}
|
||||||
|
onCargoChange={this._cargoUpdated}
|
||||||
|
onFuelChange={this._fuelUpdated}
|
||||||
|
currentMenu={menu}
|
||||||
|
sectionMenuRefs={this._sectionMenuRefs}
|
||||||
|
/>
|
||||||
|
<HardpointSlotSection
|
||||||
|
ship={ship}
|
||||||
|
code={hardpointsSlotMarker}
|
||||||
|
onChange={shipUpdated}
|
||||||
|
onCargoChange={this._cargoUpdated}
|
||||||
|
onFuelChange={this._fuelUpdated}
|
||||||
|
currentMenu={menu}
|
||||||
|
sectionMenuRefs={this._sectionMenuRefs}
|
||||||
|
/>
|
||||||
|
<UtilitySlotSection
|
||||||
|
ship={ship}
|
||||||
|
code={hardpointsSlotMarker}
|
||||||
|
onChange={shipUpdated}
|
||||||
|
onCargoChange={this._cargoUpdated}
|
||||||
|
onFuelChange={this._fuelUpdated}
|
||||||
|
currentMenu={menu}
|
||||||
|
sectionMenuRefs={this._sectionMenuRefs}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Control of ship and opponent */}
|
{/* Control of ship and opponent */}
|
||||||
<div className='group quarter'>
|
<div className="group quarter">
|
||||||
<div className='group half'>
|
<div className="group half">
|
||||||
<h2 style={{ verticalAlign: 'middle', textAlign: 'left' }}>{translate('ship control')}</h2>
|
<h2 style={{ verticalAlign: 'middle', textAlign: 'left' }}>
|
||||||
|
{translate('ship control')}
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className='group half'>
|
<div className="group half">
|
||||||
<Boost marker={boostMarker} ship={ship} boost={boost} onChange={this._boostUpdated} />
|
<Boost
|
||||||
|
marker={boostMarker}
|
||||||
|
ship={ship}
|
||||||
|
boost={boost}
|
||||||
|
onChange={this._boostUpdated}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='group quarter'>
|
<div className="group quarter">
|
||||||
<Pips sys={sys} eng={eng} wep={wep} onChange={this._pipsUpdated} />
|
<Pips
|
||||||
|
sys={sys}
|
||||||
|
eng={eng}
|
||||||
|
wep={wep}
|
||||||
|
mcSys={mcSys}
|
||||||
|
mcEng={mcEng}
|
||||||
|
mcWep={mcWep}
|
||||||
|
onChange={this._pipsUpdated}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className='group quarter'>
|
<div className="group quarter">
|
||||||
<Fuel fuelCapacity={ship.fuelCapacity} fuel={fuel} onChange={this._fuelUpdated}/>
|
<Fuel
|
||||||
|
fuelCapacity={ship.fuelCapacity}
|
||||||
|
fuel={fuel}
|
||||||
|
onChange={this._fuelUpdated}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className='group quarter'>
|
<div className="group quarter">
|
||||||
{ ship.cargoCapacity > 0 ? <Cargo cargoCapacity={ship.cargoCapacity} cargo={cargo} onChange={this._cargoUpdated}/> : null }
|
{ship.cargoCapacity > 0 ? (
|
||||||
|
<Cargo
|
||||||
|
cargoCapacity={ship.cargoCapacity}
|
||||||
|
cargo={cargo}
|
||||||
|
onChange={this._cargoUpdated}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className='group half'>
|
<div className="group half">
|
||||||
<div className='group quarter'>
|
<div className="group quarter">
|
||||||
<h2 style={{ verticalAlign: 'middle', textAlign: 'left' }}>{translate('opponent')}</h2>
|
<h2 style={{ verticalAlign: 'middle', textAlign: 'left' }}>
|
||||||
|
{translate('opponent')}
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className='group threequarters'>
|
<div className="group threequarters">
|
||||||
<ShipPicker ship={opponent.id} build={opponentBuild} onChange={this._opponentUpdated}/>
|
<ShipPicker
|
||||||
|
ship={opponent.id}
|
||||||
|
build={opponentBuild}
|
||||||
|
onChange={this._opponentUpdated}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='group half'>
|
<div className="group half">
|
||||||
<EngagementRange ship={ship} engagementRange={engagementRange} onChange={this._engagementRangeUpdated}/>
|
<EngagementRange
|
||||||
|
ship={ship}
|
||||||
|
engagementRange={engagementRange}
|
||||||
|
onChange={this._engagementRangeUpdated}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Tabbed subpages */}
|
{/* Tabbed subpages */}
|
||||||
|
|||||||
@@ -70,6 +70,13 @@ export default class Page extends React.Component {
|
|||||||
document.title = this.state.title || 'Coriolis';
|
document.title = this.state.title || 'Coriolis';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the window title upon mount
|
||||||
|
*/
|
||||||
|
componentDidMount() {
|
||||||
|
document.title = this.state.title || 'Coriolis';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the title upon change
|
* Updates the title upon change
|
||||||
* @param {Object} newProps Incoming properties
|
* @param {Object} newProps Incoming properties
|
||||||
|
|||||||
@@ -22,9 +22,11 @@ function countHp(slot) {
|
|||||||
*/
|
*/
|
||||||
function countInt(slot) {
|
function countInt(slot) {
|
||||||
let crEligible = !slot.eligible || slot.eligible.cr;
|
let crEligible = !slot.eligible || slot.eligible.cr;
|
||||||
this.int[slot.maxClass - 1]++; // Subtract 1 since there is no Class 0 Internal compartment
|
this.int[slot.maxClass - 1]++; // Subtract 1 since there is no Class 0 Internal compartment
|
||||||
this.intCount++;
|
this.intCount++;
|
||||||
this.maxCargo += crEligible ? ModuleUtils.findInternal('cr', slot.maxClass, 'E').cargo : 0;
|
this.maxCargo += crEligible ?
|
||||||
|
ModuleUtils.findInternal('cr', slot.maxClass, 'E').cargo :
|
||||||
|
0;
|
||||||
|
|
||||||
// if no eligiblity, then assume pce
|
// if no eligiblity, then assume pce
|
||||||
let passSlotType = null;
|
let passSlotType = null;
|
||||||
@@ -42,7 +44,9 @@ function countInt(slot) {
|
|||||||
passSlotType = 'pcq';
|
passSlotType = 'pcq';
|
||||||
passSlotRating = 'B';
|
passSlotRating = 'B';
|
||||||
}
|
}
|
||||||
let passengerBay = passSlotType ? ModuleUtils.findMaxInternal(passSlotType, slot.maxClass, passSlotRating) : null;
|
let passengerBay = passSlotType ?
|
||||||
|
ModuleUtils.findMaxInternal(passSlotType, slot.maxClass, passSlotRating) :
|
||||||
|
null;
|
||||||
this.maxPassengers += passengerBay ? passengerBay.passengers : 0;
|
this.maxPassengers += passengerBay ? passengerBay.passengers : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,23 +61,27 @@ function shipSummary(shipId, shipData) {
|
|||||||
id: shipId,
|
id: shipId,
|
||||||
hpCount: 0,
|
hpCount: 0,
|
||||||
intCount: 0,
|
intCount: 0,
|
||||||
|
beta: shipData.beta,
|
||||||
maxCargo: 0,
|
maxCargo: 0,
|
||||||
maxPassengers: 0,
|
maxPassengers: 0,
|
||||||
hp: [0, 0, 0, 0, 0], // Utility, Small, Medium, Large, Huge
|
hp: [0, 0, 0, 0, 0], // Utility, Small, Medium, Large, Huge
|
||||||
int: [0, 0, 0, 0, 0, 0, 0, 0], // Sizes 1 - 8
|
int: [0, 0, 0, 0, 0, 0, 0, 0], // Sizes 1 - 8
|
||||||
standard: shipData.slots.standard,
|
standard: shipData.slots.standard,
|
||||||
agility: shipData.properties.pitch + shipData.properties.yaw + shipData.properties.roll
|
agility:
|
||||||
|
shipData.properties.pitch +
|
||||||
|
shipData.properties.yaw +
|
||||||
|
shipData.properties.roll
|
||||||
};
|
};
|
||||||
Object.assign(summary, shipData.properties);
|
Object.assign(summary, shipData.properties);
|
||||||
let ship = new Ship(shipId, shipData.properties, shipData.slots);
|
let ship = new Ship(shipId, shipData.properties, shipData.slots);
|
||||||
|
|
||||||
// Build Ship
|
// Build Ship
|
||||||
ship.buildWith(shipData.defaults); // Populate with stock/default components
|
ship.buildWith(shipData.defaults); // Populate with stock/default components
|
||||||
ship.hardpoints.forEach(countHp.bind(summary)); // Count Hardpoints by class
|
ship.hardpoints.forEach(countHp.bind(summary)); // Count Hardpoints by class
|
||||||
ship.internal.forEach(countInt.bind(summary)); // Count Internal Compartments by class
|
ship.internal.forEach(countInt.bind(summary)); // Count Internal Compartments by class
|
||||||
summary.retailCost = ship.totalCost; // Record Stock/Default/retail cost
|
summary.retailCost = ship.totalCost; // Record Stock/Default/retail cost
|
||||||
ship.optimizeMass({ pd: '1D' }); // Optimize Mass with 1D PD for maximum possible jump range
|
ship.optimizeMass({ pd: '1D' }); // Optimize Mass with 1D PD for maximum possible jump range
|
||||||
summary.maxJumpRange = ship.unladenRange; // Record Jump Range
|
summary.maxJumpRange = ship.unladenRange; // Record Jump Range
|
||||||
|
|
||||||
// Best thrusters
|
// Best thrusters
|
||||||
let th;
|
let th;
|
||||||
@@ -97,7 +105,6 @@ function shipSummary(shipId, shipData) {
|
|||||||
* The Shipyard summary page
|
* The Shipyard summary page
|
||||||
*/
|
*/
|
||||||
export default class ShipyardPage extends Page {
|
export default class ShipyardPage extends Page {
|
||||||
|
|
||||||
static cachedShipSummaries = null;
|
static cachedShipSummaries = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -145,12 +152,15 @@ export default class ShipyardPage extends Page {
|
|||||||
shipPredicateIndex = undefined;
|
shipPredicateIndex = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.state.shipPredicate == shipPredicate && this.state.shipPredicateIndex == shipPredicateIndex) {
|
if (
|
||||||
|
this.state.shipPredicate == shipPredicate &&
|
||||||
|
this.state.shipPredicateIndex == shipPredicateIndex
|
||||||
|
) {
|
||||||
shipDesc = !shipDesc;
|
shipDesc = !shipDesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({ shipPredicate, shipDesc, shipPredicateIndex });
|
this.setState({ shipPredicate, shipDesc, shipPredicateIndex });
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate the table row summary for the ship
|
* Generate the table row summary for the ship
|
||||||
@@ -159,56 +169,59 @@ 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 <tr
|
return (
|
||||||
|
<tr
|
||||||
key={s.id}
|
key={s.id}
|
||||||
style={{ height: '1.5em' }}
|
style={{ height: '1.5em' }}
|
||||||
className={cn({ highlighted: noTouch && this.state.shipId === s.id, alt: highlight })}
|
className={cn({
|
||||||
|
highlighted: noTouch && this.state.shipId === s.id,
|
||||||
|
})}
|
||||||
onMouseEnter={noTouch && this._highlightShip.bind(this, s.id)}
|
onMouseEnter={noTouch && this._highlightShip.bind(this, 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>
|
||||||
<td className='ri cap'>{translate(SizeMap[s.class])}</td>
|
<td className="ri cap">{translate(SizeMap[s.class])}</td>
|
||||||
<td className='ri'>{fInt(s.crew)}</td>
|
<td className="ri">{fInt(s.crew)}</td>
|
||||||
<td className='ri'>{s.masslock}</td>
|
<td className="ri">{s.masslock}</td>
|
||||||
<td className='ri'>{fInt(s.agility)}</td>
|
<td className="ri">{fInt(s.agility)}</td>
|
||||||
<td className='ri'>{fInt(s.hardness)}</td>
|
<td className="ri">{fInt(s.hardness)}</td>
|
||||||
<td className='ri'>{fInt(s.hullMass)}</td>
|
<td className="ri">{fInt(s.hullMass)}</td>
|
||||||
<td className='ri'>{fInt(s.speed)}</td>
|
<td className="ri">{fInt(s.speed)}</td>
|
||||||
<td className='ri'>{fInt(s.boost)}</td>
|
<td className="ri">{fInt(s.boost)}</td>
|
||||||
<td className='ri'>{fInt(s.baseArmour)}</td>
|
<td className="ri">{fInt(s.baseArmour)}</td>
|
||||||
<td className='ri'>{fInt(s.baseShieldStrength)}</td>
|
<td className="ri">{fInt(s.baseShieldStrength)}</td>
|
||||||
<td className='ri'>{fInt(s.topSpeed)}</td>
|
<td className="ri">{fInt(s.topSpeed)}</td>
|
||||||
<td className='ri'>{fInt(s.topBoost)}</td>
|
<td className="ri">{fInt(s.topBoost)}</td>
|
||||||
<td className='ri'>{fRound(s.maxJumpRange)}</td>
|
<td className="ri">{fRound(s.maxJumpRange)}</td>
|
||||||
<td className='ri'>{fInt(s.maxCargo)}</td>
|
<td className="ri">{fInt(s.maxCargo)}</td>
|
||||||
<td className='ri'>{fInt(s.maxPassengers)}</td>
|
<td className="ri">{fInt(s.maxPassengers)}</td>
|
||||||
<td className='cn'>{s.standard[0]}</td>
|
<td className="cn">{s.standard[0]}</td>
|
||||||
<td className='cn'>{s.standard[1]}</td>
|
<td className="cn">{s.standard[1]}</td>
|
||||||
<td className='cn'>{s.standard[2]}</td>
|
<td className="cn">{s.standard[2]}</td>
|
||||||
<td className='cn'>{s.standard[3]}</td>
|
<td className="cn">{s.standard[3]}</td>
|
||||||
<td className='cn'>{s.standard[4]}</td>
|
<td className="cn">{s.standard[4]}</td>
|
||||||
<td className='cn'>{s.standard[5]}</td>
|
<td className="cn">{s.standard[5]}</td>
|
||||||
<td className='cn'>{s.standard[6]}</td>
|
<td className="cn">{s.standard[6]}</td>
|
||||||
<td className={cn({ disabled: !s.hp[1] })}>{s.hp[1]}</td>
|
<td className={cn({ disabled: !s.hp[1] })}>{s.hp[1]}</td>
|
||||||
<td className={cn({ disabled: !s.hp[2] })}>{s.hp[2]}</td>
|
<td className={cn({ disabled: !s.hp[2] })}>{s.hp[2]}</td>
|
||||||
<td className={cn({ disabled: !s.hp[3] })}>{s.hp[3]}</td>
|
<td className={cn({ disabled: !s.hp[3] })}>{s.hp[3]}</td>
|
||||||
<td className={cn({ disabled: !s.hp[4] })}>{s.hp[4]}</td>
|
<td className={cn({ disabled: !s.hp[4] })}>{s.hp[4]}</td>
|
||||||
<td className={cn({ disabled: !s.hp[0] })}>{s.hp[0]}</td>
|
<td className={cn({ disabled: !s.hp[0] })}>{s.hp[0]}</td>
|
||||||
<td className={cn({ disabled: !s.int[0] })}>{s.int[0]}</td>
|
<td className={cn({ disabled: !s.int[0] })}>{s.int[0]}</td>
|
||||||
<td className={cn({ disabled: !s.int[1] })}>{s.int[1]}</td>
|
<td className={cn({ disabled: !s.int[1] })}>{s.int[1]}</td>
|
||||||
<td className={cn({ disabled: !s.int[2] })}>{s.int[2]}</td>
|
<td className={cn({ disabled: !s.int[2] })}>{s.int[2]}</td>
|
||||||
<td className={cn({ disabled: !s.int[3] })}>{s.int[3]}</td>
|
<td className={cn({ disabled: !s.int[3] })}>{s.int[3]}</td>
|
||||||
<td className={cn({ disabled: !s.int[4] })}>{s.int[4]}</td>
|
<td className={cn({ disabled: !s.int[4] })}>{s.int[4]}</td>
|
||||||
<td className={cn({ disabled: !s.int[5] })}>{s.int[5]}</td>
|
<td className={cn({ disabled: !s.int[5] })}>{s.int[5]}</td>
|
||||||
<td className={cn({ disabled: !s.int[6] })}>{s.int[6]}</td>
|
<td className={cn({ disabled: !s.int[6] })}>{s.int[6]}</td>
|
||||||
<td className={cn({ disabled: !s.int[7] })}>{s.int[7]}</td>
|
<td className={cn({ disabled: !s.int[7] })}>{s.int[7]}</td>
|
||||||
</tr>;
|
</tr>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -222,7 +235,8 @@ export default class ShipyardPage extends Page {
|
|||||||
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 } = this.state;
|
||||||
let sortShips = (predicate, index) => this._sortShips.bind(this, predicate, index);
|
let sortShips = (predicate, index) =>
|
||||||
|
this._sortShips.bind(this, predicate, index);
|
||||||
|
|
||||||
let filters = {
|
let filters = {
|
||||||
// 'class': { 1: 1, 2: 1}
|
// 'class': { 1: 1, 2: 1}
|
||||||
@@ -239,7 +253,8 @@ export default class ShipyardPage extends Page {
|
|||||||
|
|
||||||
// Sort shipsOverview
|
// Sort shipsOverview
|
||||||
shipSummaries.sort((a, b) => {
|
shipSummaries.sort((a, b) => {
|
||||||
let valA = a[shipPredicate], valB = b[shipPredicate];
|
let valA = a[shipPredicate],
|
||||||
|
valB = b[shipPredicate];
|
||||||
|
|
||||||
if (shipPredicateIndex != undefined) {
|
if (shipPredicateIndex != undefined) {
|
||||||
valA = valA[shipPredicateIndex];
|
valA = valA[shipPredicateIndex];
|
||||||
@@ -252,7 +267,7 @@ export default class ShipyardPage extends Page {
|
|||||||
valB = val;
|
valB = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(valA == valB) {
|
if (valA == valB) {
|
||||||
if (a.name > b.name) {
|
if (a.name > b.name) {
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
@@ -269,47 +284,55 @@ 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];
|
detailRows[i] = this._shipRowElement(
|
||||||
if(shipPredicateIndex != undefined) {
|
s,
|
||||||
shipSortValue = shipSortValue[shipPredicateIndex];
|
translate,
|
||||||
}
|
units,
|
||||||
|
fInt,
|
||||||
if(shipSortValue != lastShipSortValue) {
|
formats.f1,
|
||||||
backgroundHighlight = !backgroundHighlight;
|
);
|
||||||
lastShipSortValue = shipSortValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
detailRows[i] = this._shipRowElement(s, translate, units, fInt, formats.f1, backgroundHighlight);
|
|
||||||
shipRows[i] = (
|
shipRows[i] = (
|
||||||
<tr
|
<tr
|
||||||
key={i}
|
key={i}
|
||||||
style={{ height: '1.5em' }}
|
style={{ height: '1.5em' }}
|
||||||
className={cn({ highlighted: noTouch && this.state.shipId === s.id, alt: backgroundHighlight })}
|
className={cn({
|
||||||
|
highlighted: noTouch && this.state.shipId === s.id,
|
||||||
|
})}
|
||||||
onMouseEnter={noTouch && this._highlightShip.bind(this, s.id)}
|
onMouseEnter={noTouch && this._highlightShip.bind(this, s.id)}
|
||||||
>
|
>
|
||||||
<td className='le'><Link href={'/outfit/' + s.id}>{s.name}</Link></td>
|
<td className="le">
|
||||||
|
<Link href={'/outfit/' + s.id}>{s.name} {s.beta === true ? '(Beta)' : null}</Link>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='page' style={{ fontSize: sizeRatio + 'em' }}>
|
<div className="page" style={{ fontSize: sizeRatio + 'em' }}>
|
||||||
<div style={{ whiteSpace: 'nowrap', margin: '0 auto', fontSize: '0.8em', position: 'relative', display: 'inline-block', maxWidth: '100%' }}>
|
<div
|
||||||
|
style={{
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
margin: '0 auto',
|
||||||
|
fontSize: '0.8em',
|
||||||
|
position: 'relative',
|
||||||
|
display: 'inline-block',
|
||||||
|
maxWidth: '100%'
|
||||||
|
}}
|
||||||
|
>
|
||||||
<table style={{ width: '12em', position: 'absolute', zIndex: 1 }}>
|
<table style={{ width: '12em', position: 'absolute', zIndex: 1 }}>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th className='le rgt'> </th>
|
<th className="le rgt"> </th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr className='main'>
|
<tr className="main">
|
||||||
<th className='sortable le rgt' onClick={sortShips('name')}>{translate('ship')}</th>
|
<th className="sortable le rgt" onClick={sortShips('name')}>
|
||||||
|
{translate('ship')}
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th className='le rgt invisible'>{units['m/s']}</th>
|
<th className="le rgt invisible">{units['m/s']}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody onMouseLeave={this._highlightShip.bind(this, null)}>
|
<tbody onMouseLeave={this._highlightShip.bind(this, null)}>
|
||||||
@@ -317,80 +340,261 @@ export default class ShipyardPage extends Page {
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div style={{ overflowX: 'scroll', maxWidth: '100%' }}>
|
<div style={{ overflowX: 'scroll', maxWidth: '100%' }}>
|
||||||
<table style={{ marginLeft: 'calc(12em - 1px)', zIndex: 0 }}>
|
<table style={{ marginLeft: 'calc(12em - 1px)', zIndex: 0 }}>
|
||||||
<thead>
|
<thead>
|
||||||
<tr className='main'>
|
<tr className="main">
|
||||||
<th rowSpan={3} className='sortable' onClick={sortShips('manufacturer')}>{translate('manufacturer')}</th>
|
<th
|
||||||
<th> </th>
|
rowSpan={3}
|
||||||
<th rowSpan={3} className='sortable' onClick={sortShips('class')}>{translate('size')}</th>
|
className="sortable"
|
||||||
<th rowSpan={3} className='sortable' onClick={sortShips('crew')}>{translate('crew')}</th>
|
onClick={sortShips('manufacturer')}
|
||||||
<th rowSpan={3} className='sortable' onMouseEnter={termtip.bind(null, 'mass lock factor')} onMouseLeave={hide} onClick={sortShips('masslock')} >{translate('MLF')}</th>
|
>
|
||||||
<th rowSpan={3} className='sortable' onClick={sortShips('agility')}>{translate('agility')}</th>
|
{translate('manufacturer')}
|
||||||
<th rowSpan={3} className='sortable' onMouseEnter={termtip.bind(null, 'hardness')} onMouseLeave={hide} onClick={sortShips('hardness')}>{translate('hrd')}</th>
|
</th>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
<th colSpan={4}>{translate('base')}</th>
|
<th
|
||||||
<th colSpan={5}>{translate('max')}</th>
|
rowSpan={3}
|
||||||
<th className='lft' colSpan={7}></th>
|
className="sortable"
|
||||||
<th className='lft' colSpan={5}></th>
|
onClick={sortShips('class')}
|
||||||
<th className='lft' colSpan={8}></th>
|
>
|
||||||
</tr>
|
{translate('size')}
|
||||||
<tr>
|
</th>
|
||||||
<th className='sortable lft' onClick={sortShips('retailCost')}>{translate('cost')}</th>
|
<th
|
||||||
<th className='sortable lft' onClick={sortShips('hullMass')}>{translate('hull')}</th>
|
rowSpan={3}
|
||||||
<th className='sortable lft' onClick={sortShips('speed')}>{translate('speed')}</th>
|
className="sortable"
|
||||||
<th className='sortable' onClick={sortShips('boost')}>{translate('boost')}</th>
|
onClick={sortShips('crew')}
|
||||||
<th className='sortable' onClick={sortShips('baseArmour')}>{translate('armour')}</th>
|
>
|
||||||
<th className='sortable' onClick={sortShips('baseShieldStrength')}>{translate('shields')}</th>
|
{translate('crew')}
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
rowSpan={3}
|
||||||
|
className="sortable"
|
||||||
|
onMouseEnter={termtip.bind(null, 'mass lock factor')}
|
||||||
|
onMouseLeave={hide}
|
||||||
|
onClick={sortShips('masslock')}
|
||||||
|
>
|
||||||
|
{translate('MLF')}
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
rowSpan={3}
|
||||||
|
className="sortable"
|
||||||
|
onClick={sortShips('agility')}
|
||||||
|
>
|
||||||
|
{translate('agility')}
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
rowSpan={3}
|
||||||
|
className="sortable"
|
||||||
|
onMouseEnter={termtip.bind(null, 'hardness')}
|
||||||
|
onMouseLeave={hide}
|
||||||
|
onClick={sortShips('hardness')}
|
||||||
|
>
|
||||||
|
{translate('hrd')}
|
||||||
|
</th>
|
||||||
|
<th> </th>
|
||||||
|
<th colSpan={4}>{translate('base')}</th>
|
||||||
|
<th colSpan={5}>{translate('max')}</th>
|
||||||
|
<th className="lft" colSpan={7} />
|
||||||
|
<th className="lft" colSpan={5} />
|
||||||
|
<th className="lft" colSpan={8} />
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th
|
||||||
|
className="sortable lft"
|
||||||
|
onClick={sortShips('retailCost')}
|
||||||
|
>
|
||||||
|
{translate('cost')}
|
||||||
|
</th>
|
||||||
|
<th className="sortable lft" onClick={sortShips('hullMass')}>
|
||||||
|
{translate('hull')}
|
||||||
|
</th>
|
||||||
|
<th className="sortable lft" onClick={sortShips('speed')}>
|
||||||
|
{translate('speed')}
|
||||||
|
</th>
|
||||||
|
<th className="sortable" onClick={sortShips('boost')}>
|
||||||
|
{translate('boost')}
|
||||||
|
</th>
|
||||||
|
<th className="sortable" onClick={sortShips('baseArmour')}>
|
||||||
|
{translate('armour')}
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
className="sortable"
|
||||||
|
onClick={sortShips('baseShieldStrength')}
|
||||||
|
>
|
||||||
|
{translate('shields')}
|
||||||
|
</th>
|
||||||
|
|
||||||
<th className='sortable lft' onClick={sortShips('topSpeed')}>{translate('speed')}</th>
|
<th className="sortable lft" onClick={sortShips('topSpeed')}>
|
||||||
<th className='sortable' onClick={sortShips('topBoost')}>{translate('boost')}</th>
|
{translate('speed')}
|
||||||
<th className='sortable' onClick={sortShips('maxJumpRange')}>{translate('jump')}</th>
|
</th>
|
||||||
<th className='sortable' onClick={sortShips('maxCargo')}>{translate('cargo')}</th>
|
<th className="sortable" onClick={sortShips('topBoost')}>
|
||||||
<th className='sortable' onClick={sortShips('maxPassengers')}>{translate('pax')}</th>
|
{translate('boost')}
|
||||||
|
</th>
|
||||||
|
<th className="sortable" onClick={sortShips('maxJumpRange')}>
|
||||||
|
{translate('jump')}
|
||||||
|
</th>
|
||||||
|
<th className="sortable" onClick={sortShips('maxCargo')}>
|
||||||
|
{translate('cargo')}
|
||||||
|
</th>
|
||||||
|
<th className="sortable" onClick={sortShips('maxPassengers')} onMouseEnter={termtip.bind(null, 'passenger capacity')}
|
||||||
|
onMouseLeave={hide}>
|
||||||
|
{translate('pax')}
|
||||||
|
</th>
|
||||||
|
<th className="lft" colSpan={7}>
|
||||||
|
{translate('core module classes')}
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
colSpan={5}
|
||||||
|
className="sortable lft"
|
||||||
|
onClick={sortShips('hpCount')}
|
||||||
|
>
|
||||||
|
{translate('hardpoints')}
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
colSpan={8}
|
||||||
|
className="sortable lft"
|
||||||
|
onClick={sortShips('intCount')}
|
||||||
|
>
|
||||||
|
{translate('internal compartments')}
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th
|
||||||
|
className="sortable lft"
|
||||||
|
onClick={sortShips('retailCost')}
|
||||||
|
>
|
||||||
|
{units.CR}
|
||||||
|
</th>
|
||||||
|
<th className="sortable lft" onClick={sortShips('hullMass')}>
|
||||||
|
{units.T}
|
||||||
|
</th>
|
||||||
|
<th className="sortable lft" onClick={sortShips('speed')}>
|
||||||
|
{units['m/s']}
|
||||||
|
</th>
|
||||||
|
<th className="sortable" onClick={sortShips('boost')}>
|
||||||
|
{units['m/s']}
|
||||||
|
</th>
|
||||||
|
<th> </th>
|
||||||
|
<th
|
||||||
|
className="sortable"
|
||||||
|
onClick={sortShips('baseShieldStrength')}
|
||||||
|
>
|
||||||
|
{units.MJ}
|
||||||
|
</th>
|
||||||
|
<th className="sortable lft" onClick={sortShips('topSpeed')}>
|
||||||
|
{units['m/s']}
|
||||||
|
</th>
|
||||||
|
<th className="sortable" onClick={sortShips('topBoost')}>
|
||||||
|
{units['m/s']}
|
||||||
|
</th>
|
||||||
|
<th className="sortable" onClick={sortShips('maxJumpRange')}>
|
||||||
|
{units.LY}
|
||||||
|
</th>
|
||||||
|
<th className="sortable" onClick={sortShips('maxCargo')}>
|
||||||
|
{units.T}
|
||||||
|
</th>
|
||||||
|
<th> </th>
|
||||||
|
<th
|
||||||
|
className="sortable lft"
|
||||||
|
onMouseEnter={termtip.bind(null, 'power plant')}
|
||||||
|
onMouseLeave={hide}
|
||||||
|
onClick={sortShips('standard', 0)}
|
||||||
|
>
|
||||||
|
{'pp'}
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
className="sortable"
|
||||||
|
onMouseEnter={termtip.bind(null, 'thrusters')}
|
||||||
|
onMouseLeave={hide}
|
||||||
|
onClick={sortShips('standard', 1)}
|
||||||
|
>
|
||||||
|
{'th'}
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
className="sortable"
|
||||||
|
onMouseEnter={termtip.bind(null, 'frame shift drive')}
|
||||||
|
onMouseLeave={hide}
|
||||||
|
onClick={sortShips('standard', 2)}
|
||||||
|
>
|
||||||
|
{'fsd'}
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
className="sortable"
|
||||||
|
onMouseEnter={termtip.bind(null, 'life support')}
|
||||||
|
onMouseLeave={hide}
|
||||||
|
onClick={sortShips('standard', 3)}
|
||||||
|
>
|
||||||
|
{'ls'}
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
className="sortable"
|
||||||
|
onMouseEnter={termtip.bind(null, 'power distriubtor')}
|
||||||
|
onMouseLeave={hide}
|
||||||
|
onClick={sortShips('standard', 4)}
|
||||||
|
>
|
||||||
|
{'pd'}
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
className="sortable"
|
||||||
|
onMouseEnter={termtip.bind(null, 'sensors')}
|
||||||
|
onMouseLeave={hide}
|
||||||
|
onClick={sortShips('standard', 5)}
|
||||||
|
>
|
||||||
|
{'s'}
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
className="sortable"
|
||||||
|
onMouseEnter={termtip.bind(null, 'fuel tank')}
|
||||||
|
onMouseLeave={hide}
|
||||||
|
onClick={sortShips('standard', 6)}
|
||||||
|
>
|
||||||
|
{'ft'}
|
||||||
|
</th>
|
||||||
|
<th className="sortable lft" onClick={sortShips('hp', 1)}>
|
||||||
|
{translate('S')}
|
||||||
|
</th>
|
||||||
|
<th className="sortable" onClick={sortShips('hp', 2)}>
|
||||||
|
{translate('M')}
|
||||||
|
</th>
|
||||||
|
<th className="sortable" onClick={sortShips('hp', 3)}>
|
||||||
|
{translate('L')}
|
||||||
|
</th>
|
||||||
|
<th className="sortable" onClick={sortShips('hp', 4)}>
|
||||||
|
{translate('H')}
|
||||||
|
</th>
|
||||||
|
<th className="sortable" onClick={sortShips('hp', 0)}>
|
||||||
|
{translate('U')}
|
||||||
|
</th>
|
||||||
|
|
||||||
<th className='lft' colSpan={7}>{translate('core module classes')}</th>
|
<th className="sortable lft" onClick={sortShips('int', 0)}>
|
||||||
<th colSpan={5} className='sortable lft' onClick={sortShips('hpCount')}>{translate('hardpoints')}</th>
|
1
|
||||||
<th colSpan={8} className='sortable lft' onClick={sortShips('intCount')}>{translate('internal compartments')}</th>
|
</th>
|
||||||
</tr>
|
<th className="sortable" onClick={sortShips('int', 1)}>
|
||||||
<tr>
|
2
|
||||||
<th className='sortable lft' onClick={sortShips('retailCost')}>{units.CR}</th>
|
</th>
|
||||||
<th className='sortable lft' onClick={sortShips('hullMass')}>{units.T}</th>
|
<th className="sortable" onClick={sortShips('int', 2)}>
|
||||||
<th className='sortable lft' onClick={sortShips('speed')}>{units['m/s']}</th>
|
3
|
||||||
<th className='sortable' onClick={sortShips('boost')}>{units['m/s']}</th>
|
</th>
|
||||||
<th> </th>
|
<th className="sortable" onClick={sortShips('int', 3)}>
|
||||||
<th className='sortable' onClick={sortShips('baseShieldStrength')}>{units.MJ}</th>
|
4
|
||||||
<th className='sortable lft' onClick={sortShips('topSpeed')}>{units['m/s']}</th>
|
</th>
|
||||||
<th className='sortable' onClick={sortShips('topBoost')}>{units['m/s']}</th>
|
<th className="sortable" onClick={sortShips('int', 4)}>
|
||||||
<th className='sortable' onClick={sortShips('maxJumpRange')}>{units.LY}</th>
|
5
|
||||||
<th className='sortable' onClick={sortShips('maxCargo')}>{units.T}</th>
|
</th>
|
||||||
<th> </th>
|
<th className="sortable" onClick={sortShips('int', 5)}>
|
||||||
<th className='sortable lft' onMouseEnter={termtip.bind(null, 'power plant')} onMouseLeave={hide} onClick={sortShips('standard', 0)}>{'pp'}</th>
|
6
|
||||||
<th className='sortable' onMouseEnter={termtip.bind(null, 'thrusters')} onMouseLeave={hide} onClick={sortShips('standard', 1)}>{'th'}</th>
|
</th>
|
||||||
<th className='sortable' onMouseEnter={termtip.bind(null, 'frame shift drive')} onMouseLeave={hide} onClick={sortShips('standard', 2)}>{'fsd'}</th>
|
<th className="sortable" onClick={sortShips('int', 6)}>
|
||||||
<th className='sortable' onMouseEnter={termtip.bind(null, 'life support')} onMouseLeave={hide} onClick={sortShips('standard', 3)}>{'ls'}</th>
|
7
|
||||||
<th className='sortable' onMouseEnter={termtip.bind(null, 'power distriubtor')} onMouseLeave={hide} onClick={sortShips('standard', 4)}>{'pd'}</th>
|
</th>
|
||||||
<th className='sortable' onMouseEnter={termtip.bind(null, 'sensors')} onMouseLeave={hide} onClick={sortShips('standard', 5)}>{'s'}</th>
|
<th className="sortable" onClick={sortShips('int', 7)}>
|
||||||
<th className='sortable' onMouseEnter={termtip.bind(null, 'fuel tank')} onMouseLeave={hide} onClick={sortShips('standard', 6)}>{'ft'}</th>
|
8
|
||||||
<th className='sortable lft' onClick={sortShips('hp',1)}>{translate('S')}</th>
|
</th>
|
||||||
<th className='sortable' onClick={sortShips('hp', 2)}>{translate('M')}</th>
|
</tr>
|
||||||
<th className='sortable' onClick={sortShips('hp', 3)}>{translate('L')}</th>
|
</thead>
|
||||||
<th className='sortable' onClick={sortShips('hp', 4)}>{translate('H')}</th>
|
<tbody onMouseLeave={this._highlightShip.bind(this, null)}>
|
||||||
<th className='sortable' onClick={sortShips('hp', 0)}>{translate('U')}</th>
|
{detailRows}
|
||||||
|
</tbody>
|
||||||
<th className='sortable lft' onClick={sortShips('int', 0)} >1</th>
|
</table>
|
||||||
<th className='sortable' onClick={sortShips('int', 1)} >2</th>
|
|
||||||
<th className='sortable' onClick={sortShips('int', 2)} >3</th>
|
|
||||||
<th className='sortable' onClick={sortShips('int', 3)} >4</th>
|
|
||||||
<th className='sortable' onClick={sortShips('int', 4)} >5</th>
|
|
||||||
<th className='sortable' onClick={sortShips('int', 5)} >6</th>
|
|
||||||
<th className='sortable' onClick={sortShips('int', 6)} >7</th>
|
|
||||||
<th className='sortable' onClick={sortShips('int', 7)} >8</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody onMouseLeave={this._highlightShip.bind(this, null)}>
|
|
||||||
{detailRows}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -94,6 +94,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 = {};
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
* Modification - a modification and its value
|
* Modification - a modification and its value
|
||||||
*/
|
*/
|
||||||
export default class Modification {
|
export default class Modification {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {String} id Unique modification ID
|
* @param {String} id Unique modification ID
|
||||||
* @param {Number} value Value of the modification
|
* @param {Number} value Value of the modification
|
||||||
@@ -11,5 +10,4 @@ export default class Modification {
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { STATS_FORMATTING, SI_PREFIXES } from './StatsFormatting';
|
|||||||
* Module - active module in a ship's buildout
|
* Module - active module in a ship's buildout
|
||||||
*/
|
*/
|
||||||
export default class Module {
|
export default class Module {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new module
|
* Construct a new module
|
||||||
* @param {Object} params Module parameters. Either grp/id or template
|
* @param {Object} params Module parameters. Either grp/id or template
|
||||||
@@ -42,6 +41,7 @@ export default class Module {
|
|||||||
* @return {object} The value of the modification. If it is a numeric value then it is returned as an integer value scaled so that 1.23% == 123
|
* @return {object} The value of the modification. If it is a numeric value then it is returned as an integer value scaled so that 1.23% == 123
|
||||||
*/
|
*/
|
||||||
getModValue(name, raw) {
|
getModValue(name, raw) {
|
||||||
|
let baseVal = this[name];
|
||||||
let result = this.mods && this.mods[name] ? this.mods[name] : null;
|
let result = this.mods && this.mods[name] ? this.mods[name] : null;
|
||||||
|
|
||||||
if ((!raw) && this.blueprint && this.blueprint.special) {
|
if ((!raw) && this.blueprint && this.blueprint.special) {
|
||||||
@@ -52,13 +52,8 @@ export default class Module {
|
|||||||
const modification = Modifications.modifications[name];
|
const modification = Modifications.modifications[name];
|
||||||
const multiplier = modification.type === 'percentage' ? 10000 : 100;
|
const multiplier = modification.type === 'percentage' ? 10000 : 100;
|
||||||
if (name === 'explres' || name === 'kinres' || name === 'thermres' || name === 'causres') {
|
if (name === 'explres' || name === 'kinres' || name === 'thermres' || name === 'causres') {
|
||||||
// Resistance modifications in itself are additive, however their
|
// Apply resistance modding mechanisms to special effects subsequently
|
||||||
// special effects are multiplicative. They affect the overall result
|
result = result + modifierActions[name] * (1 - (this[name] + result / multiplier)) * 100;
|
||||||
// by (special effect resistance) * (damage mult after modification),
|
|
||||||
// i. e. we need to apply the special effect as a multiplier to the
|
|
||||||
// overall result and then calculate the difference.
|
|
||||||
let baseMult = this[name] ? 1 - this[name] : 1;
|
|
||||||
result = (baseMult - (baseMult - result / multiplier) * (1 - modifierActions[name] / 100)) * multiplier;
|
|
||||||
} else if (modification.method === 'additive') {
|
} else if (modification.method === 'additive') {
|
||||||
result = result + modifierActions[name] * 100;
|
result = result + modifierActions[name] * 100;
|
||||||
} else if (modification.method === 'overwrite') {
|
} else if (modification.method === 'overwrite') {
|
||||||
@@ -76,15 +71,6 @@ export default class Module {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resistance modding for hull reinforcement packages has additional
|
|
||||||
// diminishing returns implemented. The mod value gets lowered by
|
|
||||||
// the amount of base resistance the hrp has.
|
|
||||||
if (!isNaN(result) && this.grp === 'hr' &&
|
|
||||||
(name === 'kinres' || name === 'thermres' || name === 'explres')) {
|
|
||||||
let baseRes = this[name];
|
|
||||||
result = result * (1 - baseRes);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sanitise the resultant value to 4dp equivalent
|
// Sanitise the resultant value to 4dp equivalent
|
||||||
return isNaN(result) ? result : Math.round(result);
|
return isNaN(result) ? result : Math.round(result);
|
||||||
}
|
}
|
||||||
@@ -109,11 +95,11 @@ export default class Module {
|
|||||||
// 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];
|
||||||
if (name === 'explres' || name === 'kinres' || name === 'thermres' || name === 'causres') {
|
if (name === 'explres' || name === 'kinres' || name === 'thermres' || name === 'causres') {
|
||||||
// Resistance modifications in itself are additive but their
|
let res = (this[name] ? this[name] : 0) + value / 10000;
|
||||||
// experimentals are applied multiplicatively therefor we must handle
|
let experimental = modifierActions[name] / 100;
|
||||||
// them differently here (cf. documentation in getModValue).
|
value = (experimental - res) / (experimental - 1) - this[name];
|
||||||
let baseMult = (this[name] ? 1 - this[name] : 1);
|
value *= 10000;
|
||||||
value = ((baseMult - value / 10000) / (1 - modifierActions[name] / 100) - baseMult) * -10000;
|
// value = ((baseMult - value / 10000) / (1 - modifierActions[name] / 100) - baseMult) * -10000;
|
||||||
} else if (modification.method === 'additive') {
|
} else if (modification.method === 'additive') {
|
||||||
value = value - modifierActions[name];
|
value = value - modifierActions[name];
|
||||||
} else if (modification.method === 'overwrite') {
|
} else if (modification.method === 'overwrite') {
|
||||||
@@ -178,10 +164,6 @@ export default class Module {
|
|||||||
baseValue = 0;
|
baseValue = 0;
|
||||||
}
|
}
|
||||||
modValue = value - baseValue;
|
modValue = value - baseValue;
|
||||||
if (this.grp === 'hr' &&
|
|
||||||
(name === 'kinres' || name === 'thermres' || name === 'explres')) {
|
|
||||||
modValue = modValue / (1 - 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 { // multiplicative
|
} else { // multiplicative
|
||||||
@@ -192,7 +174,7 @@ export default class Module {
|
|||||||
modValue = modValue * 10000;
|
modValue = modValue * 10000;
|
||||||
} else if (modification.type === 'numeric' && name !== 'burst' &&
|
} else if (modification.type === 'numeric' && name !== 'burst' &&
|
||||||
name !== 'burstrof') {
|
name !== 'burstrof') {
|
||||||
modValue = modValue * 100;
|
modValue = modValue * 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setModValue(name, modValue, valueIsWithSpecial);
|
this.setModValue(name, modValue, valueIsWithSpecial);
|
||||||
@@ -242,38 +224,38 @@ export default class Module {
|
|||||||
const modification = Modifications.modifications[name];
|
const modification = Modifications.modifications[name];
|
||||||
let result = this[name];
|
let result = this[name];
|
||||||
|
|
||||||
if (modification) {
|
if (modification) {
|
||||||
// We store percentages as decimals, so to get them back we need to divide by 10000. Otherwise
|
// We store percentages as decimals, so to get them back we need to divide by 10000. Otherwise
|
||||||
// we divide by 100. Both ways we end up with a value with two decimal places
|
// we divide by 100. Both ways we end up with a value with two decimal places
|
||||||
let modValue;
|
let modValue;
|
||||||
if (modification.type === 'percentage') {
|
if (modification.type === 'percentage') {
|
||||||
modValue = this.getModValue(name) / 10000;
|
modValue = this.getModValue(name) / 10000;
|
||||||
} else if (modification.type === 'numeric') {
|
} else if (modification.type === 'numeric') {
|
||||||
modValue = this.getModValue(name) / 100;
|
modValue = this.getModValue(name) / 100;
|
||||||
} else {
|
} else {
|
||||||
modValue = this.getModValue(name);
|
modValue = this.getModValue(name);
|
||||||
|
}
|
||||||
|
if (modValue) {
|
||||||
|
if (!result && modification.method === 'additive') {
|
||||||
|
// If the modification is additive and no value is given by default we
|
||||||
|
// start at zero
|
||||||
|
result = 0;
|
||||||
}
|
}
|
||||||
if (modValue) {
|
|
||||||
if (!result && modification.method === 'additive') {
|
|
||||||
// If the modification is additive and no value is given by default we
|
|
||||||
// start at zero
|
|
||||||
result = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result !== undefined) {
|
if (result !== undefined) {
|
||||||
if (modification.method === 'additive') {
|
if (modification.method === 'additive') {
|
||||||
result = result + modValue;
|
result = result + modValue;
|
||||||
} else if (modification.method === 'overwrite') {
|
} else if (modification.method === 'overwrite') {
|
||||||
result = modValue;
|
result = modValue;
|
||||||
} 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 {
|
||||||
result = result * (1 + modValue);
|
result = result * (1 + modValue);
|
||||||
}
|
}
|
||||||
} else if (name === 'burst' || name === 'burstrof') {
|
} else if (name === 'burstrof') {
|
||||||
// Burst and burst rate of fire are special, as it can not exist but
|
// Burst and burst rate of fire are special, as it can not exist but
|
||||||
// have a modification
|
// have a modification
|
||||||
result = modValue / 100;
|
result = modValue / 100;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1092,4 +1074,30 @@ export default class Module {
|
|||||||
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ function filter(arr, maxClass, minClass, mass) {
|
|||||||
* The available module set for a specific ship
|
* The available module set for a specific ship
|
||||||
*/
|
*/
|
||||||
export default class ModuleSet {
|
export default class ModuleSet {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiate the module set
|
* Instantiate the module set
|
||||||
* @param {Object} modules All Modules
|
* @param {Object} modules All Modules
|
||||||
@@ -165,13 +164,13 @@ export default class ModuleSet {
|
|||||||
/**
|
/**
|
||||||
* Finds the lightest usable Shield Generator
|
* Finds the lightest usable Shield Generator
|
||||||
* @param {number} hullMass Ship hull mass
|
* @param {number} hullMass Ship hull mass
|
||||||
* @return {Object} Thruster
|
* @param {string} rating The optional rating of the shield
|
||||||
|
* @return {Object} Shield Generator
|
||||||
*/
|
*/
|
||||||
lightestShieldGenerator(hullMass) {
|
lightestShieldGenerator(hullMass, rating) {
|
||||||
let sg = this.internal.sg[0];
|
let sg = this.internal.sg[0];
|
||||||
|
|
||||||
for (let s of this.internal.sg) {
|
for (let s of this.internal.sg) {
|
||||||
if (s.mass < sg.mass && s.maxmass > hullMass) {
|
if ((!rating || rating === s.rating) && s.mass <= sg.mass && s.maxmass > hullMass) {
|
||||||
sg = s;
|
sg = s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,10 @@ export function standard(type, id) {
|
|||||||
if (!isNaN(type)) {
|
if (!isNaN(type)) {
|
||||||
type = StandardArray[type];
|
type = StandardArray[type];
|
||||||
}
|
}
|
||||||
let s = Modules.standard[type].find(e => e.id == id || (e.class == id.charAt(0) && e.rating == id.charAt(1)));
|
let s = Modules.standard[type].find(e => e.id === id);
|
||||||
|
if (!s) {
|
||||||
|
s = Modules.standard[type].find(e => (e.class == id.charAt(0) && e.rating == id.charAt(1)));
|
||||||
|
}
|
||||||
if (s) {
|
if (s) {
|
||||||
s = new Module({ template: s });
|
s = new Module({ template: s });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}],
|
}],
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ function reduceToIDs(idArray, slot, slotIndex) {
|
|||||||
* Ship Model - Encapsulates and models in-game ship behavior
|
* Ship Model - Encapsulates and models in-game ship behavior
|
||||||
*/
|
*/
|
||||||
export default class Ship {
|
export default class Ship {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {String} id Unique ship Id / Key
|
* @param {String} id Unique ship Id / Key
|
||||||
* @param {Object} properties Basic ship properties such as name, manufacturer, mass, etc
|
* @param {Object} properties Basic ship properties such as name, manufacturer, mass, etc
|
||||||
@@ -416,16 +415,16 @@ export default class Ship {
|
|||||||
clearModifications(m) {
|
clearModifications(m) {
|
||||||
m.mods = {};
|
m.mods = {};
|
||||||
this.updatePowerGenerated()
|
this.updatePowerGenerated()
|
||||||
.updatePowerUsed()
|
.updatePowerUsed()
|
||||||
.recalculateMass()
|
.recalculateMass()
|
||||||
.updateJumpStats()
|
.updateJumpStats()
|
||||||
.recalculateShield()
|
.recalculateShield()
|
||||||
.recalculateShieldCells()
|
.recalculateShieldCells()
|
||||||
.recalculateArmour()
|
.recalculateArmour()
|
||||||
.recalculateDps()
|
.recalculateDps()
|
||||||
.recalculateEps()
|
.recalculateEps()
|
||||||
.recalculateHps()
|
.recalculateHps()
|
||||||
.updateMovement();
|
.updateMovement();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -506,6 +505,11 @@ export default class Ship {
|
|||||||
if (isAbsolute) {
|
if (isAbsolute) {
|
||||||
m.setPretty(name, value, sentfromui);
|
m.setPretty(name, value, sentfromui);
|
||||||
} else {
|
} else {
|
||||||
|
// Resistance modifiers scale with the base value
|
||||||
|
if (name == 'kinres' || name == 'thermres' || name == 'causres' || name == 'explres') {
|
||||||
|
let baseValue = m.get(name, false);
|
||||||
|
value = (1 - baseValue) * value;
|
||||||
|
}
|
||||||
m.setModValue(name, value, sentfromui);
|
m.setModValue(name, value, sentfromui);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -696,16 +700,16 @@ export default class Ship {
|
|||||||
// Update aggragated stats
|
// Update aggragated stats
|
||||||
if (comps) {
|
if (comps) {
|
||||||
this.updatePowerGenerated()
|
this.updatePowerGenerated()
|
||||||
.updatePowerUsed()
|
.updatePowerUsed()
|
||||||
.recalculateMass()
|
.recalculateMass()
|
||||||
.updateJumpStats()
|
.updateJumpStats()
|
||||||
.recalculateShield()
|
.recalculateShield()
|
||||||
.recalculateShieldCells()
|
.recalculateShieldCells()
|
||||||
.recalculateArmour()
|
.recalculateArmour()
|
||||||
.recalculateDps()
|
.recalculateDps()
|
||||||
.recalculateEps()
|
.recalculateEps()
|
||||||
.recalculateHps()
|
.recalculateHps()
|
||||||
.updateMovement();
|
.updateMovement();
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.updatePowerPrioritesString().updatePowerEnabledString().updateModificationsString();
|
return this.updatePowerPrioritesString().updatePowerEnabledString().updateModificationsString();
|
||||||
@@ -1187,28 +1191,28 @@ export default class Ship {
|
|||||||
// handle unladen mass
|
// handle unladen mass
|
||||||
unladenMass += chain(slots)
|
unladenMass += chain(slots)
|
||||||
.map(slot => slot.m ? slot.m.get('mass') : null)
|
.map(slot => slot.m ? slot.m.get('mass') : null)
|
||||||
.filter()
|
.map(mass => mass || 0)
|
||||||
.reduce((sum, mass) => sum + mass)
|
.reduce((sum, mass) => sum + mass)
|
||||||
.value();
|
.value();
|
||||||
|
|
||||||
// handle fuel capacity
|
// handle fuel capacity
|
||||||
fuelCapacity += chain(slots)
|
fuelCapacity += chain(slots)
|
||||||
.map(slot => slot.m ? slot.m.get('fuel') : null)
|
.map(slot => slot.m ? slot.m.get('fuel') : null)
|
||||||
.filter()
|
.map(fuel => fuel || 0)
|
||||||
.reduce((sum, fuel) => sum + fuel)
|
.reduce((sum, fuel) => sum + fuel)
|
||||||
.value();
|
.value();
|
||||||
|
|
||||||
// handle cargo capacity
|
// handle cargo capacity
|
||||||
cargoCapacity += chain(slots)
|
cargoCapacity += chain(slots)
|
||||||
.map(slot => slot.m ? slot.m.get('cargo') : null)
|
.map(slot => slot.m ? slot.m.get('cargo') : null)
|
||||||
.filter()
|
.map(cargo => cargo || 0)
|
||||||
.reduce((sum, cargo) => sum + cargo)
|
.reduce((sum, cargo) => sum + cargo)
|
||||||
.value();
|
.value();
|
||||||
|
|
||||||
// handle passenger capacity
|
// handle passenger capacity
|
||||||
passengerCapacity += chain(slots)
|
passengerCapacity += chain(slots)
|
||||||
.map(slot => slot.m ? slot.m.get('passengers') : null)
|
.map(slot => slot.m ? slot.m.get('passengers') : null)
|
||||||
.filter()
|
.map(passengers => passengers || 0)
|
||||||
.reduce((sum, passengers) => sum + passengers)
|
.reduce((sum, passengers) => sum + passengers)
|
||||||
.value();
|
.value();
|
||||||
|
|
||||||
@@ -1502,7 +1506,7 @@ export default class Ship {
|
|||||||
} else {
|
} else {
|
||||||
buffer.writeInt32LE(slotMod.value, curpos);
|
buffer.writeInt32LE(slotMod.value, curpos);
|
||||||
}
|
}
|
||||||
// const modification = _.find(Modifications.modifications, function(o) { return o.id === slotMod.id; });
|
const modification = _.find(Modifications.modifications, function(o) { return o.id === slotMod.id; });
|
||||||
// console.log('ENCODE Slot ' + i + ': ' + modification.name + ' = ' + slotMod.value);
|
// console.log('ENCODE Slot ' + i + ': ' + modification.name + ' = ' + slotMod.value);
|
||||||
curpos += 4;
|
curpos += 4;
|
||||||
}
|
}
|
||||||
@@ -1515,6 +1519,7 @@ export default class Ship {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.serialized.modifications = zlib.gzipSync(buffer).toString('base64');
|
this.serialized.modifications = zlib.gzipSync(buffer).toString('base64');
|
||||||
|
// console.log(this.serialized.modifications)
|
||||||
} else {
|
} else {
|
||||||
this.serialized.modifications = null;
|
this.serialized.modifications = null;
|
||||||
}
|
}
|
||||||
@@ -1683,11 +1688,11 @@ export default class Ship {
|
|||||||
updated;
|
updated;
|
||||||
|
|
||||||
this.useBulkhead(0)
|
this.useBulkhead(0)
|
||||||
.use(standard[2], fsd) // FSD
|
.use(standard[2], fsd) // FSD
|
||||||
.use(standard[3], ls) // Life Support
|
.use(standard[3], ls) // Life Support
|
||||||
.use(standard[5], s) // Sensors
|
.use(standard[5], s) // Sensors
|
||||||
.use(standard[4], pd) // Power Distributor
|
.use(standard[4], pd) // Power Distributor
|
||||||
.use(standard[6], ft); // Fuel Tank
|
.use(standard[6], ft); // Fuel Tank
|
||||||
|
|
||||||
// Turn off nearly everything
|
// Turn off nearly everything
|
||||||
if (m.fsdDisabled) this.setSlotEnabled(this.standard[2], false);
|
if (m.fsdDisabled) this.setSlotEnabled(this.standard[2], false);
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import * as ModuleUtils from './ModuleUtils';
|
import * as ModuleUtils from './ModuleUtils';
|
||||||
|
import { Modifications } from 'coriolis-data/dist';
|
||||||
import { canMount } from '../utils/SlotFunctions';
|
import { canMount } from '../utils/SlotFunctions';
|
||||||
|
import { getBlueprint, setPercent } from '../utils/BlueprintFunctions';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standard / typical role for multi-purpose or combat (if shielded with better bulkheads)
|
* Standard / typical role for multi-purpose or combat (if shielded with better bulkheads)
|
||||||
@@ -14,7 +16,7 @@ export function multiPurpose(ship, shielded, bulkheadIndex) {
|
|||||||
.useBulkhead(bulkheadIndex);
|
.useBulkhead(bulkheadIndex);
|
||||||
|
|
||||||
if (shielded) {
|
if (shielded) {
|
||||||
ship.internal.some(function(slot) {
|
ship.internal.some(function (slot) {
|
||||||
if (canMount(ship, slot, 'sg')) { // Assuming largest slot can hold an eligible shield
|
if (canMount(ship, slot, 'sg')) { // Assuming largest slot can hold an eligible shield
|
||||||
ship.use(slot, ModuleUtils.findInternal('sg', slot.maxClass, 'A'));
|
ship.use(slot, ModuleUtils.findInternal('sg', slot.maxClass, 'A'));
|
||||||
ship.setSlotEnabled(slot, true);
|
ship.setSlotEnabled(slot, true);
|
||||||
@@ -24,6 +26,577 @@ export function multiPurpose(ship, shielded, bulkheadIndex) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Distant Worlds 2 role
|
||||||
|
* Tiers:
|
||||||
|
* 1- Max. Jump Range, Unshielded
|
||||||
|
* 2- Max. Jump Range, Minimal Shields
|
||||||
|
* 3- Max. Jump Range, Optimal Shields
|
||||||
|
* 4- Max. Jump Range, Optimal Shields & Thrusters
|
||||||
|
*
|
||||||
|
* Engineering level:
|
||||||
|
* No engineering
|
||||||
|
* Only Felicity Farseer and Elvira Martuuk
|
||||||
|
* All exploration related engineers
|
||||||
|
*
|
||||||
|
* Role
|
||||||
|
* Exploration
|
||||||
|
* Surface exploration
|
||||||
|
* Big Rig, full mining
|
||||||
|
* Saper / Prospector mining
|
||||||
|
* Fuel rat
|
||||||
|
* Repair rat
|
||||||
|
* Mechanic
|
||||||
|
* Trucker
|
||||||
|
*
|
||||||
|
* @param ship {Ship} Ship instance
|
||||||
|
* @param tier {Number}
|
||||||
|
* @param engineeringLevel {Number}
|
||||||
|
* @param role {String}
|
||||||
|
* @param gfsb {Boolean} add Guardian FSD Booster
|
||||||
|
* @param gpp {Boolean} add Guardian Power Plant
|
||||||
|
* @param fighter {Boolean} add fighter if supported
|
||||||
|
*/
|
||||||
|
export function dw2Build(ship, tier, engineeringLevel, role, gfsb, gpp, fighter) {
|
||||||
|
ship
|
||||||
|
.emptyInternal()
|
||||||
|
.emptyHardpoints()
|
||||||
|
.emptyUtility();
|
||||||
|
const fsd = ModuleUtils.findStandard('fsd', ship.standard[2].maxClass, 'A');
|
||||||
|
ship.use(ship.standard[2], fsd);
|
||||||
|
ship.use(ship.standard[3], ModuleUtils.findStandard('ls', ship.standard[3].maxClass, 'D'));
|
||||||
|
ship.use(ship.standard[4], ModuleUtils.findStandard('pd', 1, 'D'));
|
||||||
|
ship.use(ship.standard[5], ModuleUtils.findStandard('s', ship.standard[5].maxClass, 'D'));
|
||||||
|
const fuelNeeded = ship.standard[2].m.maxfuel * 2;
|
||||||
|
const fuelTank = ship.availCS.standard[6]
|
||||||
|
.filter(e => e.fuel)
|
||||||
|
.filter(e => e.fuel >= fuelNeeded);
|
||||||
|
ship.use(ship.standard[6], fuelTank[0]);
|
||||||
|
ship.useBulkhead(0, false);
|
||||||
|
if (engineeringLevel === 2) {
|
||||||
|
const bp = getBlueprint('FSD_LongRange', ship.standard[2]);
|
||||||
|
bp.grade = 5;
|
||||||
|
bp.special = Modifications.specials['special_fsd_heavy'];
|
||||||
|
ship.standard[2].m.blueprint = bp;
|
||||||
|
setPercent(ship, ship.standard[2].m, 100);
|
||||||
|
// Sensors G3 LW
|
||||||
|
const sBP = getBlueprint('Sensor_Sensor_LightWeight', ship.standard[5]);
|
||||||
|
sBP.grade = 3;
|
||||||
|
ship.standard[5].m.blueprint = sBP;
|
||||||
|
setPercent(ship, ship.standard[5].m, 100);
|
||||||
|
} else if (engineeringLevel === 3) {
|
||||||
|
// Armour G5 HD + Deep Plating
|
||||||
|
const armourBP = getBlueprint('Armour_HeavyDuty', ship.bulkheads);
|
||||||
|
armourBP.grade = 5;
|
||||||
|
armourBP.special = Modifications.specials['special_armour_chunky'];
|
||||||
|
ship.bulkheads.m.blueprint = armourBP;
|
||||||
|
setPercent(ship, ship.bulkheads.m, 100);
|
||||||
|
// FSD G5 IR + Mass Manager
|
||||||
|
const fsdBP = getBlueprint('FSD_LongRange', ship.standard[2]);
|
||||||
|
fsdBP.grade = 5;
|
||||||
|
fsdBP.special = Modifications.specials['special_fsd_heavy'];
|
||||||
|
ship.standard[2].m.blueprint = fsdBP;
|
||||||
|
setPercent(ship, ship.standard[2].m, 100);
|
||||||
|
// LS G4 LW
|
||||||
|
const lsBP = getBlueprint('LifeSupport_LightWeight', ship.standard[3]);
|
||||||
|
lsBP.grade = 4;
|
||||||
|
ship.standard[3].m.blueprint = lsBP;
|
||||||
|
setPercent(ship, ship.standard[3].m, 100);
|
||||||
|
// Sensors G5 LW
|
||||||
|
const sBP = getBlueprint('Sensor_Sensor_LightWeight', ship.standard[5]);
|
||||||
|
sBP.grade = 5;
|
||||||
|
ship.standard[5].m.blueprint = sBP;
|
||||||
|
setPercent(ship, ship.standard[5].m, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ship.id === 'imperial_clipper') {
|
||||||
|
const fs = ModuleUtils.findInternal('fs', 4, 'A');
|
||||||
|
const slot = ship.internal.filter(a => a.maxClass === 4)[0];
|
||||||
|
ship.use(slot, fs);
|
||||||
|
} else if (ship.id === 'imperial_cutter') {
|
||||||
|
const fs = ModuleUtils.findInternal('fs', 6, 'A');
|
||||||
|
const slot = ship.internal.filter(a => a.maxClass === 6)[0];
|
||||||
|
ship.use(slot, fs);
|
||||||
|
} else if (fsd.class === 2 && fsd.rating === 'A') {
|
||||||
|
let fs = ModuleUtils.findInternal('fs', 2, 'A');
|
||||||
|
let slot = ship.internal.filter(a => a.maxClass >= 2).filter(a => a.maxClass >= fs.class)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||||
|
[0];
|
||||||
|
if (slot.m) {
|
||||||
|
fs = ModuleUtils.findInternal('fs', 1, 'A');
|
||||||
|
slot = ship.internal.filter(a => a.maxClass === 1)[0];
|
||||||
|
ship.use(slot, fs);
|
||||||
|
} else {
|
||||||
|
ship.use(slot, fs);
|
||||||
|
}
|
||||||
|
} else if (fsd.class === 3 && fsd.rating === 'A') {
|
||||||
|
let fs = ModuleUtils.findInternal('fs', 3, 'B');
|
||||||
|
let slot = ship.internal.filter(a => a.maxClass >= 3).filter(a => a.maxClass >= fs.class)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||||
|
[0];
|
||||||
|
if (slot.m) {
|
||||||
|
fs = ModuleUtils.findInternal('fs', 2, 'A');
|
||||||
|
slot = ship.internal.filter(a => a.maxClass === 2)[0];
|
||||||
|
ship.use(slot, fs);
|
||||||
|
} else {
|
||||||
|
ship.use(slot, fs);
|
||||||
|
}
|
||||||
|
} else if (fsd.class === 4 && fsd.rating === 'A') {
|
||||||
|
let fs = ModuleUtils.findInternal('fs', 4, 'b');
|
||||||
|
let slot = ship.internal.filter(a => a.maxClass >= 4).filter(a => a.maxClass >= fs.class)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||||
|
[0];
|
||||||
|
if (slot.m) {
|
||||||
|
fs = ModuleUtils.findInternal('fs', 3, 'A');
|
||||||
|
slot = ship.internal.filter(a => a.maxClass === 3)[0];
|
||||||
|
ship.use(slot, fs);
|
||||||
|
} else {
|
||||||
|
ship.use(slot, fs);
|
||||||
|
}
|
||||||
|
} else if (fsd.class === 5 && fsd.rating === 'A') {
|
||||||
|
let fs = ModuleUtils.findInternal('fs', 5, 'B');
|
||||||
|
let slot = ship.internal.filter(a => a.maxClass >= 5).filter(a => a.maxClass >= fs.class)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||||
|
[0];
|
||||||
|
if (slot.m) {
|
||||||
|
fs = ModuleUtils.findInternal('fs', 4, 'A');
|
||||||
|
slot = ship.internal.filter(a => a.maxClass === 4).filter(a => a.maxClass >= fs.class)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||||
|
[0];
|
||||||
|
if (fs) {
|
||||||
|
ship.use(slot, fs);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (fs) {
|
||||||
|
ship.use(slot, fs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (fsd.class === 6 && fsd.rating === 'A') {
|
||||||
|
let fs = ModuleUtils.findInternal('fs', 6, 'B');
|
||||||
|
let slot = ship.internal.filter(a => a.maxClass >= 6)
|
||||||
|
.filter(a => a.maxClass >= fs.class)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||||
|
[0];
|
||||||
|
if (slot.m) {
|
||||||
|
fs = ModuleUtils.findInternal('fs', 5, 'A');
|
||||||
|
slot = ship.internal.filter(a => a.maxClass === 5)[0];
|
||||||
|
if (fs) {
|
||||||
|
ship.use(slot, fs);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (fs) {
|
||||||
|
ship.use(slot, fs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (fsd.class === 7 && fsd.rating === 'A') {
|
||||||
|
let fs = ModuleUtils.findInternal('fs', 7, 'B');
|
||||||
|
let slot = ship.internal.filter(a => a.maxClass >= 7).filter(a => a.maxClass >= fs.class)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||||
|
[0];
|
||||||
|
if (slot && slot.m) {
|
||||||
|
fs = ModuleUtils.findInternal('fs', 6, 'A');
|
||||||
|
slot = ship.internal.filter(a => a.maxClass === 6)[0];
|
||||||
|
if (fs) {
|
||||||
|
ship.use(slot, fs);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (fs) {
|
||||||
|
ship.use(slot, fs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tier !== 1) {
|
||||||
|
const fuelNeeded = ship.standard[2].m.maxfuel * 3;
|
||||||
|
const fuelTank = ship.availCS.standard[6]
|
||||||
|
.filter(e => e.fuel)
|
||||||
|
.filter(e => e.fuel >= fuelNeeded);
|
||||||
|
if (fuelTank[0]) {
|
||||||
|
ship.use(ship.standard[6], fuelTank[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tier === 2) {
|
||||||
|
if (ship.id === 'alliance_chieftain' || ship.id === 'alliance_crusader' || ship.id === 'federal_gunship' || ship.id === 'vulture') {
|
||||||
|
const hrp = ModuleUtils.findInternal('hrp', 3, 'D');
|
||||||
|
const slot = ship.internal.filter(e => e.eligible && e.maxClass === 3);
|
||||||
|
if (hrp) {
|
||||||
|
ship.use(slot, hrp);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const sg = ship.getAvailableModules().lightestShieldGenerator(ship.ladenMass);
|
||||||
|
const slot = ship.internal.filter(a => !a.m)
|
||||||
|
.filter(a => a.maxClass >= sg.class)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||||
|
[0];
|
||||||
|
if (sg) {
|
||||||
|
ship.use(slot, sg);
|
||||||
|
}
|
||||||
|
if (engineeringLevel === 2) {
|
||||||
|
// ELP G3
|
||||||
|
const shieldBP = getBlueprint('ShieldGenerator_Optimised', ship.findShieldGenerator());
|
||||||
|
shieldBP.grade = 3;
|
||||||
|
ship.findShieldGenerator().blueprint = shieldBP;
|
||||||
|
setPercent(ship, ship.findShieldGenerator(), 100);
|
||||||
|
} else if (engineeringLevel === 3) {
|
||||||
|
// ELP G5
|
||||||
|
const shieldBP = getBlueprint('ShieldGenerator_Optimised', ship.findShieldGenerator());
|
||||||
|
shieldBP.grade = 5;
|
||||||
|
ship.findShieldGenerator().blueprint = shieldBP;
|
||||||
|
setPercent(ship, ship.findShieldGenerator(), 100);
|
||||||
|
}
|
||||||
|
// const shieldOrder = [1, 2, 3, 4, 5, 6, 7, 8].reverse();
|
||||||
|
// const shieldInternals = ship.internal.filter(a => !a.m)
|
||||||
|
// .filter(a => (!a.eligible) || a.eligible.sg)
|
||||||
|
// .filter(a => a.maxClass >= sg.class)
|
||||||
|
// .sort((a, b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass));
|
||||||
|
// for (let i = 0; i < shieldInternals.length; i++) {
|
||||||
|
// if (canMount(ship, shieldInternals[i], 'sg')) {
|
||||||
|
// ship.use(shieldInternals[i], sg);
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
} else if (tier === 3 || tier === 4) {
|
||||||
|
const sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass, 'A');
|
||||||
|
const slot = ship.internal.filter(a => !a.m)
|
||||||
|
.filter(a => a.maxClass >= sg.class)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||||
|
[0];
|
||||||
|
if (sg) {
|
||||||
|
ship.use(slot, sg);
|
||||||
|
}
|
||||||
|
if (engineeringLevel === 1) {
|
||||||
|
// ELP G3
|
||||||
|
const shieldBP = getBlueprint('ShieldGenerator_Optimised', ship.findShieldGenerator());
|
||||||
|
shieldBP.grade = 3;
|
||||||
|
shieldBP.special = Modifications.specials['special_shield_lightweight'];
|
||||||
|
ship.findShieldGenerator().blueprint = shieldBP;
|
||||||
|
setPercent(ship, ship.findShieldGenerator(), 100);
|
||||||
|
} else if (engineeringLevel === 2) {
|
||||||
|
// ELP G5
|
||||||
|
const shieldBP = getBlueprint('ShieldGenerator_Optimised', ship.findShieldGenerator());
|
||||||
|
shieldBP.grade = 5;
|
||||||
|
shieldBP.special = Modifications.specials['special_shield_lightweight'];
|
||||||
|
ship.findShieldGenerator().blueprint = shieldBP;
|
||||||
|
setPercent(ship, ship.findShieldGenerator(), 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tier === 4) {
|
||||||
|
let t;
|
||||||
|
if (canMount(ship, ship.standard[1], 't', ship.standard[1].maxClass - 1)) {
|
||||||
|
t = ModuleUtils.findStandard('t', ship.standard[1].maxClass - 1, 'A');
|
||||||
|
} else {
|
||||||
|
t = ModuleUtils.findStandard('t', ship.standard[1].maxClass, 'A');
|
||||||
|
}
|
||||||
|
if (t) {
|
||||||
|
ship.use(ship.standard[1], t);
|
||||||
|
}
|
||||||
|
if (engineeringLevel === 1) {
|
||||||
|
// DD G3
|
||||||
|
const tBP = getBlueprint('Engine_Dirty', ship.standard[1]);
|
||||||
|
tBP.grade = 3;
|
||||||
|
tBP.special = Modifications.specials['special_engine_lightweight'];
|
||||||
|
ship.standard[1].m.blueprint = tBP;
|
||||||
|
setPercent(ship, ship.standard[1].m, 100);
|
||||||
|
} else if (engineeringLevel === 2) {
|
||||||
|
// DD G5
|
||||||
|
const tBP = getBlueprint('Engine_Dirty', ship.standard[1]);
|
||||||
|
tBP.grade = 5;
|
||||||
|
tBP.special = Modifications.specials['special_engine_lightweight'];
|
||||||
|
ship.standard[1].m.blueprint = tBP;
|
||||||
|
setPercent(ship, ship.standard[1].m, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tier === 4 || tier === 3) {
|
||||||
|
if (engineeringLevel === 3) {
|
||||||
|
const pd = ship.availCS.standard[4]
|
||||||
|
.filter(d => d.rating === 'D')
|
||||||
|
.filter(d => (d.engcap * 1.728) >= ship.boostEnergy)
|
||||||
|
.sort((a, b) => a.class.toString().localeCompare(b.class.toString()))[0];
|
||||||
|
if (pd) {
|
||||||
|
ship.use(ship.standard[4], pd);
|
||||||
|
}
|
||||||
|
// CE G5
|
||||||
|
const pdBP = getBlueprint('PowerDistributor_HighFrequency', ship.standard[4]);
|
||||||
|
pdBP.grade = 5;
|
||||||
|
pdBP.special = Modifications.specials['special_powerdistributor_capacity'];
|
||||||
|
ship.standard[4].m.blueprint = pdBP;
|
||||||
|
setPercent(ship, ship.standard[4].m, 100);
|
||||||
|
} else {
|
||||||
|
const pd = ship.availCS.standard[4]
|
||||||
|
.filter(d => d.rating === 'D')
|
||||||
|
.sort((a, b) => a.engcap > b.engcap)
|
||||||
|
[0];
|
||||||
|
if (pd) {
|
||||||
|
ship.use(ship.standard[4], pd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (tier === 4) {
|
||||||
|
if (engineeringLevel === 3) {
|
||||||
|
const pd = ship.availCS.standard[4]
|
||||||
|
.filter(d => d.rating === 'D')
|
||||||
|
.sort((a, b) => b.class.toString().localeCompare(a.class.toString()))[0];
|
||||||
|
if (pd) {
|
||||||
|
ship.use(ship.standard[4], pd);
|
||||||
|
}
|
||||||
|
// CE G5
|
||||||
|
const pdBP = getBlueprint('PowerDistributor_HighFrequency', ship.standard[4]);
|
||||||
|
pdBP.grade = 5;
|
||||||
|
pdBP.special = Modifications.specials['special_powerdistributor_capacity'];
|
||||||
|
ship.standard[4].m.blueprint = pdBP;
|
||||||
|
setPercent(ship, ship.standard[4].m, 100);
|
||||||
|
} else {
|
||||||
|
const pd = ship.availCS.standard[4]
|
||||||
|
.filter(d => d.rating === 'D')
|
||||||
|
.sort((a, b) => b.class.toString().localeCompare(a.class.toString()))[0];
|
||||||
|
if (pd) {
|
||||||
|
ship.use(ship.standard[4], pd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ship.fighterHangars && fighter) {
|
||||||
|
const slot = ship.internal.filter(s => s.maxClass >= 5 && !s.m)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))
|
||||||
|
[0];
|
||||||
|
const mod = ModuleUtils.findInternal('fh', 5, 'D');
|
||||||
|
if (slot && mod) {
|
||||||
|
ship.use(slot, mod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tier === 1) {
|
||||||
|
const pd = ModuleUtils.findStandard('pd', 1, 'D');
|
||||||
|
if (pd) {
|
||||||
|
ship.use(ship.standard[4]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let dssPriority = 0;
|
||||||
|
let srvPriority = 0;
|
||||||
|
let afmu = true;
|
||||||
|
let cargo = false;
|
||||||
|
let miningLaserPriority = 0;
|
||||||
|
let refinery = false;
|
||||||
|
let collector = false;
|
||||||
|
let prospector = false;
|
||||||
|
let miningTools = false;
|
||||||
|
let refuelLimpets = false;
|
||||||
|
let repairLimpets = false;
|
||||||
|
console.log(role);
|
||||||
|
if (role === 'exploration') {
|
||||||
|
dssPriority = 2;
|
||||||
|
afmu = true;
|
||||||
|
} else if (role === 'surface') {
|
||||||
|
dssPriority = 2;
|
||||||
|
srvPriority = 2;
|
||||||
|
} else if (role === 'materialProspector') {
|
||||||
|
miningLaserPriority = 2;
|
||||||
|
srvPriority = 1;
|
||||||
|
} else if (role === 'propectorMining') {
|
||||||
|
dssPriority = 1;
|
||||||
|
prospector = true;
|
||||||
|
miningLaserPriority = 1;
|
||||||
|
cargo = true;
|
||||||
|
miningTools = true;
|
||||||
|
|
||||||
|
} else if (role === 'bigRigMining') {
|
||||||
|
dssPriority = 1;
|
||||||
|
miningLaserPriority = 2;
|
||||||
|
cargo = true;
|
||||||
|
collector = true;
|
||||||
|
refinery = true;
|
||||||
|
miningTools = true;
|
||||||
|
|
||||||
|
} else if (role === 'fuelRat') {
|
||||||
|
refuelLimpets = true;
|
||||||
|
cargo = true;
|
||||||
|
srvPriority = 1;
|
||||||
|
|
||||||
|
} else if (role === 'mechanic') {
|
||||||
|
repairLimpets = true;
|
||||||
|
cargo = true;
|
||||||
|
srvPriority = 1;
|
||||||
|
} else if (role === 'trucker') {
|
||||||
|
cargo = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dssPriority === 2) {
|
||||||
|
const mod = ModuleUtils.findModule('ss', '2i');
|
||||||
|
const slot = ship.internal.filter(s => !s.m)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||||
|
console.log(slot);
|
||||||
|
console.log(mod);
|
||||||
|
ship.use(slot, mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (srvPriority === 2) {
|
||||||
|
let mod;
|
||||||
|
let slot = ship.internal.filter(s => !s.m)
|
||||||
|
.filter(s => s.maxClass >= 6)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||||
|
if (slot) {
|
||||||
|
mod = ModuleUtils.findModule('pv', 'v2');
|
||||||
|
ship.use(slot, mod);
|
||||||
|
} else if (!slot) {
|
||||||
|
slot = ship.internal.filter(s => !s.m)
|
||||||
|
.filter(s => s.maxClass >= 4)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||||
|
if (slot) {
|
||||||
|
mod = ModuleUtils.findModule('pv', 'v4');
|
||||||
|
ship.use(slot, mod);
|
||||||
|
} else {
|
||||||
|
slot = ship.internal.filter(s => !s.m)
|
||||||
|
.filter(s => s.maxClass >= 2)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||||
|
if (slot) {
|
||||||
|
mod = ModuleUtils.findModule('pv', 'v6');
|
||||||
|
ship.use(slot, mod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cargo === true) {
|
||||||
|
const slot = ship.internal.filter(s => !s.m)
|
||||||
|
.sort((a, b) => b.maxClass.toString().localeCompare(a.maxClass.toString()))[0];
|
||||||
|
const mod = ModuleUtils.findInternal('cr', slot.maxClass, 'E');
|
||||||
|
ship.use(slot, mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refuelLimpets === true) {
|
||||||
|
const mod = ModuleUtils.findModule('fx', 'F4');
|
||||||
|
const slot = ship.internal.filter(s => !s.m)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||||
|
ship.use(mod, slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (repairLimpets === true) {
|
||||||
|
const slot = ship.internal.filter(s => !s.m)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||||
|
let mod;
|
||||||
|
if (slot.maxClass >= 3) {
|
||||||
|
mod = ModuleUtils.findModule('rpl', '9e');
|
||||||
|
} else {
|
||||||
|
mod = ModuleUtils.findModule('rpl', '9s');
|
||||||
|
}
|
||||||
|
ship.use(mod, slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prospector === true) {
|
||||||
|
const slot = ship.internal.filter(s => !s.m)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||||
|
let mod;
|
||||||
|
if (slot.maxClass >= 3) {
|
||||||
|
mod = ModuleUtils.findModule('pc', 'P9');
|
||||||
|
} else {
|
||||||
|
mod = ModuleUtils.findModule('pc', 'P4');
|
||||||
|
}
|
||||||
|
ship.use(mod, slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collector === true) {
|
||||||
|
const slots = ship.internal.filter(s => !s.m)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()));
|
||||||
|
if (slots.length >= 2) {
|
||||||
|
let slot = slots.find(s => s.maxClass >= 5);
|
||||||
|
let mod;
|
||||||
|
if (slot) {
|
||||||
|
mod = ModuleUtils.findInternal('cc', slot.maxClass, 'D');
|
||||||
|
} else if (slots.find(s => s.maxClass <= 4)) {
|
||||||
|
slot = slots.find(s => s.maxClass <= 4);
|
||||||
|
mod = ModuleUtils.findInternal('cc', slot.maxClass, 'D');
|
||||||
|
}
|
||||||
|
ship.use(slot, mod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refinery === true) {
|
||||||
|
const slots = ship.internal.filter(s => !s.m)
|
||||||
|
.filter(s => s.maxClass >= 4)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||||
|
if (slots) {
|
||||||
|
const mod = ModuleUtils.findInternal('rf', 4, 'A');
|
||||||
|
ship.use(slots, mod);
|
||||||
|
} else {
|
||||||
|
const slot = ship.internal.filter(s => !s.m)
|
||||||
|
.filter(s => s.maxClass <= 3)
|
||||||
|
.sort((a, b) => b.maxClass.toString().localeCompare(a.maxClass.toString()))[0];
|
||||||
|
const mod = ModuleUtils.findInternal('rf', slot.maxClass, 'A');
|
||||||
|
ship.use(slots, mod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dssPriority === 1) {
|
||||||
|
const slot = ship.internal.filter(s => !s.m)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()))[0];
|
||||||
|
const dss = ModuleUtils.findInternal('ss', 1, 'C')
|
||||||
|
if (slot) {
|
||||||
|
ship.use(slot, dss);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (srvPriority === 1) {
|
||||||
|
const slot = ship.internal.filter(s => !s.m)
|
||||||
|
.filter(s => s.maxClass >= 2)
|
||||||
|
.sort((a, b) => a.maxClass.toString().localeCompare(b.maxClass.toString()));
|
||||||
|
if (slot.find(s => s.maxClass >= 4)) {
|
||||||
|
const slot = slot.find(s => s.maxClass >= 4);
|
||||||
|
const srv = ModuleUtils.findInternal('pv', 4, 'G')
|
||||||
|
ship.use(slot, srv);
|
||||||
|
} else if (slot.find(s => s.maxClass >= 2)) {
|
||||||
|
const slot = slot.find(s => s.maxClass >= 2);
|
||||||
|
const srv = ModuleUtils.findInternal('pv', 2, 'G')
|
||||||
|
ship.use(slot, srv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gfsb === true) {
|
||||||
|
const slots = ship.internal.filter(s => !s.m)
|
||||||
|
.filter(s => s.maxClass >= 1)
|
||||||
|
.sort((a, b) => b.maxClass.toString().localeCompare(a.maxClass.toString()));
|
||||||
|
if (slots.find(s => s.maxClass >= 5)) {
|
||||||
|
const mod = ModuleUtils.findInternal('gfsb', 5, 'H');
|
||||||
|
ship.use(slots.find(s => s.maxClass >= 5), mod)
|
||||||
|
} else if (slots.find(s => s.maxClass >= 4)) {
|
||||||
|
const mod = ModuleUtils.findInternal('gfsb', 4, 'H');
|
||||||
|
ship.use(slots.find(s => s.maxClass >= 4), mod)
|
||||||
|
} else if (slots.find(s => s.maxClass >= 3)) {
|
||||||
|
const mod = ModuleUtils.findInternal('gfsb', 3, 'H');
|
||||||
|
ship.use(slots.find(s => s.maxClass >= 3), mod)
|
||||||
|
} else if (slots.find(s => s.maxClass >= 2)) {
|
||||||
|
const mod = ModuleUtils.findInternal('gfsb', 2, 'H');
|
||||||
|
ship.use(slots.find(s => s.maxClass >= 2), mod)
|
||||||
|
} else if (slots.find(s => s.maxClass >= 1)) {
|
||||||
|
const mod = ModuleUtils.findInternal('gfsb', 1, 'H');
|
||||||
|
ship.use(slots.find(s => s.maxClass >= 1), mod)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// const pp = ship.getAvailableModules().lightestPowerPlant(Math.max(ship.powerRetracted, ship.powerDeployed), 'A');
|
||||||
|
// const t = ship.getAvailableModules().lightestThruster(ship.ladenMass);
|
||||||
|
// ship.use(ship.standard[0], pp);
|
||||||
|
// ship.use(ship.standard[1], t);
|
||||||
|
|
||||||
|
// ship.useLightestStandard(standardOpts);
|
||||||
|
ship.updatePowerGenerated()
|
||||||
|
.updatePowerUsed()
|
||||||
|
.recalculateMass()
|
||||||
|
.updateJumpStats()
|
||||||
|
.recalculateShield()
|
||||||
|
.recalculateShieldCells()
|
||||||
|
.recalculateArmour()
|
||||||
|
.recalculateDps()
|
||||||
|
.recalculateEps()
|
||||||
|
.recalculateHps()
|
||||||
|
.updateMovement()
|
||||||
|
.updateModificationsString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trader Role
|
* Trader Role
|
||||||
* @param {Ship} ship Ship instance
|
* @param {Ship} ship Ship instance
|
||||||
@@ -36,7 +609,7 @@ export function trader(ship, shielded, standardOpts) {
|
|||||||
let sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
|
let sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
|
||||||
ship.useStandard('A')
|
ship.useStandard('A')
|
||||||
.use(ship.standard[3], ModuleUtils.standard(3, ship.standard[3].maxClass + 'D')) // D Life Support
|
.use(ship.standard[3], ModuleUtils.standard(3, ship.standard[3].maxClass + 'D')) // D Life Support
|
||||||
.use(ship.standard[1], ModuleUtils.standard(1, ship.standard[1].maxClass + 'D')) // D Life Support
|
.use(ship.standard[1], ModuleUtils.standard(1, ship.standard[1].maxClass + 'D')) // D Power Plant
|
||||||
.use(ship.standard[4], ModuleUtils.standard(4, ship.standard[4].maxClass + 'D')) // D Life Support
|
.use(ship.standard[4], ModuleUtils.standard(4, ship.standard[4].maxClass + 'D')) // D Life Support
|
||||||
.use(ship.standard[5], ModuleUtils.standard(5, ship.standard[5].maxClass + 'D')); // D Sensors
|
.use(ship.standard[5], ModuleUtils.standard(5, ship.standard[5].maxClass + 'D')); // D Sensors
|
||||||
|
|
||||||
@@ -45,7 +618,7 @@ export function trader(ship, shielded, standardOpts) {
|
|||||||
.filter(a => (!a.eligible) || a.eligible.sg)
|
.filter(a => (!a.eligible) || a.eligible.sg)
|
||||||
.filter(a => a.maxClass >= sg.class)
|
.filter(a => a.maxClass >= sg.class)
|
||||||
.sort((a, b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass));
|
.sort((a, b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass));
|
||||||
shieldInternals.some(function(slot) {
|
shieldInternals.some(function (slot) {
|
||||||
if (canMount(ship, slot, 'sg')) { // Assuming largest slot can hold an eligible shield
|
if (canMount(ship, slot, 'sg')) { // Assuming largest slot can hold an eligible shield
|
||||||
const shield = ModuleUtils.findInternal('sg', slot.maxClass, 'A');
|
const shield = ModuleUtils.findInternal('sg', slot.maxClass, 'A');
|
||||||
if (shield && shield.maxmass > ship.hullMass) {
|
if (shield && shield.maxmass > ship.hullMass) {
|
||||||
@@ -87,11 +660,11 @@ export function trader(ship, shielded, standardOpts) {
|
|||||||
*/
|
*/
|
||||||
export function explorer(ship, planetary) {
|
export function explorer(ship, planetary) {
|
||||||
let standardOpts = { ppRating: 'A' },
|
let standardOpts = { ppRating: 'A' },
|
||||||
heatSinkCount = 2, // Fit 2 heat sinks if possible
|
heatSinkCount = 2, // Fit 2 heat sinks if possible
|
||||||
usedSlots = [],
|
usedSlots = [],
|
||||||
sgSlot,
|
sgSlot,
|
||||||
fuelScoopSlot,
|
fuelScoopSlot,
|
||||||
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
|
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
|
||||||
|
|
||||||
if (!planetary) { // Non-planetary explorers don't really need to boost
|
if (!planetary) { // Non-planetary explorers don't really need to boost
|
||||||
standardOpts.pd = '1D';
|
standardOpts.pd = '1D';
|
||||||
@@ -216,9 +789,9 @@ export function explorer(ship, planetary) {
|
|||||||
export function miner(ship, shielded) {
|
export function miner(ship, shielded) {
|
||||||
shielded = true;
|
shielded = true;
|
||||||
let standardOpts = { ppRating: 'A' },
|
let standardOpts = { ppRating: 'A' },
|
||||||
miningLaserCount = 2,
|
miningLaserCount = 2,
|
||||||
usedSlots = [],
|
usedSlots = [],
|
||||||
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
|
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
|
||||||
|
|
||||||
// Cargo hatch should be enabled
|
// Cargo hatch should be enabled
|
||||||
ship.setSlotEnabled(ship.cargoHatch, true);
|
ship.setSlotEnabled(ship.cargoHatch, true);
|
||||||
@@ -269,7 +842,7 @@ export function miner(ship, shielded) {
|
|||||||
|
|
||||||
// Dual mining lasers of highest possible class; remove anything else
|
// Dual mining lasers of highest possible class; remove anything else
|
||||||
const miningLaserOrder = [2, 3, 4, 1, 0];
|
const miningLaserOrder = [2, 3, 4, 1, 0];
|
||||||
const miningLaserHardpoints = ship.hardpoints.concat().sort(function(a, b) {
|
const miningLaserHardpoints = ship.hardpoints.concat().sort(function (a, b) {
|
||||||
return miningLaserOrder.indexOf(a.maxClass) - miningLaserOrder.indexOf(b.maxClass);
|
return miningLaserOrder.indexOf(a.maxClass) - miningLaserOrder.indexOf(b.maxClass);
|
||||||
});
|
});
|
||||||
for (let s of miningLaserHardpoints) {
|
for (let s of miningLaserHardpoints) {
|
||||||
@@ -283,7 +856,7 @@ export function miner(ship, shielded) {
|
|||||||
|
|
||||||
// Number of collector limpets required to be active is a function of the size of the ship and the power of the lasers
|
// Number of collector limpets required to be active is a function of the size of the ship and the power of the lasers
|
||||||
const miningLaserDps = ship.hardpoints.filter(h => h.m != null)
|
const miningLaserDps = ship.hardpoints.filter(h => h.m != null)
|
||||||
.reduce(function(a, b) {
|
.reduce(function (a, b) {
|
||||||
return a + b.m.getDps();
|
return a + b.m.getDps();
|
||||||
}, 0);
|
}, 0);
|
||||||
// Find out how many internal slots we have, and their potential cargo size
|
// Find out how many internal slots we have, and their potential cargo size
|
||||||
@@ -314,7 +887,7 @@ export function miner(ship, shielded) {
|
|||||||
|
|
||||||
// Power distributor to power the mining lasers indefinitely
|
// Power distributor to power the mining lasers indefinitely
|
||||||
const wepRateRequired = ship.hardpoints.filter(h => h.m != null)
|
const wepRateRequired = ship.hardpoints.filter(h => h.m != null)
|
||||||
.reduce(function(a, b) {
|
.reduce(function (a, b) {
|
||||||
return a + b.m.getEps();
|
return a + b.m.getEps();
|
||||||
}, 0);
|
}, 0);
|
||||||
standardOpts.pd = ship.getAvailableModules().matchingPowerDist({ weprate: wepRateRequired }).id;
|
standardOpts.pd = ship.getAvailableModules().matchingPowerDist({ weprate: wepRateRequired }).id;
|
||||||
@@ -336,9 +909,9 @@ export function miner(ship, shielded) {
|
|||||||
*/
|
*/
|
||||||
export function racer(ship) {
|
export function racer(ship) {
|
||||||
let standardOpts = {},
|
let standardOpts = {},
|
||||||
usedSlots = [],
|
usedSlots = [],
|
||||||
sgSlot,
|
sgSlot,
|
||||||
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
|
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass);
|
||||||
|
|
||||||
// Cargo hatch can be disabled
|
// Cargo hatch can be disabled
|
||||||
ship.setSlotEnabled(ship.cargoHatch, false);
|
ship.setSlotEnabled(ship.cargoHatch, false);
|
||||||
|
|||||||
@@ -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' },
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ function _delete(key) {
|
|||||||
* export is an instance (see end of this file).
|
* export is an instance (see end of this file).
|
||||||
*/
|
*/
|
||||||
export class Persist extends EventEmitter {
|
export class Persist extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an instance
|
* Create an instance
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,417 +1,417 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Modifications } from 'coriolis-data/dist';
|
import { Modifications } from 'coriolis-data/dist';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a tooltip with details of a blueprint's specials
|
* Generate a tooltip with details of a blueprint's specials
|
||||||
* @param {Object} translate The translate object
|
* @param {Object} translate The translate object
|
||||||
* @param {Object} blueprint The blueprint at the required grade
|
* @param {Object} blueprint The blueprint at the required grade
|
||||||
* @param {string} grp The group of the module
|
* @param {string} grp The group of the module
|
||||||
* @param {Object} m The module to compare with
|
* @param {Object} m The module to compare with
|
||||||
* @param {string} specialName The name of the special
|
* @param {string} specialName The name of the special
|
||||||
* @returns {Object} The react components
|
* @returns {Object} The react components
|
||||||
*/
|
*/
|
||||||
export function specialToolTip(translate, blueprint, grp, m, specialName) {
|
export function specialToolTip(translate, blueprint, grp, m, specialName) {
|
||||||
const effects = [];
|
const effects = [];
|
||||||
if (!blueprint || !blueprint.features) {
|
if (!blueprint || !blueprint.features) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
if (m) {
|
if (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) {
|
if (m.blueprint) {
|
||||||
for (const feature in Modifications.modifierActions[specialName]) {
|
for (const feature in Modifications.modifierActions[specialName]) {
|
||||||
// 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) {
|
||||||
let symbol = '';
|
let symbol = '';
|
||||||
if (feature === 'jitter') {
|
if (feature === 'jitter') {
|
||||||
symbol = '°';
|
symbol = '°';
|
||||||
} else if (featureDef.type === 'percentage') {
|
} else if (featureDef.type === 'percentage') {
|
||||||
symbol = '%';
|
symbol = '%';
|
||||||
}
|
}
|
||||||
let current = m.getModValue(feature) - m.getModValue(feature, true);
|
let current = m.getModValue(feature) - m.getModValue(feature, true);
|
||||||
if (featureDef.type === 'percentage') {
|
if (featureDef.type === 'percentage') {
|
||||||
current = Math.round(current / 10) / 10;
|
current = Math.round(current / 10) / 10;
|
||||||
} else if (featureDef.type === 'numeric') {
|
} else if (featureDef.type === 'numeric') {
|
||||||
current /= 100;
|
current /= 100;
|
||||||
}
|
}
|
||||||
const currentIsBeneficial = isValueBeneficial(feature, current);
|
const currentIsBeneficial = isValueBeneficial(feature, current);
|
||||||
|
|
||||||
effects.push(
|
effects.push(
|
||||||
<tr key={feature + '_specialTT'}>
|
<tr key={feature + '_specialTT'}>
|
||||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'}
|
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'}
|
||||||
style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<table width='100%'>
|
<table width='100%'>
|
||||||
<tbody>
|
<tbody>
|
||||||
{effects}
|
{effects}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a tooltip with details of a blueprint's effects
|
* Generate a tooltip with details of a blueprint's effects
|
||||||
* @param {Object} translate The translate object
|
* @param {Object} translate The translate object
|
||||||
* @param {Object} blueprint The blueprint at the required grade
|
* @param {Object} blueprint The blueprint at the required grade
|
||||||
* @param {Array} engineers The engineers supplying this blueprint
|
* @param {Array} engineers The engineers supplying this blueprint
|
||||||
* @param {string} grp The group of the module
|
* @param {string} grp The group of the module
|
||||||
* @param {Object} m The module to compare with
|
* @param {Object} m The module to compare with
|
||||||
* @returns {Object} The react components
|
* @returns {Object} The react components
|
||||||
*/
|
*/
|
||||||
export function blueprintTooltip(translate, blueprint, engineers, grp, m) {
|
export function blueprintTooltip(translate, blueprint, engineers, grp, m) {
|
||||||
const effects = [];
|
const effects = [];
|
||||||
if (!blueprint || !blueprint.features) {
|
if (!blueprint || !blueprint.features) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
for (const feature in blueprint.features) {
|
for (const feature in blueprint.features) {
|
||||||
const featureIsBeneficial = isBeneficial(feature, blueprint.features[feature]);
|
const featureIsBeneficial = isBeneficial(feature, blueprint.features[feature]);
|
||||||
const featureDef = Modifications.modifications[feature];
|
const featureDef = Modifications.modifications[feature];
|
||||||
if (!featureDef.hidden) {
|
if (!featureDef.hidden) {
|
||||||
let symbol = '';
|
let symbol = '';
|
||||||
if (feature === 'jitter') {
|
if (feature === 'jitter') {
|
||||||
symbol = '°';
|
symbol = '°';
|
||||||
} else if (featureDef.type === 'percentage') {
|
} else if (featureDef.type === 'percentage') {
|
||||||
symbol = '%';
|
symbol = '%';
|
||||||
}
|
}
|
||||||
let lowerBound = blueprint.features[feature][0];
|
let lowerBound = blueprint.features[feature][0];
|
||||||
let upperBound = blueprint.features[feature][1];
|
let upperBound = blueprint.features[feature][1];
|
||||||
if (featureDef.type === 'percentage') {
|
if (featureDef.type === 'percentage') {
|
||||||
lowerBound = Math.round(lowerBound * 1000) / 10;
|
lowerBound = Math.round(lowerBound * 1000) / 10;
|
||||||
upperBound = Math.round(upperBound * 1000) / 10;
|
upperBound = Math.round(upperBound * 1000) / 10;
|
||||||
}
|
}
|
||||||
const lowerIsBeneficial = isValueBeneficial(feature, lowerBound);
|
const lowerIsBeneficial = isValueBeneficial(feature, lowerBound);
|
||||||
const upperIsBeneficial = isValueBeneficial(feature, upperBound);
|
const upperIsBeneficial = isValueBeneficial(feature, upperBound);
|
||||||
if (m) {
|
if (m) {
|
||||||
// We have a module - add in the current value
|
// We have a module - add in the current value
|
||||||
let current = m.getModValue(feature);
|
let current = m.getModValue(feature);
|
||||||
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
|
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
|
||||||
current = Math.round(current / 10) / 10;
|
current = Math.round(current / 10) / 10;
|
||||||
} else if (featureDef.type === 'numeric') {
|
} else if (featureDef.type === 'numeric') {
|
||||||
current /= 100;
|
current /= 100;
|
||||||
}
|
}
|
||||||
const currentIsBeneficial = isValueBeneficial(feature, current);
|
const currentIsBeneficial = isValueBeneficial(feature, current);
|
||||||
effects.push(
|
effects.push(
|
||||||
<tr key={feature}>
|
<tr key={feature}>
|
||||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
||||||
<td className={lowerBound === 0 ? '' : lowerIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{lowerBound}{symbol}</td>
|
<td className={lowerBound === 0 ? '' : lowerIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{lowerBound}{symbol}</td>
|
||||||
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
||||||
<td className={upperBound === 0 ? '' : upperIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{upperBound}{symbol}</td>
|
<td className={upperBound === 0 ? '' : upperIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{upperBound}{symbol}</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// We do not have a module, no value
|
// We do not have a module, no value
|
||||||
effects.push(
|
effects.push(
|
||||||
<tr key={feature}>
|
<tr key={feature}>
|
||||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
||||||
<td className={lowerBound === 0 ? '' : lowerIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{lowerBound}{symbol}</td>
|
<td className={lowerBound === 0 ? '' : lowerIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{lowerBound}{symbol}</td>
|
||||||
<td className={upperBound === 0 ? '' : upperIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{upperBound}{symbol}</td>
|
<td className={upperBound === 0 ? '' : upperIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{upperBound}{symbol}</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m) {
|
if (m) {
|
||||||
// Because we have a module add in any benefits that aren't part of the primary blueprint
|
// Because we have a module add in any benefits that aren't part of the primary blueprint
|
||||||
for (const feature in m.mods) {
|
for (const feature in m.mods) {
|
||||||
if (!blueprint.features[feature]) {
|
if (!blueprint.features[feature]) {
|
||||||
const featureDef = Modifications.modifications[feature];
|
const featureDef = Modifications.modifications[feature];
|
||||||
if (featureDef && !featureDef.hidden) {
|
if (featureDef && !featureDef.hidden) {
|
||||||
let symbol = '';
|
let symbol = '';
|
||||||
if (feature === 'jitter') {
|
if (feature === 'jitter') {
|
||||||
symbol = '°';
|
symbol = '°';
|
||||||
} else if (featureDef.type === 'percentage') {
|
} else if (featureDef.type === 'percentage') {
|
||||||
symbol = '%';
|
symbol = '%';
|
||||||
}
|
}
|
||||||
let current = m.getModValue(feature);
|
let current = m.getModValue(feature);
|
||||||
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
|
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
|
||||||
current = Math.round(current / 10) / 10;
|
current = Math.round(current / 10) / 10;
|
||||||
} else if (featureDef.type === 'numeric') {
|
} else if (featureDef.type === 'numeric') {
|
||||||
current /= 100;
|
current /= 100;
|
||||||
}
|
}
|
||||||
const currentIsBeneficial = isValueBeneficial(feature, current);
|
const currentIsBeneficial = isValueBeneficial(feature, current);
|
||||||
effects.push(
|
effects.push(
|
||||||
<tr key={feature}>
|
<tr key={feature}>
|
||||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.edname]) {
|
||||||
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) {
|
||||||
let symbol = '';
|
let symbol = '';
|
||||||
if (feature === 'jitter') {
|
if (feature === 'jitter') {
|
||||||
symbol = '°';
|
symbol = '°';
|
||||||
} else if (featureDef.type === 'percentage') {
|
} else if (featureDef.type === 'percentage') {
|
||||||
symbol = '%';
|
symbol = '%';
|
||||||
}
|
}
|
||||||
let current = m.getModValue(feature);
|
let current = m.getModValue(feature);
|
||||||
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
|
if (featureDef.type === 'percentage' || featureDef.name === 'burst' || featureDef.name === 'burstrof') {
|
||||||
current = Math.round(current / 10) / 10;
|
current = Math.round(current / 10) / 10;
|
||||||
} else if (featureDef.type === 'numeric') {
|
} else if (featureDef.type === 'numeric') {
|
||||||
current /= 100;
|
current /= 100;
|
||||||
}
|
}
|
||||||
const currentIsBeneficial = isValueBeneficial(feature, current);
|
const currentIsBeneficial = isValueBeneficial(feature, current);
|
||||||
effects.push(
|
effects.push(
|
||||||
<tr key={feature}>
|
<tr key={feature}>
|
||||||
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
<td style={{ textAlign: 'left' }}>{translate(feature, grp)}</td>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
<td className={current === 0 ? '' : currentIsBeneficial ? 'secondary' : 'warning'} style={{ textAlign: 'right' }}>{current}{symbol}</td>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let components;
|
let components;
|
||||||
if (!m) {
|
if (!m) {
|
||||||
components = [];
|
components = [];
|
||||||
for (const component in blueprint.components) {
|
for (const component in blueprint.components) {
|
||||||
components.push(
|
components.push(
|
||||||
<tr key={component}>
|
<tr key={component}>
|
||||||
<td style={{ textAlign: 'left' }}>{translate(component)}</td>
|
<td style={{ textAlign: 'left' }}>{translate(component)}</td>
|
||||||
<td style={{ textAlign: 'right' }}>{blueprint.components[component]}</td>
|
<td style={{ textAlign: 'right' }}>{blueprint.components[component]}</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let engineersList;
|
let engineersList;
|
||||||
if (engineers) {
|
if (engineers) {
|
||||||
engineersList = [];
|
engineersList = [];
|
||||||
for (const engineer of engineers) {
|
for (const engineer of engineers) {
|
||||||
engineersList.push(
|
engineersList.push(
|
||||||
<tr key={engineer}>
|
<tr key={engineer}>
|
||||||
<td style={{ textAlign: 'left' }}>{engineer}</td>
|
<td style={{ textAlign: 'left' }}>{engineer}</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<table width='100%'>
|
<table width='100%'>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{translate('feature')}</td>
|
<td>{translate('feature')}</td>
|
||||||
<td>{translate('worst')}</td>
|
<td>{translate('worst')}</td>
|
||||||
{m ? <td>{translate('current')}</td> : null }
|
{m ? <td>{translate('current')}</td> : null }
|
||||||
<td>{translate('best')}</td>
|
<td>{translate('best')}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{effects}
|
{effects}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{ components ? <table width='100%'>
|
{ components ? <table width='100%'>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{translate('component')}</td>
|
<td>{translate('component')}</td>
|
||||||
<td>{translate('amount')}</td>
|
<td>{translate('amount')}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{components}
|
{components}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table> : null }
|
</table> : null }
|
||||||
{ engineersList ? <table width='100%'>
|
{ engineersList ? <table width='100%'>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{translate('engineers')}</td>
|
<td>{translate('engineers')}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{engineersList}
|
{engineersList}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table> : null }
|
</table> : null }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this blueprint feature beneficial?
|
* Is this blueprint feature beneficial?
|
||||||
* @param {string} feature The name of the feature
|
* @param {string} feature The name of the feature
|
||||||
* @param {array} values The value of the feature
|
* @param {array} values The value of the feature
|
||||||
* @returns {boolean} True if this feature is beneficial
|
* @returns {boolean} True if this feature is beneficial
|
||||||
*/
|
*/
|
||||||
export function isBeneficial(feature, values) {
|
export function isBeneficial(feature, values) {
|
||||||
const fact = (values[0] < 0 || (values[0] === 0 && values[1] < 0));
|
const fact = (values[0] < 0 || (values[0] === 0 && values[1] < 0));
|
||||||
if (Modifications.modifications[feature].higherbetter) {
|
if (Modifications.modifications[feature].higherbetter) {
|
||||||
return !fact;
|
return !fact;
|
||||||
} else {
|
} else {
|
||||||
return fact;
|
return fact;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this feature value beneficial?
|
* Is this feature value beneficial?
|
||||||
* @param {string} feature The name of the feature
|
* @param {string} feature The name of the feature
|
||||||
* @param {number} value The value of the feature
|
* @param {number} value The value of the feature
|
||||||
* @returns {boolean} True if this value is beneficial
|
* @returns {boolean} True if this value is beneficial
|
||||||
*/
|
*/
|
||||||
export function isValueBeneficial(feature, value) {
|
export function isValueBeneficial(feature, value) {
|
||||||
if (Modifications.modifications[feature].higherbetter) {
|
if (Modifications.modifications[feature].higherbetter) {
|
||||||
return value > 0;
|
return value > 0;
|
||||||
} else {
|
} else {
|
||||||
return value < 0;
|
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
|
||||||
* @param {Object} module The module for which to obtain this blueprint
|
* @param {Object} module The module for which to obtain this blueprint
|
||||||
* @returns {Object} The matching blueprint
|
* @returns {Object} The matching blueprint
|
||||||
*/
|
*/
|
||||||
export function getBlueprint(name, module) {
|
export function getBlueprint(name, module) {
|
||||||
// Start with a copy of the blueprint
|
// Start with a copy of the blueprint
|
||||||
const findMod = val => Object.keys(Modifications.blueprints).find(elem => elem.toString().toLowerCase().search(val.toString().toLowerCase().replace(/(OutfittingFieldType_|persecond)/igm, '')) >= 0);
|
const findMod = val => Object.keys(Modifications.blueprints).find(elem => elem.toString().toLowerCase().search(val.toString().toLowerCase().replace(/(OutfittingFieldType_|persecond)/igm, '')) >= 0);
|
||||||
const found = Modifications.blueprints[findMod(name)];
|
const found = Modifications.blueprints[findMod(name)];
|
||||||
if (!found || !found.fdname) {
|
if (!found || !found.fdname) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
const blueprint = JSON.parse(JSON.stringify(found));
|
const blueprint = JSON.parse(JSON.stringify(found));
|
||||||
return blueprint;
|
return blueprint;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide 'percent' primary modifications
|
* Provide 'percent' primary modifications
|
||||||
* @param {Object} ship The ship for which to perform the modifications
|
* @param {Object} ship The ship for which to perform the modifications
|
||||||
* @param {Object} m The module for which to perform the modifications
|
* @param {Object} m The module for which to perform the modifications
|
||||||
* @param {Number} percent The percent to set values to of full.
|
* @param {Number} percent The percent to set values to of full.
|
||||||
*/
|
*/
|
||||||
export function setPercent(ship, m, percent) {
|
export function setPercent(ship, m, percent) {
|
||||||
ship.clearModifications(m);
|
ship.clearModifications(m);
|
||||||
// Pick given value as multiplier
|
// Pick given value as multiplier
|
||||||
const mult = percent / 100;
|
const mult = percent / 100;
|
||||||
const features = m.blueprint.grades[m.blueprint.grade].features;
|
const features = m.blueprint.grades[m.blueprint.grade].features;
|
||||||
for (const featureName in features) {
|
for (const featureName in features) {
|
||||||
let value;
|
let value;
|
||||||
if (Modifications.modifications[featureName].higherbetter) {
|
if (Modifications.modifications[featureName].higherbetter) {
|
||||||
// Higher is better, but is this making it better or worse?
|
// Higher is better, but is this making it better or worse?
|
||||||
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
||||||
value = features[featureName][1] + ((features[featureName][0] - features[featureName][1]) * mult);
|
value = features[featureName][1] + ((features[featureName][0] - features[featureName][1]) * mult);
|
||||||
} else {
|
} else {
|
||||||
value = features[featureName][0] + ((features[featureName][1] - features[featureName][0]) * mult);
|
value = features[featureName][0] + ((features[featureName][1] - features[featureName][0]) * mult);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Higher is worse, but is this making it better or worse?
|
// Higher is worse, but is this making it better or worse?
|
||||||
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
||||||
value = features[featureName][0] + ((features[featureName][1] - features[featureName][0]) * mult);
|
value = features[featureName][0] + ((features[featureName][1] - features[featureName][0]) * mult);
|
||||||
} else {
|
} else {
|
||||||
value = features[featureName][1] + ((features[featureName][0] - features[featureName][1]) * mult);
|
value = features[featureName][1] + ((features[featureName][0] - features[featureName][1]) * mult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_setValue(ship, m, featureName, value);
|
_setValue(ship, m, featureName, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide 'random' primary modifications
|
* Provide 'random' primary modifications
|
||||||
* @param {Object} ship The ship for which to perform the modifications
|
* @param {Object} ship The ship for which to perform the modifications
|
||||||
* @param {Object} m The module for which to perform the modifications
|
* @param {Object} m The module for which to perform the modifications
|
||||||
*/
|
*/
|
||||||
export function setRandom(ship, m) {
|
export function setRandom(ship, m) {
|
||||||
// Pick a single value for our randomness
|
// Pick a single value for our randomness
|
||||||
setPercent(ship, m, Math.random() * 100);
|
setPercent(ship, m, Math.random() * 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a modification feature value
|
* Set a modification feature value
|
||||||
* @param {Object} ship The ship for which to perform the modifications
|
* @param {Object} ship The ship for which to perform the modifications
|
||||||
* @param {Object} m The module for which to perform the modifications
|
* @param {Object} m The module for which to perform the modifications
|
||||||
* @param {string} featureName The feature being set
|
* @param {string} featureName The feature being set
|
||||||
* @param {number} value The value being set for the feature
|
* @param {number} value The value being set for the feature
|
||||||
*/
|
*/
|
||||||
function _setValue(ship, m, featureName, value) {
|
function _setValue(ship, m, featureName, value) {
|
||||||
if (Modifications.modifications[featureName].type == 'percentage') {
|
if (Modifications.modifications[featureName].type == 'percentage') {
|
||||||
ship.setModification(m, featureName, value * 10000);
|
ship.setModification(m, featureName, value * 10000);
|
||||||
} else if (Modifications.modifications[featureName].type == 'numeric') {
|
} else if (Modifications.modifications[featureName].type == 'numeric') {
|
||||||
ship.setModification(m, featureName, value * 100);
|
ship.setModification(m, featureName, value * 100);
|
||||||
} else {
|
} else {
|
||||||
ship.setModification(m, featureName, value);
|
ship.setModification(m, featureName, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide 'percent' primary query
|
* Provide 'percent' primary query
|
||||||
* @param {Object} m The module for which to perform the query
|
* @param {Object} m The module for which to perform the query
|
||||||
* @returns {Number} percent The percentage indicator of current applied values.
|
* @returns {Number} percent The percentage indicator of current applied values.
|
||||||
*/
|
*/
|
||||||
export function getPercent(m) {
|
export function getPercent(m) {
|
||||||
let result = null;
|
let result = null;
|
||||||
const features = m.blueprint.grades[m.blueprint.grade].features;
|
const features = m.blueprint.grades[m.blueprint.grade].features;
|
||||||
for (const featureName in features) {
|
for (const featureName in features) {
|
||||||
if (features[featureName][0] === features[featureName][1]) {
|
if (features[featureName][0] === features[featureName][1]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let value = _getValue(m, featureName);
|
let value = _getValue(m, featureName);
|
||||||
let mult;
|
let mult;
|
||||||
if (featureName == 'shieldboost') {
|
if (featureName == 'shieldboost') {
|
||||||
mult = ((1 + value) * (1 + m.shieldboost)) - 1 - m.shieldboost;
|
mult = ((1 + value) * (1 + m.shieldboost)) - 1 - m.shieldboost;
|
||||||
} else if (Modifications.modifications[featureName].higherbetter) {
|
} 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);
|
||||||
} else {
|
} else {
|
||||||
mult = Math.round((value - features[featureName][0]) / (features[featureName][1] - features[featureName][0]) * 100);
|
mult = Math.round((value - features[featureName][0]) / (features[featureName][1] - features[featureName][0]) * 100);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Higher is worse, but is this making it better or worse?
|
// Higher is worse, but is this making it better or worse?
|
||||||
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
|
||||||
mult = Math.round((value - features[featureName][0]) / (features[featureName][1] - features[featureName][0]) * 100);
|
mult = Math.round((value - features[featureName][0]) / (features[featureName][1] - features[featureName][0]) * 100);
|
||||||
} else {
|
} else {
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result && result != mult) {
|
if (result && result != mult) {
|
||||||
return null;
|
return null;
|
||||||
} else if (result != mult) {
|
} else if (result != mult) {
|
||||||
result = mult;
|
result = mult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query a feature value
|
* Query a feature value
|
||||||
* @param {Object} m The module for which to perform the query
|
* @param {Object} m The module for which to perform the query
|
||||||
* @param {string} featureName The feature being queried
|
* @param {string} featureName The feature being queried
|
||||||
* @returns {number} The value of the modification as a %
|
* @returns {number} The value of the modification as a %
|
||||||
*/
|
*/
|
||||||
function _getValue(m, featureName) {
|
function _getValue(m, featureName) {
|
||||||
if (Modifications.modifications[featureName].type == 'percentage') {
|
if (Modifications.modifications[featureName].type == 'percentage') {
|
||||||
return m.getModValue(featureName, true) / 10000;
|
return m.getModValue(featureName, true) / 10000;
|
||||||
} else if (Modifications.modifications[featureName].type == 'numeric') {
|
} else if (Modifications.modifications[featureName].type == 'numeric') {
|
||||||
return m.getModValue(featureName, true) / 100;
|
return m.getModValue(featureName, true) / 100;
|
||||||
} else {
|
} else {
|
||||||
return m.getModValue(featureName, true);
|
return m.getModValue(featureName, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ export const SHIP_FD_NAME_TO_CORIOLIS_NAME = {
|
|||||||
'Hauler': 'hauler',
|
'Hauler': 'hauler',
|
||||||
'Independant_Trader': 'keelback',
|
'Independant_Trader': 'keelback',
|
||||||
'Krait_MkII': 'krait_mkii',
|
'Krait_MkII': 'krait_mkii',
|
||||||
|
'Mamba': 'mamba',
|
||||||
|
'Krait_Light': 'krait_phantom',
|
||||||
'Orca': 'orca',
|
'Orca': 'orca',
|
||||||
'Python': 'python',
|
'Python': 'python',
|
||||||
'SideWinder': 'sidewinder',
|
'SideWinder': 'sidewinder',
|
||||||
|
|||||||
@@ -147,83 +147,79 @@ export function shipFromLoadoutJSON(json) {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
for (const module of json.Modules) {
|
if (module.Slot.toLowerCase().search(/hardpoint/) !== -1) {
|
||||||
if (module.Slot.toLowerCase().search(/hardpoint/) !== -1) {
|
// Add hardpoints
|
||||||
// Add hardpoints
|
let hardpoint;
|
||||||
let hardpoint;
|
let hardpointClassNum = -1;
|
||||||
let hardpointClassNum = -1;
|
let hardpointSlotNum = -1;
|
||||||
let hardpointSlotNum = -1;
|
let hardpointArrayNum = 0;
|
||||||
let hardpointArrayNum = 0;
|
for (let i in shipTemplate.slots.hardpoints) {
|
||||||
for (let i in shipTemplate.slots.hardpoints) {
|
if (shipTemplate.slots.hardpoints[i] === hardpointClassNum) {
|
||||||
if (shipTemplate.slots.hardpoints[i] === hardpointClassNum) {
|
// Another slot of the same class
|
||||||
// Another slot of the same class
|
hardpointSlotNum++;
|
||||||
hardpointSlotNum++;
|
} else {
|
||||||
} else {
|
// The first slot of a new class
|
||||||
// The first slot of a new class
|
hardpointClassNum = shipTemplate.slots.hardpoints[i];
|
||||||
hardpointClassNum = shipTemplate.slots.hardpoints[i];
|
hardpointSlotNum = 1;
|
||||||
hardpointSlotNum = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now that we know what we're looking for, find it
|
|
||||||
const hardpointName = HARDPOINT_NUM_TO_CLASS[hardpointClassNum] + 'Hardpoint' + hardpointSlotNum;
|
|
||||||
const hardpointSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === hardpointName.toLowerCase());
|
|
||||||
if (!hardpointSlot) {
|
|
||||||
// This can happen with old imports that don't contain new hardpoints
|
|
||||||
} else if (!hardpointSlot) {
|
|
||||||
// No module
|
|
||||||
} else {
|
|
||||||
hardpoint = _moduleFromFdName(hardpointSlot.Item);
|
|
||||||
ship.use(ship.hardpoints[hardpointArrayNum], hardpoint, true);
|
|
||||||
ship.hardpoints[hardpointArrayNum].enabled = hardpointSlot.On;
|
|
||||||
ship.hardpoints[hardpointArrayNum].priority = hardpointSlot.Priority;
|
|
||||||
modsToAdd.push({ coriolisMod: hardpoint, json: hardpointSlot });
|
|
||||||
}
|
|
||||||
hardpointArrayNum++;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (module.Slot.toLowerCase().search(/slot\d/) !== -1) {
|
|
||||||
let internalSlotNum = 1;
|
|
||||||
let militarySlotNum = 1;
|
|
||||||
for (let i in shipTemplate.slots.internal) {
|
|
||||||
if (!shipTemplate.slots.internal.hasOwnProperty(i)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const isMilitary = isNaN(shipTemplate.slots.internal[i]) ? shipTemplate.slots.internal[i].name = 'military' : false;
|
|
||||||
|
|
||||||
// The internal slot might be a standard or a military slot. Military slots have a different naming system
|
// Now that we know what we're looking for, find it
|
||||||
let internalSlot = null;
|
const hardpointName = HARDPOINT_NUM_TO_CLASS[hardpointClassNum] + 'Hardpoint' + hardpointSlotNum;
|
||||||
if (isMilitary) {
|
const hardpointSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === hardpointName.toLowerCase());
|
||||||
const internalName = 'Military0' + militarySlotNum;
|
if (!hardpointSlot) {
|
||||||
|
// This can happen with old imports that don't contain new hardpoints
|
||||||
|
} else if (!hardpointSlot) {
|
||||||
|
// No module
|
||||||
|
} else {
|
||||||
|
hardpoint = _moduleFromFdName(hardpointSlot.Item);
|
||||||
|
ship.use(ship.hardpoints[hardpointArrayNum], hardpoint, true);
|
||||||
|
ship.hardpoints[hardpointArrayNum].enabled = hardpointSlot.On;
|
||||||
|
ship.hardpoints[hardpointArrayNum].priority = hardpointSlot.Priority;
|
||||||
|
modsToAdd.push({ coriolisMod: hardpoint, json: hardpointSlot });
|
||||||
|
}
|
||||||
|
hardpointArrayNum++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let internalSlotNum = 0;
|
||||||
|
let militarySlotNum = 1;
|
||||||
|
for (let i in shipTemplate.slots.internal) {
|
||||||
|
if (!shipTemplate.slots.internal.hasOwnProperty(i)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const isMilitary = isNaN(shipTemplate.slots.internal[i]) ? shipTemplate.slots.internal[i].name == 'Military' : false;
|
||||||
|
|
||||||
|
// The internal slot might be a standard or a military slot. Military slots have a different naming system
|
||||||
|
let internalSlot = null;
|
||||||
|
if (isMilitary) {
|
||||||
|
const internalName = 'Military0' + militarySlotNum;
|
||||||
|
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase());
|
||||||
|
militarySlotNum++;
|
||||||
|
} else {
|
||||||
|
// Slot numbers are not contiguous so handle skips.
|
||||||
|
for (; internalSlot === null && internalSlotNum < 99; internalSlotNum++) {
|
||||||
|
// Slot sizes have no relationship to the actual size, either, so check all possibilities
|
||||||
|
for (let slotsize = 0; slotsize < 9; slotsize++) {
|
||||||
|
const internalName = 'Slot' + (internalSlotNum <= 9 ? '0' : '') + internalSlotNum + '_Size' + slotsize;
|
||||||
|
if (json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase())) {
|
||||||
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase());
|
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase());
|
||||||
militarySlotNum++;
|
break;
|
||||||
} else {
|
|
||||||
// Slot numbers are not contiguous so handle skips.
|
|
||||||
while (internalSlot === null && internalSlotNum < 99) {
|
|
||||||
// Slot sizes have no relationship to the actual size, either, so check all possibilities
|
|
||||||
for (let slotsize = 0; slotsize < 9; slotsize++) {
|
|
||||||
const internalName = 'Slot' + (internalSlotNum <= 9 ? '0' : '0') + internalSlotNum + '_Size' + slotsize;
|
|
||||||
if (json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase())) {
|
|
||||||
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internalSlotNum++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!internalSlot) {
|
|
||||||
// This can happen with old imports that don't contain new slots
|
|
||||||
} else {
|
|
||||||
const internalJson = internalSlot;
|
|
||||||
const internal = _moduleFromFdName(internalJson.Item);
|
|
||||||
ship.use(ship.internal[i], internal, true);
|
|
||||||
ship.internal[i].enabled = internalJson.On === true;
|
|
||||||
ship.internal[i].priority = internalJson.Priority;
|
|
||||||
modsToAdd.push({ coriolisMod: internal, json: internalSlot });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!internalSlot) {
|
||||||
|
// This can happen with old imports that don't contain new slots
|
||||||
|
} else {
|
||||||
|
const internalJson = internalSlot;
|
||||||
|
const internal = _moduleFromFdName(internalJson.Item);
|
||||||
|
ship.use(ship.internal[i], internal, true);
|
||||||
|
ship.internal[i].enabled = internalJson.On === true;
|
||||||
|
ship.internal[i].priority = internalJson.Priority;
|
||||||
|
modsToAdd.push({ coriolisMod: internal, json: internalSlot });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const i of modsToAdd) {
|
for (const i of modsToAdd) {
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ const API_ORBIS = 'https://orbis.zone/api/builds/add';
|
|||||||
* @return {Promise<any>} Either a URL or error message.
|
* @return {Promise<any>} Either a URL or error message.
|
||||||
*/
|
*/
|
||||||
export function orbisUpload(ship, creds) {
|
export function orbisUpload(ship, creds) {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async(resolve, reject) => {
|
||||||
if (window.navigator.onLine) {
|
if (window.navigator.onLine) {
|
||||||
try {
|
try {
|
||||||
agent
|
agent
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import cn from 'classnames';
|
|
||||||
import Module from '../shipyard/Module';
|
|
||||||
import { Infinite } from '../components/SvgIcons';
|
|
||||||
import Persist from '../stores/Persist';
|
import Persist from '../stores/Persist';
|
||||||
import * as ModuleUtils from '../shipyard/ModuleUtils';
|
import * as ModuleUtils from '../shipyard/ModuleUtils';
|
||||||
|
|
||||||
|
|||||||
9
src/iframe.html
Normal file
9
src/iframe.html
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script src="xdLocalStoragePostMessageApi.min.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
This is the magical iframe
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
"density": "4.0"
|
"density": "4.0"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"start_url": "https:\/\/edcd.coriolis.io",
|
"start_url": "https:\/\/coriolis.io",
|
||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
"orientation": "portrait"
|
"orientation": "portrait"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html manifest="/">
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Coriolis EDCD Edition</title>
|
<title>Coriolis EDCD Edition</title>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<link rel="stylesheet" href="<%= htmlWebpackPlugin.files.css[0] %>">
|
<link rel="stylesheet" href="<%= htmlWebpackPlugin.files.css[0] %>">
|
||||||
<!-- Standard headers -->
|
<!-- Standard headers -->
|
||||||
<meta name="description" content="A ship builder, outfitting and comparison tool for Elite Dangerous">
|
<meta name="description" content="A ship builder, outfitting and comparison
|
||||||
|
tool for Elite Dangerous">
|
||||||
<meta name="mobile-web-app-capable" content="yes">
|
<meta name="mobile-web-app-capable" content="yes">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0,
|
||||||
|
maximum-scale=1.0, user-scalable=0">
|
||||||
<link rel="manifest" href="/manifest.json">
|
<link rel="manifest" href="/manifest.json">
|
||||||
<link rel="shortcut icon" href=/favicon2.ico>
|
<link rel="shortcut icon" href=/favicon2.ico>
|
||||||
<link rel="icon" sizes="152x152 192x192" type="image/png" href="/192x192.png">
|
<link rel="icon" sizes="152x152 192x192" type="image/png"
|
||||||
|
href="/192x192.png">
|
||||||
|
|
||||||
<!-- Apple/iOS headers -->
|
<!-- Apple/iOS headers -->
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
@@ -30,16 +33,16 @@
|
|||||||
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) { %>
|
<% if (htmlWebpackPlugin.options.uaTracking) { %>
|
||||||
<script>
|
<script>
|
||||||
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
|
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
|
||||||
ga('create', '<%- htmlWebpackPlugin.options.uaTracking %>', 'auto');
|
ga('create', '<%- htmlWebpackPlugin.options.uaTracking %>', 'auto');
|
||||||
ga('send', 'pageview');
|
ga('send', 'pageview');
|
||||||
</script>
|
</script>
|
||||||
<script async src='https://www.google-analytics.com/analytics.js'></script>
|
<script async src='https://www.google-analytics.com/analytics.js'></script>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
<!-- Piwik -->
|
<!-- Piwik -->
|
||||||
<!-- <script type="text/javascript">
|
<!-- <script type="text/javascript">
|
||||||
var _paq = _paq || [];
|
var _paq = _paq || [];
|
||||||
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
|
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
|
||||||
_paq.push(["setCookieDomain", "*.coriolis.edcd.io"]);
|
_paq.push(["setCookieDomain", "*.coriolis.edcd.io"]);
|
||||||
@@ -53,19 +56,17 @@
|
|||||||
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
|
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
|
||||||
})();
|
})();
|
||||||
</script>-->
|
</script>-->
|
||||||
<!-- End Piwik Code -->
|
<!-- End Piwik Code -->
|
||||||
|
|
||||||
<!-- Bugsnag -->
|
<!-- Bugsnag -->
|
||||||
<script src="//d2wy8f7a9ursnm.cloudfront.net/v4/bugsnag.min.js"></script>
|
<script src="https://d2wy8f7a9ursnm.cloudfront.net/v5.0.0/bugsnag.min.js"></script>
|
||||||
<script src="//d2wy8f7a9ursnm.cloudfront.net/bugsnag-plugins/v1/bugsnag-react.min.js"></script>
|
<script>
|
||||||
<script>
|
|
||||||
window.bugsnagClient = bugsnag('ba9fae819372850fb660755341fa6ef5', {appVersion: window.BUGSNAG_VERSION || undefined})
|
window.bugsnagClient = bugsnag('ba9fae819372850fb660755341fa6ef5', {appVersion: window.BUGSNAG_VERSION || undefined})
|
||||||
window.Bugsnag = window.bugsnagClient
|
window.Bugsnag = window.bugsnagClient
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body style="background-color:#000;">
|
<body style="background-color:#000;">
|
||||||
<section id="coriolis"></section>
|
<section id="coriolis"></section>
|
||||||
<script src="<%= htmlWebpackPlugin.files.chunks.lib.entry %>" charset="utf-8" crossorigin="anonymous"></script>
|
|
||||||
<script src="<%= htmlWebpackPlugin.files.chunks.app.entry %>" charset="utf-8" crossorigin="anonymous"></script>
|
</body>
|
||||||
</body>
|
</html>
|
||||||
</html>
|
|
||||||
|
|||||||
@@ -171,3 +171,16 @@ footer {
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.announcement-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 10px;
|
||||||
|
justify-content: center;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement {
|
||||||
|
border: 1px @secondary solid;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,6 +12,12 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A multi-crew pip
|
||||||
|
.mc {
|
||||||
|
stroke: @secondary;
|
||||||
|
fill: @secondary;
|
||||||
|
}
|
||||||
|
|
||||||
// A full pip
|
// A full pip
|
||||||
.full {
|
.full {
|
||||||
stroke: @primary;
|
stroke: @primary;
|
||||||
|
|||||||
@@ -22,6 +22,15 @@ select {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.react-fuzzy-search > * {
|
||||||
|
padding: 0 !important;
|
||||||
|
color: @primary;
|
||||||
|
& > input {
|
||||||
|
border: 1px solid @primary !important;
|
||||||
|
color: @primary-bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.cmdr-select {
|
.cmdr-select {
|
||||||
border: 1px solid @primary;
|
border: 1px solid @primary;
|
||||||
padding: 0.5em 0.5em;
|
padding: 0.5em 0.5em;
|
||||||
|
|||||||
@@ -74,7 +74,7 @@
|
|||||||
border-color:#fff;
|
border-color:#fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
input:disabled {
|
input.greyed-out {
|
||||||
border-color: #888;
|
border-color: #888;
|
||||||
color: #888;
|
color: #888;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ tbody tr {
|
|||||||
background-color: @warning-bg;
|
background-color: @warning-bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.alt {
|
&:nth-child(odd){
|
||||||
background-color: @alt-primary-bg;
|
background-color: @alt-primary-bg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
51
src/sw.js
51
src/sw.js
@@ -1,9 +1,22 @@
|
|||||||
console.log('Hello from sw.js');
|
console.log('Hello from sw.js');
|
||||||
|
|
||||||
if (workbox) {
|
if (workbox) {
|
||||||
workbox.skipWaiting();
|
|
||||||
workbox.clientsClaim();
|
|
||||||
console.log('Yay! Workbox is loaded 🎉');
|
console.log('Yay! Workbox is loaded 🎉');
|
||||||
|
workbox.precaching.precacheAndRoute(self.__precacheManifest);
|
||||||
|
|
||||||
|
workbox.routing.registerNavigationRoute('/index.html');
|
||||||
|
|
||||||
|
workbox.routing.registerRoute(
|
||||||
|
new RegExp('/(.*?)'),
|
||||||
|
workbox.strategies.staleWhileRevalidate({
|
||||||
|
plugins: [
|
||||||
|
new workbox.cacheableResponse.Plugin({
|
||||||
|
statuses: [0, 200]
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
workbox.routing.registerRoute(
|
workbox.routing.registerRoute(
|
||||||
new RegExp('https://fonts.(?:googleapis|gstatic).com/(.*)'),
|
new RegExp('https://fonts.(?:googleapis|gstatic).com/(.*)'),
|
||||||
workbox.strategies.cacheFirst({
|
workbox.strategies.cacheFirst({
|
||||||
@@ -18,24 +31,7 @@ if (workbox) {
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
workbox.routing.registerRoute(
|
|
||||||
/\.(?:png|gif|jpg|jpeg|svg)$/,
|
|
||||||
workbox.strategies.cacheFirst({
|
|
||||||
cacheName: 'images',
|
|
||||||
plugins: [
|
|
||||||
new workbox.expiration.Plugin({
|
|
||||||
maxEntries: 60,
|
|
||||||
maxAgeSeconds: 30 * 24 * 60 * 60 // 30 Days
|
|
||||||
})
|
|
||||||
]
|
|
||||||
})
|
|
||||||
);
|
|
||||||
workbox.routing.registerRoute(
|
|
||||||
/\.(?:js|css)$/,
|
|
||||||
workbox.strategies.staleWhileRevalidate({
|
|
||||||
cacheName: 'static-resources'
|
|
||||||
})
|
|
||||||
);
|
|
||||||
try {
|
try {
|
||||||
workbox.googleAnalytics.initialize();
|
workbox.googleAnalytics.initialize();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -44,3 +40,18 @@ if (workbox) {
|
|||||||
} else {
|
} else {
|
||||||
console.log('Boo! Workbox didn\'t load 😬');
|
console.log('Boo! Workbox didn\'t load 😬');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.addEventListener('message', event => {
|
||||||
|
if (!event.data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (event.data) {
|
||||||
|
case 'skipWaiting':
|
||||||
|
self.skipWaiting();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// NOOP
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
1
src/xdLocalStoragePostMessageApi.min.js
vendored
Normal file
1
src/xdLocalStoragePostMessageApi.min.js
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
"use strict";window.XdUtils=window.XdUtils||function(){function a(a,b){var c,d=b||{};for(c in a)a.hasOwnProperty(c)&&(d[c]=a[c]);return d}return{extend:a}}(),function(){function a(a,b){var c=XdUtils.extend(b,l);c.id=a,parent.postMessage(JSON.stringify(c),"*")}function b(b,c){a(b,{key:c,value:localStorage.getItem(c)})}function c(b,c,d){localStorage.setItem(c,d),a(b,{success:localStorage.getItem(c)===d})}function d(b,c){localStorage.removeItem(c),a(b,{})}function e(b,c){a(b,{key:localStorage.key(c)})}function f(b){a(b,{size:JSON.stringify(localStorage).length})}function g(b){a(b,{length:localStorage.length})}function h(b){localStorage.clear(),a(b,{})}function i(a){var i;try{i=JSON.parse(a.data)}catch(a){}i&&i.namespace===k&&("set"===i.action?c(i.id,i.key,i.value):"get"===i.action?b(i.id,i.key):"remove"===i.action?d(i.id,i.key):"key"===i.action?e(i.id,i.key):"size"===i.action?f(i.id):"length"===i.action?g(i.id):"clear"===i.action&&h(i.id))}function j(){var a={namespace:k,id:"iframe-ready"};parent.postMessage(JSON.stringify(a),"*")}var k="cross-domain-local-message",l={namespace:k};window.addEventListener?window.addEventListener("message",i,!1):window.attachEvent("onmessage",i),j()}();
|
||||||
@@ -1,49 +1,42 @@
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const exec = require('child_process').exec;
|
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||||
const WebpackNotifierPlugin = require('webpack-notifier');
|
const WebpackNotifierPlugin = require('webpack-notifier');
|
||||||
const pkgJson = require('./package');
|
const pkgJson = require('./package');
|
||||||
const buildDate = new Date();
|
const buildDate = new Date();
|
||||||
function CopyDirPlugin(source, destination) {
|
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
this.source = source;
|
|
||||||
this.destination = destination;
|
|
||||||
}
|
|
||||||
|
|
||||||
CopyDirPlugin.prototype.apply = function(compiler) {
|
|
||||||
compiler.plugin('done', () => {
|
|
||||||
console.log(compiler.outputPath, this.destination);
|
|
||||||
exec('cp -r ' + this.source + ' ' + path.join(compiler.outputPath, this.destination));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
devtool: 'source-map',
|
devtool: 'source-map',
|
||||||
devServer: {
|
devServer: {
|
||||||
headers: { 'Access-Control-Allow-Origin': '*' }
|
headers: { 'Access-Control-Allow-Origin': '*' }
|
||||||
},
|
},
|
||||||
|
mode: 'development',
|
||||||
entry: {
|
entry: {
|
||||||
app: ['webpack-dev-server/client?http://0.0.0.0:3300', 'webpack/hot/only-dev-server', path.join(__dirname, 'src/app/index.js')],
|
main: './src/app/index.js',
|
||||||
lib: ['d3', 'react', 'react-dom', 'classnames', 'fbemitter', 'lz-string']
|
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
// When requiring, you don't need to add these extensions
|
// When requiring, you don't need to add these extensions
|
||||||
extensions: ['.js', '.jsx', '.json', '.less']
|
extensions: ['.js', '.jsx', '.json', '.less']
|
||||||
},
|
},
|
||||||
|
optimization: {
|
||||||
|
minimize: false,
|
||||||
|
usedExports: true
|
||||||
|
},
|
||||||
output: {
|
output: {
|
||||||
path: path.join(__dirname, 'build'),
|
path: path.join(__dirname, 'build'),
|
||||||
filename: 'app.js',
|
chunkFilename: '[name].bundle.js',
|
||||||
publicPath: '/'
|
publicPath: '/'
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new CopyDirPlugin(path.join(__dirname, 'src/.htaccess'), ''),
|
new CopyWebpackPlugin(['src/.htaccess', 'src/iframe.html', 'src/xdLocalStoragePostMessageApi.min.js']),
|
||||||
new webpack.optimize.CommonsChunkPlugin({
|
// new webpack.optimize.CommonsChunkPlugin({
|
||||||
name: 'lib',
|
// name: 'lib',
|
||||||
filename: 'lib.js'
|
// filename: 'lib.js'
|
||||||
}),
|
// }),
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
inject: false,
|
inject: true,
|
||||||
template: path.join(__dirname, 'src/index.ejs'),
|
template: path.join(__dirname, 'src/index.ejs'),
|
||||||
version: pkgJson.version,
|
version: pkgJson.version,
|
||||||
date: buildDate,
|
date: buildDate,
|
||||||
@@ -61,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' },
|
||||||
|
|||||||
@@ -1,63 +1,44 @@
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const exec = require('child_process').exec;
|
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||||
const { InjectManifest } = require('workbox-webpack-plugin');
|
const { InjectManifest } = require('workbox-webpack-plugin');
|
||||||
|
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
const { BugsnagSourceMapUploaderPlugin } = require('webpack-bugsnag-plugins');
|
const { BugsnagSourceMapUploaderPlugin, BugsnagBuildReporterPlugin } = require('webpack-bugsnag-plugins');
|
||||||
const pkgJson = require('./package');
|
const pkgJson = require('./package');
|
||||||
const buildDate = new Date();
|
const buildDate = new Date();
|
||||||
function CopyDirPlugin(source, destination) {
|
|
||||||
this.source = source;
|
|
||||||
this.destination = destination;
|
|
||||||
}
|
|
||||||
|
|
||||||
CopyDirPlugin.prototype.apply = function(compiler) {
|
|
||||||
compiler.plugin('done', () => {
|
|
||||||
console.log(compiler.outputPath, this.destination);
|
|
||||||
exec('cp -r ' + this.source + ' ' + path.join(compiler.outputPath, this.destination));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
cache: true,
|
|
||||||
devtool: 'source-map',
|
devtool: 'source-map',
|
||||||
entry: {
|
entry: {
|
||||||
app: ['babel-polyfill', path.resolve(__dirname, 'src/app/index')],
|
main: './src/app/index.js'
|
||||||
lib: ['d3', 'react', 'react-dom', 'classnames', 'fbemitter', 'lz-string']
|
|
||||||
},
|
},
|
||||||
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].[chunkhash:6].js',
|
chunkFilename: '[name].bundle.js',
|
||||||
chunkFilename: '[name].[chunkhash:6]',
|
publicPath: '/',
|
||||||
publicPath: '/'
|
globalObject: 'this'
|
||||||
|
},
|
||||||
|
mode: 'production',
|
||||||
|
optimization: {
|
||||||
|
minimize: true,
|
||||||
|
usedExports: true
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.optimize.UglifyJsPlugin({
|
new CopyWebpackPlugin(['src/.htaccess', { from: 'src/schemas', to: 'schemas' }, {
|
||||||
'screw-ie8': true,
|
from: 'src/images/logo/*',
|
||||||
sourceMap: true
|
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'
|
||||||
// }),
|
// }),
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
inject: false,
|
inject: true,
|
||||||
appCache: 'coriolis.appcache',
|
|
||||||
minify: {
|
|
||||||
collapseBooleanAttributes: true,
|
|
||||||
collapseWhitespace: true,
|
|
||||||
removeAttributeQuotes: true,
|
|
||||||
removeComments: true,
|
|
||||||
removeEmptyAttributes: true,
|
|
||||||
removeRedundantAttributes: true,
|
|
||||||
removeScriptTypeAttributes: true,
|
|
||||||
removeStyleLinkTypeAttributes: true
|
|
||||||
},
|
|
||||||
template: path.join(__dirname, 'src/index.ejs'),
|
template: path.join(__dirname, 'src/index.ejs'),
|
||||||
uaTracking: process.env.CORIOLIS_UA_TRACKING || '',
|
uaTracking: process.env.CORIOLIS_UA_TRACKING || '',
|
||||||
gapiKey: process.env.CORIOLIS_GAPI_KEY || '',
|
gapiKey: process.env.CORIOLIS_GAPI_KEY || '',
|
||||||
@@ -65,17 +46,19 @@ module.exports = {
|
|||||||
version: pkgJson.version
|
version: pkgJson.version
|
||||||
}),
|
}),
|
||||||
new ExtractTextPlugin({
|
new ExtractTextPlugin({
|
||||||
filename: '[contenthash:6].css',
|
filename: '[hash:6].css',
|
||||||
disable: false,
|
disable: false,
|
||||||
allChunks: true
|
allChunks: true
|
||||||
}),
|
}),
|
||||||
new BugsnagSourceMapUploaderPlugin({
|
// new BugsnagBuildReporterPlugin({
|
||||||
apiKey: 'ba9fae819372850fb660755341fa6ef5',
|
// apiKey: 'ba9fae819372850fb660755341fa6ef5',
|
||||||
appVersion: `${pkgJson.version}-${buildDate.toISOString()}`
|
// appVersion: `${pkgJson.version}-${buildDate.toISOString()}`
|
||||||
}),
|
// }, { /* opts */ }),
|
||||||
new CopyDirPlugin(path.join(__dirname, 'src/schemas'), 'schemas'),
|
// new BugsnagSourceMapUploaderPlugin({
|
||||||
new CopyDirPlugin(path.join(__dirname, 'src/images/logo/*'), ''),
|
// apiKey: 'ba9fae819372850fb660755341fa6ef5',
|
||||||
new CopyDirPlugin(path.join(__dirname, 'src/.htaccess'), ''),
|
// overwrite: true,
|
||||||
|
// appVersion: `${pkgJson.version}-${buildDate.toISOString()}`
|
||||||
|
// }),
|
||||||
new InjectManifest({
|
new InjectManifest({
|
||||||
swSrc: './src/sw.js',
|
swSrc: './src/sw.js',
|
||||||
importWorkboxFrom: 'cdn',
|
importWorkboxFrom: 'cdn',
|
||||||
@@ -85,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