Compare commits

...

83 Commits

Author SHA1 Message Date
Alex Williams
e545397d12 Merge pull request #792 from chennin/patch-1
Remove link to squatted domain
2024-10-20 10:02:58 +01:00
Alex Williams
d06388f7c5 Merge pull request #793 from Brighter-Applications/develop
Type 8 added to Shipyard with Announcement (#33)
2024-10-20 10:01:56 +01:00
Alex Williams
9a41153868 Type 8 added to Shipyard with Announcement (#33) 2024-10-20 10:01:19 +01:00
Chris
b7e6e7ab8b Remove link to squatted domain
`http://www.edshipyard.com/` is now owned by a Vietnamese betting company (Mu88). Remove the link to avoid giving them traffic.

I considered replacing the link with an archived version, but, for me, 
https://web.archive.org/web/20231030223647/http://www.edshipyard.com/ just shows a mostly-white page with some light grey text at the top, so it didn't seem useful.
2024-10-19 09:53:00 -04:00
David Sangrey
480466ff2a Merge pull request #772 from Brighter-Applications/make_modal_better_clean
Modal Changes to export and link shortener
2024-07-09 16:59:56 -04:00
Alex Williams
d1cb0fdcb5 Modal Changes to export and link shortener 2024-07-09 20:10:04 +01:00
David Sangrey
2362ded438 Merge pull request #768 from Brighter-Applications/develop
Fix missile rack glitch (#23)
2024-06-24 10:17:27 -04:00
Alex Williams
cb1612d828 Fix missile rack glitch (#23)
* Adding autodeploy for new 'beta' branch

* Fixing directory for beta deployment

* Updating beta autodeploy with nvm info

* Adding autodeploy for live site

* Making autodeploy aware of its target branch name (#16)

* Fixes for autodeploy (#17)

* Autodeploy fixes (#18)

* Fixes for autodeploy

* Adding npm start command to build dist from coriolis-data

* Adding missing Constants for Advanced and Enhanced Weaponry

* Removing workflow code merged in by github
2024-06-22 17:55:16 +01:00
David Sangrey
4b5940e651 Merge pull request #767 from Brighter-Applications/Issue_703_EDOMH_integration
Issue 703 edomh integration
2024-06-09 17:24:50 -04:00
Alex Williams
06552dd860 Removing debugging console.log entries that are no longer needed for EDOMH fix 2024-06-07 18:24:57 +01:00
Alex Williams
ca91401507 Removing Autodeploy from this branch, it was merged in by github 2024-06-07 11:58:38 +01:00
Alex Williams
ed5ffbc9f8 Fixed issue with special blueprint item not being correctly jsonified for export to EDOMH 2024-06-07 11:58:38 +01:00
Alex Williams
45935b90e4 Adding fix for broken Armour Module Selection 2024-06-07 11:58:38 +01:00
Alex Williams
5d41575e66 Adding tag to manual dispatch of workflow 2024-06-07 11:58:38 +01:00
Alex Williams
b86e90de4b Issue 764 unknown modules are selectable (#11)
* Adds valid module checking to all types of modules on import

* Adds the Advanced MC's, AX MC's, AX MR's and Nanite Torpedo

* Changes as per comments on the PR

* Fixed 'Missing Module' category showing up in Optional Selection drop-down and fixed 'Missing Power Plant', 'Missing Power Distributor' and 'Missing Frameshift Drive' showing up in the Selection drop-downs for those module slots.

---------

Co-authored-by: David Sangrey <davidsangrey@gmail.com>
Co-authored-by: Felix Linker <linkerfelix@gmail.com>
2024-06-07 11:58:38 +01:00
Alex Williams
105fc60f43 Issue 703 edomh integration (#10)
* Adds valid module checking to all types of modules on import

* Adds the Advanced MC's, AX MC's, AX MR's and Nanite Torpedo

* Changes as per comments on the PR

* Modified export to EDOMH/EDEngineer page to be less 'bodged', allow EDOMH button to be clickable without checking for EDEngineer API (If they have EDOMH, they probably don't have EDEngineer...) and added a workaround for Coriolis sending bogus data for bulkheads.

* Fixed autodeploy to do latest coriolis-data dist. Fixed sendToEDOMH function to only send the blueprint at the selected grade, not each grade up to that grade.

* Fixed miscalculation of mats and got rid of unhelpful 'rolls' table, as the mats are calculated for the whole build and some blueprints may not be all the way up to g5.

* Removed console.log lines which were only needed for testing.

---------

Co-authored-by: David Sangrey <davidsangrey@gmail.com>
Co-authored-by: Felix Linker <linkerfelix@gmail.com>
2024-06-07 11:58:11 +01:00
Alex Williams
7ccfa09ddd Issue 703 edomh integration (#9)
* Adds valid module checking to all types of modules on import

* Adds the Advanced MC's, AX MC's, AX MR's and Nanite Torpedo

* Changes as per comments on the PR

* Modified export to EDOMH/EDEngineer page to be less 'bodged', allow EDOMH button to be clickable without checking for EDEngineer API (If they have EDOMH, they probably don't have EDEngineer...) and added a workaround for Coriolis sending bogus data for bulkheads.

* Fixed autodeploy to do latest coriolis-data dist. Fixed sendToEDOMH function to only send the blueprint at the selected grade, not each grade up to that grade.

* Fixed miscalculation of mats and got rid of unhelpful 'rolls' table, as the mats are calculated for the whole build and some blueprints may not be all the way up to g5.

---------

Co-authored-by: David Sangrey <davidsangrey@gmail.com>
Co-authored-by: Felix Linker <linkerfelix@gmail.com>
2024-06-07 11:58:11 +01:00
Alex Williams
ab3c93d52d Issue 703 edomh integration (#8)
* Adds valid module checking to all types of modules on import

* Adds the Advanced MC's, AX MC's, AX MR's and Nanite Torpedo

* Changes as per comments on the PR

* Modified export to EDOMH/EDEngineer page to be less 'bodged', allow EDOMH button to be clickable without checking for EDEngineer API (If they have EDOMH, they probably don't have EDEngineer...) and added a workaround for Coriolis sending bogus data for bulkheads.

* Fixed autodeploy to do latest coriolis-data dist. Fixed sendToEDOMH function to only send the blueprint at the selected grade, not each grade up to that grade.

---------

Co-authored-by: David Sangrey <davidsangrey@gmail.com>
Co-authored-by: Felix Linker <linkerfelix@gmail.com>
2024-06-07 11:57:22 +01:00
Alex Williams
ee04416e2b Adding in buildname to EDOMH Export 2024-06-07 11:57:22 +01:00
Alex Williams
4efc47dff0 Removed console.log lines which were only needed for testing. 2024-06-07 11:56:42 +01:00
Alex Williams
bd2e6eaf51 Fixed miscalculation of mats and got rid of unhelpful 'rolls' table, as the mats are calculated for the whole build and some blueprints may not be all the way up to g5. 2024-06-07 11:56:42 +01:00
Alex Williams
42b2e39064 Issue 703 edomh integration (#7)
* Adds valid module checking to all types of modules on import

* Adds the Advanced MC's, AX MC's, AX MR's and Nanite Torpedo

* Changes as per comments on the PR

* Modified export to EDOMH/EDEngineer page to be less 'bodged', allow EDOMH button to be clickable without checking for EDEngineer API (If they have EDOMH, they probably don't have EDEngineer...) and added a workaround for Coriolis sending bogus data for bulkheads.

---------

Co-authored-by: David Sangrey <davidsangrey@gmail.com>
Co-authored-by: Felix Linker <linkerfelix@gmail.com>
2024-06-07 11:56:42 +01:00
Alex Williams
d1217439bd Fixed autodeploy to do latest coriolis-data dist. Fixed sendToEDOMH function to only send the blueprint at the selected grade, not each grade up to that grade. 2024-06-07 11:53:43 +01:00
Alex Williams
2a6ae0f2ff Modified export to EDOMH/EDEngineer page to be less 'bodged', allow EDOMH button to be clickable without checking for EDEngineer API (If they have EDOMH, they probably don't have EDEngineer...) and added a workaround for Coriolis sending bogus data for bulkheads. 2024-06-07 11:53:43 +01:00
Alex Williams
dedd2ddbba Merge pull request #766 from alex-williams/ISSUE_764_Previous_fix_fix_due_to_bug
Fixing bug introduced by the previous PR for ISSUE_764. The previous …
2024-06-06 22:41:51 +01:00
Alex Williams
f86ecede9b Fixing bug introduced by the previous PR for ISSUE_764. The previous fix introduced a bug which caused Armour Selection to error, due to Armour modules being completely different to other modules of any other type 2024-06-06 22:39:30 +01:00
David Sangrey
436a50cb45 Merge pull request #765 from alex-williams/ISSUE_764_Unknown_Modules_Are_Selectable
Issue 764 unknown modules are selectable
2024-06-03 11:04:25 -04:00
David Sangrey
f7cf39a9ae Merge branch 'develop' into ISSUE_764_Unknown_Modules_Are_Selectable 2024-06-03 11:04:14 -04:00
David Sangrey
680f3b10f3 Merge pull request #762 from alex-williams/issue_600_add_advanced_weapons
Added 'special' field to certain modules to allow for clearer …
2024-06-03 11:02:17 -04:00
Alex Williams
b31de9c37a Merge pull request #763 from leonardofelin/patch-2
Update PT-BR translations
2024-06-02 20:17:06 +01:00
Alex Williams
9ef054c271 Fixed 'Missing Module' category showing up in Optional Selection drop-down and fixed 'Missing Power Plant', 'Missing Power Distributor' and 'Missing Frameshift Drive' showing up in the Selection drop-downs for those module slots. 2024-06-02 20:03:12 +01:00
leonardofelin
aa620be113 Update PT-BR translations
Added translated strings for coriolis-data PRs 106 & 107
2024-05-27 19:45:44 -03:00
Alex Williams
27f19a72a6 Merge branch 'alpha' into issue_600_add_advanced_weapons 2024-05-27 17:02:42 +01:00
Alex Williams
634be1f197 Added 'special' field to certain modules to allow for clearer appearance in search results that they are the special type of module. Updated English descriptions of Advanced Modules and Special Modules 2024-05-27 15:50:32 +01:00
Felix Linker
f747b25f26 Merge pull request #759 from alex-williams/Issue_754_Imports_need_to_be_more_graceful
Adds valid module checking to all types of modules on import
2024-05-27 08:49:11 +02:00
Felix Linker
02bf133c98 Merge branch 'develop' into Issue_754_Imports_need_to_be_more_graceful 2024-05-27 08:48:49 +02:00
Alex Williams
6c34a26273 Issue 754 imports need to be more graceful (#5)
* Adds valid module checking to all types of modules on import

* Changes as per comments on the PR
2024-05-24 18:23:04 +01:00
Alex Williams
b0b5c82131 Merge branch 'alpha' into Issue_754_Imports_need_to_be_more_graceful 2024-05-24 18:22:53 +01:00
Alex Williams
ee92f2f2e4 Adds the Advanced MC's, AX MC's, AX MR's and Nanite Torpedo (#4) 2024-05-24 17:56:20 +01:00
Alex Williams
0d749202e2 Changing to clone single branch for deployment, not the whole repo 2024-05-24 17:41:27 +01:00
Alex Williams
4283b0b839 Changed deployment ordering 2024-05-24 17:38:47 +01:00
Alex Williams
fbd9c3d282 Improving workflow 2024-05-24 16:23:08 +01:00
Alex Williams
cd68199a41 Adding workflow for autodeploy 2024-05-24 16:23:08 +01:00
Alex Williams
f885fde04f Fix changed files issue (#3)
* Copied de.js contents to new file de-fix.js

* Copied de.js contents back from de-fix.js

* Copied contents of ko.js to ko-fix.js

* Copied ko.js contents back from ko-fix.js

* Copied contents from BlueprintFunctions.js to BlueprintFunctions-fix.js

* Copied contents back from BlueprintFunctions-fix.js to BlueprintFunctions.js

* Copied contents of LineChart.jsx to LineChart-fix.jsx

* Copied contents back from LineChart-fix.jsx to LineChart.jsx

* Copied contents of PieChart.jsx to PieChart-fix.jsx

* Copied contents back from PieChart-fix.jsx to PieChart.jsx

* Copied contents from Slider.jsx to Slider-fix.jsx

* Copied contents back from Slider-fix.jsx to Slider.jsx

* Copied contents from VerticalBarChart.jsx to VerticalBarChart-fix.jsx

* Copied contents back from VerticalBarChart-fix.jsx to VerticalBarChart.jsx

* Deleting 'fix' files
2024-05-24 16:03:03 +01:00
David Sangrey
8f5375f732 Merge pull request #760 from alex-williams/Issue_758_adding_ax_nanite_torps_and_enhanced_missile_racks
Adds the Advanced MC's, AX MC's, AX MR's and Nanite Torpedo
2024-05-20 12:49:53 -04:00
Alex Williams
5c8ff57d16 Changes as per comments on the PR 2024-05-17 15:24:29 +01:00
Alex Williams
3156b6a533 Adds the Advanced MC's, AX MC's, AX MR's and Nanite Torpedo 2024-05-17 08:45:15 +01:00
Alex Williams
14ffa26ef9 Adds valid module checking to all types of modules on import 2024-05-16 19:23:33 +01:00
Alex Williams
18d7ada65f Merge pull request #755 from leonardofelin/pt-br_translations
Updated PT-BR translation with Planetary Approach Suite
2024-05-14 17:18:40 +01:00
leonardofelin
8593e18de4 Updated PT-BR translation with Planetary Approach Suite 2024-05-14 13:13:56 -03:00
leonardofelin
284b0b3ce2 Update pt.json - Brazilian Portuguese translations (#752)
* Update pt.json

Update Brazilian Portuguese translations:
- Updated Modules
- Engineering & Experimental Effect
- Corrections

* Update Portuguese Brazilian

Fixed Tab/Spaces indentation
2024-05-14 13:25:51 +02:00
David Sangrey
c3cb2cfa3b Add SCO Module Check (#748)
* Add SCO Module Check

Goes hand-in-hand with https://github.com/EDCD/coriolis-data/pull/98

* [748] Updated Filter Function

This time, readable!
2024-05-12 13:51:17 +02:00
Alex Williams
5d54eb8862 Adding python_nx to SHIP_FD_NAME_TO_CORIOLIS_NAME to fix import issue with Python Mk II 2024-05-12 13:48:28 +02:00
Felix Linker
9fc6508be4 coriolis-data specified as relative dependency again 2024-04-29 08:24:34 +02:00
Aleksandr
ef82cf4a00 [744] add support of experimental weapon stabilizer (#745) 2024-04-29 08:23:20 +02:00
Felix Linker
9766f78e21 Move eddb.io links to inara.cz 2023-04-07 19:25:16 +01:00
Felix Linker
6d8bd6ca44 Dependency update 2023-04-07 19:18:28 +01:00
Sam Clayton
875af31ffe Update to Webpack 5 (fixes crypto error on build) (#738)
* Updating react-number-editor dependency from stale named branch

* Remove references to deprecated react-addons-perf package

* Issue #25 Webpack updated to current version, many
dependencies updated, Babel & Webpack configs updated.
Add dev & prod Dockerfiles and update README with Docker instructions
Created webpack.common.js.
Coriolis-data now specified as github dependency

* Bump bugfix versions of react & react-dom only

* Workbox dependency upgrade for webpack 5 compat

* Stab at upgrading workbox dep
Far more fatal webpack errors :(

* Automate reinstall/rebuild with npm script

* Working build again w updated deps
Disabled/commented out all bugsnag references
Added production-like Docker build for troubleshooting issues that don't
 appear in dev server

* Remove deprecated @babel/polyfill import & dependency

* Fix to service worker to v5 of workbox
and align with webpack 5 plugin

* Disabling recent round of polyfills. Don't think
they're necessary.

* Whitespace in package.json

* Add Buffer as Webpack plugin. Fix indenting.
Fix deprecated call to Buffer.

* Remove bugsnag and deprecated babel code that was
 commented out, per convo with Felix

---------

Co-authored-by: Sam Clayton <sam@goranku.com>
2023-03-01 21:55:23 +01:00
Felix Linker
93adcb3daf Merge pull request #730 from Sid127/edomh-v1
Initial EDOMH integration
2022-12-27 13:19:05 +01:00
Felix Linker
ec9a07b143 Merge pull request #732 from EDCD/dependabot/npm_and_yarn/decode-uri-component-0.2.2
Bump decode-uri-component from 0.2.0 to 0.2.2
2022-12-26 13:37:46 +01:00
dependabot[bot]
bb8eeb4d3f Bump decode-uri-component from 0.2.0 to 0.2.2
Bumps [decode-uri-component](https://github.com/SamVerschueren/decode-uri-component) from 0.2.0 to 0.2.2.
- [Release notes](https://github.com/SamVerschueren/decode-uri-component/releases)
- [Commits](https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.0...v0.2.2)

---
updated-dependencies:
- dependency-name: decode-uri-component
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-09 17:17:50 +00:00
Sid Pranjale
8b7a7192a4 Initial EDOMH integration 2022-11-27 14:55:56 +05:30
Felix Linker
6688a1fbe3 Merge pull request #728 from AndricReal/patch-1
Update of russian localisation
2022-11-27 10:11:55 +01:00
AndricReal
2ea5fe5d58 Update ru.json
Corrected translation
2022-11-20 16:08:27 +05:00
Felix Linker
efd644c6f1 Merge pull request #726 from Sid127/matlist-fix
Matlist fix
2022-11-11 20:18:22 +01:00
Sid Pranjale
17c6ec1f97 Do nothing if a module has no experimentals
This fixes materials not being shown for modules that can be engineered but not having experimental effects
2022-11-09 21:19:02 +05:30
Felix Linker
9bc6e36f14 Remove/replace react 16 dependencies 2022-10-29 11:53:36 +02:00
Felix Linker
062815054c Add package-lock 2022-10-29 11:43:02 +02:00
Felix Linker
7bc40d24d8 Merge pull request #708 from Sid127/develop
Quick fix for missing group info in JSON exports
2022-10-21 17:13:11 +02:00
Felix Linker
d9da250f50 Merge pull request #709 from Sid127/uuids-fix
Add mats for experimental effects to mat list
2022-10-21 17:11:39 +02:00
Sid Pranjale
801969dc07 Add mats for experimental effects to mat list 2022-10-09 16:34:04 +05:30
Sid Pranjale
6bf820934f Quick fix for missing group info in JSON exports 2022-10-09 11:45:18 +05:30
Felix Linker
887dbc25f8 Merge remote-tracking branch 'unknowngamer/master' into develop 2022-10-02 11:53:56 +02:00
Felix Linker
50de77d613 Merge remote-tracking branch 'origin/master' into develop 2022-10-02 11:53:48 +02:00
Felix Linker
13561ee21a Merge pull request #704 from green1052/develop
Add Korean translate
2022-10-02 11:44:48 +02:00
green1052
333feaa6bf Add Korean translate
Co-authored-by: jackfrost <jackfrost5446@naver.com>
2022-10-01 15:35:56 +09:00
Rob
1e37fd15eb Fix link to data wiki 2022-08-26 07:28:17 +01:00
ItsUnknownGamer
f82b0212b5 shield recovery time depending on distributor draw 2022-03-04 17:44:49 +01:00
Felix Linker
32138f5546 Merge pull request #689 from Sid127/develop
Minor modifications for Multi-limpet Controllers
2022-01-05 10:53:54 +01:00
Sid
85ddce14a5 Minor modifications for Multi-limpet Controllers 2022-01-05 13:09:34 +05:30
Felix Linker
7e44772f2e Hotfix 2021-12-30 17:06:02 +01:00
Felix Linker
e90bfe9b68 Multi limpet controllers have max of 1 2021-12-30 14:21:21 +01:00
Felix Linker
64002e1ae0 Add translation for multi limpet controllers 2021-12-30 13:53:07 +01:00
57 changed files with 15896 additions and 1836 deletions

View File

@@ -7,6 +7,8 @@
"@babel/plugin-syntax-dynamic-import", "@babel/plugin-syntax-dynamic-import",
"@babel/plugin-syntax-import-meta", "@babel/plugin-syntax-import-meta",
["@babel/plugin-proposal-class-properties", { "loose": true }], ["@babel/plugin-proposal-class-properties", { "loose": true }],
"@babel/plugin-proposal-do-expressions",
"@babel/plugin-proposal-function-bind",
"@babel/plugin-proposal-json-strings", "@babel/plugin-proposal-json-strings",
[ [
"@babel/plugin-proposal-decorators", "@babel/plugin-proposal-decorators",
@@ -28,7 +30,7 @@
} }
], ],
"@babel/plugin-proposal-nullish-coalescing-operator", "@babel/plugin-proposal-nullish-coalescing-operator",
"@babel/plugin-proposal-do-expressions", ["@babel/plugin-proposal-private-methods", { "loose": true }],
"@babel/plugin-proposal-function-bind" ["@babel/plugin-proposal-private-property-in-object", { "loose": true }]
] ]
} }

7
.dockerignore Normal file
View File

@@ -0,0 +1,7 @@
Dockerfile
.dockerignore
.gitignore
README.md
build
node_modules

14
.gitattributes vendored Normal file
View File

@@ -0,0 +1,14 @@
# Set the default behavior, in case people don't have core.autocrlf set, in order to prevent line ending inconsistency.
* text=auto
# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
*.jsx text
*.js text
# Declare files that will always have CRLF line endings on checkout.
# *.sln text eol=crlf
# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary

1
.gitignore vendored
View File

@@ -10,4 +10,3 @@ env
.project .project
.vscode/ .vscode/
docs/ docs/
package-lock.json

1
.npmrc
View File

@@ -1 +0,0 @@
package-lock=false

25
Dockerfile Normal file
View File

@@ -0,0 +1,25 @@
#syntax=docker/dockerfile:1.4
# Run this from within this directory. Change the location of coriolis-data repo and image name/tag as needed.
# docker buildx build --build-context data=../coriolis-data --tag coriolis .
FROM node:18-alpine
# TODO: For a production build, we may want to just build the bundle and copy that in. No need for local copy of source.
WORKDIR /app
ADD . .
COPY --from=data . /coriolis-data/
# Git is required before install if any modules (like coriolis-data) are loaded from github
RUN apk update
RUN apk add git
WORKDIR /app/coriolis-data
RUN npm install
WORKDIR /app
RUN npm install
# Bundle for production config with webpack & log
RUN npm run build > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2)
# Optimally, this will start a static asset server like nginx/apache. Currently, this will start dev webpack server.
CMD ["npm", "start"]
EXPOSE 3300

23
Dockerfile-dev Normal file
View File

@@ -0,0 +1,23 @@
#syntax=docker/dockerfile:1.4
# Run this from within this directory. Change the location of coriolis-data repo and image name/tag as needed.
# docker buildx build --build-context data=../coriolis-data --tag coriolis -f ./Dockerfile-dev .
FROM node:18-alpine
WORKDIR /app
ADD . .
COPY --from=data . /coriolis-data/
# Install git & any other desired in-container dev tools
# Git is required before install if any modules (like coriolis-data) are loaded from github
RUN apk update
RUN apk add git
WORKDIR /app/coriolis-data
RUN npm install
WORKDIR /app
RUN npm install
CMD ["npm", "start"]
EXPOSE 3300

32
Dockerfile-local-prod Normal file
View File

@@ -0,0 +1,32 @@
#syntax=docker/dockerfile:1.4
# Run this from within this directory. Change the location of coriolis-data repo and image name/tag as needed.
# docker buildx build --build-context data=../coriolis-data --tag coriolis:0.0.7-local-prod -f Dockerfile-local-prod .
# docker run -d -p 80:8080 coriolis:0.0.7-local-prod
FROM node:18-alpine
# TODO: For a production build, we may want to just build the bundle and copy that in. No need for local copy of source.
WORKDIR /app
ADD . .
# COPY --from=data . /coriolis-data/
# Git is required before install if any modules (like coriolis-data is now referenced in the package.json) are loaded from github
RUN apk update
RUN apk add git
# WORKDIR /app/coriolis-data
# RUN npm install
# WORKDIR /app
# RUN npm install
# Bundle for production config with webpack & log
# In this version of the dockerfile, I'm deferring automated webpack build so I can monitor a manual build
# RUN npm run build > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2)
RUN npm install -g http-server
# Optimally, this will start a static asset server like nginx/apache. Currently, this will start dev webpack server.
# CMD ["http-server", "/app/build", "-c-1"]
CMD ["/bin/ash"]
# CMD [""]
EXPOSE 8080

View File

@@ -2,7 +2,7 @@
## About ## About
The Coriolis project was inspired by [E:D Shipyard](http://www.edshipyard.com/) and, of course, [Elite Dangerous](http://www.elitedangerous.com). The ultimate goal of Coriolis is to provide rich features to support in-game play and planning while engaging the E:D community to support its development. The Coriolis project was inspired by E:D Shipyard and, of course, [Elite Dangerous](http://www.elitedangerous.com). The ultimate goal of Coriolis is to provide rich features to support in-game play and planning while engaging the E:D community to support its development.
Coriolis was created using assets and imagery from Elite: Dangerous, with the permission of Frontier Developments plc, for non-commercial purposes. It is not endorsed by nor reflects the views or opinions of Frontier Developments and no employee of Frontier Developments was involved in the making of it. Coriolis was created using assets and imagery from Elite: Dangerous, with the permission of Frontier Developments plc, for non-commercial purposes. It is not endorsed by nor reflects the views or opinions of Frontier Developments and no employee of Frontier Developments was involved in the making of it.
@@ -14,7 +14,16 @@ Coriolis was created using assets and imagery from Elite: Dangerous, with the pe
## Development ## Development
To get a local instance of coriolis running, perform the following steps in a shell: This release includes the ability to run the app as a Docker container.
```sh
> git clone https://github.com/EDCD/coriolis.git
> git clone https://github.com/EDCD/coriolis-data.git
> cd coriolis
> docker buildx build --build-context data=../coriolis-data --tag coriolis .
> docker run -d -p 3300:3300 coriolis
```
Or to run an instance of coriolis without Docker Desktop, perform the following steps in a shell:
```sh ```sh
> git clone https://github.com/EDCD/coriolis.git > git clone https://github.com/EDCD/coriolis.git
> git clone https://github.com/EDCD/coriolis-data.git > git clone https://github.com/EDCD/coriolis-data.git
@@ -29,7 +38,7 @@ You will then have a development server running on `localhost:3300`.
### Ship and Module Database ### Ship and Module Database
See the [Data wiki](https://github.com/cmmcleod/coriolis-data/wiki) for details on structure, etc. See the [Data wiki](https://github.com/EDCD/coriolis-data/wiki) for details on structure, etc.
## Deployment ## Deployment

View File

@@ -3,24 +3,13 @@ var WebpackDevServer = require("webpack-dev-server");
var config = require('./webpack.config.dev'); var config = require('./webpack.config.dev');
new WebpackDevServer(webpack(config), { new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: true, hot: true,
disableHostCheck: true,
headers: { "Access-Control-Allow-Origin": "*" }, headers: { "Access-Control-Allow-Origin": "*" },
historyApiFallback: { historyApiFallback: {
rewrites: [ rewrites: [
// For some reason connect-history-api-fallback does not allow '.' in the URL for history fallback... // For some reason connect-history-api-fallback does not allow '.' in the URL for history fallback...
{ from: /\/outfit\//, to: '/index.html' } { from: /\/outfit\//, to: '/index.html' }
] ]
},
stats: {
assets: true,
colors: true,
version: false,
hash: false,
timings: true,
chunks: false,
chunkModules: false
} }
}).listen(3300, "0.0.0.0", function (err, result) { }).listen(3300, "0.0.0.0", function (err, result) {
if (err) { if (err) {

12992
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,19 @@
{ {
"name": "coriolis_shipyard", "name": "coriolis_shipyard",
"version": "3.0.0", "version": "3.0.1",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/EDCD/coriolis" "url": "https://github.com/EDCD/coriolis"
}, },
"homepage": "https://coriolis.io", "homepage": "https://coriolis.io",
"bugs": "https://github.com/EDCD/coriolis/issues", "bugs": "https://github.com/EDCD/coriolis/issues",
"contributors": [
{ "name": "cmdrmcdonald" },
{ "name": "willb321" },
{ "name": "felixlinker" }
],
"private": true, "private": true,
"engine": "node >= 4.8.1", "engine": "node >= 10.13.0",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"extract-translations": "grep -hroE \"(translate\\('[^']+'\\))|(tip.bind\\(null, '[^']+')\" src/* | grep -oE \"'[^']+'\" | grep -oE \"[^']+\" | sort -u -f", "extract-translations": "grep -hroE \"(translate\\('[^']+'\\))|(tip.bind\\(null, '[^']+')\" src/* | grep -oE \"'[^']+'\" | grep -oE \"[^']+\" | sort -u -f",
@@ -18,7 +23,8 @@
"test": "jest", "test": "jest",
"prod-serve": "nginx -p $(pwd) -c nginx.conf", "prod-serve": "nginx -p $(pwd) -c nginx.conf",
"prod-stop": "kill -QUIT $(cat nginx.pid)", "prod-stop": "kill -QUIT $(cat nginx.pid)",
"build": "npm run clean && cross-env NODE_ENV=production webpack -p --config webpack.config.prod.js", "buildfresh": "rimraf node_modules && rm package-lock.json && npm install && npm run build > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2)",
"build": "npm run clean && cross-env NODE_ENV=production webpack --config webpack.config.prod.js",
"rsync": "rsync -ae \"ssh -i $CORIOLIS_PEM\" --delete build/ $CORIOLIS_USER@$CORIOLIS_HOST:~/wwws", "rsync": "rsync -ae \"ssh -i $CORIOLIS_PEM\" --delete build/ $CORIOLIS_USER@$CORIOLIS_HOST:~/wwws",
"deploy": "npm run lint && npm test && npm run build && npm run rsync" "deploy": "npm run lint && npm test && npm run build && npm run rsync"
}, },
@@ -55,7 +61,7 @@
] ]
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.0.0", "@babel/core": "^7.20.12",
"@babel/plugin-proposal-class-properties": "^7.0.0", "@babel/plugin-proposal-class-properties": "^7.0.0",
"@babel/plugin-proposal-decorators": "^7.0.0", "@babel/plugin-proposal-decorators": "^7.0.0",
"@babel/plugin-proposal-do-expressions": "^7.0.0", "@babel/plugin-proposal-do-expressions": "^7.0.0",
@@ -74,15 +80,12 @@
"@babel/plugin-syntax-import-meta": "^7.0.0", "@babel/plugin-syntax-import-meta": "^7.0.0",
"@babel/preset-env": "^7.0.0", "@babel/preset-env": "^7.0.0",
"@babel/preset-react": "^7.0.0", "@babel/preset-react": "^7.0.0",
"appcache-webpack-plugin": "^1.4.0", "@rollup/plugin-node-resolve": "^15.0.1",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^10.0.1",
"babel-jest": "^23.6.0",
"babel-loader": "^8.0.0", "babel-loader": "^8.0.0",
"copy-webpack-plugin": "^4.5.2", "copy-webpack-plugin": "^10.2.4",
"create-react-class": "^15.6.3", "create-react-class": "^15.6.3",
"cross-env": "^5.2.0", "cross-env": "^5.2.0",
"css-loader": "^1.0.0", "css-loader": "^6.7.3",
"d3-selection": "^1.3.2", "d3-selection": "^1.3.2",
"esdoc": "^1.1.0", "esdoc": "^1.1.0",
"esdoc-custom-theme": "^1.4.2", "esdoc-custom-theme": "^1.4.2",
@@ -93,54 +96,66 @@
"esdoc-standard-plugin": "^1.0.0", "esdoc-standard-plugin": "^1.0.0",
"eslint": "^5.6.0", "eslint": "^5.6.0",
"eslint-plugin-react": "^7.11.1", "eslint-plugin-react": "^7.11.1",
"expose-loader": "^0.7.5", "expose-loader": "^3.1.0",
"express": "^4.16.3", "express": "^4.18.2",
"extract-text-webpack-plugin": "^4.0.0-beta.0", "html-webpack-plugin": "^5.5.0",
"file-loader": "^2.0.0", "jsen": "^0.6.6",
"html-webpack-plugin": "^3.0.7",
"jest-cli": "^23.6.0",
"jsen": "^0.6.4",
"json-loader": "^0.5.4", "json-loader": "^0.5.4",
"less": "^3.8.1", "less": "^3.8.1",
"less-loader": "^4.1.0", "less-loader": "^11.1.0",
"react-addons-perf": "^15.4.2", "mini-css-extract-plugin": "^2.7.2",
"react-container-dimensions": "^1.4.1", "react-container-dimensions": "^1.4.1",
"react-testutils-additions": "^16.0.0", "react-testutils-additions": "^15.0.0",
"react-transition-group": "^2.5.0", "react-transition-group": "^2.5.0",
"rimraf": "^2.6.1", "rimraf": "^4.1.2",
"rollup": "^0.66.2", "rollup": "^3.17.2",
"rollup-plugin-node-resolve": "^3.4.0", "style-loader": "^3.3.1",
"style-loader": "^0.23.0", "uglify-js": "^3.17.4",
"uglify-js": "^3.4.9", "webpack": "^5.75.0",
"url-loader": "^1.1.1", "webpack-cli": "^5.0.1",
"webpack": "^4.20.2", "webpack-dev-server": "^4.11.1",
"webpack-bugsnag-plugins": "^1.2.2", "webpack-merge": "^5.8.0",
"webpack-cli": "^3.1.1", "webpack-notifier": "^1.15.0",
"webpack-dev-server": "^3.1.9", "workbox-cacheable-response": "^6.5.4",
"webpack-notifier": "^1.6.0", "workbox-expiration": "^6.5.4",
"workbox-webpack-plugin": "^3.6.1" "workbox-precaching": "^6.5.4",
"workbox-routing": "^6.5.4",
"workbox-strategies": "^6.5.4",
"workbox-webpack-plugin": "^6.5.4"
}, },
"sideEffects": false, "sideEffects": false,
"dependencies": { "dependencies": {
"@babel/polyfill": "^7.0.0", "assert": "^1.5.0",
"auto-bind": "^5.0.1",
"base64url": "^3.0.1",
"browserify-zlib-next": "^1.0.1", "browserify-zlib-next": "^1.0.1",
"buffer": "^5.7.0",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"constants-browserify": "^1.0.0",
"core-js": "^3.28.0",
"coriolis-data": "../coriolis-data", "coriolis-data": "../coriolis-data",
"crypto-browserify": "^3.12.0",
"d3": "^5.7.0", "d3": "^5.7.0",
"detect-browser": "^3.0.1", "detect-browser": "^3.0.1",
"fbemitter": "^2.1.1", "fbemitter": "^2.1.1",
"https-browserify": "^1.0.0",
"lodash": "^4.17.11", "lodash": "^4.17.11",
"lz-string": "^1.4.4", "lz-string": "^1.4.4",
"pako": "^1.0.6", "os-browserify": "^0.3.0",
"pako": "^2.1.0",
"path-browserify": "^1.0.1",
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
"react": "^15.5.4", "react": "^15.6.2",
"react-dom": "^15.5.4", "react-dom": "^15.6.2",
"react-extras": "^0.7.1",
"react-fuzzy": "^0.5.2", "react-fuzzy": "^0.5.2",
"react-ga": "^2.5.3", "react-ga": "^2.5.3",
"react-number-editor": "Athanasius/react-number-editor.git#miggy", "react-number-editor": "^4.0.3",
"recharts": "^1.2.0", "recharts": "^1.2.0",
"register-service-worker": "^1.5.2", "register-service-worker": "^1.7.2",
"superagent": "^3.8.3" "stream-browserify": "^3.0.0",
"stream-http": "^3.2.0",
"superagent": "^3.8.3",
"url": "^0.11.0",
"vm-browserify": "^1.1.2"
} }
} }

View File

@@ -1,4 +1,4 @@
import nodeResolve from "rollup-plugin-node-resolve"; import nodeResolve from "@rollup/plugin-node-resolve";
export default { export default {
entry: "d3-funcs.js", entry: "d3-funcs.js",

View File

@@ -214,7 +214,7 @@ Options -MultiViews
# </Files> # </Files>
AddType application/x-web-app-manifest+json webapp AddType application/x-web-app-manifest+json webapp
AddType text/cache-manifest appcache manifest # AddType text/cache-manifest appcache manifest
# Media files # Media files
AddType audio/mp4 f4a f4b m4a AddType audio/mp4 f4a f4b m4a

View File

@@ -68,7 +68,7 @@ export default class Coriolis extends React.Component {
this.state = { this.state = {
noTouch: !('ontouchstart' in window || navigator.msMaxTouchPoints || navigator.maxTouchPoints), noTouch: !('ontouchstart' in window || navigator.msMaxTouchPoints || navigator.maxTouchPoints),
page: null, page: null,
announcements: [], announcements: [{expiry: "31-08-2024", text: "25/08/2024: Type 8 Transporter added to the shipyard"}],
language: getLanguage(Persist.getLangCode()), language: getLanguage(Persist.getLangCode()),
route: {}, route: {},
sizeRatio: Persist.getSizeRatio() sizeRatio: Persist.getSizeRatio()
@@ -93,7 +93,7 @@ export default class Coriolis extends React.Component {
_importBuild(r) { _importBuild(r) {
try { try {
// Need to decode and gunzip the data, then build the ship // Need to decode and gunzip the data, then build the ship
const data = zlib.inflate(new Buffer(r.params.data, 'base64'), { to: 'string' }); const data = zlib.inflate(new Buffer.from(r.params.data, 'base64'), { to: 'string' });
const json = JSON.parse(data); const json = JSON.parse(data);
console.info('Ship import data: '); console.info('Ship import data: ');
console.info(json); console.info(json);
@@ -149,13 +149,6 @@ export default class Coriolis extends React.Component {
*/ */
_onError(msg, scriptUrl, line, col, errObj) { _onError(msg, scriptUrl, line, col, errObj) {
console && console.error && console.error(arguments); // eslint-disable-line no-console console && console.error && console.error(arguments); // eslint-disable-line no-console
if (errObj) {
if (errObj instanceof Error) {
bugsnagClient.notify(errObj); // eslint-disable-line
} else if (errObj instanceof String) {
bugsnagClient.notify(msg, errObj); // eslint-disable-line
}
}
this.setState({ this.setState({
error: <ErrorDetails error={{ message: msg, details: { scriptUrl, line, col, error: JSON.stringify(errObj) } }}/>, error: <ErrorDetails error={{ message: msg, details: { scriptUrl, line, col, error: JSON.stringify(errObj) } }}/>,
page: null, page: null,

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { autoBind } from 'react-extras'; import autoBind from 'auto-bind';
/** /**
* Announcement component * Announcement component

View File

@@ -4,7 +4,7 @@ import * as ModuleUtils from '../shipyard/ModuleUtils';
import TranslatedComponent from './TranslatedComponent'; import TranslatedComponent from './TranslatedComponent';
import { stopCtxPropagation } from '../utils/UtilityFunctions'; import { stopCtxPropagation } from '../utils/UtilityFunctions';
import cn from 'classnames'; import cn from 'classnames';
import { MountFixed, MountGimballed, MountTurret } from './SvgIcons'; import { CoriolisLogo, MountFixed, MountGimballed, MountTurret } from './SvgIcons';
import FuzzySearch from 'react-fuzzy'; import FuzzySearch from 'react-fuzzy';
const PRESS_THRESHOLD = 500; // mouse/touch down threshold const PRESS_THRESHOLD = 500; // mouse/touch down threshold
@@ -20,6 +20,7 @@ const GRPCAT = {
'cc': 'limpet controllers', 'cc': 'limpet controllers',
'fx': 'limpet controllers', 'fx': 'limpet controllers',
'hb': 'limpet controllers', 'hb': 'limpet controllers',
'mlc': 'limpet controllers',
'pc': 'limpet controllers', 'pc': 'limpet controllers',
'rpl': 'limpet controllers', 'rpl': 'limpet controllers',
'pce': 'passenger cabins', 'pce': 'passenger cabins',
@@ -38,13 +39,18 @@ const GRPCAT = {
'ml': 'lasers', 'ml': 'lasers',
'c': 'projectiles', 'c': 'projectiles',
'mc': 'projectiles', 'mc': 'projectiles',
'advmc': 'projectiles',
'axmc': 'experimental', 'axmc': 'experimental',
'axmce': 'experimental',
'ntp': 'experimental',
'fc': 'projectiles', 'fc': 'projectiles',
'rfl': 'experimental', 'rfl': 'experimental',
'pa': 'projectiles', 'pa': 'projectiles',
'rg': 'projectiles', 'rg': 'projectiles',
'mr': 'ordnance', 'mr': 'ordnance',
'amr': 'ordnance',
'axmr': 'experimental', 'axmr': 'experimental',
'axmre': 'experimental',
'rcpl': 'experimental', 'rcpl': 'experimental',
'dtl': 'experimental', 'dtl': 'experimental',
'tbsc': 'experimental', 'tbsc': 'experimental',
@@ -83,6 +89,8 @@ const GRPCAT = {
// Assists // Assists
'dc': 'flight assists', 'dc': 'flight assists',
'sua': 'flight assists', 'sua': 'flight assists',
// Stabilizers
'ews': 'weapon stabilizers',
}; };
// Order here is the order in which items will be shown in the modules menu // Order here is the order in which items will be shown in the modules menu
const CATEGORIES = { const CATEGORIES = {
@@ -92,7 +100,7 @@ const CATEGORIES = {
'fi': ['fi'], 'fi': ['fi'],
'fuel': ['ft', 'fs'], 'fuel': ['ft', 'fs'],
'hangars': ['fh', 'pv'], 'hangars': ['fh', 'pv'],
'limpet controllers': ['cc', 'fx', 'hb', 'pc', 'rpl'], 'limpet controllers': ['cc', 'fx', 'hb', 'pc', 'rpl', 'mlc'],
'passenger cabins': ['pce', 'pci', 'pcm', 'pcq'], 'passenger cabins': ['pce', 'pci', 'pcm', 'pcq'],
'rf': ['rf'], 'rf': ['rf'],
'shields': ['sg', 'bsg', 'psg', 'scb'], 'shields': ['sg', 'bsg', 'psg', 'scb'],
@@ -101,16 +109,17 @@ const CATEGORIES = {
// Hardpoints // Hardpoints
'lasers': ['pl', 'ul', 'bl'], 'lasers': ['pl', 'ul', 'bl'],
'projectiles': ['mc', 'c', 'fc', 'pa', 'rg'], 'projectiles': ['mc', 'advmc', 'c', 'fc', 'pa', 'rg'],
'ordnance': ['mr', 'tp', 'nl'], 'ordnance': ['mr', 'amr', 'tp', 'nl'],
// Utilities // Utilities
'sb': ['sb'], 'sb': ['sb'],
'hs': ['hs'], 'hs': ['hs'],
'csl': ['csl'],
'defence': ['ch', 'po', 'ec'], 'defence': ['ch', 'po', 'ec'],
'scanners': ['sc', 'ss', 'cs', 'kw', 'ws'], // Overloaded with internal scanners 'scanners': ['sc', 'ss', 'cs', 'kw', 'ws'], // Overloaded with internal scanners
// Experimental // Experimental
'experimental': ['axmc', 'axmr', 'rfl', 'tbrfl', 'tbsc', 'tbem', 'xs', 'sfn', 'rcpl', 'dtl', 'rsl', 'mahr',], 'experimental': ['axmc', 'axmce', 'axmr', 'axmre', 'ntp','rfl', 'tbrfl', 'tbsc', 'tbem', 'xs', 'sfn', 'rcpl', 'dtl', 'rsl', 'mahr',],
'weapon stabilizers': ['ews'],
// Guardian // Guardian
'guardian': ['gpp', 'gpd', 'gpc', 'ggc', 'gsrp', 'gfsb', 'ghrp', 'gmrp', 'gsc'], 'guardian': ['gpp', 'gpd', 'gpc', 'ggc', 'gsrp', 'gfsb', 'ghrp', 'gmrp', 'gsc'],
@@ -209,17 +218,31 @@ export default class AvailableModulesMenu extends TranslatedComponent {
if (categories.length === 1) { if (categories.length === 1) {
// Show category header instead of group header // Show category header instead of group header
if (m && grp == m.grp) { if (m && grp == m.grp) {
// If this is a missing module/weapon, skip it
if (m.grp == "mh" || m.grp == "mm"){
continue;
} else {
list.push(<div ref={(elem) => this.groupElem = elem} key={category} list.push(<div ref={(elem) => this.groupElem = elem} key={category}
className={'select-category upp'}>{translate(category)}</div>); className={'select-category upp'}>{translate(category)}</div>);
}
} else {
if (category == "mh" || category == "mm"){
continue;
} 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>);
} }
}
} else { } else {
// Show category header as well as group header // Show category header as well as group header
if (!categoryHeader) { if (!categoryHeader) {
if (category == "mh" || category == "mm"){
continue;
}
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>);
categoryHeader = true; categoryHeader = true;
} }
}
if (m && grp == m.grp) { if (m && grp == m.grp) {
list.push(<div ref={(elem) => this.groupElem = elem} key={grp} list.push(<div ref={(elem) => this.groupElem = elem} key={grp}
className={'select-group cap'}>{translate(grp)}</div>); className={'select-group cap'}>{translate(grp)}</div>);
@@ -237,7 +260,11 @@ export default class AvailableModulesMenu extends TranslatedComponent {
} else if (i.mount === 'T') { } else if (i.mount === 'T') {
mount = 'Turreted'; mount = 'Turreted';
} }
const fuzz = { grp, m: i, name: `${i.class}${i.rating}${mount ? ' ' + mount : ''} ${translate(grp)}` }; let special = '';
if (typeof(i.special) !== 'undefined') {
special = `(${translate(i.special)})`;
}
const fuzz = { grp, m: i, name: `${i.class}${i.rating}${mount ? ' ' + mount : ''} ${translate(grp)} ${translate(special)}` };
fuzzy.push(fuzz); fuzzy.push(fuzz);
} }
} }
@@ -249,6 +276,24 @@ export default class AvailableModulesMenu extends TranslatedComponent {
return { list, currentGroup, fuzzy, trackingFocus }; return { list, currentGroup, fuzzy, trackingFocus };
} }
/**
* Return Is expiremental capacity reached
* @return {boolean} Is experimental capacity reached
*/
_experimentalCapacityReached() {
const ship = this.props.ship;
const ews = ship.internal.filter(o => o.m && o.m.grp === 'ews');
let expCap;
if(ews.length < 1){
expCap = 4;
} else{
expCap = ews[0].m.class == 3 ? 5 : 6;
}
return expCap <= this.props.ship.hardpoints.filter(o => o.m && o.m.experimental).length;
}
/** /**
* Generate React Components for Module Group * Generate React Components for Module Group
* @param {Ship} ship Ship the selection is for * @param {Ship} ship Ship the selection is for
@@ -276,6 +321,11 @@ export default class AvailableModulesMenu extends TranslatedComponent {
let itemsOnThisRow = 0; let itemsOnThisRow = 0;
for (let i = 0; i < sortedModules.length; i++) { for (let i = 0; i < sortedModules.length; i++) {
let m = sortedModules[i]; let m = sortedModules[i];
// If m.grp is mh or mm, or m.symbol contains 'Missing' skip it
if (m.grp == 'mh' || m.grp == 'mm' || (typeof(m.symbol) !== 'undefined' && m.symbol.includes("Missing"))) {
// If this is a missing module, skip it
continue;
}
let mount = null; let mount = null;
let disabled = false; let disabled = false;
prevName = m.name; prevName = m.name;
@@ -285,7 +335,9 @@ export default class AvailableModulesMenu extends TranslatedComponent {
// If the mounted module is experimental as well, we can replace it so // If the mounted module is experimental as well, we can replace it so
// the maximum does not apply // the maximum does not apply
} else if (m.experimental && (!mountedModule || !mountedModule.experimental)) { } else if (m.experimental && (!mountedModule || !mountedModule.experimental)) {
disabled = 4 <= ship.hardpoints.filter(o => o.m && o.m.experimental).length; disabled = this._experimentalCapacityReached();
} else if (m.grp === 'mlc' && (!mountedModule || mountedModule.grp !== 'mlc')) {
disabled = 1 <= ship.internal.filter(o => o.m && o.m.grp === 'mlc').length;
} }
let active = mountedModule && mountedModule.id === m.id; let active = mountedModule && mountedModule.id === m.id;
let classes = cn(m.name ? 'lc' : 'c', { let classes = cn(m.name ? 'lc' : 'c', {
@@ -382,6 +434,7 @@ export default class AvailableModulesMenu extends TranslatedComponent {
if (this.props.modules instanceof Array) { if (this.props.modules instanceof Array) {
return; return;
} }
const mountedModule = this.props.m;
return ( return (
<FuzzySearch <FuzzySearch
list={this.state.fuzzy} list={this.state.fuzzy}
@@ -393,11 +446,20 @@ export default class AvailableModulesMenu extends TranslatedComponent {
onSelect={e => this.props.onSelect.bind(null, e.m)()} onSelect={e => this.props.onSelect.bind(null, e.m)()}
resultsTemplate={(props, state, styles, clickHandler) => { resultsTemplate={(props, state, styles, clickHandler) => {
return state.results.map((val, i) => { return state.results.map((val, i) => {
let disabled;
if(val.m.experimental && (!mountedModule || !mountedModule.experimental)) {
disabled = this._experimentalCapacityReached();
} else{
disabled = false;
}
const handler = disabled ? null : () => clickHandler(i);
return ( return (
<div <div
key={i} key={i}
className={'lc'} className={cn('lc', {disabled})}
onClick={() => clickHandler(i)} onClick={handler}
> >
{val.name} {val.name}
</div> </div>
@@ -516,6 +578,15 @@ export default class AvailableModulesMenu extends TranslatedComponent {
return 1; return 1;
} }
} }
// Sort multi limpet controllers by name
if (a.grp === 'mlc') {
if (a.name[0] <= b.name[0]) {
return -1;
}
if (a.name[0] > b.name[0]) {
return 1;
}
}
// Rating ordered from highest (A) to lowest (E) // Rating ordered from highest (A) to lowest (E)
if (a.rating < b.rating) { if (a.rating < b.rating) {
return -1; return -1;

View File

@@ -32,7 +32,7 @@ export default class CostSection extends TranslatedComponent {
this._buildRetrofitShip = this._buildRetrofitShip.bind(this); this._buildRetrofitShip = this._buildRetrofitShip.bind(this);
this._onBaseRetrofitChange = this._onBaseRetrofitChange.bind(this); this._onBaseRetrofitChange = this._onBaseRetrofitChange.bind(this);
this._defaultRetrofitName = this._defaultRetrofitName.bind(this); this._defaultRetrofitName = this._defaultRetrofitName.bind(this);
this._eddbShoppingList = this._eddbShoppingList.bind(this); this._eddbShoppingList = this._inaraShoppingList.bind(this);
let data = Ships[props.ship.id]; // Retrieve the basic ship properties, slots and defaults let data = Ships[props.ship.id]; // Retrieve the basic ship properties, slots and defaults
let retrofitName = this._defaultRetrofitName(props.ship.id, props.buildName); let retrofitName = this._defaultRetrofitName(props.ship.id, props.buildName);
@@ -328,9 +328,9 @@ export default class CostSection extends TranslatedComponent {
} }
/** /**
* Open up a window for EDDB with a shopping list of our retrofit components * Open up a window for inara with a shopping list of our retrofit components
*/ */
_eddbShoppingList() { _inaraShoppingList() {
const { retrofitCosts } = this.state; const { retrofitCosts } = this.state;
const { ship } = this.props; const { ship } = this.props;
@@ -338,7 +338,7 @@ export default class CostSection extends TranslatedComponent {
const modIds = retrofitCosts.filter(item => item.retroItem.incCost && item.buyId && !item.buyPp).map(item => item.buyId).filter((v, i, a) => a.indexOf(v) === i); const modIds = retrofitCosts.filter(item => item.retroItem.incCost && item.buyId && !item.buyPp).map(item => item.buyId).filter((v, i, a) => a.indexOf(v) === i);
// Open up the relevant URL // Open up the relevant URL
window.open('https://eddb.io/station?m=' + modIds.join(',')); window.open('https://inara.cz/inapi/corisearch.php?m=' + modIds.join(','));
} }
/** /**
@@ -387,7 +387,7 @@ export default class CostSection extends TranslatedComponent {
<tbody> <tbody>
{rows} {rows}
<tr className='ri'> <tr className='ri'>
<td className='lbl' ><button onClick={this._eddbShoppingList} onMouseOver={termtip.bind(null, 'PHRASE_REFIT_SHOPPING_LIST')} onMouseOut={tooltip.bind(null, null)}><ShoppingIcon className='lg' style={{ fill: 'black' }}/></button></td> <td className='lbl' ><button onClick={this._inaraShoppingList} onMouseOver={termtip.bind(null, 'PHRASE_REFIT_SHOPPING_LIST')} onMouseOut={tooltip.bind(null, null)}><ShoppingIcon className='lg' style={{ fill: 'black' }}/></button></td>
<td colSpan='3' className='lbl' >{translate('cost')}</td> <td colSpan='3' className='lbl' >{translate('cost')}</td>
<td colSpan='2' className={cn('val', retrofitTotal > 0 ? 'warning' : 'secondary-disabled')} style={{ borderBottom:'none' }}> <td colSpan='2' className={cn('val', retrofitTotal > 0 ? 'warning' : 'secondary-disabled')} style={{ borderBottom:'none' }}>
{int(retrofitTotal)}{units.CR} {int(retrofitTotal)}{units.CR}

View File

@@ -136,6 +136,7 @@ export default class HardpointSlot extends Slot {
{showModuleResistances && m.getThermalResistance() ? <div {showModuleResistances && m.getThermalResistance() ? <div
className='l'>{translate('thermres')}: {formats.pct(m.getThermalResistance())}</div> : null} className='l'>{translate('thermres')}: {formats.pct(m.getThermalResistance())}</div> : null}
{m.getIntegrity() ? <div className='l'>{translate('integrity')}: {formats.int(m.getIntegrity())}</div> : null} {m.getIntegrity() ? <div className='l'>{translate('integrity')}: {formats.int(m.getIntegrity())}</div> : null}
{m.getInfo() ? <div className='l'>{translate(m.getInfo())}</div> : null}
{m && validMods.length > 0 ? <div className='r' tabIndex="0" ref={modButton => this.modButton = modButton}> {m && validMods.length > 0 ? <div className='r' tabIndex="0" ref={modButton => this.modButton = modButton}>
<button tabIndex="-1" onClick={this._toggleModifications.bind(this)} onContextMenu={stopCtxPropagation} <button tabIndex="-1" onClick={this._toggleModifications.bind(this)} onContextMenu={stopCtxPropagation}
onMouseOver={termtip.bind(null, 'modifications')} onMouseOut={tooltip.bind(null, null)}> onMouseOver={termtip.bind(null, 'modifications')} onMouseOut={tooltip.bind(null, null)}>

View File

@@ -88,6 +88,7 @@ export default class InternalSlot extends Slot {
{ m.getHullReinforcement() ? <div className='l'>{translate('armour')}: {formats.int(m.getHullReinforcement() + ship.baseArmour * m.getModValue('hullboost') / 10000)}</div> : null } { m.getHullReinforcement() ? <div className='l'>{translate('armour')}: {formats.int(m.getHullReinforcement() + ship.baseArmour * m.getModValue('hullboost') / 10000)}</div> : null }
{ m.getProtection() ? <div className='l'>{translate('protection')}: {formats.rPct(m.getProtection())}</div> : null } { m.getProtection() ? <div className='l'>{translate('protection')}: {formats.rPct(m.getProtection())}</div> : null }
{ m.getIntegrity() ? <div className='l'>{translate('integrity')}: {formats.int(m.getIntegrity())}</div> : null } { m.getIntegrity() ? <div className='l'>{translate('integrity')}: {formats.int(m.getIntegrity())}</div> : null }
{ m.getInfo() ? <div className='l'>{translate(m.getInfo())}</div> : null }
{ m && validMods.length > 0 ? <div className='r' tabIndex="0" ref={ modButton => this.modButton = modButton }><button tabIndex="-1" onClick={this._toggleModifications.bind(this)} onContextMenu={stopCtxPropagation} onMouseOver={termtip.bind(null, 'modifications')} onMouseOut={tooltip.bind(null, null)}><ListModifications /></button></div> : null } { m && validMods.length > 0 ? <div className='r' tabIndex="0" ref={ modButton => this.modButton = modButton }><button tabIndex="-1" onClick={this._toggleModifications.bind(this)} onContextMenu={stopCtxPropagation} onMouseOver={termtip.bind(null, 'modifications')} onMouseOut={tooltip.bind(null, null)}><ListModifications /></button></div> : null }
</div> </div>
</div>; </div>;

View File

@@ -34,6 +34,18 @@ export default class ModalPermalink extends TranslatedComponent {
); );
} }
/**
* Copy the shortened URL to the clipboard
* @param {Event} e Click event
* @return {void}
*/
copyShortLink() {
let copyText = document.getElementById("shortenedUrl");
// Copy the text inside the shortendUrl input to the clipboard
copyText.select();
document.execCommand("copy");
}
/** /**
* Render the modal * Render the modal
* @return {React.Component} Modal Content * @return {React.Component} Modal Content
@@ -42,15 +54,17 @@ export default class ModalPermalink extends TranslatedComponent {
let translate = this.context.language.translate; let translate = this.context.language.translate;
return <div className='modal' onClick={ (e) => e.stopPropagation() }> return <div className='modal' onClick={ (e) => e.stopPropagation() }>
<h2>{translate('permalink')}</h2> <h3>{translate('permalink')}</h3>
<br/> <br/>
<h3>{translate('URL')}</h3> <h3>{translate('URL')}</h3>
<input value={this.props.url} size={40} readOnly onFocus={ (e) => e.target.select() }/> <input value={this.props.url} size={40} readOnly onFocus={ (e) => e.target.select() }/>
<br/><br/> <br/><br/>
<h3 >{translate('shortened')}</h3> <h3 >{translate('shortened')}</h3>
<input value={this.state.shortenedUrl} readOnly size={25} onFocus={ (e) => e.target.select() }/> <input id={'shortenedUrl'} value={this.state.shortenedUrl} readOnly size={25} onFocus={ (e) => e.target.select() }/><button className={'cb dismiss cap'} onClick={this.copyShortLink}>{translate('copy to clipboard')}</button>
<br/><br/> <br/><br/>
<p>s.orbis.zone is the new URL shortener domain, old eddp.co urls are considered end of life and could go down at any moment. Sorry for any inconvenience.</p> <hr />
<p>s.orbis.zone is the URL shortener domain. These links should persist indefinitely going forward. If for some reason there is a problem with the link shortening process, please report it in the EDCD Discord Server.</p>
<hr />
<button className={'r dismiss cap'} onClick={this.context.hideModal}>{translate('close')}</button> <button className={'r dismiss cap'} onClick={this.context.hideModal}>{translate('close')}</button>
</div>; </div>;
} }

View File

@@ -3,6 +3,8 @@ import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent'; import TranslatedComponent from './TranslatedComponent';
import request from 'superagent'; import request from 'superagent';
import Persist from '../stores/Persist'; import Persist from '../stores/Persist';
const zlib = require('zlib');
const base64url = require('base64url');
/** /**
* Permalink modal * Permalink modal
@@ -10,7 +12,8 @@ import Persist from '../stores/Persist';
export default class ModalShoppingList extends TranslatedComponent { export default class ModalShoppingList extends TranslatedComponent {
static propTypes = { static propTypes = {
ship: PropTypes.object.isRequired ship: PropTypes.object.isRequired,
buildName: PropTypes.string
}; };
/** /**
@@ -56,7 +59,6 @@ export default class ModalShoppingList extends TranslatedComponent {
continue; continue;
} }
if (module.m.blueprint.special) { if (module.m.blueprint.special) {
console.log(module.m.blueprint.special);
blueprints.push({ uuid: module.m.blueprint.special.uuid, number: 1 }); blueprints.push({ uuid: module.m.blueprint.special.uuid, number: 1 });
} }
for (const g in module.m.blueprint.grades) { for (const g in module.m.blueprint.grades) {
@@ -89,8 +91,10 @@ export default class ModalShoppingList extends TranslatedComponent {
request request
.get('http://localhost:44405/commanders') .get('http://localhost:44405/commanders')
.end((err, res) => { .end((err, res) => {
this.display = 'block';
if (err) { if (err) {
console.log(err); console.log(err);
this.display = 'none';
return this.setState({ failed: true }); return this.setState({ failed: true });
} }
const cmdrs = JSON.parse(res.text); const cmdrs = JSON.parse(res.text);
@@ -146,6 +150,113 @@ export default class ModalShoppingList extends TranslatedComponent {
} }
} }
/**
* Fix issues with the item name for bulkheads when sending to EDOMH
* @param {*} ship Ship object
* @param {*} item Item name
* @returns updated item name
*/
fixArmourItemNameForEDOMH(ship, item) {
// The module blueprint fdname contains "Armour_" it's a bulkhead and we need to pre-populate the item field with the correct name from the ship object
switch (ship.bulkheads.m.name){
case "Lightweight Alloy":
item = ship.id + "_Armour_Grade1";
break;
case "Reinforced Alloy":
item = ship.id + "_Armour_Grade2";
break;
case "Military Grade Composite":
item = ship.id + "_Armour_Grade3";
break;
case "Mirrored Surface Composite":
item = ship.id + "_Armour_Mirrored";
break;
case "Reactive Surface Composite":
item = ship.id + "_Armour_Reactive";
break;
}
return item;
}
/**
* Send all blueprints to EDOMH. This is a modified copy of registerBPs because this.state.blueprints was empty when I tried to modify sendToEDEng and I couldn't figure out why
* @param {Event} event React event
*/
sendToEDOMH(event) {
event.preventDefault();
const ship = this.props.ship;
const buildName = this.props.buildName;
let blueprints = [];
//create the json
for (const module of ship.costList) {
if (module.type === 'SHIP') {
continue;
}
if (module.m && module.m.blueprint) {
if (!module.m.blueprint.grade || !module.m.blueprint.grades) {
continue;
}
if (module.m.blueprint.special) {
let item = "";
// If the module blueprint fdname contains "Armour_" it's a bulkhead and we need to pre-populate the item field with the correct name from the ship object
if (module.m.blueprint.fdname.includes("Armour_")) {
item = this.fixArmourItemNameForEDOMH(ship, item)
}
else {
item = module.m.symbol;
}
blueprints.push({
"item": item,
"blueprint": module.m.blueprint.special.edname
});
}
for (let g in module.m.blueprint.grades) {
if (!module.m.blueprint.grades.hasOwnProperty(g)) {
continue;
}
// We only want the grade that the module is currently at, not every grade up to that point
if (Number(g) !== module.m.blueprint.grade) {
continue;
}
let item = "";
// If the module blueprint fdname contains "Armour_" it's a bulkhead and we need to pre-populate the item field with the correct name from the ship object
if (module.m.blueprint.fdname.includes("Armour_")) {
item = this.fixArmourItemNameForEDOMH(ship, item)
}
else {
item = module.m.symbol;
}
blueprints.push({
"item": item,
"blueprint": module.m.blueprint.fdname,
"grade": module.m.blueprint.grade,
"highestGradePercentage":1.0
});
}
}
}
let shipName = buildName + " - " + ship.name;
//create JSON to encode
let baseJson = {
"version":1,
"name": shipName, // TO-DO: Import build name and put that here correctly
"items": blueprints
}
let JSONString = JSON.stringify(baseJson)
let deflated = zlib.deflateSync(JSONString)
//actually encode
let link = base64url.encode(deflated)
link = "edomh://coriolis/?" + link;
window.open(link, "_self")
}
/** /**
* Convert mats object to string * Convert mats object to string
*/ */
@@ -160,14 +271,15 @@ export default class ModalShoppingList extends TranslatedComponent {
if (!module.m.blueprint.grade || !module.m.blueprint.grades) { if (!module.m.blueprint.grade || !module.m.blueprint.grades) {
continue; continue;
} }
for (const g in module.m.blueprint.grades) { for (let g in module.m.blueprint.grades) {
if (!module.m.blueprint.grades.hasOwnProperty(g)) { if (!module.m.blueprint.grades.hasOwnProperty(g)) {
continue; continue;
} }
if (g > module.m.blueprint.grade) { // Ignore grades higher than the grade selected
if (Number(g) > module.m.blueprint.grade) {
continue; continue;
} }
for (const i in module.m.blueprint.grades[g].components) { for (let i in module.m.blueprint.grades[g].components) {
if (!module.m.blueprint.grades[g].components.hasOwnProperty(i)) { if (!module.m.blueprint.grades[g].components.hasOwnProperty(i)) {
continue; continue;
} }
@@ -178,6 +290,18 @@ export default class ModalShoppingList extends TranslatedComponent {
} }
} }
} }
if (module.m.blueprint.special) {
for (const j in module.m.blueprint.special.components) {
if (!module.m.blueprint.special.components.hasOwnProperty(j)) {
continue;
}
if (mats[j]) {
mats[j] += module.m.blueprint.special.components[j];
} else {
mats[j] = module.m.blueprint.special.components[j];
}
}
}
} }
} }
let matsString = ''; let matsString = '';
@@ -229,34 +353,48 @@ export default class ModalShoppingList extends TranslatedComponent {
const compatible = this.checkBrowserIsCompatible(); const compatible = this.checkBrowserIsCompatible();
this.cmdrChangeHandler = this.cmdrChangeHandler.bind(this); this.cmdrChangeHandler = this.cmdrChangeHandler.bind(this);
this.sendToEDEng = this.sendToEDEng.bind(this); this.sendToEDEng = this.sendToEDEng.bind(this);
this.sendToEDOMH = this.sendToEDOMH.bind(this);
return <div className='modal' onClick={ (e) => e.stopPropagation() }> return <div className='modal' onClick={ (e) => e.stopPropagation() }>
<h2>{translate('PHRASE_SHOPPING_MATS')}</h2> <h3>{translate('PHRASE_SHOPPING_MATS')}</h3>
<label>{translate('Grade 1 rolls ')}</label>
<input id={1} type={'number'} min={0} defaultValue={this.state.matsPerGrade[1]} onChange={this.changeHandler} />
<br/>
<label>{translate('Grade 2 rolls ')}</label>
<input id={2} type={'number'} min={0} defaultValue={this.state.matsPerGrade[2]} onChange={this.changeHandler} />
<br/>
<label>{translate('Grade 3 rolls ')}</label>
<input id={3} type={'number'} min={0} value={this.state.matsPerGrade[3]} onChange={this.changeHandler} />
<br/>
<label>{translate('Grade 4 rolls ')}</label>
<input id={4} type={'number'} min={0} value={this.state.matsPerGrade[4]} onChange={this.changeHandler} />
<br/>
<label>{translate('Grade 5 rolls ')}</label>
<input id={5} type={'number'} min={0} value={this.state.matsPerGrade[5]} onChange={this.changeHandler} />
<div> <div>
<textarea className='cb json' readOnly value={this.state.matsList} /> <p>{translate('PHRASE_DIFFERENT_ROLLS')}</p>
<label>{translate('G1')}</label>
<input className={'groll'} id={1} type={'number'} min={0} defaultValue={this.state.matsPerGrade[1]} onChange={this.changeHandler} />
&nbsp;|&nbsp;<label>{translate('G2')}</label>
<input className={'groll'} id={2} type={'number'} min={0} defaultValue={this.state.matsPerGrade[2]} onChange={this.changeHandler} />
&nbsp;|&nbsp;<label>{translate('G3')}</label>
<input className={'groll'} id={3} type={'number'} min={0} value={this.state.matsPerGrade[3]} onChange={this.changeHandler} />
&nbsp;|&nbsp;<label>{translate('G4')}</label>
<input className={'groll'} id={4} type={'number'} min={0} value={this.state.matsPerGrade[4]} onChange={this.changeHandler} />
&nbsp;|&nbsp;<label>{translate('G5')}</label>
<input className={'groll'} id={5} type={'number'} min={0} value={this.state.matsPerGrade[5]} onChange={this.changeHandler} />
</div> </div>
<label hidden={!compatible} className={'l cap'}>{translate('CMDR Name')}</label>
<br/> <div>
<select hidden={!compatible} className={'cmdr-select l cap'} onChange={this.cmdrChangeHandler} defaultValue={this.state.cmdrName}> <p>{translate('PHRASE_ALL_MODULES_ALL_ROLLS')}</p>
<textarea className='cb json' readOnly value={this.state.matsList} />
<p>{translate('PHRASE_FOR_FINER_CONTROL')}</p>
</div>
<div id='edengineer' display={this.display} hidden={!!this.state.failed && !compatible}>
<hr />
<h3>ED Engineer</h3>
<h4 hidden={compatible} id={'browserbad'} className={'l'}>{translate('PHRASE_FIREFOX_EDENGINEER')}</h4>
<h4 hidden={!this.state.failed} id={'failed'} className={'l'}>{translate('PHRASE_FAILED_TO_FIND_EDENGINEER')}</h4>
<label for='cmdr-select' hidden={!!this.state.failed || !compatible} className={'l cap'}>{translate('CMDR Name:')}</label>
<select id='cmdr-select' hidden={!!this.state.failed || !compatible} className={'cmdr-select l cap'} onChange={this.cmdrChangeHandler} defaultValue={this.state.cmdrName}>
{this.state.cmdrs.map(e => <option key={e}>{e}</option>)} {this.state.cmdrs.map(e => <option key={e}>{e}</option>)}
</select> </select>
<br/> <br/>
<p hidden={!this.state.failed} id={'failed'} className={'l'}>{translate('PHRASE_FAIL_EDENGINEER')}</p>
<p hidden={compatible} id={'browserbad'} className={'l'}>{translate('PHRASE_FIREFOX_EDENGINEER')}</p>
<button className={'l cb dismiss cap'} disabled={!!this.state.failed || !compatible} onClick={this.sendToEDEng}>{translate('Send to EDEngineer')}</button> <button className={'l cb dismiss cap'} disabled={!!this.state.failed || !compatible} onClick={this.sendToEDEng}>{translate('Send to EDEngineer')}</button>
</div>
<div id='edomh'>
<hr />
<h3>ED Odyssey Materials Helper</h3>
<p>{translate('PHRASE_ENSURE_EDOMH')}</p>
<button className={'l cb dismiss cap'} onClick={this.sendToEDOMH}>{translate('Send to EDOMH')}</button>
</div>
<hr />
<button className={'r dismiss cap'} onClick={this.context.hideModal}>{translate('close')}</button> <button className={'r dismiss cap'} onClick={this.context.hideModal}>{translate('close')}</button>
</div>; </div>;
} }

View File

@@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import TranslatedComponent from './TranslatedComponent'; import TranslatedComponent from './TranslatedComponent';
import { Pip } from './SvgIcons'; import { Pip } from './SvgIcons';
import { autoBind } from 'react-extras'; import autoBind from 'auto-bind';
/** /**
* Pips displays SYS/ENG/WEP pips and allows users to change them with key presses by clicking on the relevant area. * Pips displays SYS/ENG/WEP pips and allows users to change them with key presses by clicking on the relevant area.

View File

@@ -99,6 +99,7 @@ export default class Slot extends TranslatedComponent {
let translate = language.translate; let translate = language.translate;
let { ship, m, enabled, dropClass, dragOver, onOpen, onChange, selected, eligible, onSelect, warning, availableModules } = this.props; let { ship, m, enabled, dropClass, dragOver, onOpen, onChange, selected, eligible, onSelect, warning, availableModules } = this.props;
let slotDetails, modificationsMarker, menu; let slotDetails, modificationsMarker, menu;
let missing = false;
if (!selected) { if (!selected) {
// If not selected then sure that modifications flag is unset // If not selected then sure that modifications flag is unset
@@ -108,6 +109,11 @@ export default class Slot extends TranslatedComponent {
if (m) { if (m) {
slotDetails = this._getSlotDetails(m, enabled, translate, language.formats, language.units); // Must be implemented by sub classes slotDetails = this._getSlotDetails(m, enabled, translate, language.formats, language.units); // Must be implemented by sub classes
modificationsMarker = JSON.stringify(m); modificationsMarker = JSON.stringify(m);
if(typeof m.grp !== 'undefined' || m.grp !== null) {
if(m.grp == "mh" || m.grp == "mm") {
missing = true;
}
}
} else { } else {
slotDetails = <div className={'empty'}>{translate(eligible ? 'emptyrestricted' : 'empty')}</div>; slotDetails = <div className={'empty'}>{translate(eligible ? 'emptyrestricted' : 'empty')}</div>;
modificationsMarker = ''; modificationsMarker = '';
@@ -141,7 +147,10 @@ export default class Slot extends TranslatedComponent {
return ( return (
<div className={cn('slot', dropClass, { selected })} onClick={onOpen} onKeyDown={this._keyDown} onContextMenu={this._contextMenu} onDragOver={dragOver} tabIndex="0" ref={slotDiv => this.slotDiv = slotDiv}> <div className={cn('slot', dropClass, { selected })} onClick={onOpen} onKeyDown={this._keyDown} onContextMenu={this._contextMenu} onDragOver={dragOver} tabIndex="0" ref={slotDiv => this.slotDiv = slotDiv}>
<div className='details-container'> {
// If missing module/hardpoint, set the div container to warning status.
}
<div className={ missing === true ? 'details-container warning' : 'details-container'}>
<div className='sz'>{this._getMaxClassLabel(translate)}</div> <div className='sz'>{this._getMaxClassLabel(translate)}</div>
{slotDetails} {slotDetails}
</div> </div>

View File

@@ -93,6 +93,11 @@ export default class StandardSlot extends TranslatedComponent {
this._modificationsSelected = false; this._modificationsSelected = false;
} }
// If this is a missing module, therefore has the 'info' field, set the warning value on the module to be true when loaded.
if (m.info) {
warning = () => true;
}
const modificationsMarker = JSON.stringify(m); const modificationsMarker = JSON.stringify(m);
if (selected) { if (selected) {
@@ -124,7 +129,7 @@ export default class StandardSlot extends TranslatedComponent {
<div className={cn('details-container', { warning: warning && warning(slot.m), disabled: m.grp !== 'bh' && !slot.enabled })}> <div className={cn('details-container', { warning: warning && warning(slot.m), disabled: m.grp !== 'bh' && !slot.enabled })}>
<div className={'sz'}>{m.grp == 'bh' ? m.name.charAt(0) : slot.maxClass}</div> <div className={'sz'}>{m.grp == 'bh' ? m.name.charAt(0) : slot.maxClass}</div>
<div> <div>
<div className={'l'}>{classRating} {translate(m.name || m.grp)}{m.mods && Object.keys(m.mods).length > 0 ? <span className='r' onMouseOver={termtip.bind(null, modTT)} onMouseOut={tooltip.bind(null, null)}><Modified /></span> : null }</div> <div className={'l'}>{classRating} {m.getInfo() ? translate(m.ukName) : translate(m.name || m.grp)}{m.mods && Object.keys(m.mods).length > 0 ? <span className='r' onMouseOver={termtip.bind(null, modTT)} onMouseOut={tooltip.bind(null, null)}><Modified /></span> : null }</div>
<div className={'r'}>{formats.round(mass)}{units.T}</div> <div className={'r'}>{formats.round(mass)}{units.T}</div>
<div/> <div/>
<div className={'cb'}> <div className={'cb'}>
@@ -144,7 +149,8 @@ export default class StandardSlot extends TranslatedComponent {
{ showModuleResistances && m.getKineticResistance() ? <div className='l'>{translate('kinres')}: {formats.pct(m.getKineticResistance())}</div> : null } { showModuleResistances && m.getKineticResistance() ? <div className='l'>{translate('kinres')}: {formats.pct(m.getKineticResistance())}</div> : null }
{ showModuleResistances && m.getThermalResistance() ? <div className='l'>{translate('thermres')}: {formats.pct(m.getThermalResistance())}</div> : null } { showModuleResistances && m.getThermalResistance() ? <div className='l'>{translate('thermres')}: {formats.pct(m.getThermalResistance())}</div> : null }
{ m.getIntegrity() ? <div className='l'>{translate('integrity')}: {formats.int(m.getIntegrity())}</div> : null } { m.getIntegrity() ? <div className='l'>{translate('integrity')}: {formats.int(m.getIntegrity())}</div> : null }
{ validMods.length > 0 ? <div className='r' tabIndex="0" ref={ modButton => this.modButton = modButton }><button tabIndex="-1" onClick={this._toggleModifications.bind(this)} onContextMenu={stopCtxPropagation} onMouseOver={termtip.bind(null, 'modifications')} onMouseOut={tooltip.bind(null, null)}><ListModifications /></button></div> : null } { m.getInfo() ? <div className='l'>{translate(m.getInfo())}</div> : null }
{ m.getInfo() ? <div className='r'></div> : validMods.length > 0 ? <div className='r' tabIndex="0" ref={ modButton => this.modButton = modButton }><button tabIndex="-1" onClick={this._toggleModifications.bind(this)} onContextMenu={stopCtxPropagation} onMouseOver={termtip.bind(null, 'modifications')} onMouseOut={tooltip.bind(null, null)}><ListModifications /></button></div> : null }
</div> </div>
</div> </div>
</div> </div>

View File

@@ -8,6 +8,7 @@ import * as RU from './ru';
import * as PL from './pl'; import * as PL from './pl';
import * as PT from './pt'; import * as PT from './pt';
import * as CN from './cn'; import * as CN from './cn';
import * as KO from './ko';
import * as d3 from 'd3'; import * as d3 from 'd3';
let fallbackTerms = EN.terms; let fallbackTerms = EN.terms;
@@ -29,6 +30,7 @@ export function getLanguage(langCode) {
case 'pl': lang = PL; break; case 'pl': lang = PL; break;
case 'pt': lang = PT; break; case 'pt': lang = PT; break;
case 'cn': lang = CN; break; case 'cn': lang = CN; break;
case 'ko': lang = KO; break;
default: default:
lang = EN; lang = EN;
} }
@@ -97,5 +99,6 @@ export const Languages = {
ru: 'ру́сский', ru: 'ру́сский',
pl: 'polski', pl: 'polski',
pt: 'português', pt: 'português',
cn: '中文' cn: '中文',
ko: '한국어'
}; };

View File

@@ -398,6 +398,7 @@
"No modded components.": "没有改装的部件", "No modded components.": "没有改装的部件",
"Sending...": "发送中...", "Sending...": "发送中...",
"Send to EDEngineer": "发送至EDEngineer", "Send to EDEngineer": "发送至EDEngineer",
"Send to EDOMH": "发送至EDOMH",
"PHASE_UPLOAD_ORBIS": "上传到orbis.zone测试阶段", "PHASE_UPLOAD_ORBIS": "上传到orbis.zone测试阶段",
"orbis username": "orbis.zone的Email或用户名", "orbis username": "orbis.zone的Email或用户名",
"orbis password": "orbis.zone的密码", "orbis password": "orbis.zone的密码",

View File

@@ -26,6 +26,9 @@
"PHRASE_NO_SPECIAL": "No experimental effect", "PHRASE_NO_SPECIAL": "No experimental effect",
"PHRASE_SHOPPING_LIST": "Stations that sell this build", "PHRASE_SHOPPING_LIST": "Stations that sell this build",
"PHRASE_SHOPPING_MATS": "Materials needed for this build", "PHRASE_SHOPPING_MATS": "Materials needed for this build",
"PHRASE_DIFFERENT_ROLLS": "Material requirements will differ, based on the number of rolls per grade, per module.",
"PHRASE_FOR_FINER_CONTROL": "For finer control over rolls per grade/module, a more accurate list of required mats and help in finding those mats, please consider using the export options below to ED Odyssey Materials Helper, or ED Engineer, or use the Crafting Lists feature on inara.cz.",
"PHRASE_ALL_MODULES_ALL_ROLLS": "The list below, assumes standard to G5 Engineered (approx 80% - 90%) with the rolls above, for ALL engineered modules in the build. You can adjust the number of rolls above for each grade, however it will still apply to all engineered modules in the build.",
"PHRASE_REFIT_SHOPPING_LIST": "Stations that sell required modules", "PHRASE_REFIT_SHOPPING_LIST": "Stations that sell required modules",
"PHRASE_TOTAL_EFFECTIVE_SHIELD": "Total amount of damage that can be taken from each damage type, if using all shield cells", "PHRASE_TOTAL_EFFECTIVE_SHIELD": "Total amount of damage that can be taken from each damage type, if using all shield cells",
"PHRASE_TIME_TO_LOSE_SHIELDS": "Shields will hold for", "PHRASE_TIME_TO_LOSE_SHIELDS": "Shields will hold for",
@@ -81,8 +84,10 @@
"TT_SUMMARY_UNLADEN_TOTAL_JUMP": "Farthest possible range with no cargo, a full fuel tank, and jumping as far as possible each time", "TT_SUMMARY_UNLADEN_TOTAL_JUMP": "Farthest possible range with no cargo, a full fuel tank, and jumping as far as possible each time",
"TT_SUMMARY_LADEN_TOTAL_JUMP": "Farthest possible range with full cargo, a full fuel tank, and jumping as far as possible each time", "TT_SUMMARY_LADEN_TOTAL_JUMP": "Farthest possible range with full cargo, a full fuel tank, and jumping as far as possible each time",
"HELP_MODIFICATIONS_MENU": "Click on a number to enter a new value, or drag along the bar for small changes", "HELP_MODIFICATIONS_MENU": "Click on a number to enter a new value, or drag along the bar for small changes",
"PHRASE_FAIL_EDENGINEER": "Failed to send to EDEngineer (Launch EDEngineer and make sure the API is started then refresh the page.)", "PHRASE_ENSURE_EDOMH": "Ensure ED Odyssey Material Helper is installed and registered to handle edomh:// urls, else this button will do nothing!",
"PHRASE_FIREFOX_EDENGINEER": "Sending to EDEngineer is not compatible with Firefox's security settings. Please try again with Chrome.", "PHRASE_FIREFOX_EDENGINEER": "Sending to EDEngineer is not compatible with Firefox's security settings. Please try again with Chrome.",
"PHRASE_FAILED_TO_FIND_EDENGINEER": "Failed to find ED Engineer API. Please ensure it is running and try again.",
"MISSING_MODULES": "Missing Modules",
"am": "Auto Field-Maintenance Unit", "am": "Auto Field-Maintenance Unit",
"bh": "Bulkheads", "bh": "Bulkheads",
"bl": "Beam Laser", "bl": "Beam Laser",
@@ -93,6 +98,7 @@
"ch": "Chaff Launcher", "ch": "Chaff Launcher",
"cr": "Cargo Rack", "cr": "Cargo Rack",
"cs": "Manifest Scanner", "cs": "Manifest Scanner",
"csl": "Caustic Sink Launcher",
"dc": "Docking Computer", "dc": "Docking Computer",
"ec": "Electronic Countermeasure", "ec": "Electronic Countermeasure",
"fc": "Fragment Cannon", "fc": "Fragment Cannon",
@@ -108,10 +114,18 @@
"kw": "Kill Warrant Scanner", "kw": "Kill Warrant Scanner",
"ls": "Life Support", "ls": "Life Support",
"mc": "Multi-cannon", "mc": "Multi-cannon",
"mh": "Missing Weapon/Utility",
"mm": "Missing Module",
"advmc": "Multi-cannon (Advanced)",
"axmc": "AX Multi-cannon", "axmc": "AX Multi-cannon",
"axmce": "AX Multi-cannon (Enhanced)",
"ml": "Mining Laser", "ml": "Mining Laser",
"mlc": "Multi Limpet Controller",
"mr": "Missile Rack", "mr": "Missile Rack",
"amr": "Missile Rack (Advanced)",
"axmr": "AX Missile Rack", "axmr": "AX Missile Rack",
"axmre": "AX Missile Rack (Enhanced)",
"ews": "Experimental Weapon Stabilizer",
"mrp": "Module Reinforcement Package", "mrp": "Module Reinforcement Package",
"nl": "Mine Launcher", "nl": "Mine Launcher",
"pa": "Plasma Accelerator", "pa": "Plasma Accelerator",
@@ -156,8 +170,10 @@
"sua": "Supercruise Assist", "sua": "Supercruise Assist",
"t": "thrusters", "t": "thrusters",
"tp": "Torpedo Pylon", "tp": "Torpedo Pylon",
"ntp": "Nanite Torpedo Pylon",
"ul": "Burst Laser", "ul": "Burst Laser",
"Send To EDEngineer": "Send To EDEngineer", "Send To EDEngineer": "Send To EDEngineer",
"Send To EDOMH": "Send To EDOMH",
"ws": "Frame Shift Wake Scanner", "ws": "Frame Shift Wake Scanner",
"rpl": "Repair Limpet Controller", "rpl": "Repair Limpet Controller",
"rcpl": "Recon Limpet Controller", "rcpl": "Recon Limpet Controller",
@@ -208,6 +224,7 @@
"boost interval": "Boost interval", "boost interval": "Boost interval",
"total": "Total", "total": "Total",
"ammo": "Ammunition maximum", "ammo": "Ammunition maximum",
"info": "Info",
"boot": "Boot time", "boot": "Boot time",
"hacktime": "Hack time", "hacktime": "Hack time",
"brokenregen": "Broken regeneration rate", "brokenregen": "Broken regeneration rate",

16
src/app/i18n/ko.js Normal file
View File

@@ -0,0 +1,16 @@
export const formats = {
decimal: '.',
thousands: ',',
grouping: [3],
currency: ['₩', ''],
dateTime: '%a %b %e %X %Y',
date: '%Y/%m/%d',
time: '%H:%M:%S',
periods: ['오전', '오후'],
days: ['일요일', '월요일', '화요일', '수요일', '목요일', '금요일', '토요일'],
shortDays: ['일', '월', '화', '수', '목', '금', '토'],
months: ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'],
shortMonths: ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월']
};
export { default as terms } from './ko.json';

369
src/app/i18n/ko.json Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -13,7 +13,7 @@
"PHRASE_SG_RECOVER": "Восстановление с 0% до 50% объема щита, учитывая полный аккумулятор СИС в начале", "PHRASE_SG_RECOVER": "Восстановление с 0% до 50% объема щита, учитывая полный аккумулятор СИС в начале",
"PHRASE_UNLADEN": "Масса корабля без учета топлива и грузов", "PHRASE_UNLADEN": "Масса корабля без учета топлива и грузов",
"PHRASE_UPDATE_RDY": "Доступна новая версия. Нажмите для обновления.", "PHRASE_UPDATE_RDY": "Доступна новая версия. Нажмите для обновления.",
"PHRASE_ENGAGEMENT_RANGE": "Дистанция между кораблем и целью", "PHRASE_ENGAGEMENT_RANGE": "Дистанция между кораблём и целью",
"PHRASE_SELECT_BLUEPRINT": "Нажмите чтобы выбрать чертеж", "PHRASE_SELECT_BLUEPRINT": "Нажмите чтобы выбрать чертеж",
"PHRASE_BLUEPRINT_WORST": "Худшие основные значения для чертежа", "PHRASE_BLUEPRINT_WORST": "Худшие основные значения для чертежа",
"PHRASE_BLUEPRINT_FIFTY": "50% значения для чертежа", "PHRASE_BLUEPRINT_FIFTY": "50% значения для чертежа",
@@ -24,9 +24,9 @@
"PHRASE_BLUEPRINT_RESET": "Сбросить все модификаторы и чертеж", "PHRASE_BLUEPRINT_RESET": "Сбросить все модификаторы и чертеж",
"PHRASE_SELECT_SPECIAL": "Нажмите, чтобы выбрать экспериментальный эффект", "PHRASE_SELECT_SPECIAL": "Нажмите, чтобы выбрать экспериментальный эффект",
"PHRASE_NO_SPECIAL": "Без экспериментального эффекта", "PHRASE_NO_SPECIAL": "Без экспериментального эффекта",
"PHRASE_SHOPPING_LIST": "Станции, что продают эту сборку", "PHRASE_SHOPPING_LIST": "Станции, на которых продают эту сборку",
"PHRASE_SHOPPING_MATS": "Материалы которые нужны для сборки", "PHRASE_SHOPPING_MATS": "Материалы которые нужны для сборки",
"PHRASE_REFIT_SHOPPING_LIST": "Станции, что продают необходимые модули", "PHRASE_REFIT_SHOPPING_LIST": "Станции, на которых продают необходимые модули",
"PHRASE_TOTAL_EFFECTIVE_SHIELD": "Общий урон, что может быть нанесен в каждым типе, если используются все щитонакопители", "PHRASE_TOTAL_EFFECTIVE_SHIELD": "Общий урон, что может быть нанесен в каждым типе, если используются все щитонакопители",
"PHRASE_TIME_TO_LOSE_SHIELDS": "Щиты продержатся", "PHRASE_TIME_TO_LOSE_SHIELDS": "Щиты продержатся",
"PHRASE_TIME_TO_RECOVER_SHIELDS": "Щиты восстановятся за", "PHRASE_TIME_TO_RECOVER_SHIELDS": "Щиты восстановятся за",
@@ -37,36 +37,36 @@
"PHRASE_EFFECTIVE_ARMOUR": "Эффективная сила брони против разных типов урона", "PHRASE_EFFECTIVE_ARMOUR": "Эффективная сила брони против разных типов урона",
"PHRASE_DAMAGE_TAKEN": "% общих повреждений полученных в разных типах урона", "PHRASE_DAMAGE_TAKEN": "% общих повреждений полученных в разных типах урона",
"PHRASE_TIME_TO_LOSE_ARMOUR": "Броня продержится", "PHRASE_TIME_TO_LOSE_ARMOUR": "Броня продержится",
"PHRASE_MODULE_PROTECTION_EXTERNAL": "Защита гнезд", "PHRASE_MODULE_PROTECTION_EXTERNAL": "Защита гнёзд",
"PHRASE_MODULE_PROTECTION_INTERNAL": "Защита всех остальных модулей", "PHRASE_MODULE_PROTECTION_INTERNAL": "Защита всех остальных модулей",
"PHRASE_OVERALL_DAMAGE": "Разбивка источников устойчивого ДПС", "PHRASE_OVERALL_DAMAGE": "Разбивка источников устойчивого УвС",
"PHRASE_SHIELD_DAMAGE": "Подробности источников поддерживаемого ДПС против щитов", "PHRASE_SHIELD_DAMAGE": "Подробности источников поддерживаемого УвС против щитов",
"PHRASE_ARMOUR_DAMAGE": "Подробности источников поддерживаемого ДПС против брони", "PHRASE_ARMOUR_DAMAGE": "Подробности источников поддерживаемого УвС против брони",
"PHRASE_TIME_TO_REMOVE_SHIELDS": "Снимет щиты за", "PHRASE_TIME_TO_REMOVE_SHIELDS": "Снимет щиты за",
"PHRASE_MULTI_CREW_CAPACITOR_POINTS": "Щелкните правой кновкой мыши чтобы объединить в группу.", "PHRASE_MULTI_CREW_CAPACITOR_POINTS": "Щелкните правой кновкой мыши чтобы объединить в группу.",
"TT_TIME_TO_REMOVE_SHIELDS": "Непрерывным огнем из всех орудий", "TT_TIME_TO_REMOVE_SHIELDS": "Непрерывным огнём из всех орудий",
"PHRASE_TIME_TO_REMOVE_ARMOUR": "Снимет броню за", "PHRASE_TIME_TO_REMOVE_ARMOUR": "Снимет броню за",
"TT_TIME_TO_REMOVE_ARMOUR": "Непрерывным огнем из всех орудий", "TT_TIME_TO_REMOVE_ARMOUR": "Непрерывным огнём из всех орудий",
"PHRASE_TIME_TO_DRAIN_WEP": "Опустошит ОРУ за", "PHRASE_TIME_TO_DRAIN_WEP": "Опустошит ОРУ за",
"TT_TIME_TO_DRAIN_WEP": "Время, за которое опустошится аккумулятор ОРУ при стрельбе из всех орудий", "TT_TIME_TO_DRAIN_WEP": "Время, за которое опустошится аккумулятор ОРУ при стрельбе из всех орудий",
"TT_TIME_TO_LOSE_SHIELDS": "Против поддерживаемой стрельбы из всех орудий противника", "TT_TIME_TO_LOSE_SHIELDS": "Против поддерживаемой стрельбы из всех орудий противника",
"TT_TIME_TO_LOSE_ARMOUR": "Против поддерживаемой стрельбы из всех орудий противника", "TT_TIME_TO_LOSE_ARMOUR": "Против поддерживаемой стрельбы из всех орудий противника",
"TT_MODULE_ARMOUR": "Броня, защищающая модули от урона", "TT_MODULE_ARMOUR": "Броня, защищающая модули от урона",
"TT_MODULE_PROTECTION_EXTERNAL": "Процент урона, перенаправленного от гнезд на наборы для усиления модулей", "TT_MODULE_PROTECTION_EXTERNAL": "Процент урона, перенаправленного от гнезд на наборы для усиления модулей",
"TT_MODULE_PROTECTION_INTERNAL": "Процент урона, перенаправленного от модулей вне гнезд на наборы для усиления модулей", "TT_MODULE_PROTECTION_INTERNAL": "Процент урона, перенаправленного от модулей вне гнёзд на наборы для усиления модулей",
"TT_EFFECTIVE_SDPS_SHIELDS": "Реальный поддерживаемый ДПС пока аккумулятор ОРУ не пуст", "TT_EFFECTIVE_SDPS_SHIELDS": "Реальный поддерживаемый УвС пока ёмкость ОРУ не пуста",
"TT_EFFECTIVENESS_SHIELDS": "Эффективность в сравнении с попаданием по цели с 0-сопротивляемостью без пунктов в СИС на 0 метрах", "TT_EFFECTIVENESS_SHIELDS": "Эффективность в сравнении с попаданием по цели с 0-сопротивляемостью без пунктов в СИС на 0 метрах",
"TT_EFFECTIVE_SDPS_ARMOUR": "Реальный поддерживаемый ДПС пока аккумулятор ОРУ не пуст", "TT_EFFECTIVE_SDPS_ARMOUR": "Реальный поддерживаемый УвС пока аккумулятор ОРУ не пуст",
"TT_EFFECTIVENESS_ARMOUR": "Эффективность в сравнении с попаданием по цели с 0-сопротивляемостью на 0 метрах", "TT_EFFECTIVENESS_ARMOUR": "Эффективность в сравнении с попаданием по цели с 0-сопротивляемостью на 0 метрах",
"PHRASE_EFFECTIVE_SDPS_SHIELDS": ДПС против щитов", "PHRASE_EFFECTIVE_SDPS_SHIELDS": УвС против щитов",
"PHRASE_EFFECTIVE_SDPS_ARMOUR": ДПС против брони", "PHRASE_EFFECTIVE_SDPS_ARMOUR": УвС против брони",
"TT_SUMMARY_SPEED": "С полным топливным баком и 4 пунктами в ДВГ", "TT_SUMMARY_SPEED": "С полным топливным баком и 4 пунктами в ДВГ",
"TT_SUMMARY_SPEED_NONFUNCTIONAL": "Маневровые двигатели выключены или превышена максимальная масса с топливом и грузом", "TT_SUMMARY_SPEED_NONFUNCTIONAL": "Маневровые двигатели выключены или превышена максимальная масса с топливом и грузом",
"TT_SUMMARY_BOOST": "С полным топливным баком и 4 пунктами в ДВГ", "TT_SUMMARY_BOOST": "С полным топливным баком и 4 пунктами в ДВГ",
"TT_SUMMARY_BOOST_INTERVAL": "Время заполнения с 4 пунктами в СИС", "TT_SUMMARY_BOOST_INTERVAL": "Время заполнения с 4 пунктами в СИС",
"TT_SUMMARY_BOOST_NONFUNCTIONAL": "Распределитель питания не может обеспечить достаточно энергии для форсажа", "TT_SUMMARY_BOOST_NONFUNCTIONAL": "Распределитель питания не может обеспечить достаточно энергии для форсажа",
"TT_SUMMARY_SHIELDS": "Чистая сила щита, включая усилители", "TT_SUMMARY_SHIELDS": "Чистая сила щита, включая усилители",
"TT_SUMMARY_SHIELDS_SCB": "Прочность щита, включая бустеры и SCB", "TT_SUMMARY_SHIELDS_SCB": "Прочность щита, включая бустеры и щитонакопители",
"TT_SUMMARY_SHIELDS_NONFUNCTIONAL": "Шитогенератор отсутствует или выключен", "TT_SUMMARY_SHIELDS_NONFUNCTIONAL": "Шитогенератор отсутствует или выключен",
"TT_SUMMARY_INTEGRITY": "Целостность корабля, включая переборки и наборы для усиления корпуса", "TT_SUMMARY_INTEGRITY": "Целостность корабля, включая переборки и наборы для усиления корпуса",
"TT_SUMMARY_HULL_MASS": "Масса корпуса без каких-либо модулей", "TT_SUMMARY_HULL_MASS": "Масса корпуса без каких-либо модулей",
@@ -88,22 +88,23 @@
"bl": "Пучковый лазер", "bl": "Пучковый лазер",
"bsg": "Двухпоточный щитогенератор", "bsg": "Двухпоточный щитогенератор",
"c": "Пушка", "c": "Пушка",
"causres": "Каустическое сопротивление", "causres": "Сопротивление едк.урону",
"Caustic resistance": "Каустическое сопротивление", "Caustic resistance": "Сопротивление едк.урону",
"cc": "Контроллер магнитного снаряда для сбора", "cc": "Контроллер дронов-сборщиков",
"ch": "Разбрасыватель дипольных отражателей", "ch": "Разбрасыватель дипольных отражателей",
"cr": "Грузовой стеллаж", "cr": "Грузовой стеллаж",
"cs": "Сканер содержимого", "cs": "Сканер содержимого",
"csl": "Антикор катапульта",
"dc": "Стыковочный компьютер", "dc": "Стыковочный компьютер",
"ec": "Электр. противодействие", "ec": "Радиоэлектронное подавление",
"fc": "Залповое орудие", "fc": "Залповое орудие",
"fh": "Ангар для истребителя", "fh": "Ангар для истребителя",
"fi": "FSD-перехватчик", "fi": "FSD-перехватчик",
"fs": "Топливозаборник", "fs": "Топливозаборник",
"fsd": "Рамочно-сместительный двигатель", "fsd": "Рамочно-сместительный двигатель",
"ft": "Топливный бак", "ft": "Топливный бак",
"fx": "Контроллер магнитного снаряда для топлива", "fx": "Контроллер дронов-заправщиков",
"hb": "Контроллер магнитного снаряда для взлома трюма", "hb": "Контроллер дронов-взломщиков трюмов",
"hr": "Набор для усиления корпуса", "hr": "Набор для усиления корпуса",
"hs": "Теплоотводная катапульта", "hs": "Теплоотводная катапульта",
"kw": "Сканер преступников", "kw": "Сканер преступников",
@@ -111,13 +112,14 @@
"mc": "Многоствольное орудие", "mc": "Многоствольное орудие",
"axmc": "Многоствольное орудие АИ", "axmc": "Многоствольное орудие АИ",
"ml": "Проходочный лазер", "ml": "Проходочный лазер",
"mr": "Ракетный лоток", "mr": "Блок ракет",
"axmr": "Блок ракет АИ", "axmr": "Блок ракет АИ",
"ews": "Стабилизатор экспериментального вооружения",
"mrp": "Набор для усиления модуля", "mrp": "Набор для усиления модуля",
"nl": "Мины", "nl": "Мины",
"pa": "Ускоритель плазмы", "pa": "Ускоритель плазмы",
"pas": "Комплект для сближения с планетой", "pas": "Комплект для сближения с планетой",
"pc": "Контроллер магнитного снаряда для геологоразведки", "pc": "Контроллер дронов-геологоразведчиков",
"pce": "Каюта пассажира эконом-класса", "pce": "Каюта пассажира эконом-класса",
"passenger capacity": "Количество пассажиров", "passenger capacity": "Количество пассажиров",
"pci": "Каюта пассажира бизнес-класса", "pci": "Каюта пассажира бизнес-класса",
@@ -143,36 +145,38 @@
"gsc": "Осколочное орудие Стражей", "gsc": "Осколочное орудие Стражей",
"psg": "Призматический щитогенератор", "psg": "Призматический щитогенератор",
"pv": "Гараж для планетарного транспорта", "pv": "Гараж для планетарного транспорта",
"rf": "Устройство переработки", "rf": "Очиститель",
"rfl": "Зенитная установка (снаряды с дистанционным подрывом)", "rfl": "Зенитная установка (снаряды с дистанционным подрывом)",
"rg": "Электромагнитная пушка", "rg": "Рельсотрон",
"rsl": "Дроны-исследователи", "rsl": "Контроллер дронов-исследователей",
"s": "Сенсоры", "s": "Сенсоры",
"sb": "Усилитель щита", "sb": "Усилитель щита",
"sc": "Сканер обнаружения", "sc": "Сканер обнаружения",
"scb": "Щитонакопитель", "scb": "Щитонакопитель",
"sfn": "Нейтрализатор глушащего поля", "sfn": "Нейтрализатор отключающего поля",
"sg": "Щитогенератор", "sg": "Щитогенератор",
"ss": "Сканер поверхностей", "ss": "Сканер поверхностей",
"sua": "Помощь в гиперкрейсерском режиме", "sua": "Помощь в гиперкрейсерском режиме",
"t": "Маневровые двигатели", "t": "Маневровые двигатели",
"tp": "Торпедная стойка", "tp": "Торпедная установка",
"ul": "Пульсирующие лазеры", "ul": "Пульсирующий лазер",
"Send To EDEngineer": "Отправить в EDEngineer", "Send To EDEngineer": "Отправить в EDEngineer",
"Send To EDOMH": "Отправить в EDOMH",
"ws": "Сканер следа FSD", "ws": "Сканер следа FSD",
"rpl": "Дроны-ремонтники", "rpl": "Контроллер дронов-ремонтников",
"rcpl": "Дроны-разведчики", "rcpl": "Контроллер дронов-разведчиков",
"xs": "Сканер «инопланетянин»", "xs": "Ксено-сканер",
"tbem": "Блок энзимных ракет", "tbem": "Блок энзимных ракет",
"tbrfl": "Установка для стрельбы стреловидными снарядами с дистанционным подрывом", "tbrfl": "Установка для стрельбы стреловидными снарядами с дистанционным подрывом",
"dtl": "Дроны-очистители", "dtl": "Контроллер дронов-очистителей",
"mahr": "Набор для усиления корпуса из Метасплава", "mlc": "Мультиконтроллер",
"mahr": "Метасплавное усиление корпуса",
"emptyrestricted": "пусто (ограниченно)", "emptyrestricted": "пусто (ограниченно)",
"damage dealt to": "Урон нанесен", "damage dealt to": "Урон нанесён",
"damage received from": "Урон получен от", "damage received from": "Урон получен от",
"against shields": "Против щитов", "against shields": "Против щитов",
"against hull": "Против корпуса", "against hull": "Против корпуса",
"total effective shield": "Общие эффективные щиты", "total effective shield": "Общая эффективность щита",
"ammunition": "Припасы", "ammunition": "Припасы",
"secs": "с", "secs": "с",
"bays": "Ячейки", "bays": "Ячейки",
@@ -201,7 +205,7 @@
"shield cells": "Щитонакопители", "shield cells": "Щитонакопители",
"recovery": "включение", "recovery": "включение",
"recharge": "перезарядка", "recharge": "перезарядка",
"engine pips": "Пункты в двигателе", "engine pips": "Ячейки питания на ДВГ",
"4b": "4 пункта и Форсаж", "4b": "4 пункта и Форсаж",
"speed": "скорость", "speed": "скорость",
"pitch": "Тангаж", "pitch": "Тангаж",
@@ -287,12 +291,12 @@
"explosive": "Взрывч.", "explosive": "Взрывч.",
"kinetic": "Механич.", "kinetic": "Механич.",
"thermal": "Тепл.", "thermal": "Тепл.",
"caustic": "Каустич.", "caustic": "Едкий",
"generator": "Генератор", "generator": "Генератор",
"boosters": "Усилители", "boosters": "Усилители",
"cells": "Ячейки", "cells": "Ячейки",
"shield addition": Обавления к щиту", "shield addition": обавления к щиту",
"jump addition": Обавления к прыжку", "jump addition": обавления к прыжку",
"bulkheads": "Переборки", "bulkheads": "Переборки",
"reinforcement": "Усилители", "reinforcement": "Усилители",
"power and costs": "Энергия и стоимость", "power and costs": "Энергия и стоимость",
@@ -374,9 +378,9 @@
"/s": "/с", "/s": "/с",
"/min": "/мин", "/min": "/мин",
"m/s": "м/с", "m/s": "м/с",
"Ls": "Св.сек", "Ls": "Св.с",
"LY": "Св.лет", "LY": "Св.лет",
"CR": "кр.", "CR": "КР.",
"S": "М", "S": "М",
"M": "С", "M": "С",
"L": "Б", "L": "Б",
@@ -435,7 +439,7 @@
"deployed": "Открыты", "deployed": "Открыты",
"disabled": "Отключено", "disabled": "Отключено",
"discount": "Скидка", "discount": "Скидка",
"DPS": "УВС", "DPS": "УвС",
"efficiency": "Эффективность", "efficiency": "Эффективность",
"empty": "пусто", "empty": "пусто",
"ENG": "ДВГ", "ENG": "ДВГ",
@@ -449,7 +453,7 @@
"jumps": "Прыжков", "jumps": "Прыжков",
"laden": "Груж", "laden": "Груж",
"language": "Язык", "language": "Язык",
"maneuverability": "Маневренность", "maneuverability": "Манёвренность",
"max": "Макс", "max": "Макс",
"no": "Нет", "no": "Нет",
"pen": "ПБ", "pen": "ПБ",
@@ -462,7 +466,7 @@
"repair": "Починка", "repair": "Починка",
"ret": "Убр", "ret": "Убр",
"retracted": "Убрано", "retracted": "Убрано",
"ROF": "В\/сек", "ROF": "В\/с",
"save": "Сохранить", "save": "Сохранить",
"sell": "Продать", "sell": "Продать",
"settings": "Настройки", "settings": "Настройки",
@@ -492,7 +496,7 @@
"module": "модуль", "module": "модуль",
"announcements": "объявления", "announcements": "объявления",
"resistance": "сопротивление", "resistance": "сопротивление",
"Lightweight Alloy": егкие сплавы", "Lightweight Alloy": ёгкие сплавы",
"base": "базовые", "base": "базовые",
"core module classes": "основные модули", "core module classes": "основные модули",
"Group highlighted ships": "Сгруппировать выделенные корабли", "Group highlighted ships": "Сгруппировать выделенные корабли",
@@ -511,7 +515,7 @@
"maximum speed": "максимальная скорость", "maximum speed": "максимальная скорость",
"maximum range": "максимальная дальность", "maximum range": "максимальная дальность",
"shortlink": "короткая ссылка", "shortlink": "короткая ссылка",
"guardian": "стражи", "guardian": "Стражи",
"engineers": "инженеры", "engineers": "инженеры",
"component": "компонент", "component": "компонент",
"amount": "кол-во", "amount": "кол-во",
@@ -520,35 +524,35 @@
"Heat Sink Launcher": "Теплоотводная катапульта", "Heat Sink Launcher": "Теплоотводная катапульта",
"scanners": "сканеры", "scanners": "сканеры",
"experimental": "экспериментальное", "experimental": "экспериментальное",
"mining": "шахтерство", "mining": "добыча ресурсов",
"lasers": "лазеры", "lasers": "лазеры",
"ordnance": "артиллерия", "ordnance": "артиллерия",
"projectiles": "с боеприпасами", "projectiles": "с боеприпасами",
"hangars": "ангары", "hangars": "ангары",
"limpet controllers": "контроллеры снарядов", "limpet controllers": "контроллеры дронов",
"passenger cabins": "каюты пассажиров", "passenger cabins": "каюты пассажиров",
"structural reinforcement": "структурные усиления", "structural reinforcement": "усиление конструктива",
"flight assists": "помощники в полете", "flight assists": "помощь в полёте",
"modifications": "модификации", "modifications": "модификации",
"wep_reload": "перезарядка", "wep_reload": "перезарядка",
"optimal multiplier": "оптимальный усилитель", "optimal multiplier": "оптимальный усилитель",
"Cargo Hatch": "Грузовой люк", "Cargo Hatch": "Грузовой люк",
"Chaff Launcher": "Разбрасыватель дипольных отражателей", "Chaff Launcher": "Разбрасыватель дипольных отражателей",
"Point Defence": "Точечная оборона", "Point Defence": "Точечная оборона",
"Electronic Countermeasure": "Электронное противодействие", "Electronic Countermeasure": "Радиоэлектронное подавление",
"Xeno Scanner": "Сканер «инопланетянин»", "Xeno Scanner": "Ксено-сканер",
"Shutdown Field Neutraliser": "Нейтрализатор глушащего поля", "Shutdown Field Neutraliser": "Нейтрализатор отключающего поля",
"Disruptor": "Диверсант", "Disruptor": "«Диверсант»",
"Pacifier": "Миротворец", "Pacifier": "«Миротворец»",
"Advanced Plasma Accelerator": "Улучшенный ускоритель плазмы", "Advanced Plasma Accelerator": "Улучшенный ускоритель плазмы",
"Cytoscrambler": "Дезинтегратор", "Cytoscrambler": "«Дезинтегратор»",
"Retributor": "Каратель", "Retributor": "«Каратель»",
"Enforcer": "Убийца", "Enforcer": "«Убийца»",
"Imperial Hammer": "Имперский молот", "Imperial Hammer": "«Имперский молот»",
"Rocket Propelled FSD Disruptor": "Ракетный FSD-разрушитель", "Rocket Propelled FSD Disruptor": "Ракетный FSD-разрушитель",
"Pack-Hound": "Гончие", "Pack-Hound": "«Гончие»",
"Shock Mine Launcher": "Установщик шоковых мин", "Shock Mine Launcher": "Установщик шоковых мин",
"Mining Lance": "Копье шахтера", "Mining Lance": "«Копьё шахтера»",
"Corrosion Resistant": "Коррозийно-устойчивый стеллаж", "Corrosion Resistant": "Коррозийно-устойчивый стеллаж",
"Standard Docking Computer": "Стандартный стыковочный компьютер", "Standard Docking Computer": "Стандартный стыковочный компьютер",
"Advanced Docking Computer": "Улучшенный стыковочный компьютер", "Advanced Docking Computer": "Улучшенный стыковочный компьютер",
@@ -557,20 +561,20 @@
"Guardian Power Distributor": "Рапределитель питания Стражей", "Guardian Power Distributor": "Рапределитель питания Стражей",
"Enhanced Performance": "Усиленные маневровые двигатели", "Enhanced Performance": "Усиленные маневровые двигатели",
"Guardian Hybrid Power Plant": "Гибридная силовая установка Стражей", "Guardian Hybrid Power Plant": "Гибридная силовая установка Стражей",
"Reinforced Alloy": "Укрепленные сплавы", "Reinforced Alloy": "Укреплённые сплавы",
"Military Grade Composite": "Композит военного класса", "Military Grade Composite": "Композит военного класса",
"Mirrored Surface Composite": "Композит с зеркальной поверхностью", "Mirrored Surface Composite": "Композит с зеркальной поверхностью",
"Reactive Surface Composite": "Композит с реактивной поверхностью", "Reactive Surface Composite": "Композит с реактивной поверхностью",
"Proto Light Alloys": "Опытные легкие сплавы", "Proto Light Alloys": "Опытные лёгкие сплавы",
"Ammo capacity": "Вместимость магазина", "Ammo capacity": "Вместимость магазина",
"Lightweight": "Облегченный", "Lightweight": "Облегчённый",
"Reinforced": "Усиленный", "Reinforced": "Усиленный",
"Shielded": "Защищенный", "Shielded": "Защищённый",
"Fast scan": "Быстрое сканирование", "Fast scan": "Быстрое сканирование",
"Long range": "Дальнего действия", "Long range": "Дальнего действия",
"Wide angle": "Широкоугольный", "Wide angle": "Широкоугольный",
"Blast resistant": "Взрывостойкий", "Blast resistant": "Взрывостойкий",
"Heavy duty": "Надежный", "Heavy duty": "Надёжный",
"Kinetic resistant": "Противокинетический", "Kinetic resistant": "Противокинетический",
"Resistance augmented": "С универсальной защитой", "Resistance augmented": "С универсальной защитой",
"Thermal resistant": "Термостойкий", "Thermal resistant": "Термостойкий",
@@ -622,7 +626,7 @@
"Penetrator Munitions": "Бронебойные боеголовки", "Penetrator Munitions": "Бронебойные боеголовки",
"Mass lock munition": "Боеприпасы с гравитационным захватом", "Mass lock munition": "Боеприпасы с гравитационным захватом",
"Mass Lock Munition": "Боеприпасы с гравитационным захватом", "Mass Lock Munition": "Боеприпасы с гравитационным захватом",
"Reverberating cascade": "Отраженный залп", "Reverberating cascade": "Отражённый залп",
"Shift-lock canister": "Рамоблокирующая кассета", "Shift-lock canister": "Рамоблокирующая кассета",
"Ion disruptor": "Ионный дестабилизатор", "Ion disruptor": "Ионный дестабилизатор",
"Radiant Canister": "Светящаяся кассета", "Radiant Canister": "Светящаяся кассета",
@@ -639,7 +643,7 @@
"Reflective Plating": "Отражающая броня", "Reflective Plating": "Отражающая броня",
"Angled Plating": "Угловая броня", "Angled Plating": "Угловая броня",
"Layered Plating": "Многослойная броня", "Layered Plating": "Многослойная броня",
"Deep Plating": "Утолщенная броня", "Deep Plating": "Утолщённая броня",
"Expanded Probe Scanning Radius": "Увеличение радиуса сканирования зондов", "Expanded Probe Scanning Radius": "Увеличение радиуса сканирования зондов",
"High charge capacity": "Высокоёмкий", "High charge capacity": "Высокоёмкий",
"Charge enhanced": "Быстрозаряжающийся", "Charge enhanced": "Быстрозаряжающийся",
@@ -666,8 +670,8 @@
"Combat": "Боец", "Combat": "Боец",
"Trader": "Торговец", "Trader": "Торговец",
"Explorer": "Исследователь", "Explorer": "Исследователь",
"Planetary Explorer": "Планетарный исследователь", "Planetary Explorer": "Исследователь планет",
"Miner": "Шахтер", "Miner": "Старатель",
"Racer": "Гонщик", "Racer": "Гонщик",
"Aberrant Shield Pattern Analysis": "Анализ аномального поведения щита", "Aberrant Shield Pattern Analysis": "Анализ аномального поведения щита",
@@ -691,7 +695,7 @@
"Chemical Manipulators": "Манипуляторы для работы с химикатами", "Chemical Manipulators": "Манипуляторы для работы с химикатами",
"Chemical Processors": "Оборудование для химобработки", "Chemical Processors": "Оборудование для химобработки",
"Chromium": "Хром", "Chromium": "Хром",
"Classified Scan Databanks": "Засекреченные базы данных сканированоя", "Classified Scan Databanks": "Засекреченные базы данных сканирования",
"Classified Scan Fragment": "Засекреченные фрагменты данных сканирования", "Classified Scan Fragment": "Засекреченные фрагменты данных сканирования",
"Compound Shielding": "Многоступенчатая защита", "Compound Shielding": "Многоступенчатая защита",
"Conductive Ceramics": "Проводящая керамика", "Conductive Ceramics": "Проводящая керамика",
@@ -702,7 +706,7 @@
"Cracked Industrial Firmware": "Взломанные промышленные микропрограммы", "Cracked Industrial Firmware": "Взломанные промышленные микропрограммы",
"Datamined Wake Exceptions": "Исключения из глубинного анализа данных следа", "Datamined Wake Exceptions": "Исключения из глубинного анализа данных следа",
"Decoded Emission Data": "Расшифрованные данные об излучении", "Decoded Emission Data": "Расшифрованные данные об излучении",
"Distorted Shield Cycle Recordings": "Поврежденные цикличные записи щита", "Distorted Shield Cycle Recordings": "Повреждённые цикличные записи щита",
"Divergent Scan Data": "Неформатные данные сканирования", "Divergent Scan Data": "Неформатные данные сканирования",
"Eccentric Hyperspace Trajectories": "Аномальные траектории в гиперпространстве", "Eccentric Hyperspace Trajectories": "Аномальные траектории в гиперпространстве",
"Electrochemical Arrays": "Электрохимические массивы", "Electrochemical Arrays": "Электрохимические массивы",
@@ -717,7 +721,7 @@
"Heat Dispersion Plate": "Теплорассеивающая пластина", "Heat Dispersion Plate": "Теплорассеивающая пластина",
"Heat Exchangers": "Теплообменные агрегаты", "Heat Exchangers": "Теплообменные агрегаты",
"Heat Vanes": "Тепловые заслонки", "Heat Vanes": "Тепловые заслонки",
"High Density Composites": "Высокоплотные композиты", "High Density Composites": "Высокоплотностные композиты",
"Hybrid Capacitors": "Гибридные конденсаторы", "Hybrid Capacitors": "Гибридные конденсаторы",
"Imperial Shielding": "Имперская защита", "Imperial Shielding": "Имперская защита",
"Improvised Components": "Кустарные компоненты", "Improvised Components": "Кустарные компоненты",
@@ -731,8 +735,8 @@
"Mercury": "Ртуть", "Mercury": "Ртуть",
"Military Grade Alloys": "Сплавы военного назначения", "Military Grade Alloys": "Сплавы военного назначения",
"Military Supercapacitors": "Военные суперконденсаторы", "Military Supercapacitors": "Военные суперконденсаторы",
"Modified Consumer Firmware": "Измененные пользовательские микропрограммы", "Modified Consumer Firmware": "Изменённые пользовательские микропрограммы",
"Modified Embedded Firmware": "Измененные встроенные микропрограммы", "Modified Embedded Firmware": "Изменённые встроенные микропрограммы",
"Molybdenum": "Молибден", "Molybdenum": "Молибден",
"Nickel": "Никель", "Nickel": "Никель",
"Niobium": "Ниобий", "Niobium": "Ниобий",
@@ -741,7 +745,7 @@
"Phase Alloys": "Фазовые сплавы", "Phase Alloys": "Фазовые сплавы",
"Phosphorus": "Фосфор", "Phosphorus": "Фосфор",
"Polymer Capacitors": "Полимерные конденсаторы", "Polymer Capacitors": "Полимерные конденсаторы",
"Precipitated Alloys": "Осажденные сплавы", "Precipitated Alloys": "Осаждённые сплавы",
"Proprietary Composites": "Патентованные композиты", "Proprietary Composites": "Патентованные композиты",
"Proto Heat Radiators": "Прототипы теплоизлучателей", "Proto Heat Radiators": "Прототипы теплоизлучателей",
"Proto Radiolic Alloys": "Сплавы для изготовления зондов", "Proto Radiolic Alloys": "Сплавы для изготовления зондов",
@@ -749,15 +753,15 @@
"Ruthenium": "Рутений", "Ruthenium": "Рутений",
"Salvaged Alloys": "Захваченные сплавы", "Salvaged Alloys": "Захваченные сплавы",
"Security Firmware Patch": "Обновление для защитной микропрограммы", "Security Firmware Patch": "Обновление для защитной микропрограммы",
"Selenium": "Селениум", "Selenium": "Селен",
"Shield Emitters": "Щитоизлучатели", "Shield Emitters": "Щитоизлучатели",
"Shielding Sensors": "Сенсоры системы экранирования", "Shielding Sensors": "Сенсоры системы экранирования",
"Specialised Legacy Firmware": "Специальные микропрограммы предыдущего поколения", "Specialised Legacy Firmware": "Специальные микропрограммы предыдущего поколения",
"Strange Wake Solutions": "Странные расчеты следа", "Strange Wake Solutions": "Странные расчёты следа",
"Sulphur": "Сера", "Sulphur": "Сера",
"Tagged Encryption Codes": "Меченные шифровальные коды", "Tagged Encryption Codes": "Меченные шифровальные коды",
"Technetium": "Технеций", "Technetium": "Технеций",
"Tellurium": "Теллурий", "Tellurium": "Теллур",
"Thermic Alloys": "Термические сплавы", "Thermic Alloys": "Термические сплавы",
"Tin": "Олово", "Tin": "Олово",
"Tungsten": "Вольфрам", "Tungsten": "Вольфрам",

View File

@@ -1,12 +1,6 @@
import '@babel/polyfill';
import React from 'react'; import React from 'react';
import { render } from 'react-dom'; import { render } from 'react-dom';
import '../less/app.less'; import '../less/app.less';
import Coriolis from './Coriolis'; import Coriolis from './Coriolis';
// import TapEventPlugin from 'react/lib/TapEventPlugin';
// import EventPluginHub from 'react/lib/EventPluginHub';
// onTouchTap not ready for primetime yet, too many issues with preventing default
// EventPluginHub.injection.injectEventPluginsByName({ TapEventPlugin });
render(<Coriolis />, document.getElementById('coriolis')); render(<Coriolis />, document.getElementById('coriolis'));

View File

@@ -45,6 +45,9 @@ export default class ErrorDetails extends React.Component {
return <div className='error'> return <div className='error'>
<h1>Jameson, we have a problem..</h1> <h1>Jameson, we have a problem..</h1>
<h1><small>{error.message}</small></h1> <h1><small>{error.message}</small></h1>
Import Error handling has been improved, but still isn't perfect. <br/>MOST Import failures are a result of missing modules in Coriolis, <br />OR incorrect import strings generated by third party apps. If you're seeing this page, we may have failed to handle the errors in your import correctly. Please see the data output below, specifically the 'scriptUrl:' section if it's there and then if you feel confident enough, please check the github issues page linked below and see if there is a similar issue already logged. If not, please create a new issue with the data below. If you're not confident, please ask for help on the Coriolis Channel of the EDCD Discord server.
<br/>
<br/>
<br/> <br/>
{importerror ? <div>If you are attempting to import a ship from EDDI or EDMC and are seeing a 'Z_BUF_ERROR' it means that the URL has not been provided correctly. This is a common problem when using Microsoft Internet Explorer or Microsoft Edge, and you should use another browser instead.</div> : null } {importerror ? <div>If you are attempting to import a ship from EDDI or EDMC and are seeing a 'Z_BUF_ERROR' it means that the URL has not been provided correctly. This is a common problem when using Microsoft Internet Explorer or Microsoft Edge, and you should use another browser instead.</div> : null }
<br/> <br/>

View File

@@ -1,5 +1,4 @@
import React from 'react'; import React from 'react';
// import Perf from 'react-addons-perf';
import { Ships } from 'coriolis-data/dist'; import { Ships } from 'coriolis-data/dist';
import cn from 'classnames'; import cn from 'classnames';
import Page from './Page'; import Page from './Page';
@@ -58,7 +57,6 @@ export default class OutfittingPage extends Page {
*/ */
constructor(props, context) { constructor(props, context) {
super(props, context); super(props, context);
// window.Perf = Perf;
this.state = this._initState(props, context); this.state = this._initState(props, context);
this._keyDown = this._keyDown.bind(this); this._keyDown = this._keyDown.bind(this);
this._exportBuild = this._exportBuild.bind(this); this._exportBuild = this._exportBuild.bind(this);
@@ -679,9 +677,9 @@ export default class OutfittingPage extends Page {
} }
/** /**
* Open up a window for EDDB with a shopping list of our components * Open up a window for inara with a shopping list of our components
*/ */
_eddbShoppingList() { _inaraShoppingList() {
const ship = this.state.ship; const ship = this.state.ship;
const shipId = Ships[ship.id].eddbID; const shipId = Ships[ship.id].eddbID;
@@ -694,7 +692,7 @@ export default class OutfittingPage extends Page {
// Open up the relevant URL // Open up the relevant URL
window.open( window.open(
'https://eddb.io/station?s=' + shipId + '&m=' + modIds.join(',') 'https://inara.cz/inapi/corisearch.php?s=' + shipId + '&m=' + modIds.join(',')
); );
} }
@@ -702,7 +700,9 @@ export default class OutfittingPage extends Page {
* Generates the shopping list * Generates the shopping list
*/ */
_genShoppingList() { _genShoppingList() {
this.context.showModal(<ModalShoppingList ship={this.state.ship} />); this.context.showModal(<ModalShoppingList
ship={this.state.ship}
buildName={this.state.buildName} />);
} }
/** /**
@@ -914,7 +914,7 @@ export default class OutfittingPage extends Page {
<Download className="lg" /> <Download className="lg" />
</button> </button>
<button <button
onClick={this._eddbShoppingList} onClick={this._inaraShoppingList}
onMouseOver={termtip.bind(null, 'PHRASE_SHOPPING_LIST')} onMouseOver={termtip.bind(null, 'PHRASE_SHOPPING_LIST')}
onMouseOut={hide} onMouseOut={hide}
> >

View File

@@ -383,7 +383,8 @@ export function shieldMetrics(ship, sys) {
// Our initial regeneration comes from the SYS capacitor store, which is replenished as it goes // Our initial regeneration comes from the SYS capacitor store, which is replenished as it goes
// 0.6 is a magic number from FD: each 0.6 MW of energy from the power distributor recharges 1 MJ/s of regeneration // 0.6 is a magic number from FD: each 0.6 MW of energy from the power distributor recharges 1 MJ/s of regeneration
let capacitorDrain = (shieldGenerator.getBrokenRegenerationRate() * 0.6) - sysRechargeRate; let capacitorDrain = (shieldGenerator.getBrokenRegenerationRate() * shieldGenerator.getDistDraw()) - sysRechargeRate;
let capacitorLifetime = powerDistributor.getSystemsCapacity() / capacitorDrain; let capacitorLifetime = powerDistributor.getSystemsCapacity() / capacitorDrain;
let recover = 16; let recover = 16;
@@ -399,7 +400,7 @@ export function shieldMetrics(ship, sys) {
recover = Math.Infinity; recover = Math.Infinity;
} else { } else {
// Recover remaining shields at the rate of the power distributor's recharge // Recover remaining shields at the rate of the power distributor's recharge
recover += remainingShieldToRecover / (sysRechargeRate / 0.6); recover += remainingShieldToRecover / (sysRechargeRate / shieldGenerator.getDistDraw());
} }
} }
@@ -408,7 +409,7 @@ export function shieldMetrics(ship, sys) {
// Our initial regeneration comes from the SYS capacitor store, which is replenished as it goes // Our initial regeneration comes from the SYS capacitor store, which is replenished as it goes
// 0.6 is a magic number from FD: each 0.6 MW of energy from the power distributor recharges 1 MJ/s of regeneration // 0.6 is a magic number from FD: each 0.6 MW of energy from the power distributor recharges 1 MJ/s of regeneration
capacitorDrain = (shieldGenerator.getRegenerationRate() * 0.6) - sysRechargeRate; capacitorDrain = (shieldGenerator.getRegenerationRate() * shieldGenerator.getDistDraw()) - sysRechargeRate;
capacitorLifetime = powerDistributor.getSystemsCapacity() / capacitorDrain; capacitorLifetime = powerDistributor.getSystemsCapacity() / capacitorDrain;
let recharge = 0; let recharge = 0;
@@ -424,7 +425,7 @@ export function shieldMetrics(ship, sys) {
recharge = Math.Inf; recharge = Math.Inf;
} else { } else {
// Recharge remaining shields at the rate of the power distributor's recharge // Recharge remaining shields at the rate of the power distributor's recharge
recharge += remainingShieldToRecharge / (sysRechargeRate / 0.6); recharge += remainingShieldToRecharge / (sysRechargeRate / shieldGenerator.getDistDraw());
} }
} }

View File

@@ -25,7 +25,6 @@ export const ModuleGroupToName = {
pd: 'Power Distributor', pd: 'Power Distributor',
s: 'Sensors', s: 'Sensors',
ft: 'Fuel Tank', ft: 'Fuel Tank',
pas: 'Planetary Approach Suite',
// Internal // Internal
fs: 'Fuel Scoop', fs: 'Fuel Scoop',
@@ -58,6 +57,9 @@ export const ModuleGroupToName = {
gmrp: 'Guardian Module Reinforcement Package', gmrp: 'Guardian Module Reinforcement Package',
mahr: 'Meta Alloy Hull Reinforcement Package', mahr: 'Meta Alloy Hull Reinforcement Package',
sua: 'Supercruise Assist', sua: 'Supercruise Assist',
mlc: "Multi Limpet Controller",
rpl: "Repair Limpet Controller",
pas: 'Planetary Approach Suite',
// Hard Points // Hard Points
bl: 'Beam Laser', bl: 'Beam Laser',
@@ -75,11 +77,15 @@ export const ModuleGroupToName = {
nl: 'Mine Launcher', nl: 'Mine Launcher',
ml: 'Mining Laser', ml: 'Mining Laser',
mr: 'Missile Rack', mr: 'Missile Rack',
amr: 'Missile Rack (Advanced)',
axmr: 'AX Missile Rack', axmr: 'AX Missile Rack',
axmre: 'AX Missile Rack (Enhanced)',
pa: 'Plasma Accelerator', pa: 'Plasma Accelerator',
po: 'Point Defence', po: 'Point Defence',
mc: 'Multi-cannon', mc: 'Multi-cannon',
advmc: 'Multi-cannon (Advanced)',
axmc: 'AX Multi-cannon', axmc: 'AX Multi-cannon',
axmce: 'AX Multi-cannon (Enhanced)',
pl: 'Pulse Laser', pl: 'Pulse Laser',
rg: 'Rail Gun', rg: 'Rail Gun',
sb: 'Shield Booster', sb: 'Shield Booster',

View File

@@ -439,6 +439,15 @@ export default class Module {
return this.get('integrity', modified); return this.get('integrity', modified);
} }
/**
* Get the info of this module
* @param {Boolean} [modified=false] Whether to take modifications into account
* @return {String} the info of this module
*/
getInfo(modified = false) {
return (modified && this.getModValue('info')) || this.info;
}
/** /**
* Get the mass of this module * Get the mass of this module
* @param {Boolean} [modified=true] Whether to take modifications into account * @param {Boolean} [modified=true] Whether to take modifications into account

View File

@@ -13,6 +13,19 @@ function filter(arr, maxClass, minClass, mass) {
return arr.filter(m => m.class <= maxClass && m.class >= minClass && (m.maxmass === undefined || mass <= m.maxmass)); return arr.filter(m => m.class <= maxClass && m.class >= minClass && (m.maxmass === undefined || mass <= m.maxmass));
} }
/**
* Filter SCO Modules to only return legal size.
* @param {Array} arr Array of available FSD modules.
* @param {number} maxSize Maximum allowable size for SCO modules.
* @return {Array} Subset of modules filtered based on legal size amd type.
*/
function sco_filter(arr, maxSize) {
return arr.filter(module => {
return !(module.hasOwnProperty('name') && module['name'] === "Frame Shift Drive (SCO)" && module['class'] < maxSize);
});
}
/** /**
* The available module set for a specific ship * The available module set for a specific ship
*/ */
@@ -41,6 +54,7 @@ export default class ModuleSet {
this.standard[0] = filter(stnd.pp, maxStandardArr[0], 0, mass); // Power Plant this.standard[0] = filter(stnd.pp, maxStandardArr[0], 0, mass); // Power Plant
this.standard[2] = filter(stnd.fsd, maxStandardArr[2], 0, mass); // FSD this.standard[2] = filter(stnd.fsd, maxStandardArr[2], 0, mass); // FSD
this.standard[2] = sco_filter(this.standard[2], maxStandardArr[2]) // FSD - Filter SCO Modules
this.standard[4] = filter(stnd.pd, maxStandardArr[4], 0, mass); // Power Distributor this.standard[4] = filter(stnd.pd, maxStandardArr[4], 0, mass); // Power Distributor
this.standard[6] = filter(stnd.ft, maxStandardArr[6], 0, mass); // Fuel Tank this.standard[6] = filter(stnd.ft, maxStandardArr[6], 0, mass); // Fuel Tank
// Thrusters, filter modules by class only (to show full list of ratings for that class) // Thrusters, filter modules by class only (to show full list of ratings for that class)

View File

@@ -10,7 +10,7 @@ import { Ships, Modifications } from 'coriolis-data/dist';
import { chain } from 'lodash'; import { chain } from 'lodash';
const zlib = require('zlib'); const zlib = require('zlib');
const UNIQUE_MODULES = ['psg', 'sg', 'bsg', 'rf', 'fs', 'fh', 'gfsb', 'dc']; const UNIQUE_MODULES = ['psg', 'sg', 'bsg', 'rf', 'fs', 'fh', 'gfsb', 'dc', 'ews'];
// Constants for modifications struct // Constants for modifications struct
const SLOT_ID_DONE = -1; const SLOT_ID_DONE = -1;

View File

@@ -108,9 +108,9 @@ export class Persist extends EventEmitter {
this.matsPerGrade = matsPerGrade || { this.matsPerGrade = matsPerGrade || {
1: 2, 1: 2,
2: 2, 2: 2,
3: 4, 3: 3,
4: 4, 4: 4,
5: 10 5: 5
}; };
this.cmdrName = cmdrName || { selected: '', cmdrs: [] }; this.cmdrName = cmdrName || { selected: '', cmdrs: [] };
this.tooltipsEnabled = tips === null ? true : tips; this.tooltipsEnabled = tips === null ? true : tips;

View File

@@ -34,9 +34,11 @@ export const SHIP_FD_NAME_TO_CORIOLIS_NAME = {
'Krait_Light': 'krait_phantom', 'Krait_Light': 'krait_phantom',
'Orca': 'orca', 'Orca': 'orca',
'Python': 'python', 'Python': 'python',
'Python_nx': 'python_nx',
'SideWinder': 'sidewinder', 'SideWinder': 'sidewinder',
'Type6': 'type_6_transporter', 'Type6': 'type_6_transporter',
'Type7': 'type_7_transport', 'Type7': 'type_7_transport',
'Type8': 'type_8_transport',
'Type9': 'type_9_heavy', 'Type9': 'type_9_heavy',
'Type9_Military': 'type_10_defender', 'Type9_Military': 'type_10_defender',
'TypeX': 'alliance_chieftain', 'TypeX': 'alliance_chieftain',

View File

@@ -6,6 +6,22 @@ import { Modules } from 'coriolis-data/dist';
import { Modifications } from 'coriolis-data/dist'; import { Modifications } from 'coriolis-data/dist';
import { getBlueprint, setQualityCB } from './BlueprintFunctions'; import { getBlueprint, setQualityCB } from './BlueprintFunctions';
/**
* Check if an imported module is valid
* @param {Object} module the module to check
* @param {Object} moduleType the type of module to check
* @return {boolean} true if the module is valid
*/
function _isValidImportedModule(module, moduleType) {
// First of all, has the _moduleFromFdName function returned 'null'?
if (!module){
return false
}
else {
return true
}
}
/** /**
* Obtain a module given its FD Name * Obtain a module given its FD Name
* @param {string} fdname the FD Name of the module * @param {string} fdname the FD Name of the module
@@ -98,49 +114,90 @@ export function shipFromLoadoutJSON(json) {
if (module.Engineering) _addModifications(ship.bulkheads.m, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect); if (module.Engineering) _addModifications(ship.bulkheads.m, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
break; break;
case 'powerplant': case 'powerplant':
const powerplant = _moduleFromFdName(module.Item); let powerplant = _moduleFromFdName(module.Item);
// Check the powerplant returned is valid
if (!_isValidImportedModule(powerplant, 'powerplant'))
{
powerplant = _moduleFromFdName('Int_Missing_Powerplant');
module.Engineering = null;
}
ship.use(ship.standard[0], powerplant, true); ship.use(ship.standard[0], powerplant, true);
ship.standard[0].enabled = module.On; ship.standard[0].enabled = module.On;
ship.standard[0].priority = module.Priority; ship.standard[0].priority = module.Priority;
if (module.Engineering) _addModifications(powerplant, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect); if (module.Engineering) _addModifications(powerplant, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
break; break;
case 'mainengines': case 'mainengines':
const thrusters = _moduleFromFdName(module.Item); let thrusters = _moduleFromFdName(module.Item);
// Check the thrusters returned is valid
if (!_isValidImportedModule(thrusters, 'thrusters'))
{
thrusters = _moduleFromFdName('Int_Missing_Engine');
module.Engineering = null;
}
ship.use(ship.standard[1], thrusters, true); ship.use(ship.standard[1], thrusters, true);
ship.standard[1].enabled = module.On; ship.standard[1].enabled = module.On;
ship.standard[1].priority = module.Priority; ship.standard[1].priority = module.Priority;
if (module.Engineering) _addModifications(thrusters, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect); if (module.Engineering) _addModifications(thrusters, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
break; break;
case 'frameshiftdrive': case 'frameshiftdrive':
const frameshiftdrive = _moduleFromFdName(module.Item); let frameshiftdrive = _moduleFromFdName(module.Item);
// Check the frameshiftdrive returned is valid
if (!_isValidImportedModule(frameshiftdrive, 'frameshiftdrive'))
{
frameshiftdrive = _moduleFromFdName('Int_Missing_Hyperdrive');
module.Engineering = null;
}
ship.use(ship.standard[2], frameshiftdrive, true); ship.use(ship.standard[2], frameshiftdrive, true);
ship.standard[2].enabled = module.On; ship.standard[2].enabled = module.On;
ship.standard[2].priority = module.Priority; ship.standard[2].priority = module.Priority;
if (module.Engineering) _addModifications(frameshiftdrive, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect); if (module.Engineering) _addModifications(frameshiftdrive, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
break; break;
case 'lifesupport': case 'lifesupport':
const lifesupport = _moduleFromFdName(module.Item); let lifesupport = _moduleFromFdName(module.Item);
// Check the lifesupport returned is valid
if (!_isValidImportedModule(lifesupport, 'lifesupport'))
{
lifesupport = _moduleFromFdName('Int_Missing_LifeSupport');
module.Engineering = null;
}
ship.use(ship.standard[3], lifesupport, true); ship.use(ship.standard[3], lifesupport, true);
ship.standard[3].enabled = module.On === true; ship.standard[3].enabled = module.On === true;
ship.standard[3].priority = module.Priority; ship.standard[3].priority = module.Priority;
if (module.Engineering) _addModifications(lifesupport, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect); if (module.Engineering) _addModifications(lifesupport, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
break; break;
case 'powerdistributor': case 'powerdistributor':
const powerdistributor = _moduleFromFdName(module.Item); let powerdistributor = _moduleFromFdName(module.Item);
// Check the powerdistributor returned is valid
if (!_isValidImportedModule(powerdistributor, 'powerdistributor'))
{
powerdistributor = _moduleFromFdName('Int_Missing_PowerDistributor');
module.Engineering = null;
}
ship.use(ship.standard[4], powerdistributor, true); ship.use(ship.standard[4], powerdistributor, true);
ship.standard[4].enabled = module.On; ship.standard[4].enabled = module.On;
ship.standard[4].priority = module.Priority; ship.standard[4].priority = module.Priority;
if (module.Engineering) _addModifications(powerdistributor, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect); if (module.Engineering) _addModifications(powerdistributor, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
break; break;
case 'radar': case 'radar':
const sensors = _moduleFromFdName(module.Item); let sensors = _moduleFromFdName(module.Item);
// Check the sensors returned is valid
if (!_isValidImportedModule(sensors, 'sensors'))
{
sensors = _moduleFromFdName('Int_Missing_Sensors');
module.Engineering = null;
}
ship.use(ship.standard[5], sensors, true); ship.use(ship.standard[5], sensors, true);
ship.standard[5].enabled = module.On; ship.standard[5].enabled = module.On;
ship.standard[5].priority = module.Priority; ship.standard[5].priority = module.Priority;
if (module.Engineering) _addModifications(sensors, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect); if (module.Engineering) _addModifications(sensors, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
break; break;
case 'fueltank': case 'fueltank':
const fueltank = _moduleFromFdName(module.Item); let fueltank = _moduleFromFdName(module.Item);
// Check the fueltank returned is valid
if (!_isValidImportedModule(fueltank, 'fueltank'))
{
fueltank = _moduleFromFdName('Int_Missing_FuelTank');
}
ship.use(ship.standard[6], fueltank, true); ship.use(ship.standard[6], fueltank, true);
ship.standard[6].enabled = true; ship.standard[6].enabled = true;
ship.standard[6].priority = 0; ship.standard[6].priority = 0;
@@ -170,11 +227,28 @@ export function shipFromLoadoutJSON(json) {
// This can happen with old imports that don't contain new hardpoints // This can happen with old imports that don't contain new hardpoints
} else { } else {
hardpoint = _moduleFromFdName(hardpointSlot.Item); hardpoint = _moduleFromFdName(hardpointSlot.Item);
// Check the hardpoint module returned is valid
if (!_isValidImportedModule(hardpoint, 'hardpoint')){
// Check if it's a Utility or Hardpoint
if (hardpointSlot.Slot.toLowerCase().search(/tiny/))
{
// Use the missing_hardpoint module 'Missing Hardpoint' which will inform the user that the module is missing
hardpoint = _moduleFromFdName('Hpt_Missing_Hardpoint');
}
else {
// Use the missing_hardpoint module 'Missing Utility' which will inform the user that the module is missing
hardpoint = _moduleFromFdName('Hpt_Missing_Utility');
}
ship.use(ship.hardpoints[hardpointArrayNum], hardpoint, true);
ship.hardpoints[hardpointArrayNum].enabled = hardpointSlot.On;
ship.hardpoints[hardpointArrayNum].priority = hardpointSlot.Priority;
} else {
ship.use(ship.hardpoints[hardpointArrayNum], hardpoint, true); ship.use(ship.hardpoints[hardpointArrayNum], hardpoint, true);
ship.hardpoints[hardpointArrayNum].enabled = hardpointSlot.On; ship.hardpoints[hardpointArrayNum].enabled = hardpointSlot.On;
ship.hardpoints[hardpointArrayNum].priority = hardpointSlot.Priority; ship.hardpoints[hardpointArrayNum].priority = hardpointSlot.Priority;
modsToAdd.push({ coriolisMod: hardpoint, json: hardpointSlot }); modsToAdd.push({ coriolisMod: hardpoint, json: hardpointSlot });
} }
}
hardpointArrayNum++; hardpointArrayNum++;
} }
} }
@@ -187,13 +261,17 @@ export function shipFromLoadoutJSON(json) {
continue; continue;
} }
const isMilitary = isNaN(shipTemplate.slots.internal[i]) ? shipTemplate.slots.internal[i].name == 'Military' : false; const isMilitary = isNaN(shipTemplate.slots.internal[i]) ? shipTemplate.slots.internal[i].name == 'Military' : false;
const isPlanetary = isNaN(shipTemplate.slots.internal[i]) ? shipTemplate.slots.internal[i].name == 'PlanetaryApproachSuite' : false;
// The internal slot might be a standard or a military slot. Military slots have a different naming system // The internal slot might be a standard or a military slot, or a planetary slot. Military and Planetary slots have a different naming system
let internalSlot = null; let internalSlot = null;
if (isMilitary) { if (isMilitary) {
const internalName = 'Military0' + militarySlotNum; const internalName = 'Military0' + militarySlotNum;
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase()); internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase());
militarySlotNum++; militarySlotNum++;
} else if (isPlanetary) {
const internalName = 'PlanetaryApproachSuite';
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase());
} else { } else {
// Slot numbers are not contiguous so handle skips. // Slot numbers are not contiguous so handle skips.
for (; internalSlot === null && internalSlotNum < 99; internalSlotNum++) { for (; internalSlot === null && internalSlotNum < 99; internalSlotNum++) {
@@ -212,13 +290,24 @@ export function shipFromLoadoutJSON(json) {
// This can happen with old imports that don't contain new slots // This can happen with old imports that don't contain new slots
} else { } else {
const internalJson = internalSlot; const internalJson = internalSlot;
const internal = _moduleFromFdName(internalJson.Item); let internal = _moduleFromFdName(internalJson.Item);
// Check the internal module returned is valid
if (!_isValidImportedModule(internal, 'internal'))
{
internal = _moduleFromFdName('Int_Missing_Module');
ship.use(ship.internal[i], internal, true);
ship.internal[i].enabled = internalJson.On === true;
ship.internal[i].priority = internalJson.Priority;
//throw 'Unknown internal module: "' + module.Item + '"';
}
else {
ship.use(ship.internal[i], internal, true); ship.use(ship.internal[i], internal, true);
ship.internal[i].enabled = internalJson.On === true; ship.internal[i].enabled = internalJson.On === true;
ship.internal[i].priority = internalJson.Priority; ship.internal[i].priority = internalJson.Priority;
modsToAdd.push({ coriolisMod: internal, json: internalSlot }); modsToAdd.push({ coriolisMod: internal, json: internalSlot });
} }
} }
}
for (const i of modsToAdd) { for (const i of modsToAdd) {
if (i.json.Engineering) { if (i.json.Engineering) {

View File

@@ -40,18 +40,8 @@
window.dataLayer = window.dataLayer || []; window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);} function gtag(){dataLayer.push(arguments);}
gtag('js', new Date()); gtag('js', new Date());
gtag('config', 'UA-55840909-18'); gtag('config', 'UA-55840909-18');
</script> </script>
<!-- Bugsnag -->
<script src="https://d2wy8f7a9ursnm.cloudfront.net/v5.0.0/bugsnag.min.js"></script>
<script>
window.bugsnagClient = bugsnag('ba9fae819372850fb660755341fa6ef5', {appVersion: window.BUGSNAG_VERSION || undefined})
window.Bugsnag = window.bugsnagClient
</script>
</head> </head>
<body style="background-color:#000;"> <body style="background-color:#000;">
<section id="coriolis"> <section id="coriolis">

View File

@@ -41,6 +41,48 @@
h2 { h2 {
margin: 0; margin: 0;
} }
h4 {
text-transform: uppercase;
font-family: @fStandard;
font-weight: normal;
font-size: 1em;
margin: 1em;
color: @warning;
}
p {
margin: 1em;
text-wrap: pretty;
}
button {
clear: bottom;
margin: 5px;
}
hr {
clear: both;
margin: 15px, 10px, 15px, 10px;
padding: top, 5;
}
select {
clear: bottom;
margin: 10px;
width: 50%;
}
label {
clear: bottom;
margin: 20px;
color: @primary;
}
.groll {
width: 6%;
margin: 5px;
text-align: center;
} }
textarea { textarea {
@@ -55,10 +97,11 @@ textarea {
min-height: 10em; min-height: 10em;
resize: vertical; resize: vertical;
user-select: text; user-select: text;
margin:2em 0; margin:1em 0;
} }
} }
.dismiss { .dismiss {
background-color: @primary-bg; background-color: @primary-bg;
} }
}

View File

@@ -24,12 +24,6 @@
type="image/png" type="image/png"
href="/192x192.png" href="/192x192.png"
/> />
<!-- Bugsnag -->
<script src="https://d2wy8f7a9ursnm.cloudfront.net/v5.0.0/bugsnag.min.js"></script>
<script>
window.bugsnagClient = bugsnag('ba9fae819372850fb660755341fa6ef5', {appVersion: window.BUGSNAG_VERSION || undefined})
window.Bugsnag = window.bugsnagClient
</script>
<!-- Apple/iOS headers --> <!-- Apple/iOS headers -->
<meta name="apple-mobile-web-app-capable" content="yes" /> <meta name="apple-mobile-web-app-capable" content="yes" />

View File

@@ -1,46 +1,54 @@
import {precacheAndRoute, createHandlerBoundToURL} from 'workbox-precaching';
import {NavigationRoute, registerRoute} from 'workbox-routing';
import {StaleWhileRevalidate, CacheFirst} from 'workbox-strategies';
import {CacheableResponsePlugin} from 'workbox-cacheable-response'
import {ExpirationPlugin} from 'workbox-expiration';
console.log('Hello from sw.js'); console.log('Hello from sw.js');
if (workbox) { // See https://developer.chrome.com/docs/workbox/migration/migrate-from-v4/ for guide to changes made
console.log('Yay! Workbox is loaded 🎉'); console.log('Yay! Workbox is loaded 🎉');
workbox.precaching.precacheAndRoute(self.__precacheManifest); precacheAndRoute(self.__WB_MANIFEST || []);
workbox.routing.registerNavigationRoute('/index.html'); const handler = createHandlerBoundToURL('/index.html');
const navigationRoute = new NavigationRoute(handler
// , {allowlist: [...], denylist: [...],}
);
registerRoute(navigationRoute);
workbox.routing.registerRoute(
registerRoute(
/\.(?:png|jpg|jpeg|svg|gif)$/, /\.(?:png|jpg|jpeg|svg|gif)$/,
new workbox.strategies.CacheFirst({ new CacheFirst({
plugins: [ plugins: [
new workbox.cacheableResponse.Plugin({ new CacheableResponsePlugin({
statuses: [0, 200] statuses: [0, 200]
}) })
] ]
}) })
); );
workbox.routing.registerRoute( registerRoute(
/\.(?:js|css)$/, /\.(?:js|css)$/,
new workbox.strategies.StaleWhileRevalidate({ new StaleWhileRevalidate({
cacheName: 'static-resources', cacheName: 'static-resources',
}) })
); );
workbox.routing.registerRoute( registerRoute(
new RegExp('https://fonts.(?:googleapis|gstatic).com/(.*)'), new RegExp('https://fonts.(?:googleapis|gstatic).com/(.*)'),
new workbox.strategies.CacheFirst({ new CacheFirst({
cacheName: 'google-fonts', cacheName: 'google-fonts',
plugins: [ plugins: [
new workbox.expiration.Plugin({ new ExpirationPlugin({
maxEntries: 30 maxEntries: 30
}), }),
new workbox.cacheableResponse.Plugin({ new CacheableResponsePlugin({
statuses: [0, 200] statuses: [0, 200]
}) })
] ]
}) })
); );
} else {
console.log('Boo! Workbox didn\'t load 😬');
}
self.addEventListener('message', event => { self.addEventListener('message', event => {
if (!event.data) { if (!event.data) {

81
webpack.common.js Normal file
View File

@@ -0,0 +1,81 @@
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const pkgJson = require('./package');
const buildDate = new Date();
module.exports = {
entry: {
main: './src/app/index.js'
},
resolve: {
// When requiring, you don't need to add these extensions
extensions: ['.js', '.jsx', '.json', '.less'],
fallback: {
// Consider replacing brwoserify-zlib-next c. 2016 package with pako, which it's just a wrapper for
/* Some of these polyfills may not even be necessary, and were added in an attempt to deal with build issues
while upgrading to Webpack v5 */
"zlib": require.resolve("browserify-zlib-next"),
"assert": require.resolve("assert/"),
"buffer": require.resolve("buffer/"),
"stream": require.resolve("stream-browserify"),
/*
"url": require.resolve("url/"),
"path": require.resolve("path-browserify"),
"crypto": require.resolve("crypto-browserify"),
"os": require.resolve("os-browserify/browser"),
"https": require.resolve("https-browserify"),
"http": require.resolve("stream-http"),
"vm": require.resolve("vm-browserify"),
"constants": require.resolve("constants-browserify"),
// "fs": false
*/
}
},
optimization: {
usedExports: true
},
output: {
path: path.join(__dirname, 'build'),
chunkFilename: '[name].bundle.js',
// assetModuleFilename: '[contenthash][ext]',
publicPath: '/',
clean: true // we already do rimraf on the build dir, but this should obviate that
},
plugins: [
// new webpack.optimize.CommonsChunkPlugin({
// name: 'lib',
// filename: 'lib.js'
// }),
new HtmlWebpackPlugin({
inject: true,
template: path.join(__dirname, 'src/index.ejs'),
version: pkgJson.version,
// gapiKey: process.env.CORIOLIS_GAPI_KEY || '',
date: buildDate,
}),
new MiniCssExtractPlugin({
filename: 'app.css',
}),
// Solve missing Buffer polyfill that breaks module engineering
new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer'],
}),
],
module: {
rules: [
{ test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader' ]},
{
test: /\.less$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader' ]
},
{ test: /\.(js|jsx)$/, use: ['babel-loader'], include: path.join(__dirname, 'src') },
{
test: /\.(jpe?g|svg|png|gif|ico|eot|ttf|woff|woff2?)(\?v=\d+\.\d+\.\d+)?$/i,
type: 'asset/resource',
},
]
}
};

View File

@@ -1,69 +1,27 @@
const path = require('path');
const webpack = require('webpack'); const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin'); const { merge } = require('webpack-merge');
const ExtractTextPlugin = require('extract-text-webpack-plugin'); const common = require('./webpack.common.js');
const WebpackNotifierPlugin = require('webpack-notifier');
const pkgJson = require('./package');
const buildDate = new Date();
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = { const CopyWebpackPlugin = require('copy-webpack-plugin');
const WebpackNotifierPlugin = require('webpack-notifier');
module.exports = merge(common, {
devtool: 'source-map', devtool: 'source-map',
devServer: { devServer: {
headers: { 'Access-Control-Allow-Origin': '*' } headers: { 'Access-Control-Allow-Origin': '*' }
}, },
mode: 'development', mode: 'development',
entry: {
main: './src/app/index.js',
},
resolve: {
// When requiring, you don't need to add these extensions
extensions: ['.js', '.jsx', '.json', '.less']
},
optimization: { optimization: {
minimize: false, minimize: false,
usedExports: true
},
output: {
path: path.join(__dirname, 'build'),
chunkFilename: '[name].bundle.js',
publicPath: '/'
}, },
plugins: [ plugins: [
new CopyWebpackPlugin(['src/.htaccess', 'src/iframe.html', 'src/xdLocalStoragePostMessageApi.min.js']), new CopyWebpackPlugin({
// new webpack.optimize.CommonsChunkPlugin({ patterns: [
// name: 'lib', 'src/.htaccess',
// filename: 'lib.js' 'src/iframe.html',
// }), 'src/xdLocalStoragePostMessageApi.min.js'
new HtmlWebpackPlugin({ ]}),
inject: true,
template: path.join(__dirname, 'src/index.ejs'),
version: pkgJson.version,
date: buildDate,
gapiKey: process.env.CORIOLIS_GAPI_KEY || ''
}),
new ExtractTextPlugin({
filename: 'app.css',
disable: false,
allChunks: true
}),
new WebpackNotifierPlugin({ alwaysNotify: true }), new WebpackNotifierPlugin({ alwaysNotify: true }),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin() new webpack.NoEmitOnErrorsPlugin()
],
module: {
rules: [
{ test: /\.css$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader' }) },
{
test: /\.less$/,
loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader!less-loader' })
},
{ test: /\.(js|jsx)$/, loaders: ['babel-loader'], include: path.join(__dirname, 'src') },
{ test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff' },
{ test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff' },
{ test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/octet-stream' },
{ test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader' },
{ test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=image/svg+xml' }
] ]
} });
};

View File

@@ -1,54 +1,37 @@
const path = require('path'); const { merge } = require('webpack-merge');
const webpack = require('webpack'); const common = require('./webpack.common.js');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const { InjectManifest } = require('workbox-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const { BugsnagSourceMapUploaderPlugin, BugsnagBuildReporterPlugin } = require('webpack-bugsnag-plugins');
const pkgJson = require('./package');
const buildDate = new Date();
module.exports = { const path = require('path');
devtool: 'source-map', const CopyWebpackPlugin = require('copy-webpack-plugin');
entry: { const MiniCssExtractPlugin = require('mini-css-extract-plugin');
main: './src/app/index.js' const { InjectManifest } = require('workbox-webpack-plugin');
},
resolve: { module.exports = merge(common, {
extensions: ['.js', '.jsx', '.json', '.less'] // devtool: 'source-map',
},
output: {
path: path.join(__dirname, 'build'),
chunkFilename: '[name].bundle.js',
publicPath: '/',
globalObject: 'this'
},
mode: 'production', mode: 'production',
optimization: { optimization: {
minimize: true, minimize: true,
usedExports: true },
output: {
globalObject: 'this'
}, },
plugins: [ plugins: [
new CopyWebpackPlugin(['src/.htaccess', { from: 'src/schemas', to: 'schemas' }, { new CopyWebpackPlugin({
patterns: [
'src/.htaccess',
'src/iframe.html',
'src/xdLocalStoragePostMessageApi.min.js',
{ from: 'src/schemas', to: 'schemas' },
{
from: 'src/images/logo/*', from: 'src/images/logo/*',
flatten: true, to: '[name][ext]'
to: '' }
}, 'src/iframe.html', 'src/xdLocalStoragePostMessageApi.min.js']), ]}),
// new webpack.optimize.CommonsChunkPlugin({ /* new HtmlWebpackPlugin({
// name: 'lib', // uaTracking: process.env.CORIOLIS_UA_TRACKING || '',
// filename: 'lib.[chunkhash:6].js' }), */
// }), new MiniCssExtractPlugin({
new HtmlWebpackPlugin({ filename: '[contenthash:6].css',
inject: true,
template: path.join(__dirname, 'src/index.ejs'),
uaTracking: process.env.CORIOLIS_UA_TRACKING || '',
gapiKey: process.env.CORIOLIS_GAPI_KEY || '',
date: buildDate,
version: pkgJson.version
}),
new ExtractTextPlugin({
filename: '[hash:6].css',
disable: false,
allChunks: true
}), }),
// new BugsnagBuildReporterPlugin({ // new BugsnagBuildReporterPlugin({
// apiKey: 'ba9fae819372850fb660755341fa6ef5', // apiKey: 'ba9fae819372850fb660755341fa6ef5',
@@ -59,25 +42,11 @@ module.exports = {
// overwrite: true, // overwrite: true,
// appVersion: `${pkgJson.version}-${buildDate.toISOString()}` // appVersion: `${pkgJson.version}-${buildDate.toISOString()}`
// }), // }),
new InjectManifest({ new InjectManifest({
swSrc: './src/sw.js', swSrc: './src/sw.js',
importWorkboxFrom: 'cdn',
swDest: 'service-worker.js' swDest: 'service-worker.js'
}), }),
],
module: {
rules: [
{ test: /\.css$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader' }) },
{
test: /\.less$/,
loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader!less-loader' })
},
{ test: /\.(js|jsx)$/, loader: 'babel-loader?cacheDirectory=true', include: path.join(__dirname, 'src') },
{ test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff' },
{ test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff' },
{ test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/octet-stream' },
{ test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader' },
{ test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=image/svg+xml' }
] ]
} });
};