Compare commits

..

116 Commits
2.4.2 ... 2.9.6

Author SHA1 Message Date
willyb321
f3bc900f16 Merge branch 'release/2.9.6' 2018-04-22 07:00:47 +10:00
willyb321
38842417b0 bump 2018-04-22 06:59:08 +10:00
willyb321
82d485a98e fix preset rolls locked to low value 2018-04-22 06:49:43 +10:00
willyb321
fac71feea7 Lowercase armour check
Fixes #231
2018-04-21 12:56:51 +10:00
willyb321
ec148847a9 Merge branch 'develop' 2018-04-21 11:39:19 +10:00
willyb321
445c63878b add guard for tooltips crashing the import 2018-04-21 11:39:02 +10:00
willyb321
0474af912a Merge branch 'release/2.9.5' 2018-04-21 11:05:29 +10:00
willyb321
7df5953824 bump 2018-04-21 11:05:19 +10:00
willyb321
e391b563fb change preset rolls to 100%, 75%, 50% and random 2018-04-21 11:03:23 +10:00
willyb321
53f62f96d0 Merge branch 'master' into develop 2018-04-21 07:17:11 +10:00
willyb321
18745979a0 update about page 2018-04-20 19:20:47 +10:00
willyb321
c1966a38ff Merge branch 'master' into develop 2018-04-20 12:49:10 +10:00
willyb321
d86973f3b1 specify appVersion for bugsnag 2018-04-20 12:48:46 +10:00
willyb321
56b8d19649 Merge branch 'release/2.9.4' 2018-04-19 07:17:21 +10:00
willyb321
7cb037e0bc bump 2018-04-19 07:17:06 +10:00
willyb321
56e1b3f9e9 Revert "prep for guardian"
This reverts commit 7e67bd80dd.
2018-04-19 07:14:24 +10:00
willyb321
c792323a8a misc bits 2018-04-19 07:14:13 +10:00
willyb321
4d2865de13 fix resistance blueprint values 2018-04-19 07:14:02 +10:00
willyb321
0d360bc367 bugsnag update 2018-04-19 07:13:20 +10:00
willyb321
91c9b46b91 clean up webpack configs 2018-04-19 06:44:02 +10:00
willyb321
7e67bd80dd prep for guardian 2018-04-19 06:26:53 +10:00
willyb321
2f775ea09b Merge branch 'release/2.9.3' 2018-04-18 18:04:42 +10:00
willyb321
0603c55089 bump 2018-04-18 18:04:28 +10:00
willyb321
41f25a44e9 Merge branch 'master' into develop 2018-04-18 10:33:17 +10:00
willyb321
35440b7273 allow specials in internal and standard slots 2018-04-18 10:33:11 +10:00
willyb321
7d68b91018 Merge branch 'release/2.9.2' 2018-04-17 17:33:45 +10:00
willyb321
deaa61b848 bump version 2018-04-17 17:32:56 +10:00
willyb321
2d00cbc41b fix more values (hopefully done)
also, Fixes #247 by changing passengers to pax
2018-04-17 17:31:11 +10:00
willyb321
57c1e83c67 apply new experimentals structure 2018-04-17 15:01:09 +10:00
William
b7079dbd4e Merge pull request #246 from pnellesen/feature/bugfix_245
Fix for issue 245
2018-04-17 12:38:21 +10:00
willyb321
be642a5373 Merge branch 'master' into develop 2018-04-17 07:59:42 +10:00
willyb321
ffc691c1a2 Merge branch 'release/2.9.1' 2018-04-17 07:57:44 +10:00
willyb321
6122d99369 version bump 2018-04-17 07:57:13 +10:00
willyb321
b73a8bcdab hopefully fix some values and crashes
resistances are buggered on shields and armour by the looks of things
2018-04-17 07:55:17 +10:00
willyb321
dd624537b7 fix hardpoints / internals having the wrong mod applied 2018-04-17 07:50:57 +10:00
willyb321
50a67f73fd get rid of some redundant code 2018-04-17 07:50:13 +10:00
willyb321
2262a980d4 Merge remote-tracking branch 'origin/develop' into develop 2018-04-17 07:46:35 +10:00
willyb321
84964ceb5f add source maps to assist with debugging.
also upload them to bugsnag
2018-04-17 07:46:26 +10:00
William Blythe
c4bdb7a66e Merge remote-tracking branch 'origin/master' into develop 2018-04-16 13:11:44 +10:00
Pat
21309e129f Fix for issue 245 - check that the passenger property is defined for a slot before calculating total passenger capacity 2018-04-14 08:50:48 -05:00
willyb321
928e02c718 Merge branch 'release/2.9.0' 2018-04-14 16:53:08 +10:00
willyb321
7f494dd200 bump 2018-04-14 16:52:05 +10:00
William
f38e743e59 Merge pull request #244 from EDCD/feature/beyond-coriolis
Engineer mods.
2018-04-14 15:14:13 +10:00
Willyb321
58b55eb3da Engineers. Are. Back. Probably. 2018-04-14 14:50:37 +10:00
willyb321
8375ad95b3 Merge branch 'master' into feature/beyond-coriolis 2018-04-14 10:16:20 +10:00
willyb321
506d027a2d Merge branch 'develop' 2018-04-14 09:52:03 +10:00
willyb321
fbeb6237cf fix webpack 2018-04-14 09:51:46 +10:00
willyb321
bd95e2c5a5 Merge branch 'master' into develop 2018-04-14 09:48:03 +10:00
willyb321
f3276e557a Merge branch 'release/2.5.3' 2018-04-14 09:47:08 +10:00
willyb321
8b813e0e7f bump 2018-04-14 09:46:41 +10:00
willyb321
d660d2959f more roles fixing
use a smaller shield, add boosters, d rate some internals
2018-04-14 09:44:29 +10:00
willyb321
014ebda7d2 start fixing suggested roles. Thanks to rinzler + others 2018-04-14 08:06:44 +10:00
William
607398d364 Merge pull request #241 from Blackth0rn/fix/#240_incorrect_passenger_counts
Fix/#240 incorrect passenger counts
2018-04-13 16:20:52 +10:00
willyb321
97d141ce2b update lockfile version 2018-04-13 16:17:59 +10:00
willyb321
9f492db9c6 source map 2018-04-13 16:16:42 +10:00
willyb321
6ed82b366c update bugsnag 2018-04-13 16:16:01 +10:00
willyb321
a7ca037f48 loadout event prep 2018-04-13 14:38:22 +10:00
willyb321
6e21d0e74a Work on engineering import 2018-04-13 13:39:33 +10:00
willyb321
e6c75bf2af Merge branch 'develop' into feature/beyond-coriolis 2018-04-13 09:16:23 +10:00
willyb321
270c2f386e Merge branch 'release/2.5.2' 2018-04-13 07:56:38 +10:00
willyb321
83f7880c58 bump version 2018-04-13 07:51:07 +10:00
William
51d29aee38 Merge pull request #235 from pnellesen/feature/fueltank_column
Added fuel tank column to Core Module Classes on Shipyard
2018-04-13 07:38:07 +10:00
William
c7754c0365 Merge pull request #234 from joelgarboden/feature/remote_testing
Disable 'localhost' host header requirement
2018-04-13 07:34:59 +10:00
Greg Matthews
94037cea38 Fix #240: Added passenger count to individual ship page 2018-04-11 21:09:57 -07:00
Greg Matthews
5c1a9d9eea Fix #240: There is no size 7 passenger cabin so use the new findMaxInternal function to get the biggest one that fits in the slot 2018-04-11 21:07:00 -07:00
Greg Matthews
3835c73ffd Add findMaxInternal function to find the biggest module of a given group, rating, slotsize 2018-04-11 21:06:07 -07:00
Pat
b8c1effecb Update for issue #183 - use first letter of bulkhead instead of "Max Rating" value 2018-04-09 23:10:28 -05:00
Pat
dd07241dd9 Added fuel tank column to Core Module Classes on Shipyard 2018-04-07 18:57:54 -05:00
Joel Garboden
5ad828a613 Disable 'localhost' limit
Disale host header so webpack allows more than localhost access
2018-04-07 22:34:50 +00:00
Unknown
9856df5527 Portiguese 2018-03-22 22:00:19 +00:00
Unknown
7b249900ec Portuguese 2018-03-22 21:59:50 +00:00
Unknown
e3b9267c3f Merge remote-tracking branch 'origin/feature/beyond-coriolis' into develop 2018-03-22 21:59:37 +00:00
willyb321
a996b8135a inital engineerless import working 2018-03-23 08:51:48 +11:00
willyb321
5e1237390b Initial work on 3.0 imports.
Decided to split journal imports to a separate file.
2018-03-22 16:22:59 +11:00
Willyb321
83571b4bef add .editorconfig
Makes contributing and not messing up the codestyle easier
2018-03-22 12:07:19 +11:00
Willyb321
c2a0dad9a8 Export textarea select
Fixes #146
2018-03-22 12:06:36 +11:00
Unknown
f6f057689c Merge branch 'feature/chieftain' into develop 2018-01-27 11:47:17 +00:00
willyb321
4378f0020e add chieftain to map
also remove console logs that i forgot to remove
2018-01-27 10:55:37 +11:00
Unknown
2e9e7c4fc6 Merge branch 'release/2.5.1' 2018-01-24 09:18:58 +00:00
Unknown
b7b8ee5580 Merge branch 'release/2.5.1' into develop 2018-01-24 09:18:36 +00:00
Unknown
c630dbbed0 Version Bump 2018-01-24 09:18:21 +00:00
Unknown
fa6703a3b8 Merge remote-tracking branch 'Blackth0rn/feature/#186-passenger-totals' into develop 2018-01-24 08:45:54 +00:00
Unknown
bdcb64c9d1 Merge remote-tracking branch 'willyb321/feature/fix-engineer-values' into develop 2018-01-24 08:45:48 +00:00
Unknown
a1afc869a7 Merge remote-tracking branch 'Ghnuberath/feature/ax-modules' into develop 2018-01-24 08:45:44 +00:00
Unknown
d8ce26c7cf Merge remote-tracking branch 'origin/master' into develop 2018-01-24 08:44:45 +00:00
Sean McIntyre
95c474dc05 Recategorizing experimental modules into an "experimental" category 2018-01-22 16:48:10 -05:00
Sean McIntyre
56ca73b4ad Forgot Remote Release Flak Launcher 2018-01-22 16:43:29 -05:00
Sean McIntyre
d82cd6a89e Removing unnecessary change 2018-01-22 15:21:59 -05:00
Sean McIntyre
bf20d32364 Adding AX modules 2018-01-22 15:20:41 -05:00
willyb321
e968e62fca Fix clip size (hopefully) 2018-01-16 08:14:21 +11:00
Unknown
b9c9ca9fa1 Merge branch 'release/2.5.0' 2018-01-11 21:59:31 +00:00
Unknown
6e965e2e98 Version Bump 2018-01-11 21:59:20 +00:00
Unknown
7d569f9036 Merge branch 'feature/fix-engineers' into develop 2018-01-11 21:51:35 +00:00
Unknown
df5a77199d Merge branch 'develop' 2018-01-11 21:50:28 +00:00
Greg Matthews
3c8dfebfdc Issue #186. Added passenger totals to shipyard screen 2018-01-10 21:20:27 -08:00
Unknown
3cc422596f Something something consistant naming 2017-12-24 09:47:49 +00:00
Unknown
4ed167de22 Add T10 2017-12-24 09:47:33 +00:00
Unknown
b420647501 Something something consistant naming 2017-12-24 09:46:49 +00:00
Unknown
0c318b5e68 Add T10 2017-12-23 12:03:21 +00:00
willyb321
1c627297b8 shorten the terrible _addModifications call 2017-12-19 16:39:42 +11:00
willyb321
f41e2d0552 fix indent and hopefully fix ammo clip
dont know if it was broken, if someone has it DM it to me thanks
2017-12-19 16:28:05 +11:00
willyb321
1a1d539c60 fix engagement range slider and armour integrity
hopefully
2017-12-19 16:18:20 +11:00
willyb321
ba2e46f88f fix rate of fire
probably
2017-12-19 14:49:04 +11:00
willyb321
c2f1fa81af remove console logs 2017-12-17 18:48:24 +11:00
willyb321
752e03fa0f possible armour fix
need more data to confirm however
2017-12-17 18:24:34 +11:00
willyb321
1da69664d7 shields should be accurate now
dont now what the issue with hull is
if you see it let me know
2017-12-17 14:49:51 +11:00
willyb321
9aa986a133 thanks webstorm 2017-12-17 12:48:13 +11:00
willyb321
bdbfb28c4a missed a spot 2017-12-17 12:47:02 +11:00
willyb321
162156bb2b fix random weird indents 2017-12-17 12:46:18 +11:00
willyb321
64c5d542e9 more work on mods 2017-12-17 12:27:04 +11:00
willyb321
31dc789f6e initial (re)implementation of engineer mods
still some kinds to work out.
2017-12-17 11:16:50 +11:00
Unknown
b0e2cfd7db Merge branch 'feature/#112_ship_table_highlights' into develop 2017-12-04 09:41:54 +00:00
Greg Matthews
54ddb0d014 Rename sortValue and tmpSortValue to be more meaningful 2017-11-11 13:29:59 -08:00
Greg Matthews
e19688e96f Add alternate row highlighting for sorted value 2017-11-11 13:25:17 -08:00
Greg Matthews
4f53d75999 Fix whitespace in html 2017-11-11 13:24:57 -08:00
Unknown
93c4f6f3c0 Merge branch 'release/2.4.2' into develop 2017-11-09 17:23:32 +00:00
34 changed files with 2717 additions and 423 deletions

21
.editorconfig Normal file
View File

@@ -0,0 +1,21 @@
root = true
[*]
# change these settings to your own preference
indent_style = space
indent_size = 4
# we recommend you to keep these unchanged
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[{package,bower}.json]
indent_style = space
indent_size = 2

View File

@@ -1,3 +1,13 @@
#2.5.1
* Passenger count on main page
* AX Modules
* Engineering fixes
* Use coriolis-data 2.5.1
#2.5.0
* willyb321 and myself have conquered engineering. Mainly him though...
* Use coriolis-data 2.5.0
#2.4.2 #2.4.2
Lots of kind people have helped out for this release! Check out the PR history! Lots of kind people have helped out for this release! Check out the PR history!
* Uses coriolis-data update: * Uses coriolis-data update:

1
devServer.js Normal file → Executable file
View File

@@ -5,6 +5,7 @@ var config = require('./webpack.config.dev');
new WebpackDevServer(webpack(config), { new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath, publicPath: config.output.publicPath,
hot: true, hot: true,
disableHostCheck: true,
headers: { "Access-Control-Allow-Origin": "*" }, headers: { "Access-Control-Allow-Origin": "*" },
historyApiFallback: { historyApiFallback: {
rewrites: [ rewrites: [

1565
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{ {
"name": "coriolis_shipyard", "name": "coriolis_shipyard",
"version": "2.4.2", "version": "2.9.6",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/EDCD/coriolis" "url": "https://github.com/EDCD/coriolis"
@@ -19,7 +19,7 @@
"test": "jest", "test": "jest",
"prod-serve": "nginx -p $(pwd) -c nginx.conf", "prod-serve": "nginx -p $(pwd) -c nginx.conf",
"prod-stop": "kill -QUIT $(cat nginx.pid)", "prod-stop": "kill -QUIT $(cat nginx.pid)",
"build": "npm run clean && NODE_ENV=production webpack -p --config webpack.config.prod.js", "build": "npm run clean && cross-env NODE_ENV=production webpack -p --config webpack.config.prod.js",
"rsync": "rsync -ae \"ssh -i $CORIOLIS_PEM\" --delete build/ $CORIOLIS_USER@$CORIOLIS_HOST:~/wwws", "rsync": "rsync -ae \"ssh -i $CORIOLIS_PEM\" --delete build/ $CORIOLIS_USER@$CORIOLIS_HOST:~/wwws",
"deploy": "npm run lint && npm test && npm run build && npm run rsync" "deploy": "npm run lint && npm test && npm run build && npm run rsync"
}, },
@@ -66,6 +66,7 @@
"babel-preset-stage-0": "*", "babel-preset-stage-0": "*",
"create-react-class": "^15.6.2", "create-react-class": "^15.6.2",
"css-loader": "^0.28.0", "css-loader": "^0.28.0",
"cross-env": "^5.1.4",
"d3-selection": "1", "d3-selection": "1",
"eslint": "3.19.0", "eslint": "3.19.0",
"eslint-plugin-react": "^6.10.3", "eslint-plugin-react": "^6.10.3",
@@ -87,10 +88,12 @@
"rollup": "0.41", "rollup": "0.41",
"rollup-plugin-node-resolve": "3", "rollup-plugin-node-resolve": "3",
"style-loader": "^0.16.1", "style-loader": "^0.16.1",
"uglify-js": "^2.4.11",
"url-loader": "^0.5.8", "url-loader": "^0.5.8",
"webpack": "^2.4.1", "webpack": "^2.4.1",
"webpack-dev-server": "^2.4.4", "webpack-dev-server": "^2.4.4",
"uglify-js": "^2.4.11" "webpack-notifier": "^1.6.0",
"webpack-bugsnag-plugins": "^1.1.1"
}, },
"dependencies": { "dependencies": {
"babel-polyfill": "*", "babel-polyfill": "*",

View File

@@ -12,6 +12,7 @@ import ModalHelp from './components/ModalHelp';
import ModalImport from './components/ModalImport'; import ModalImport from './components/ModalImport';
import ModalPermalink from './components/ModalPermalink'; import ModalPermalink from './components/ModalPermalink';
import * as CompanionApiUtils from './utils/CompanionApiUtils'; import * as CompanionApiUtils from './utils/CompanionApiUtils';
import * as JournalUtils from './utils/JournalUtils';
import AboutPage from './pages/AboutPage'; import AboutPage from './pages/AboutPage';
import NotFoundPage from './pages/NotFoundPage'; import NotFoundPage from './pages/NotFoundPage';
@@ -92,7 +93,14 @@ export default class Coriolis extends React.Component {
// 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(r.params.data, 'base64'), { to: 'string' });
const json = JSON.parse(data); const json = JSON.parse(data);
const ship = CompanionApiUtils.shipFromJson(json); console.log('Ship import data: ');
console.log(json);
let ship;
if (json && json.modules) {
ship = CompanionApiUtils.shipFromJson(json);
} else if (json && json.Modules) {
ship = JournalUtils.shipFromLoadoutJSON(json);
}
r.params.ship = ship.id; r.params.ship = ship.id;
r.params.code = ship.toString(); r.params.code = ship.toString();
this._setPage(OutfittingPage, r); this._setPage(OutfittingPage, r);
@@ -126,9 +134,9 @@ export default class Coriolis extends React.Component {
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) {
if (errObj instanceof Error) { if (errObj instanceof Error) {
Bugsnag.notifyException(errObj) // eslint-disable-line bugsnagClient.notify(errObj) // eslint-disable-line
} else if (errObj instanceof String) { } else if (errObj instanceof String) {
Bugsnag.notify(msg, errObj) // eslint-disable-line bugsnagClient.notify(msg, errObj) // eslint-disable-line
} }
} }
this.setState({ this.setState({

View File

@@ -37,10 +37,13 @@ const GRPCAT = {
'ml': 'lasers', 'ml': 'lasers',
'c': 'projectiles', 'c': 'projectiles',
'mc': 'projectiles', 'mc': 'projectiles',
'axmc': 'experimental',
'fc': 'projectiles', 'fc': 'projectiles',
'rfl': 'experimental',
'pa': 'projectiles', 'pa': 'projectiles',
'rg': 'projectiles', 'rg': 'projectiles',
'mr': 'ordnance', 'mr': 'ordnance',
'axmr': 'experimental',
'tp': 'ordnance', 'tp': 'ordnance',
'nl': 'ordnance', 'nl': 'ordnance',
'sc': 'scanners', 'sc': 'scanners',
@@ -49,9 +52,11 @@ const GRPCAT = {
'cs': 'scanners', 'cs': 'scanners',
'kw': 'scanners', 'kw': 'scanners',
'ws': 'scanners', 'ws': 'scanners',
'xs': 'scanners',
'ch': 'defence', 'ch': 'defence',
'po': 'defence', 'po': 'defence',
'ec': 'defence', 'ec': 'defence',
'sfn': 'defence'
}; };
// 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 = {
@@ -76,6 +81,8 @@ const CATEGORIES = {
'hs': ['hs'], 'hs': ['hs'],
'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': ['axmc', 'axmr', 'rfl', 'xs', 'sfn']
}; };
/** /**

View File

@@ -25,7 +25,7 @@ export default class EngagementRange extends TranslatedComponent {
const { ship } = props; const { ship } = props;
const maxRange = this._calcMaxRange(ship); const maxRange = Math.round(this._calcMaxRange(ship));
this.state = { this.state = {
maxRange maxRange

View File

@@ -33,6 +33,9 @@ export default class InternalSlot extends Slot {
let modTT = translate('modified'); let modTT = translate('modified');
if (m && m.blueprint && m.blueprint.name) { if (m && m.blueprint && m.blueprint.name) {
modTT = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade; modTT = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade;
if (m.blueprint.special && m.blueprint.special.id >= 0) {
modTT += ', ' + translate(m.blueprint.special.name);
}
modTT = ( modTT = (
<div> <div>
<div>{modTT}</div> <div>{modTT}</div>

View File

@@ -6,7 +6,7 @@ import { isEmpty, stopCtxPropagation } from '../utils/UtilityFunctions';
import cn from 'classnames'; import cn from 'classnames';
import { Modifications } from 'coriolis-data/dist'; import { Modifications } from 'coriolis-data/dist';
import Modification from './Modification'; import Modification from './Modification';
import { getBlueprint, blueprintTooltip, setWorst, setBest, setExtreme, setRandom } from '../utils/BlueprintFunctions'; import { getBlueprint, blueprintTooltip, setPercent, setRandom } from '../utils/BlueprintFunctions';
/** /**
* Modifications menu * Modifications menu
@@ -30,10 +30,10 @@ export default class ModificationsMenu extends TranslatedComponent {
this._toggleBlueprintsMenu = this._toggleBlueprintsMenu.bind(this); this._toggleBlueprintsMenu = this._toggleBlueprintsMenu.bind(this);
this._toggleSpecialsMenu = this._toggleSpecialsMenu.bind(this); this._toggleSpecialsMenu = this._toggleSpecialsMenu.bind(this);
this._rollWorst = this._rollWorst.bind(this); this._rollFifty = this._rollFifty.bind(this);
this._rollRandom = this._rollRandom.bind(this); this._rollRandom = this._rollRandom.bind(this);
this._rollBest = this._rollBest.bind(this); this._rollBest = this._rollBest.bind(this);
this._rollExtreme = this._rollExtreme.bind(this); this._rollSevenFive = this._rollSevenFive.bind(this);
this._reset = this._reset.bind(this); this._reset = this._reset.bind(this);
this.state = { this.state = {
@@ -168,11 +168,11 @@ export default class ModificationsMenu extends TranslatedComponent {
} }
/** /**
* Provide a 'worst' roll within the information we have * Provide a '50%' roll within the information we have
*/ */
_rollWorst() { _rollFifty() {
const { m, ship } = this.props; const { m, ship } = this.props;
setWorst(ship, m); setPercent(ship, m, 50);
this.props.onChange(); this.props.onChange();
} }
@@ -190,16 +190,16 @@ export default class ModificationsMenu extends TranslatedComponent {
*/ */
_rollBest() { _rollBest() {
const { m, ship } = this.props; const { m, ship } = this.props;
setBest(ship, m); setPercent(ship, m, 100);
this.props.onChange(); this.props.onChange();
} }
/** /**
* Provide an 'extreme' roll within the information we have * Provide an '75%' roll within the information we have
*/ */
_rollExtreme() { _rollSevenFive() {
const { m, ship } = this.props; const { m, ship } = this.props;
setExtreme(ship, m); setPercent(ship, m, 75);
this.props.onChange(); this.props.onChange();
} }
@@ -226,9 +226,9 @@ export default class ModificationsMenu extends TranslatedComponent {
const _toggleBlueprintsMenu = this._toggleBlueprintsMenu; const _toggleBlueprintsMenu = this._toggleBlueprintsMenu;
const _toggleSpecialsMenu = this._toggleSpecialsMenu; const _toggleSpecialsMenu = this._toggleSpecialsMenu;
const _rollBest = this._rollBest; const _rollFull = this._rollBest;
const _rollExtreme = this._rollExtreme; const _rollSevenFive = this._rollSevenFive;
const _rollWorst = this._rollWorst; const _rollFifty = this._rollFifty;
const _rollRandom = this._rollRandom; const _rollRandom = this._rollRandom;
const _reset = this._reset; const _reset = this._reset;
@@ -275,9 +275,9 @@ export default class ModificationsMenu extends TranslatedComponent {
{ showRolls ? { showRolls ?
<tr> <tr>
<td> { translate('roll') }: </td> <td> { translate('roll') }: </td>
<td style={{ cursor: 'pointer' }} onClick={_rollWorst} onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_WORST')} onMouseOut={tooltip.bind(null, null)}> { translate('worst') } </td> <td style={{ cursor: 'pointer' }} onClick={_rollFifty} onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_FIFTY')} onMouseOut={tooltip.bind(null, null)}> { translate('50%') } </td>
<td style={{ cursor: 'pointer' }} onClick={_rollBest}onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_BEST')} onMouseOut={tooltip.bind(null, null)}> { translate('best') } </td> <td style={{ cursor: 'pointer' }} onClick={_rollSevenFive} onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_SEVEN_FIVE')} onMouseOut={tooltip.bind(null, null)}> { translate('75%') } </td>
<td style={{ cursor: 'pointer' }} onClick={_rollExtreme}onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_EXTREME')} onMouseOut={tooltip.bind(null, null)}> { translate('extreme') } </td> <td style={{ cursor: 'pointer' }} onClick={_rollFull} onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_BEST')} onMouseOut={tooltip.bind(null, null)}> { translate('100%') } </td>
<td style={{ cursor: 'pointer' }} onClick={_rollRandom} onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_RANDOM')} onMouseOut={tooltip.bind(null, null)}> { translate('random') } </td> <td style={{ cursor: 'pointer' }} onClick={_rollRandom} onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_RANDOM')} onMouseOut={tooltip.bind(null, null)}> { translate('random') } </td>
</tr> : null } </tr> : null }
{ showReset ? { showReset ?

View File

@@ -53,6 +53,7 @@ export default class ShipSummaryTable extends TranslatedComponent {
<th rowSpan={2}>{translate('TTD')}</th> <th rowSpan={2}>{translate('TTD')}</th>
{/* <th onMouseEnter={termtip.bind(null, 'heat per second')} onMouseLeave={hide} rowSpan={2}>{translate('HPS')}</th> */} {/* <th onMouseEnter={termtip.bind(null, 'heat per second')} onMouseLeave={hide} rowSpan={2}>{translate('HPS')}</th> */}
<th rowSpan={2}>{translate('cargo')}</th> <th rowSpan={2}>{translate('cargo')}</th>
<th rowSpan={2}>{translate('pax')}</th>
<th rowSpan={2}>{translate('fuel')}</th> <th rowSpan={2}>{translate('fuel')}</th>
<th colSpan={3}>{translate('mass')}</th> <th colSpan={3}>{translate('mass')}</th>
<th onMouseEnter={termtip.bind(null, 'hull hardness', { cap: 0 })} onMouseLeave={hide} rowSpan={2}>{translate('hrd')}</th> <th onMouseEnter={termtip.bind(null, 'hull hardness', { cap: 0 })} onMouseLeave={hide} rowSpan={2}>{translate('hrd')}</th>
@@ -86,6 +87,7 @@ export default class ShipSummaryTable extends TranslatedComponent {
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_TTD', { cap: 0 })} onMouseLeave={hide}>{timeToDrain === Infinity ? '∞' : time(timeToDrain)}</td> <td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_TTD', { cap: 0 })} onMouseLeave={hide}>{timeToDrain === Infinity ? '∞' : time(timeToDrain)}</td>
{/* <td>{f1(ship.totalHps)}</td> */} {/* <td>{f1(ship.totalHps)}</td> */}
<td>{round(ship.cargoCapacity)}{u.T}</td> <td>{round(ship.cargoCapacity)}{u.T}</td>
<td>{ship.passengerCapacity}</td>
<td>{round(ship.fuelCapacity)}{u.T}</td> <td>{round(ship.fuelCapacity)}{u.T}</td>
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_HULL_MASS', { cap: 0 })} onMouseLeave={hide}>{ship.hullMass}{u.T}</td> <td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_HULL_MASS', { cap: 0 })} onMouseLeave={hide}>{ship.hullMass}{u.T}</td>
<td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_UNLADEN_MASS', { cap: 0 })} onMouseLeave={hide}>{int(ship.unladenMass)}{u.T}</td> <td onMouseEnter={termtip.bind(null, 'TT_SUMMARY_UNLADEN_MASS', { cap: 0 })} onMouseLeave={hide}>{int(ship.unladenMass)}{u.T}</td>

View File

@@ -56,6 +56,9 @@ export default class StandardSlot extends TranslatedComponent {
let modTT = translate('modified'); let modTT = translate('modified');
if (m && m.blueprint && m.blueprint.name) { if (m && m.blueprint && m.blueprint.name) {
modTT = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade; modTT = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade;
if (m.blueprint.special && m.blueprint.special.id >= 0) {
modTT += ', ' + translate(m.blueprint.special.name);
}
modTT = ( modTT = (
<div> <div>
<div>{modTT}</div> <div>{modTT}</div>
@@ -96,7 +99,7 @@ export default class StandardSlot extends TranslatedComponent {
return ( return (
<div className={cn('slot', { selected: this.props.selected })} onClick={this.props.onOpen} onContextMenu={stopCtxPropagation}> <div className={cn('slot', { selected: this.props.selected })} onClick={this.props.onOpen} onContextMenu={stopCtxPropagation}>
<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'}>{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} {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>

View File

@@ -235,12 +235,10 @@ export default class StandardSlotSection extends SlotSection {
<ul> <ul>
<li className='lc' onClick={this._multiPurpose.bind(this, false, 0)}>{translate('Multi-purpose')}</li> <li className='lc' onClick={this._multiPurpose.bind(this, false, 0)}>{translate('Multi-purpose')}</li>
<li className='lc' onClick={this._multiPurpose.bind(this, true, 2)}>{translate('Combat')}</li> <li className='lc' onClick={this._multiPurpose.bind(this, true, 2)}>{translate('Combat')}</li>
<li className='lc' onClick={this._optimizeCargo.bind(this, false)}>{translate('Trader')}</li> <li className='lc' onClick={this._optimizeCargo.bind(this, true)}>{translate('Trader')}</li>
<li className='lc' onClick={this._optimizeCargo.bind(this, true)}>{translate('Shielded Trader')}</li>
<li className='lc' onClick={this._optimizeExplorer.bind(this, false)}>{translate('Explorer')}</li> <li className='lc' onClick={this._optimizeExplorer.bind(this, false)}>{translate('Explorer')}</li>
<li className={cn('lc', { disabled: planetaryDisabled })} onClick={!planetaryDisabled && this._optimizeExplorer.bind(this, true)}>{translate('Planetary Explorer')}</li> <li className={cn('lc', { disabled: planetaryDisabled })} onClick={!planetaryDisabled && this._optimizeExplorer.bind(this, true)}>{translate('Planetary Explorer')}</li>
<li className='lc' onClick={this._optimizeMiner.bind(this, false)}>{translate('Miner')}</li> <li className='lc' onClick={this._optimizeMiner.bind(this, true)}>{translate('Miner')}</li>
<li className='lc' onClick={this._optimizeMiner.bind(this, true)}>{translate('Shielded Miner')}</li>
<li className='lc' onClick={this._optimizeRacer.bind(this)}>{translate('Racer')}</li> <li className='lc' onClick={this._optimizeRacer.bind(this)}>{translate('Racer')}</li>
</ul> </ul>
</div>; </div>;

View File

@@ -6,6 +6,7 @@ import * as FR from './fr';
import * as IT from './it'; import * as IT from './it';
import * as RU from './ru'; import * as RU from './ru';
import * as PL from './pl'; import * as PL from './pl';
import * as PT from './pt';
import * as d3 from 'd3'; import * as d3 from 'd3';
let fallbackTerms = EN.terms; let fallbackTerms = EN.terms;
@@ -25,6 +26,7 @@ export function getLanguage(langCode) {
case 'it': lang = IT; break; case 'it': lang = IT; break;
case 'ru': lang = RU; break; case 'ru': lang = RU; break;
case 'pl': lang = PL; break; case 'pl': lang = PL; break;
case 'pt': lang = PT; break;
default: default:
lang = EN; lang = EN;
} }
@@ -88,5 +90,6 @@ export const Languages = {
es: 'Español', es: 'Español',
fr: 'Français', fr: 'Français',
ru: 'ру́сский', ru: 'ру́сский',
pl: 'polski' pl: 'polski',
pt: 'português'
}; };

View File

@@ -16,6 +16,8 @@
"PHRASE_ENGAGEMENT_RANGE": "The distance between your ship and its target", "PHRASE_ENGAGEMENT_RANGE": "The distance between your ship and its target",
"PHRASE_SELECT_BLUEPRINT": "Click to select a blueprint", "PHRASE_SELECT_BLUEPRINT": "Click to select a blueprint",
"PHRASE_BLUEPRINT_WORST": "Worst primary values for this blueprint", "PHRASE_BLUEPRINT_WORST": "Worst primary values for this blueprint",
"PHRASE_BLUEPRINT_FIFTY": "50% of full values for this blueprint",
"PHRASE_BLUEPRINT_SEVEN_FIVE": "75% of full values for this blueprint",
"PHRASE_BLUEPRINT_RANDOM": "Random selection between worst and best primary values for this blueprint", "PHRASE_BLUEPRINT_RANDOM": "Random selection between worst and best primary values for this blueprint",
"PHRASE_BLUEPRINT_BEST": "Best primary values for this blueprint", "PHRASE_BLUEPRINT_BEST": "Best primary values for this blueprint",
"PHRASE_BLUEPRINT_EXTREME": "Best beneficial and worst detrimental primary values for this blueprint", "PHRASE_BLUEPRINT_EXTREME": "Best beneficial and worst detrimental primary values for this blueprint",
@@ -98,8 +100,10 @@
"kw": "Kill Warrant Scanner", "kw": "Kill Warrant Scanner",
"ls": "Life Support", "ls": "Life Support",
"mc": "Multi-cannon", "mc": "Multi-cannon",
"axmc": "AX Multi-cannon",
"ml": "Mining Laser", "ml": "Mining Laser",
"mr": "Missile Rack", "mr": "Missile Rack",
"axmr": "AX Missile Rack",
"mrp": "Module Reinforcement Package", "mrp": "Module Reinforcement Package",
"nl": "Mine Launcher", "nl": "Mine Launcher",
"pa": "Plasma Accelerator", "pa": "Plasma Accelerator",
@@ -116,11 +120,13 @@
"psg": "Prismatic Shield Generator", "psg": "Prismatic Shield Generator",
"pv": "Planetary Vehicle Hangar", "pv": "Planetary Vehicle Hangar",
"rf": "Refinery", "rf": "Refinery",
"rfl": "Remote Release Flak Launcher",
"rg": "Rail Gun", "rg": "Rail Gun",
"s": "Sensors", "s": "Sensors",
"sb": "Shield Booster", "sb": "Shield Booster",
"sc": "Stellar Scanners", "sc": "Stellar Scanners",
"scb": "Shield Cell Bank", "scb": "Shield Cell Bank",
"sfn": "Shutdown Field Neutraliser",
"sg": "Shield Generator", "sg": "Shield Generator",
"ss": "Surface Scanners", "ss": "Surface Scanners",
"t": "thrusters", "t": "thrusters",
@@ -128,6 +134,7 @@
"ul": "Burst Laser", "ul": "Burst Laser",
"ws": "Frame Shift Wake Scanner", "ws": "Frame Shift Wake Scanner",
"rpl": "Repair Limpet Controller", "rpl": "Repair Limpet Controller",
"xs": "Xeno Scanner",
"emptyrestricted": "empty (restricted)", "emptyrestricted": "empty (restricted)",
"damage dealt to": "Damage dealt to", "damage dealt to": "Damage dealt to",
"damage received from": "Damage received from", "damage received from": "Damage received from",

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

@@ -0,0 +1,16 @@
export const formats = {
decimal: ',',
thousands: '.',
grouping: [3],
currency: ['', ' €'],
dateTime: '%A, %e de %B de %Y, %X',
date: '%d/%m/%Y',
time: '%H:%M:%S',
periods: ['AM', 'PM'],
days: ['domingo', 'lunes', 'martes', 'miércoles', 'jueves', 'viernes', 'sábado'],
shortDays: ['dom', 'lun', 'mar', 'mié', 'jue', 'vie', 'sáb'],
months: ['enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio', 'julio', 'agosto', 'septiembre', 'octubre', 'noviembre', 'diciembre'],
shortMonths: ['ene', 'feb', 'mar', 'abr', 'may', 'jun', 'jul', 'ago', 'sep', 'oct', 'nov', 'dic']
};
export { default as terms } from './pt.json';

278
src/app/i18n/pt.json Normal file

File diff suppressed because one or more lines are too long

View File

@@ -41,6 +41,9 @@ export default class AboutPage extends Page {
<h3>Chat</h3> <h3>Chat</h3>
<p>You can chat to us on our <a href='https://discord.gg/0uwCh6R62aPRjk9w' target='_blank'>EDCD Discord server</a>.</p> <p>You can chat to us on our <a href='https://discord.gg/0uwCh6R62aPRjk9w' target='_blank'>EDCD Discord server</a>.</p>
<h3>Supporting Coriolis</h3>
<p>Coriolis is an open source project, and I work on it in my free time. I have set up a patreon at <a href='https://www.patreon.com/coriolis_elite'>patreon.com/coriolis_elite</a>, which will be used to keep Coriolis up to date and the servers running.</p>
</div>; </div>;
} }
} }

View File

@@ -73,13 +73,10 @@ export default class OutfittingPage extends Page {
let buildName = params.bn; let buildName = params.bn;
let data = Ships[shipId]; // Retrieve the basic ship properties, slots and defaults let data = Ships[shipId]; // Retrieve the basic ship properties, slots and defaults
let savedCode = Persist.getBuild(shipId, buildName); let savedCode = Persist.getBuild(shipId, buildName);
if (!data) { if (!data) {
return { error: { message: 'Ship not found: ' + shipId } }; return { error: { message: 'Ship not found: ' + shipId } };
} }
let ship = new Ship(shipId, data.properties, data.slots); // Create a new Ship instance let ship = new Ship(shipId, data.properties, data.slots); // Create a new Ship instance
if (code) { if (code) {
ship.buildFrom(code); // Populate modules from serialized 'code' URL param ship.buildFrom(code); // Populate modules from serialized 'code' URL param
} else { } else {

View File

@@ -25,6 +25,25 @@ function countInt(slot) {
this.int[slot.maxClass - 1]++; // Subtract 1 since there is no Class 0 Internal compartment this.int[slot.maxClass - 1]++; // Subtract 1 since there is no Class 0 Internal compartment
this.intCount++; this.intCount++;
this.maxCargo += crEligible ? ModuleUtils.findInternal('cr', slot.maxClass, 'E').cargo : 0; this.maxCargo += crEligible ? ModuleUtils.findInternal('cr', slot.maxClass, 'E').cargo : 0;
// if no eligiblity, then assume pce
let passSlotType = null;
let passSlotRating = null;
if (!slot.eligible || slot.eligible.pce) {
passSlotType = 'pce';
passSlotRating = 'E';
} else if (slot.eligible.pci) {
passSlotType = 'pci';
passSlotRating = 'D';
} else if (slot.eligible.pcm) {
passSlotType = 'pcm';
passSlotRating = 'C';
} else if (slot.eligible.pcq) {
passSlotType = 'pcq';
passSlotRating = 'B';
}
let passengerBay = passSlotType ? ModuleUtils.findMaxInternal(passSlotType, slot.maxClass, passSlotRating) : null;
this.maxPassengers += passengerBay ? passengerBay.passengers : 0;
} }
/** /**
@@ -39,6 +58,7 @@ function shipSummary(shipId, shipData) {
hpCount: 0, hpCount: 0,
intCount: 0, intCount: 0,
maxCargo: 0, maxCargo: 0,
maxPassengers: 0,
hp: [0, 0, 0, 0, 0], // Utility, Small, Medium, Large, Huge hp: [0, 0, 0, 0, 0], // Utility, Small, Medium, Large, Huge
int: [0, 0, 0, 0, 0, 0, 0, 0], // Sizes 1 - 8 int: [0, 0, 0, 0, 0, 0, 0, 0], // Sizes 1 - 8
standard: shipData.slots.standard, standard: shipData.slots.standard,
@@ -139,15 +159,16 @@ export default class ShipyardPage extends Page {
* @param {Object} u Localized unit map * @param {Object} u Localized unit map
* @param {Function} fInt Localized integer formatter * @param {Function} fInt Localized integer formatter
* @param {Function} fRound Localized round formatter * @param {Function} fRound Localized round formatter
* @param {Boolean} highlight Should this row be highlighted
* @return {React.Component} Table Row * @return {React.Component} Table Row
*/ */
_shipRowElement(s, translate, u, fInt, fRound) { _shipRowElement(s, translate, u, fInt, fRound, highlight) {
let noTouch = this.context.noTouch; let noTouch = this.context.noTouch;
return <tr return <tr
key={s.id} key={s.id}
style={{ height: '1.5em' }} style={{ height: '1.5em' }}
className={cn({ highlighted: noTouch && this.state.shipId === s.id })} className={cn({ highlighted: noTouch && this.state.shipId === s.id, alt: highlight })}
onMouseEnter={noTouch && this._highlightShip.bind(this, s.id)} onMouseEnter={noTouch && this._highlightShip.bind(this, s.id)}
> >
<td className='ri'>{s.manufacturer}</td> <td className='ri'>{s.manufacturer}</td>
@@ -166,12 +187,14 @@ export default class ShipyardPage extends Page {
<td className='ri'>{fInt(s.topBoost)}</td> <td className='ri'>{fInt(s.topBoost)}</td>
<td className='ri'>{fRound(s.maxJumpRange)}</td> <td className='ri'>{fRound(s.maxJumpRange)}</td>
<td className='ri'>{fInt(s.maxCargo)}</td> <td className='ri'>{fInt(s.maxCargo)}</td>
<td className='ri'>{fInt(s.maxPassengers)}</td>
<td className='cn'>{s.standard[0]}</td> <td className='cn'>{s.standard[0]}</td>
<td className='cn'>{s.standard[1]}</td> <td className='cn'>{s.standard[1]}</td>
<td className='cn'>{s.standard[2]}</td> <td className='cn'>{s.standard[2]}</td>
<td className='cn'>{s.standard[3]}</td> <td className='cn'>{s.standard[3]}</td>
<td className='cn'>{s.standard[4]}</td> <td className='cn'>{s.standard[4]}</td>
<td className='cn'>{s.standard[5]}</td> <td className='cn'>{s.standard[5]}</td>
<td className='cn'>{s.standard[6]}</td>
<td className={cn({ disabled: !s.hp[1] })}>{s.hp[1]}</td> <td className={cn({ disabled: !s.hp[1] })}>{s.hp[1]}</td>
<td className={cn({ disabled: !s.hp[2] })}>{s.hp[2]}</td> <td className={cn({ disabled: !s.hp[2] })}>{s.hp[2]}</td>
<td className={cn({ disabled: !s.hp[3] })}>{s.hp[3]}</td> <td className={cn({ disabled: !s.hp[3] })}>{s.hp[3]}</td>
@@ -246,13 +269,26 @@ export default class ShipyardPage extends Page {
let shipRows = new Array(shipSummaries.length); let shipRows = new Array(shipSummaries.length);
let detailRows = new Array(shipSummaries.length); let detailRows = new Array(shipSummaries.length);
let lastShipSortValue = null;
let backgroundHighlight = false;
for (let s of shipSummaries) { for (let s of shipSummaries) {
detailRows[i] = this._shipRowElement(s, translate, units, fInt, formats.f1); let shipSortValue = s[shipPredicate];
if( shipPredicateIndex != undefined ) {
shipSortValue = shipSortValue[shipPredicateIndex];
}
if( shipSortValue != lastShipSortValue ) {
backgroundHighlight = !backgroundHighlight;
lastShipSortValue = shipSortValue;
}
detailRows[i] = this._shipRowElement(s, translate, units, fInt, formats.f1, backgroundHighlight);
shipRows[i] = ( shipRows[i] = (
<tr <tr
key={i} key={i}
style={{ height: '1.5em' }} style={{ height: '1.5em' }}
className={cn({ highlighted: noTouch && this.state.shipId === s.id })} className={cn({ highlighted: noTouch && this.state.shipId === s.id, alt: backgroundHighlight })}
onMouseEnter={noTouch && this._highlightShip.bind(this, s.id)} onMouseEnter={noTouch && this._highlightShip.bind(this, s.id)}
> >
<td className='le'><Link href={'/outfit/' + s.id}>{s.name}</Link></td> <td className='le'><Link href={'/outfit/' + s.id}>{s.name}</Link></td>
@@ -293,8 +329,8 @@ export default class ShipyardPage extends Page {
<th rowSpan={3} className='sortable' onMouseEnter={termtip.bind(null, 'hardness')} onMouseLeave={hide} onClick={sortShips('hardness')}>{translate('hrd')}</th> <th rowSpan={3} className='sortable' onMouseEnter={termtip.bind(null, 'hardness')} onMouseLeave={hide} onClick={sortShips('hardness')}>{translate('hrd')}</th>
<th>&nbsp;</th> <th>&nbsp;</th>
<th colSpan={4}>{translate('base')}</th> <th colSpan={4}>{translate('base')}</th>
<th colSpan={4}>{translate('max')}</th> <th colSpan={5}>{translate('max')}</th>
<th className='lft' colSpan={6}></th> <th className='lft' colSpan={7}></th>
<th className='lft' colSpan={5}></th> <th className='lft' colSpan={5}></th>
<th className='lft' colSpan={8}></th> <th className='lft' colSpan={8}></th>
</tr> </tr>
@@ -310,29 +346,31 @@ export default class ShipyardPage extends Page {
<th className='sortable' onClick={sortShips('topBoost')}>{translate('boost')}</th> <th className='sortable' onClick={sortShips('topBoost')}>{translate('boost')}</th>
<th className='sortable' onClick={sortShips('maxJumpRange')}>{translate('jump')}</th> <th className='sortable' onClick={sortShips('maxJumpRange')}>{translate('jump')}</th>
<th className='sortable' onClick={sortShips('maxCargo')}>{translate('cargo')}</th> <th className='sortable' onClick={sortShips('maxCargo')}>{translate('cargo')}</th>
<th className='sortable' onClick={sortShips('maxPassengers')}>{translate('pax')}</th>
<th className='lft' colSpan={6}>{translate('core module classes')}</th> <th className='lft' colSpan={7}>{translate('core module classes')}</th>
<th colSpan={5} className='sortable lft' onClick={sortShips('hpCount')}>{translate('hardpoints')}</th> <th colSpan={5} className='sortable lft' onClick={sortShips('hpCount')}>{translate('hardpoints')}</th>
<th colSpan={8} className='sortable lft' onClick={sortShips('intCount')}>{translate('internal compartments')}</th> <th colSpan={8} className='sortable lft' onClick={sortShips('intCount')}>{translate('internal compartments')}</th>
</tr> </tr>
<tr> <tr>
<th className='sortable lft' onClick={sortShips('retailCost')}>{units.CR}</th> <th className='sortable lft' onClick={sortShips('retailCost')}>{units.CR}</th>
<th className='sortable lft' onClick={sortShips('hullMass')}>{units.T}</th> <th className='sortable lft' onClick={sortShips('hullMass')}>{units.T}</th>
<th className='sortable lft' onClick={sortShips('speed')}>{units['m/s']}</th> <th className='sortable lft' onClick={sortShips('speed')}>{units['m/s']}</th>
<th className='sortable' onClick={sortShips('boost')}>{units['m/s']}</th> <th className='sortable' onClick={sortShips('boost')}>{units['m/s']}</th>
<th>&nbsp;</th> <th>&nbsp;</th>
<th className='sortable' onClick={sortShips('baseShieldStrength')}>{units.MJ}</th> <th className='sortable' onClick={sortShips('baseShieldStrength')}>{units.MJ}</th>
<th className='sortable lft' onClick={sortShips('topSpeed')}>{units['m/s']}</th> <th className='sortable lft' onClick={sortShips('topSpeed')}>{units['m/s']}</th>
<th className='sortable' onClick={sortShips('topBoost')}>{units['m/s']}</th> <th className='sortable' onClick={sortShips('topBoost')}>{units['m/s']}</th>
<th className='sortable' onClick={sortShips('maxJumpRange')}>{units.LY}</th> <th className='sortable' onClick={sortShips('maxJumpRange')}>{units.LY}</th>
<th className='sortable' onClick={sortShips('maxCargo')}>{units.T}</th> <th className='sortable' onClick={sortShips('maxCargo')}>{units.T}</th>
<th>&nbsp;</th>
<th className='sortable lft' onMouseEnter={termtip.bind(null, 'power plant')} onMouseLeave={hide} onClick={sortShips('standard', 0)}>{'pp'}</th> <th className='sortable lft' onMouseEnter={termtip.bind(null, 'power plant')} onMouseLeave={hide} onClick={sortShips('standard', 0)}>{'pp'}</th>
<th className='sortable' onMouseEnter={termtip.bind(null, 'thrusters')} onMouseLeave={hide} onClick={sortShips('standard', 1)}>{'th'}</th> <th className='sortable' onMouseEnter={termtip.bind(null, 'thrusters')} onMouseLeave={hide} onClick={sortShips('standard', 1)}>{'th'}</th>
<th className='sortable' onMouseEnter={termtip.bind(null, 'frame shift drive')} onMouseLeave={hide} onClick={sortShips('standard', 2)}>{'fsd'}</th> <th className='sortable' onMouseEnter={termtip.bind(null, 'frame shift drive')} onMouseLeave={hide} onClick={sortShips('standard', 2)}>{'fsd'}</th>
<th className='sortable' onMouseEnter={termtip.bind(null, 'life support')} onMouseLeave={hide} onClick={sortShips('standard', 3)}>{'ls'}</th> <th className='sortable' onMouseEnter={termtip.bind(null, 'life support')} onMouseLeave={hide} onClick={sortShips('standard', 3)}>{'ls'}</th>
<th className='sortable' onMouseEnter={termtip.bind(null, 'power distriubtor')} onMouseLeave={hide} onClick={sortShips('standard', 4)}>{'pd'}</th> <th className='sortable' onMouseEnter={termtip.bind(null, 'power distriubtor')} onMouseLeave={hide} onClick={sortShips('standard', 4)}>{'pd'}</th>
<th className='sortable' onMouseEnter={termtip.bind(null, 'sensors')} onMouseLeave={hide} onClick={sortShips('standard', 5)}>{'s'}</th> <th className='sortable' onMouseEnter={termtip.bind(null, 'sensors')} onMouseLeave={hide} onClick={sortShips('standard', 5)}>{'s'}</th>
<th className='sortable' onMouseEnter={termtip.bind(null, 'fuel tank')} onMouseLeave={hide} onClick={sortShips('standard', 6)}>{'ft'}</th>
<th className='sortable lft' onClick={sortShips('hp',1)}>{translate('S')}</th> <th className='sortable lft' onClick={sortShips('hp',1)}>{translate('S')}</th>
<th className='sortable' onClick={sortShips('hp', 2)}>{translate('M')}</th> <th className='sortable' onClick={sortShips('hp', 2)}>{translate('M')}</th>
<th className='sortable' onClick={sortShips('hp', 3)}>{translate('L')}</th> <th className='sortable' onClick={sortShips('hp', 3)}>{translate('L')}</th>
@@ -358,4 +396,4 @@ export default class ShipyardPage extends Page {
</div> </div>
); );
} }
} }

View File

@@ -58,19 +58,24 @@ export const ModuleGroupToName = {
cm: 'Countermeasure', cm: 'Countermeasure',
ec: 'Electronic Countermeasure', ec: 'Electronic Countermeasure',
fc: 'Fragment Cannon', fc: 'Fragment Cannon',
rfl: 'Remote Release Flak Launcher',
hs: 'Heat Sink Launcher', hs: 'Heat Sink Launcher',
ws: 'Frame Shift Wake Scanner', ws: 'Frame Shift Wake Scanner',
kw: 'Kill Warrant Scanner', kw: 'Kill Warrant Scanner',
nl: 'Mine Launcher', nl: 'Mine Launcher',
ml: 'Mining Laser', ml: 'Mining Laser',
mr: 'Missile Rack', mr: 'Missile Rack',
axmr: 'AX Missile Rack',
pa: 'Plasma Accelerator', pa: 'Plasma Accelerator',
po: 'Point Defence', po: 'Point Defence',
mc: 'Multi-cannon', mc: 'Multi-cannon',
axmc: 'AX Multi-cannon',
pl: 'Pulse Laser', pl: 'Pulse Laser',
rg: 'Rail Gun', rg: 'Rail Gun',
sb: 'Shield Booster', sb: 'Shield Booster',
tp: 'Torpedo Pylon' tp: 'Torpedo Pylon',
sfn: 'Shutdown Field Neutraliser',
xs: 'Xeno Scanner'
}; };
let GrpNameToCodeMap = {}; let GrpNameToCodeMap = {};

View File

@@ -64,7 +64,6 @@ export default class Module {
} }
} }
} }
// Sanitise the resultant value to 4dp equivalent // Sanitise the resultant value to 4dp equivalent
return isNaN(result) ? result : Math.round(result); return isNaN(result) ? result : Math.round(result);
} }
@@ -79,6 +78,9 @@ export default class Module {
if (!this.mods) { if (!this.mods) {
this.mods = {}; this.mods = {};
} }
if (!this.origVals) {
this.origVals = {};
}
if (valueiswithspecial && this.blueprint && this.blueprint.special) { if (valueiswithspecial && this.blueprint && this.blueprint.special) {
// This module has a special effect, see if we need to alter the stored value // This module has a special effect, see if we need to alter the stored value
const modifierActions = Modifications.modifierActions[this.blueprint.special.edname]; const modifierActions = Modifications.modifierActions[this.blueprint.special.edname];
@@ -117,7 +119,6 @@ export default class Module {
_getModifiedValue(name) { _getModifiedValue(name) {
const modification = Modifications.modifications[name]; const modification = Modifications.modifications[name];
let result = this[name]; let result = this[name];
if (!result) { if (!result) {
if (modification && modification.method === 'additive') { if (modification && modification.method === 'additive') {
// Additive modifications start at 0 rather than NULL // Additive modifications start at 0 rather than NULL
@@ -135,7 +136,7 @@ export default class Module {
if (modification.type === 'percentage') { if (modification.type === 'percentage') {
modValue = this.getModValue(name) / 10000; modValue = this.getModValue(name) / 10000;
} else if (modification.type === 'numeric') { } else if (modification.type === 'numeric') {
modValue = this.getModValue(name) / 100; modValue = this.getModValue(name)/ 100;
} else { } else {
modValue = this.getModValue(name); modValue = this.getModValue(name);
} }

View File

@@ -63,7 +63,6 @@ export function standard(type, id) {
if (!isNaN(type)) { if (!isNaN(type)) {
type = StandardArray[type]; type = StandardArray[type];
} }
let s = Modules.standard[type].find(e => e.id == id || (e.class == id.charAt(0) && e.rating == id.charAt(1))); let s = Modules.standard[type].find(e => e.id == id || (e.class == id.charAt(0) && e.rating == id.charAt(1)));
if (s) { if (s) {
s = new Module({ template: s }); s = new Module({ template: s });
@@ -196,6 +195,29 @@ export function findInternal(groupName, clss, rating, name) {
return null; return null;
} }
/**
* Finds an internal module based on Class, Rating, Group and/or name.
* At least one of Group name or unique module name must be provided.
* will start searching at specified class and proceed lower until a
* module is found or 0 is hit
* Uses findInternal internally
*
* @param {String} groupName [Optional] Full name or abbreviated name for module group
* @param {integer} clss module Class
* @param {String} rating module Rating
* @param {String} name [Optional] Long/unique name for module -e.g. 'Advanced Discover Scanner'
* @return {Object} The module if found, null if not found
*/
export function findMaxInternal(groupName, clss, rating, name) {
let foundModule = null;
let currentClss = clss;
while (currentClss > 0 && foundModule == null) {
foundModule = findInternal(groupName, currentClss, rating, name);
currentClss = currentClss - 1;
}
return foundModule;
}
/** /**
* Finds an internal Module ID based on Class, Rating, Group and/or name. * Finds an internal Module ID based on Class, Rating, Group and/or name.
* At least one ofGroup name or unique module name must be provided * At least one ofGroup name or unique module name must be provided

View File

@@ -490,7 +490,6 @@ export default class Ship {
// Value passed is invalid; reset it to 0 // Value passed is invalid; reset it to 0
value = 0; value = 0;
} }
// Handle special cases // Handle special cases
if (name === 'pgen') { if (name === 'pgen') {
// Power generation // Power generation
@@ -569,6 +568,7 @@ export default class Ship {
// Reset Cumulative stats // Reset Cumulative stats
this.fuelCapacity = 0; this.fuelCapacity = 0;
this.cargoCapacity = 0; this.cargoCapacity = 0;
this.passengerCapacity = 0;
this.ladenMass = 0; this.ladenMass = 0;
this.armour = this.baseArmour; this.armour = this.baseArmour;
this.shield = this.baseShieldStrength; this.shield = this.baseShieldStrength;
@@ -616,7 +616,7 @@ export default class Ship {
standard[i].cat = 0; standard[i].cat = 0;
standard[i].priority = priorities && priorities[i + 1] ? priorities[i + 1] * 1 : 0; standard[i].priority = priorities && priorities[i + 1] ? priorities[i + 1] * 1 : 0;
standard[i].type = 'SYS'; standard[i].type = 'SYS';
standard[i].m = null; // Resetting 'old' modul if there was one standard[i].m = null; // Resetting 'old' module if there was one
standard[i].discountedCost = 0; standard[i].discountedCost = 0;
if (comps) { if (comps) {
let module = ModuleUtils.standard(i, comps.standard[i]); let module = ModuleUtils.standard(i, comps.standard[i]);
@@ -770,7 +770,7 @@ export default class Ship {
// Alter as required due to changes in the (build) code from one version to the next // Alter as required due to changes in the (build) code from one version to the next
this.upgradeInternals(internal, 1 + this.standard.length + this.hardpoints.length, priorities, enabled, modifications, blueprints, version); this.upgradeInternals(internal, 1 + this.standard.length + this.hardpoints.length, priorities, enabled, modifications, blueprints, version);
} }
return this.buildWith( return this.buildWith(
{ {
bulkheads: code.charAt(0) * 1, bulkheads: code.charAt(0) * 1,
@@ -1188,6 +1188,7 @@ export default class Ship {
let unladenMass = this.hullMass; let unladenMass = this.hullMass;
let cargoCapacity = 0; let cargoCapacity = 0;
let fuelCapacity = 0; let fuelCapacity = 0;
let passengerCapacity = 0;
unladenMass += this.bulkheads.m.getMass(); unladenMass += this.bulkheads.m.getMass();
@@ -1209,6 +1210,10 @@ export default class Ship {
fuelCapacity += slot.m.fuel; fuelCapacity += slot.m.fuel;
} else if (slot.m.grp === 'cr') { } else if (slot.m.grp === 'cr') {
cargoCapacity += slot.m.cargo; cargoCapacity += slot.m.cargo;
} else if (slot.m.grp.slice(0,2) === 'pc') {
if (slot.m.passengers) {
passengerCapacity += slot.m.passengers;
}
} }
} }
} }
@@ -1224,6 +1229,7 @@ export default class Ship {
this.unladenMass = unladenMass; this.unladenMass = unladenMass;
this.cargoCapacity = cargoCapacity; this.cargoCapacity = cargoCapacity;
this.fuelCapacity = fuelCapacity; this.fuelCapacity = fuelCapacity;
this.passengerCapacity = passengerCapacity;
this.ladenMass = unladenMass + fuelCapacity + cargoCapacity; this.ladenMass = unladenMass + fuelCapacity + cargoCapacity;
return this; return this;

View File

@@ -1,5 +1,5 @@
import * as ModuleUtils from './ModuleUtils'; import * as ModuleUtils from './ModuleUtils'
import { canMount } from '../utils/SlotFunctions'; import { canMount } from '../utils/SlotFunctions'
/** /**
* Standard / typical role for multi-purpose or combat (if shielded with better bulkheads) * Standard / typical role for multi-purpose or combat (if shielded with better bulkheads)
@@ -7,20 +7,20 @@ import { canMount } from '../utils/SlotFunctions';
* @param {Boolean} shielded True if shield generator should be included * @param {Boolean} shielded True if shield generator should be included
* @param {integer} bulkheadIndex Bulkhead to use see Constants.BulkheadNames * @param {integer} bulkheadIndex Bulkhead to use see Constants.BulkheadNames
*/ */
export function multiPurpose(ship, shielded, bulkheadIndex) { export function multiPurpose (ship, shielded, bulkheadIndex) {
ship.useStandard('A') ship.useStandard('A')
.use(ship.standard[3], ModuleUtils.standard(3, ship.standard[3].maxClass + 'D')) // D Life Support .use(ship.standard[3], ModuleUtils.standard(3, ship.standard[3].maxClass + 'D')) // D Life Support
.use(ship.standard[5], ModuleUtils.standard(5, ship.standard[5].maxClass + 'D')) // D Sensors .use(ship.standard[5], ModuleUtils.standard(5, ship.standard[5].maxClass + 'D')) // D Sensors
.useBulkhead(bulkheadIndex); .useBulkhead(bulkheadIndex)
if (shielded) { if (shielded) {
ship.internal.some(function(slot) { ship.internal.some(function (slot) {
if (canMount(ship, slot, 'sg')) { // Assuming largest slot can hold an eligible shield if (canMount(ship, slot, 'sg')) { // Assuming largest slot can hold an eligible shield
ship.use(slot, ModuleUtils.findInternal('sg', slot.maxClass, 'A')); ship.use(slot, ModuleUtils.findInternal('sg', slot.maxClass, 'A'))
ship.setSlotEnabled(slot, true); ship.setSlotEnabled(slot, true)
return true; return true
} }
}); })
} }
} }
@@ -30,40 +30,55 @@ export function multiPurpose(ship, shielded, bulkheadIndex) {
* @param {Boolean} shielded True if shield generator should be included * @param {Boolean} shielded True if shield generator should be included
* @param {Object} standardOpts [Optional] Standard module optional overrides * @param {Object} standardOpts [Optional] Standard module optional overrides
*/ */
export function trader(ship, shielded, standardOpts) { export function trader (ship, shielded, standardOpts) {
let usedSlots = [], let usedSlots = []
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass); let bstCount = 2
let sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass)
// Shield generator if required ship.useStandard('A')
if (shielded) { .use(ship.standard[3], ModuleUtils.standard(3, ship.standard[3].maxClass + 'D')) // D Life Support
const shieldOrder = [1, 2, 3, 4, 5, 6, 7, 8]; .use(ship.standard[1], ModuleUtils.standard(1, ship.standard[1].maxClass + 'D')) // D Life Support
const shieldInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1) .use(ship.standard[4], ModuleUtils.standard(4, ship.standard[4].maxClass + 'D')) // D Life Support
.filter(a => (!a.eligible) || a.eligible.sg) .use(ship.standard[5], ModuleUtils.standard(5, ship.standard[5].maxClass + 'D')) // D Sensors
.filter(a => a.maxClass >= sg.class)
.sort((a,b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass)); const shieldOrder = [1, 2, 3, 4, 5, 6, 7, 8]
for (let i = 0; i < shieldInternals.length; i++) { const shieldInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
if (canMount(ship, shieldInternals[i], 'sg')) { .filter(a => (!a.eligible) || a.eligible.sg)
ship.use(shieldInternals[i], sg); .filter(a => a.maxClass >= sg.class)
usedSlots.push(shieldInternals[i]); .sort((a, b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass))
break; shieldInternals.some(function (slot) {
if (canMount(ship, slot, 'sg')) { // Assuming largest slot can hold an eligible shield
const shield = ModuleUtils.findInternal('sg', slot.maxClass, 'A')
if (shield && shield.maxmass > ship.hullMass) {
console.log(shield)
ship.use(slot, shield)
ship.setSlotEnabled(slot, true)
usedSlots.push(slot)
return true
} }
} }
} })
// Fill the empty internals with cargo racks // Fill the empty internals with cargo racks
for (let i = ship.internal.length; i--;) { for (let i = ship.internal.length; i--;) {
let slot = ship.internal[i]; let slot = ship.internal[i]
if (usedSlots.indexOf(slot) == -1 && canMount(ship, slot, 'cr')) { if (usedSlots.indexOf(slot) == -1 && canMount(ship, slot, 'cr')) {
ship.use(slot, ModuleUtils.findInternal('cr', slot.maxClass, 'E')); ship.use(slot, ModuleUtils.findInternal('cr', slot.maxClass, 'E'))
} }
} }
// Empty the hardpoints // Empty the hardpoints
for (let s of ship.hardpoints) { for (let s of ship.hardpoints) {
ship.use(s, null); ship.use(s, null)
} }
for (let s of ship.hardpoints) {
ship.useLightestStandard(standardOpts); if (s.maxClass == 0 && bstCount) { // Mount up to 2 boosters
ship.use(s, ModuleUtils.hardpoints('04'))
bstCount--
} else {
ship.use(s, null)
}
}
// ship.useLightestStandard(standardOpts);
} }
/** /**
@@ -71,127 +86,127 @@ export function trader(ship, shielded, standardOpts) {
* @param {Ship} ship Ship instance * @param {Ship} ship Ship instance
* @param {Boolean} planetary True if Planetary Vehicle Hangar (PVH) should be included * @param {Boolean} planetary True if Planetary Vehicle Hangar (PVH) should be included
*/ */
export function explorer(ship, planetary) { export function explorer (ship, planetary) {
let standardOpts = { ppRating: 'A' }, let standardOpts = {ppRating: 'A'},
heatSinkCount = 2, // Fit 2 heat sinks if possible heatSinkCount = 2, // Fit 2 heat sinks if possible
usedSlots = [], usedSlots = [],
sgSlot, sgSlot,
fuelScoopSlot, fuelScoopSlot,
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass); sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass)
if (!planetary) { // Non-planetary explorers don't really need to boost if (!planetary) { // Non-planetary explorers don't really need to boost
standardOpts.pd = '1D'; standardOpts.pd = '1D'
} }
// Cargo hatch can be disabled // Cargo hatch can be disabled
ship.setSlotEnabled(ship.cargoHatch, false); ship.setSlotEnabled(ship.cargoHatch, false)
// Advanced Discovery Scanner - class 1 or higher // Advanced Discovery Scanner - class 1 or higher
const adsOrder = [1, 2, 3, 4, 5, 6, 7, 8]; const adsOrder = [1, 2, 3, 4, 5, 6, 7, 8]
const adsInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const adsInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.sc) .filter(a => (!a.eligible) || a.eligible.sc)
.sort((a,b) => adsOrder.indexOf(a.maxClass) - adsOrder.indexOf(b.maxClass)); .sort((a, b) => adsOrder.indexOf(a.maxClass) - adsOrder.indexOf(b.maxClass))
for (let i = 0; i < adsInternals.length; i++) { for (let i = 0; i < adsInternals.length; i++) {
if (canMount(ship, adsInternals[i], 'sc')) { if (canMount(ship, adsInternals[i], 'sc')) {
ship.use(adsInternals[i], ModuleUtils.internal('2f')); ship.use(adsInternals[i], ModuleUtils.internal('2f'))
usedSlots.push(adsInternals[i]); usedSlots.push(adsInternals[i])
break; break
} }
} }
if (planetary) { if (planetary) {
// Planetary Vehicle Hangar - class 2 or higher // Planetary Vehicle Hangar - class 2 or higher
const pvhOrder = [2, 3, 4, 5, 6, 7, 8, 1]; const pvhOrder = [2, 3, 4, 5, 6, 7, 8, 1]
const pvhInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const pvhInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.pv) .filter(a => (!a.eligible) || a.eligible.pv)
.sort((a,b) => pvhOrder.indexOf(a.maxClass) - pvhOrder.indexOf(b.maxClass)); .sort((a, b) => pvhOrder.indexOf(a.maxClass) - pvhOrder.indexOf(b.maxClass))
for (let i = 0; i < pvhInternals.length; i++) { for (let i = 0; i < pvhInternals.length; i++) {
if (canMount(ship, pvhInternals[i], 'pv')) { if (canMount(ship, pvhInternals[i], 'pv')) {
// Planetary Vehical Hangar only has even classes // Planetary Vehical Hangar only has even classes
const pvhClass = pvhInternals[i].maxClass % 2 === 1 ? pvhInternals[i].maxClass - 1 : pvhInternals[i].maxClass; const pvhClass = pvhInternals[i].maxClass % 2 === 1 ? pvhInternals[i].maxClass - 1 : pvhInternals[i].maxClass
ship.use(pvhInternals[i], ModuleUtils.findInternal('pv', pvhClass, 'G')); // G is lower mass ship.use(pvhInternals[i], ModuleUtils.findInternal('pv', pvhClass, 'G')) // G is lower mass
ship.setSlotEnabled(pvhInternals[i], false); // Disable power for Planetary Vehical Hangar ship.setSlotEnabled(pvhInternals[i], false) // Disable power for Planetary Vehical Hangar
usedSlots.push(pvhInternals[i]); usedSlots.push(pvhInternals[i])
break; break
} }
} }
} }
// Shield generator // Shield generator
const shieldOrder = [1, 2, 3, 4, 5, 6, 7, 8]; const shieldOrder = [1, 2, 3, 4, 5, 6, 7, 8]
const shieldInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const shieldInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.sg) .filter(a => (!a.eligible) || a.eligible.sg)
.filter(a => a.maxClass >= sg.class) .filter(a => a.maxClass >= sg.class)
.sort((a,b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass)); .sort((a, b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass))
for (let i = 0; i < shieldInternals.length; i++) { for (let i = 0; i < shieldInternals.length; i++) {
if (canMount(ship, shieldInternals[i], 'sg')) { if (canMount(ship, shieldInternals[i], 'sg')) {
ship.use(shieldInternals[i], sg); ship.use(shieldInternals[i], sg)
usedSlots.push(shieldInternals[i]); usedSlots.push(shieldInternals[i])
sgSlot = shieldInternals[i]; sgSlot = shieldInternals[i]
break; break
} }
} }
// Detailed Surface Scanner // Detailed Surface Scanner
const dssOrder = [1, 2, 3, 4, 5, 6, 7, 8]; const dssOrder = [1, 2, 3, 4, 5, 6, 7, 8]
const dssInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const dssInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.sc) .filter(a => (!a.eligible) || a.eligible.sc)
.sort((a,b) => dssOrder.indexOf(a.maxClass) - dssOrder.indexOf(b.maxClass)); .sort((a, b) => dssOrder.indexOf(a.maxClass) - dssOrder.indexOf(b.maxClass))
for (let i = 0; i < dssInternals.length; i++) { for (let i = 0; i < dssInternals.length; i++) {
if (canMount(ship, dssInternals[i], 'sc')) { if (canMount(ship, dssInternals[i], 'sc')) {
ship.use(dssInternals[i], ModuleUtils.internal('2i')); ship.use(dssInternals[i], ModuleUtils.internal('2i'))
usedSlots.push(dssInternals[i]); usedSlots.push(dssInternals[i])
break; break
} }
} }
// Fuel scoop - best possible // Fuel scoop - best possible
const fuelScoopOrder = [8, 7, 6, 5, 4, 3, 2, 1]; const fuelScoopOrder = [8, 7, 6, 5, 4, 3, 2, 1]
const fuelScoopInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const fuelScoopInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.fs) .filter(a => (!a.eligible) || a.eligible.fs)
.sort((a,b) => fuelScoopOrder.indexOf(a.maxClass) - fuelScoopOrder.indexOf(b.maxClass)); .sort((a, b) => fuelScoopOrder.indexOf(a.maxClass) - fuelScoopOrder.indexOf(b.maxClass))
for (let i = 0; i < fuelScoopInternals.length; i++) { for (let i = 0; i < fuelScoopInternals.length; i++) {
if (canMount(ship, fuelScoopInternals[i], 'fs')) { if (canMount(ship, fuelScoopInternals[i], 'fs')) {
ship.use(fuelScoopInternals[i], ModuleUtils.findInternal('fs', fuelScoopInternals[i].maxClass, 'A')); ship.use(fuelScoopInternals[i], ModuleUtils.findInternal('fs', fuelScoopInternals[i].maxClass, 'A'))
usedSlots.push(fuelScoopInternals[i]); usedSlots.push(fuelScoopInternals[i])
fuelScoopSlot = fuelScoopInternals[i]; fuelScoopSlot = fuelScoopInternals[i]
break; break
} }
} }
// AFMUs - fill as they are 0-weight // AFMUs - fill as they are 0-weight
const afmuOrder = [8, 7, 6, 5, 4, 3, 2, 1]; const afmuOrder = [8, 7, 6, 5, 4, 3, 2, 1]
const afmuInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const afmuInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.pc) .filter(a => (!a.eligible) || a.eligible.pc)
.sort((a,b) => afmuOrder.indexOf(a.maxClass) - afmuOrder.indexOf(b.maxClass)); .sort((a, b) => afmuOrder.indexOf(a.maxClass) - afmuOrder.indexOf(b.maxClass))
for (let i = 0; i < afmuInternals.length; i++) { for (let i = 0; i < afmuInternals.length; i++) {
if (canMount(ship, afmuInternals[i], 'am')) { if (canMount(ship, afmuInternals[i], 'am')) {
ship.use(afmuInternals[i], ModuleUtils.findInternal('am', afmuInternals[i].maxClass, 'A')); ship.use(afmuInternals[i], ModuleUtils.findInternal('am', afmuInternals[i].maxClass, 'A'))
usedSlots.push(afmuInternals[i]); usedSlots.push(afmuInternals[i])
ship.setSlotEnabled(afmuInternals[i], false); // Disable power for AFM Unit ship.setSlotEnabled(afmuInternals[i], false) // Disable power for AFM Unit
} }
} }
for (let s of ship.hardpoints) { for (let s of ship.hardpoints) {
if (s.maxClass == 0 && heatSinkCount) { // Mount up to 2 heatsinks if (s.maxClass == 0 && heatSinkCount) { // Mount up to 2 heatsinks
ship.use(s, ModuleUtils.hardpoints('02')); ship.use(s, ModuleUtils.hardpoints('02'))
ship.setSlotEnabled(s, heatSinkCount == 2); // Only enable a single Heatsink ship.setSlotEnabled(s, heatSinkCount == 2) // Only enable a single Heatsink
heatSinkCount--; heatSinkCount--
} else { } else {
ship.use(s, null); ship.use(s, null)
} }
} }
if (sgSlot && fuelScoopSlot) { if (sgSlot && fuelScoopSlot) {
// The SG and Fuel scoop to not need to be powered at the same time // The SG and Fuel scoop to not need to be powered at the same time
if (sgSlot.m.getPowerUsage() > fuelScoopSlot.m.getPowerUsage()) { // The Shield generator uses the most power if (sgSlot.m.getPowerUsage() > fuelScoopSlot.m.getPowerUsage()) { // The Shield generator uses the most power
ship.setSlotEnabled(fuelScoopSlot, false); ship.setSlotEnabled(fuelScoopSlot, false)
} else { // The Fuel scoop uses the most power } else { // The Fuel scoop uses the most power
ship.setSlotEnabled(sgSlot, false); ship.setSlotEnabled(sgSlot, false)
} }
} }
ship.useLightestStandard(standardOpts); ship.useLightestStandard(standardOpts)
} }
/** /**
@@ -199,187 +214,188 @@ export function explorer(ship, planetary) {
* @param {Ship} ship Ship instance * @param {Ship} ship Ship instance
* @param {Boolean} shielded True if shield generator should be included * @param {Boolean} shielded True if shield generator should be included
*/ */
export function miner(ship, shielded) { export function miner (ship, shielded) {
let standardOpts = { ppRating: 'A' }, shielded = true
miningLaserCount = 2, let standardOpts = {ppRating: 'A'},
usedSlots = [], miningLaserCount = 2,
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass); usedSlots = [],
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass)
// Cargo hatch should be enabled // Cargo hatch should be enabled
ship.setSlotEnabled(ship.cargoHatch, true); ship.setSlotEnabled(ship.cargoHatch, true)
// Largest possible refinery // Largest possible refinery
const refineryOrder = [4, 5, 6, 7, 8, 3, 2, 1]; const refineryOrder = [4, 5, 6, 7, 8, 3, 2, 1]
const refineryInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const refineryInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.rf) .filter(a => (!a.eligible) || a.eligible.rf)
.sort((a,b) => refineryOrder.indexOf(a.maxClass) - refineryOrder.indexOf(b.maxClass)); .sort((a, b) => refineryOrder.indexOf(a.maxClass) - refineryOrder.indexOf(b.maxClass))
for (let i = 0; i < refineryInternals.length; i++) { for (let i = 0; i < refineryInternals.length; i++) {
if (canMount(ship, refineryInternals[i], 'rf')) { if (canMount(ship, refineryInternals[i], 'rf')) {
ship.use(refineryInternals[i], ModuleUtils.findInternal('rf', Math.min(refineryInternals[i].maxClass, 4), 'A')); ship.use(refineryInternals[i], ModuleUtils.findInternal('rf', Math.min(refineryInternals[i].maxClass, 4), 'A'))
usedSlots.push(refineryInternals[i]); usedSlots.push(refineryInternals[i])
break; break
} }
} }
// Prospector limpet controller - 3A if possible // Prospector limpet controller - 3A if possible
const prospectorOrder = [3, 4, 5, 6, 7, 8, 2, 1]; const prospectorOrder = [3, 4, 5, 6, 7, 8, 2, 1]
const prospectorInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const prospectorInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.pc) .filter(a => (!a.eligible) || a.eligible.pc)
.sort((a,b) => prospectorOrder.indexOf(a.maxClass) - prospectorOrder.indexOf(b.maxClass)); .sort((a, b) => prospectorOrder.indexOf(a.maxClass) - prospectorOrder.indexOf(b.maxClass))
for (let i = 0; i < prospectorInternals.length; i++) { for (let i = 0; i < prospectorInternals.length; i++) {
if (canMount(ship, prospectorInternals[i], 'pc')) { if (canMount(ship, prospectorInternals[i], 'pc')) {
// Prospector only has odd classes // Prospector only has odd classes
const prospectorClass = prospectorInternals[i].maxClass % 2 === 0 ? prospectorInternals[i].maxClass - 1 : prospectorInternals[i].maxClass; const prospectorClass = prospectorInternals[i].maxClass % 2 === 0 ? prospectorInternals[i].maxClass - 1 : prospectorInternals[i].maxClass
ship.use(prospectorInternals[i], ModuleUtils.findInternal('pc', prospectorClass, 'A')); ship.use(prospectorInternals[i], ModuleUtils.findInternal('pc', prospectorClass, 'A'))
usedSlots.push(prospectorInternals[i]); usedSlots.push(prospectorInternals[i])
break; break
} }
} }
// Shield generator if required // Shield generator if required
if (shielded) { if (shielded) {
const shieldOrder = [1, 2, 3, 4, 5, 6, 7, 8]; const shieldOrder = [1, 2, 3, 4, 5, 6, 7, 8]
const shieldInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const shieldInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.sg) .filter(a => (!a.eligible) || a.eligible.sg)
.filter(a => a.maxClass >= sg.class) .filter(a => a.maxClass >= sg.class)
.sort((a,b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass)); .sort((a, b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass))
for (let i = 0; i < shieldInternals.length; i++) { for (let i = 0; i < shieldInternals.length; i++) {
if (canMount(ship, shieldInternals[i], 'sg')) { if (canMount(ship, shieldInternals[i], 'sg')) {
ship.use(shieldInternals[i], sg); ship.use(shieldInternals[i], sg)
usedSlots.push(shieldInternals[i]); usedSlots.push(shieldInternals[i])
break; break
} }
} }
} }
// Dual mining lasers of highest possible class; remove anything else // Dual mining lasers of highest possible class; remove anything else
const miningLaserOrder = [2, 3, 4, 1, 0]; const miningLaserOrder = [2, 3, 4, 1, 0]
const miningLaserHardpoints = ship.hardpoints.concat().sort(function(a,b) { const miningLaserHardpoints = ship.hardpoints.concat().sort(function (a, b) {
return miningLaserOrder.indexOf(a.maxClass) - miningLaserOrder.indexOf(b.maxClass); return miningLaserOrder.indexOf(a.maxClass) - miningLaserOrder.indexOf(b.maxClass)
}); })
for (let s of miningLaserHardpoints) { for (let s of miningLaserHardpoints) {
if (s.maxClass >= 1 && miningLaserCount) { if (s.maxClass >= 1 && miningLaserCount) {
ship.use(s, ModuleUtils.hardpoints(s.maxClass >= 2 ? '2m' : '2l')); ship.use(s, ModuleUtils.hardpoints(s.maxClass >= 2 ? '2m' : '2l'))
miningLaserCount--; miningLaserCount--
} else { } else {
ship.use(s, null); ship.use(s, null)
} }
} }
// Number of collector limpets required to be active is a function of the size of the ship and the power of the lasers // Number of collector limpets required to be active is a function of the size of the ship and the power of the lasers
const miningLaserDps = ship.hardpoints.filter(h => h.m != null) const miningLaserDps = ship.hardpoints.filter(h => h.m != null)
.reduce(function(a, b) { .reduce(function (a, b) {
return a + b.m.getDps(); return a + b.m.getDps()
}, 0); }, 0)
// Find out how many internal slots we have, and their potential cargo size // Find out how many internal slots we have, and their potential cargo size
const potentialCargo = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const potentialCargo = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.cr) .filter(a => (!a.eligible) || a.eligible.cr)
.map(b => Math.pow(2, b.maxClass)); .map(b => Math.pow(2, b.maxClass))
// One collector for each 1.25 DPS, multiply by 1.25 for medium ships and 1.5 for large ships as they have further to travel // One collector for each 1.25 DPS, multiply by 1.25 for medium ships and 1.5 for large ships as they have further to travel
// 0 if we only have 1 cargo slot, otherwise minium of 1 and maximum of 6 (excluding size modifier) // 0 if we only have 1 cargo slot, otherwise minium of 1 and maximum of 6 (excluding size modifier)
const sizeModifier = ship.class == 2 ? 1.2 : ship.class == 3 ? 1.5 : 1; const sizeModifier = ship.class == 2 ? 1.2 : ship.class == 3 ? 1.5 : 1
let collectorLimpetsRequired = potentialCargo.length == 1 ? 0 : Math.ceil(sizeModifier * Math.min(6, Math.floor(miningLaserDps / 1.25))); let collectorLimpetsRequired = potentialCargo.length == 1 ? 0 : Math.ceil(sizeModifier * Math.min(6, Math.floor(miningLaserDps / 1.25)))
if (collectorLimpetsRequired > 0) { if (collectorLimpetsRequired > 0) {
const collectorOrder = [1, 2, 3, 4, 5, 6, 7, 8]; const collectorOrder = [1, 2, 3, 4, 5, 6, 7, 8]
const collectorInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const collectorInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.cc) .filter(a => (!a.eligible) || a.eligible.cc)
.sort((a,b) => collectorOrder.indexOf(a.maxClass) - collectorOrder.indexOf(b.maxClass)); .sort((a, b) => collectorOrder.indexOf(a.maxClass) - collectorOrder.indexOf(b.maxClass))
// Always keep at least 2 slots free for cargo racks (1 for shielded) // Always keep at least 2 slots free for cargo racks (1 for shielded)
for (let i = 0; i < collectorInternals.length - (shielded ? 1 : 2) && collectorLimpetsRequired > 0; i++) { for (let i = 0; i < collectorInternals.length - (shielded ? 1 : 2) && collectorLimpetsRequired > 0; i++) {
if (canMount(ship, collectorInternals[i], 'cc')) { if (canMount(ship, collectorInternals[i], 'cc')) {
// Collector only has odd classes // Collector only has odd classes
const collectorClass = collectorInternals[i].maxClass % 2 === 0 ? collectorInternals[i].maxClass - 1 : collectorInternals[i].maxClass; const collectorClass = collectorInternals[i].maxClass % 2 === 0 ? collectorInternals[i].maxClass - 1 : collectorInternals[i].maxClass
ship.use(collectorInternals[i], ModuleUtils.findInternal('cc', collectorClass, 'D')); ship.use(collectorInternals[i], ModuleUtils.findInternal('cc', collectorClass, 'D'))
usedSlots.push(collectorInternals[i]); usedSlots.push(collectorInternals[i])
collectorLimpetsRequired -= collectorInternals[i].m.maximum; collectorLimpetsRequired -= collectorInternals[i].m.maximum
} }
} }
} }
// Power distributor to power the mining lasers indefinitely // Power distributor to power the mining lasers indefinitely
const wepRateRequired = ship.hardpoints.filter(h => h.m != null) const wepRateRequired = ship.hardpoints.filter(h => h.m != null)
.reduce(function(a, b) { .reduce(function (a, b) {
return a + b.m.getEps(); return a + b.m.getEps()
}, 0); }, 0)
standardOpts.pd = ship.getAvailableModules().matchingPowerDist({ weprate: wepRateRequired }).id; standardOpts.pd = ship.getAvailableModules().matchingPowerDist({weprate: wepRateRequired}).id
// Fill the empty internals with cargo racks // Fill the empty internals with cargo racks
for (let i = ship.internal.length; i--;) { for (let i = ship.internal.length; i--;) {
let slot = ship.internal[i]; let slot = ship.internal[i]
if (usedSlots.indexOf(slot) == -1 && canMount(ship, slot, 'cr')) { if (usedSlots.indexOf(slot) == -1 && canMount(ship, slot, 'cr')) {
ship.use(slot, ModuleUtils.findInternal('cr', slot.maxClass, 'E')); ship.use(slot, ModuleUtils.findInternal('cr', slot.maxClass, 'E'))
} }
} }
ship.useLightestStandard(standardOpts); ship.useLightestStandard(standardOpts)
} }
/** /**
* Racer Role * Racer Role
* @param {Ship} ship Ship instance * @param {Ship} ship Ship instance
*/ */
export function racer(ship) { export function racer (ship) {
let standardOpts = {}, let standardOpts = {},
usedSlots = [], usedSlots = [],
sgSlot, sgSlot,
sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass); sg = ship.getAvailableModules().lightestShieldGenerator(ship.hullMass)
// Cargo hatch can be disabled // Cargo hatch can be disabled
ship.setSlotEnabled(ship.cargoHatch, false); ship.setSlotEnabled(ship.cargoHatch, false)
// Shield generator // Shield generator
const shieldOrder = [1, 2, 3, 4, 5, 6, 7, 8]; const shieldOrder = [1, 2, 3, 4, 5, 6, 7, 8]
const shieldInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1) const shieldInternals = ship.internal.filter(a => usedSlots.indexOf(a) == -1)
.filter(a => (!a.eligible) || a.eligible.sg) .filter(a => (!a.eligible) || a.eligible.sg)
.filter(a => a.maxClass >= sg.class) .filter(a => a.maxClass >= sg.class)
.sort((a,b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass)); .sort((a, b) => shieldOrder.indexOf(a.maxClass) - shieldOrder.indexOf(b.maxClass))
for (let i = 0; i < shieldInternals.length; i++) { for (let i = 0; i < shieldInternals.length; i++) {
if (canMount(ship, shieldInternals[i], 'sg')) { if (canMount(ship, shieldInternals[i], 'sg')) {
ship.use(shieldInternals[i], sg); ship.use(shieldInternals[i], sg)
usedSlots.push(shieldInternals[i]); usedSlots.push(shieldInternals[i])
sgSlot = shieldInternals[i]; sgSlot = shieldInternals[i]
break; break
} }
} }
// Empty the hardpoints // Empty the hardpoints
for (let s of ship.hardpoints) { for (let s of ship.hardpoints) {
ship.use(s, null); ship.use(s, null)
} }
// Empty the internals // Empty the internals
for (let i = ship.internal.length; i--;) { for (let i = ship.internal.length; i--;) {
let slot = ship.internal[i]; let slot = ship.internal[i]
if (usedSlots.indexOf(slot) == -1) { if (usedSlots.indexOf(slot) == -1) {
ship.use(slot, null); ship.use(slot, null)
} }
} }
// Best thrusters // Best thrusters
if (ship.standard[1].maxClass === 3) { if (ship.standard[1].maxClass === 3) {
standardOpts.th = 'tz'; standardOpts.th = 'tz'
} else if (ship.standard[1].maxClass === 2) { } else if (ship.standard[1].maxClass === 2) {
standardOpts.th = 'u0'; standardOpts.th = 'u0'
} else { } else {
standardOpts.th = ship.standard[1].maxClass + 'A'; standardOpts.th = ship.standard[1].maxClass + 'A'
} }
// Best power distributor for more boosting // Best power distributor for more boosting
standardOpts.pd = ship.standard[4].maxClass + 'A'; standardOpts.pd = ship.standard[4].maxClass + 'A'
// Smallest possible FSD drive // Smallest possible FSD drive
standardOpts.fsd = '2D'; standardOpts.fsd = '2D'
// Minimal fuel tank // Minimal fuel tank
standardOpts.ft = '1C'; standardOpts.ft = '1C'
// Disable nearly everything // Disable nearly everything
standardOpts.fsdDisabled = true; standardOpts.fsdDisabled = true
standardOpts.sDisabled = true; standardOpts.sDisabled = true
standardOpts.pdDisabled = true; standardOpts.pdDisabled = true
standardOpts.lsDisabled = true; standardOpts.lsDisabled = true
ship.useLightestStandard(standardOpts); ship.useLightestStandard(standardOpts)
// Apply engineering to each module // Apply engineering to each module
// ship.standard[1].m.blueprint = getBlueprint('Engine_Dirty', ship.standard[0]); // ship.standard[1].m.blueprint = getBlueprint('Engine_Dirty', ship.standard[0]);

View File

@@ -12,6 +12,9 @@ import { Modifications } from 'coriolis-data/dist';
*/ */
export function blueprintTooltip(translate, blueprint, engineers, grp, m) { export function blueprintTooltip(translate, blueprint, engineers, grp, m) {
const effects = []; const effects = [];
if (!blueprint || !blueprint.features) {
return undefined;
}
for (const feature in blueprint.features) { for (const feature in blueprint.features) {
const featureIsBeneficial = isBeneficial(feature, blueprint.features[feature]); const featureIsBeneficial = isBeneficial(feature, blueprint.features[feature]);
const featureDef = Modifications.modifications[feature]; const featureDef = Modifications.modifications[feature];
@@ -225,27 +228,13 @@ export function isValueBeneficial(feature, value) {
*/ */
export function getBlueprint(name, module) { export function getBlueprint(name, module) {
// Start with a copy of the blueprint // Start with a copy of the blueprint
const blueprint = JSON.parse(JSON.stringify(Modifications.blueprints[name])); const findMod = val => Object.keys(Modifications.blueprints).find(elem => elem.toString().toLowerCase().search(val.toString().toLowerCase().replace(/(OutfittingFieldType_|persecond)/igm, '')) >= 0)
const found = Modifications.blueprints[findMod(name)];
if (!found || !found.fdname) {
return {};
}
const blueprint = JSON.parse(JSON.stringify(found));
if (module) { if (module) {
if (module.grp === 'bh' || module.grp === 'hr' || module.grp === 'sg' || module.grp === 'psg' || module.grp === 'bsg') {
// Bulkheads, hull reinforcements and shield generators need to have their resistances altered by the base values
for (const grade in blueprint.grades) {
for (const feature in blueprint.grades[grade].features) {
if (feature === 'explres') {
blueprint.grades[grade].features[feature][0] *= (1 - module.explres);
blueprint.grades[grade].features[feature][1] *= (1 - module.explres);
}
if (feature === 'kinres') {
blueprint.grades[grade].features[feature][0] *= (1 - module.kinres);
blueprint.grades[grade].features[feature][1] *= (1 - module.kinres);
}
if (feature === 'thermres') {
blueprint.grades[grade].features[feature][0] *= (1 - module.thermres);
blueprint.grades[grade].features[feature][1] *= (1 - module.thermres);
}
}
}
}
if (module.grp === 'sb') { if (module.grp === 'sb') {
// Shield boosters are treated internally as straight modifiers, so rather than (for example) // Shield boosters are treated internally as straight modifiers, so rather than (for example)
// being a 4% boost they are a 104% multiplier. We need to fix the values here so that they look // being a 4% boost they are a 104% multiplier. We need to fix the values here so that they look
@@ -267,57 +256,19 @@ export function getBlueprint(name, module) {
* Provide 'worst' primary modifications * Provide 'worst' primary modifications
* @param {Object} ship The ship for which to perform the modifications * @param {Object} ship The ship for which to perform the modifications
* @param {Object} m The module for which to perform the modifications * @param {Object} m The module for which to perform the modifications
* @param {Number} percent The percent to set values to of full.
*/ */
export function setWorst(ship, m) { export function setPercent(ship, m, percent) {
ship.clearModifications(m);
const features = m.blueprint.grades[m.blueprint.grade].features;
for (const featureName in features) {
const value = features[featureName][0];
_setValue(ship, m, featureName, value);
}
}
/**
* Provide 'best' primary modifications
* @param {Object} ship The ship for which to perform the modifications
* @param {Object} m The module for which to perform the modifications
*/
export function setBest(ship, m) {
ship.clearModifications(m); ship.clearModifications(m);
const features = m.blueprint.grades[m.blueprint.grade].features; const features = m.blueprint.grades[m.blueprint.grade].features;
for (const featureName in features) { for (const featureName in features) {
const value = features[featureName][1]; const value = features[featureName][1];
_setValue(ship, m, featureName, value); const featureIsBeneficial = isBeneficial(featureName, features[featureName]);
} if (featureIsBeneficial === true) {
} _setValue(ship, m, featureName, (percent / 100) * value);
/**
* Provide 'extreme' primary modifications
* @param {Object} ship The ship for which to perform the modifications
* @param {Object} m The module for which to perform the modifications
*/
export function setExtreme(ship, m) {
ship.clearModifications(m);
const features = m.blueprint.grades[m.blueprint.grade].features;
for (const featureName in features) {
let value;
if (Modifications.modifications[featureName].higherbetter) {
// Higher is better, but is this making it better or worse?
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
value = features[featureName][0];
} else {
value = features[featureName][1];
}
} else { } else {
// Higher is worse, but is this making it better or worse? _setValue(ship, m, featureName, value);
if (features[featureName][0] < 0 || (features[featureName][0] === 0 && features[featureName][1] < 0)) {
value = features[featureName][1];
} else {
value = features[featureName][0];
}
} }
_setValue(ship, m, featureName, value);
} }
} }

View File

@@ -35,13 +35,15 @@ const SHIP_FD_NAME_TO_CORIOLIS_NAME = {
'Type6': 'type_6_transporter', 'Type6': 'type_6_transporter',
'Type7': 'type_7_transport', 'Type7': 'type_7_transport',
'Type9': 'type_9_heavy', 'Type9': 'type_9_heavy',
'Type9_Military': 'type_10_defender',
'TypeX': 'alliance_chieftain',
'Viper': 'viper', 'Viper': 'viper',
'Viper_MkIV': 'viper_mk_iv', 'Viper_MkIV': 'viper_mk_iv',
'Vulture': 'vulture' 'Vulture': 'vulture'
}; };
// Mapping from hardpoint class to name in companion API // Mapping from hardpoint class to name in companion API
const HARDPOINT_NUM_TO_CLASS = { export const HARDPOINT_NUM_TO_CLASS = {
0: 'Tiny', 0: 'Tiny',
1: 'Small', 1: 'Small',
2: 'Medium', 2: 'Medium',
@@ -104,7 +106,7 @@ function _moduleFromEdId(edId) {
* @return {string} the Coriolis model of the ship * @return {string} the Coriolis model of the ship
*/ */
function _shipModelFromEDName(edName) { function _shipModelFromEDName(edName) {
return SHIP_FD_NAME_TO_CORIOLIS_NAME[edName]; return SHIP_FD_NAME_TO_CORIOLIS_NAME[Object.keys(SHIP_FD_NAME_TO_CORIOLIS_NAME).find(elem => elem.toLowerCase() === edName.toLowerCase())];
} }
/** /**
@@ -113,7 +115,7 @@ function _shipModelFromEDName(edName) {
* @return {string} the Coriolis model of the ship * @return {string} the Coriolis model of the ship
*/ */
export function shipModelFromJson(json) { export function shipModelFromJson(json) {
return _shipModelFromEDName(json.name); return _shipModelFromEDName(json.name || json.Ship);
} }
/** /**
@@ -141,30 +143,34 @@ export function shipFromJson(json) {
ship.cargoHatch.enabled = false; ship.cargoHatch.enabled = false;
ship.cargoHatch.priority = 4; ship.cargoHatch.priority = 4;
} }
let rootModule;
// Add the bulkheads // Add the bulkheads
const armourJson = json.modules.Armour.module; const armourJson = json.modules.Armour.module;
if (armourJson.name.endsWith('_Armour_Grade1')) { if (armourJson.name.toLowerCase().endsWith('_armour_grade1')) {
ship.useBulkhead(0, true); ship.useBulkhead(0, true);
} else if (armourJson.name.endsWith('_Armour_Grade2')) { } else if (armourJson.name.toLowerCase().endsWith('_armour_grade2')) {
ship.useBulkhead(1, true); ship.useBulkhead(1, true);
} else if (armourJson.name.endsWith('_Armour_Grade3')) { } else if (armourJson.name.toLowerCase().endsWith('_armour_grade3')) {
ship.useBulkhead(2, true); ship.useBulkhead(2, true);
} else if (armourJson.name.endsWith('_Armour_Mirrored')) { } else if (armourJson.name.toLowerCase().endsWith('_armour_mirrored')) {
ship.useBulkhead(3, true); ship.useBulkhead(3, true);
} else if (armourJson.name.endsWith('_Armour_Reactive')) { } else if (armourJson.name.toLowerCase().endsWith('_armour_reactive')) {
ship.useBulkhead(4, true); ship.useBulkhead(4, true);
} else { } else {
throw 'Unknown bulkheads "' + armourJson.name + '"'; throw 'Unknown bulkheads "' + armourJson.name + '"';
} }
ship.bulkheads.enabled = true; ship.bulkheads.enabled = true;
if (armourJson.modifiers) _addModifications(ship.bulkheads.m, armourJson.modifiers, armourJson.recipeName, armourJson.recipeLevel); rootModule = json.modules.Armour;
if (rootModule.WorkInProgress_modifications) _addModifications(ship.bulkheads.m, rootModule.WorkInProgress_modifications, rootModule.engineer.recipeName, rootModule.engineer.recipeLevel);
// Add the standard modules // Add the standard modules
// Power plant // Power plant
const powerplantJson = json.modules.PowerPlant.module; const powerplantJson = json.modules.PowerPlant.module;
const powerplant = _moduleFromEdId(powerplantJson.id); const powerplant = _moduleFromEdId(powerplantJson.id);
if (powerplantJson.modifiers) _addModifications(powerplant, powerplantJson.modifiers, powerplantJson.recipeName, powerplantJson.recipeLevel); rootModule = json.modules.PowerPlant;
if (rootModule.WorkInProgress_modifications) _addModifications(powerplant, rootModule.WorkInProgress_modifications, rootModule.engineer.recipeName, rootModule.engineer.recipeLevel);
ship.use(ship.standard[0], powerplant, true); ship.use(ship.standard[0], powerplant, true);
ship.standard[0].enabled = powerplantJson.on === true; ship.standard[0].enabled = powerplantJson.on === true;
ship.standard[0].priority = powerplantJson.priority; ship.standard[0].priority = powerplantJson.priority;
@@ -172,7 +178,8 @@ export function shipFromJson(json) {
// Thrusters // Thrusters
const thrustersJson = json.modules.MainEngines.module; const thrustersJson = json.modules.MainEngines.module;
const thrusters = _moduleFromEdId(thrustersJson.id); const thrusters = _moduleFromEdId(thrustersJson.id);
if (thrustersJson.modifiers) _addModifications(thrusters, thrustersJson.modifiers, thrustersJson.recipeName, thrustersJson.recipeLevel); rootModule = json.modules.MainEngines;
if (rootModule.WorkInProgress_modifications) _addModifications(thrusters, rootModule.WorkInProgress_modifications, rootModule.engineer.recipeName, rootModule.engineer.recipeLevel);
ship.use(ship.standard[1], thrusters, true); ship.use(ship.standard[1], thrusters, true);
ship.standard[1].enabled = thrustersJson.on === true; ship.standard[1].enabled = thrustersJson.on === true;
ship.standard[1].priority = thrustersJson.priority; ship.standard[1].priority = thrustersJson.priority;
@@ -180,7 +187,8 @@ export function shipFromJson(json) {
// FSD // FSD
const frameshiftdriveJson = json.modules.FrameShiftDrive.module; const frameshiftdriveJson = json.modules.FrameShiftDrive.module;
const frameshiftdrive = _moduleFromEdId(frameshiftdriveJson.id); const frameshiftdrive = _moduleFromEdId(frameshiftdriveJson.id);
if (frameshiftdriveJson.modifiers) _addModifications(frameshiftdrive, frameshiftdriveJson.modifiers, frameshiftdriveJson.recipeName, frameshiftdriveJson.recipeLevel); rootModule = json.modules.FrameShiftDrive;
if (rootModule.WorkInProgress_modifications) _addModifications(frameshiftdrive, rootModule.WorkInProgress_modifications, rootModule.engineer.recipeName, rootModule.engineer.recipeLevel);
ship.use(ship.standard[2], frameshiftdrive, true); ship.use(ship.standard[2], frameshiftdrive, true);
ship.standard[2].enabled = frameshiftdriveJson.on === true; ship.standard[2].enabled = frameshiftdriveJson.on === true;
ship.standard[2].priority = frameshiftdriveJson.priority; ship.standard[2].priority = frameshiftdriveJson.priority;
@@ -188,7 +196,8 @@ export function shipFromJson(json) {
// Life support // Life support
const lifesupportJson = json.modules.LifeSupport.module; const lifesupportJson = json.modules.LifeSupport.module;
const lifesupport = _moduleFromEdId(lifesupportJson.id); const lifesupport = _moduleFromEdId(lifesupportJson.id);
if (lifesupportJson.modifiers)_addModifications(lifesupport, lifesupportJson.modifiers, lifesupportJson.recipeName, lifesupportJson.recipeLevel); rootModule = json.modules.LifeSupport;
if (rootModule.WorkInProgress_modifications) _addModifications(lifesupport, rootModule.WorkInProgress_modifications, rootModule.engineer.recipeName, rootModule.engineer.recipeLevel);
ship.use(ship.standard[3], lifesupport, true); ship.use(ship.standard[3], lifesupport, true);
ship.standard[3].enabled = lifesupportJson.on === true; ship.standard[3].enabled = lifesupportJson.on === true;
ship.standard[3].priority = lifesupportJson.priority; ship.standard[3].priority = lifesupportJson.priority;
@@ -196,7 +205,8 @@ export function shipFromJson(json) {
// Power distributor // Power distributor
const powerdistributorJson = json.modules.PowerDistributor.module; const powerdistributorJson = json.modules.PowerDistributor.module;
const powerdistributor = _moduleFromEdId(powerdistributorJson.id); const powerdistributor = _moduleFromEdId(powerdistributorJson.id);
if (powerdistributorJson.modifiers) _addModifications(powerdistributor, powerdistributorJson.modifiers, powerdistributorJson.recipeName, powerdistributorJson.recipeLevel); rootModule = json.modules.PowerDistributor;
if (rootModule.WorkInProgress_modifications) _addModifications(powerdistributor, rootModule.WorkInProgress_modifications, rootModule.engineer.recipeName, rootModule.engineer.recipeLevel);
ship.use(ship.standard[4], powerdistributor, true); ship.use(ship.standard[4], powerdistributor, true);
ship.standard[4].enabled = powerdistributorJson.on === true; ship.standard[4].enabled = powerdistributorJson.on === true;
ship.standard[4].priority = powerdistributorJson.priority; ship.standard[4].priority = powerdistributorJson.priority;
@@ -204,7 +214,8 @@ export function shipFromJson(json) {
// Sensors // Sensors
const sensorsJson = json.modules.Radar.module; const sensorsJson = json.modules.Radar.module;
const sensors = _moduleFromEdId(sensorsJson.id); const sensors = _moduleFromEdId(sensorsJson.id);
if (sensorsJson.modifiers) _addModifications(sensors, sensorsJson.modifiers, sensorsJson.recipeName, sensorsJson.recipeLevel); rootModule = json.modules.Radar;
if (rootModule.WorkInProgress_modifications) _addModifications(sensors, rootModule.WorkInProgress_modifications, rootModule.engineer.recipeName, rootModule.engineer.recipeLevel);
ship.use(ship.standard[5], sensors, true); ship.use(ship.standard[5], sensors, true);
ship.standard[5].enabled = sensorsJson.on === true; ship.standard[5].enabled = sensorsJson.on === true;
ship.standard[5].priority = sensorsJson.priority; ship.standard[5].priority = sensorsJson.priority;
@@ -240,7 +251,8 @@ export function shipFromJson(json) {
} else { } else {
const hardpointJson = hardpointSlot.module; const hardpointJson = hardpointSlot.module;
const hardpoint = _moduleFromEdId(hardpointJson.id); const hardpoint = _moduleFromEdId(hardpointJson.id);
if (hardpointJson.modifiers) _addModifications(hardpoint, hardpointJson.modifiers, hardpointJson.recipeName, hardpointJson.recipeLevel); rootModule = hardpointSlot;
if (rootModule.WorkInProgress_modifications) _addModifications(hardpoint, rootModule.WorkInProgress_modifications, rootModule.engineer.recipeName, rootModule.engineer.recipeLevel, rootModule.specialModifications);
ship.use(ship.hardpoints[hardpointArrayNum], hardpoint, true); ship.use(ship.hardpoints[hardpointArrayNum], hardpoint, true);
ship.hardpoints[hardpointArrayNum].enabled = hardpointJson.on === true; ship.hardpoints[hardpointArrayNum].enabled = hardpointJson.on === true;
ship.hardpoints[hardpointArrayNum].priority = hardpointJson.priority; ship.hardpoints[hardpointArrayNum].priority = hardpointJson.priority;
@@ -282,7 +294,8 @@ export function shipFromJson(json) {
} else { } else {
const internalJson = internalSlot.module; const internalJson = internalSlot.module;
const internal = _moduleFromEdId(internalJson.id); const internal = _moduleFromEdId(internalJson.id);
if (internalJson.modifiers) _addModifications(internal, internalJson.modifiers, internalJson.recipeName, internalJson.recipeLevel); rootModule = internalSlot;
if (rootModule.WorkInProgress_modifications) _addModifications(internal, rootModule.WorkInProgress_modifications, rootModule.engineer.recipeName, rootModule.engineer.recipeLevel);
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;
@@ -299,35 +312,48 @@ export function shipFromJson(json) {
* @param {Object} modifiers the modifiers * @param {Object} modifiers the modifiers
* @param {Object} blueprint the blueprint of the modification * @param {Object} blueprint the blueprint of the modification
* @param {Object} grade the grade of the modification * @param {Object} grade the grade of the modification
* @param {Object} specialModifications special modification
*/ */
function _addModifications(module, modifiers, blueprint, grade) { function _addModifications(module, modifiers, blueprint, grade, specialModifications) {
if (!modifiers || !modifiers.modifiers) return; if (!modifiers) return;
let special; let special;
for (const i in modifiers.modifiers) { if (specialModifications) {
special = Modifications.specials[Object.keys(specialModifications)[0]]
}
for (const i in modifiers) {
// Some special modifications // Some special modifications
if (modifiers.modifiers[i].name === 'mod_weapon_clip_size_override') { if (modifiers[i].name === 'mod_weapon_clip_size_override') {
// This is a numeric addition to the clip size, but we need to work it out in terms of being a percentage so // This is a numeric addition to the clip size, but we need to work it out in terms of being a percentage so
// that it works the same as other modifications // that it works the same as other modifications
const origClip = module.clip || 1; const origClip = module.clip || 1;
module.setModValue('clip', ((modifiers.modifiers[i].value - origClip) / origClip) * 10000); module.setModValue('clip', ((modifiers[i].value - origClip) / origClip) * 10000);
} else if (modifiers.modifiers[i].name === 'mod_weapon_burst_size') { } else if (modifiers[i].name === 'mod_weapon_burst_size') {
// This is an absolute number that acts as an override // This is an absolute number that acts as an override
module.setModValue('burst', modifiers.modifiers[i].value * 100); module.setModValue('burst', modifiers[i].value * 100);
} else if (modifiers.modifiers[i].name === 'mod_weapon_burst_rof') { } else if (modifiers[i].name === 'mod_weapon_burst_rof') {
// This is an absolute number that acts as an override // This is an absolute number that acts as an override
module.setModValue('burstrof', modifiers.modifiers[i].value * 100); module.setModValue('burstrof', modifiers[i].value * 100);
} else if (modifiers.modifiers[i].name === 'mod_weapon_falloffrange_from_range') { } else if (modifiers[i].name === 'mod_weapon_falloffrange_from_range') {
// Obtain the falloff value directly from the range // Obtain the falloff value directly from the range
module.setModValue('fallofffromrange', 1); module.setModValue('fallofffromrange', 1);
} else if (modifiers.modifiers[i].name && modifiers.modifiers[i].name.startsWith('special_')) { } else if (modifiers[i].name && modifiers[i].name.startsWith('special_')) {
// We don't add special effects directly, but keep a note of them so they can be added when fetching values // We don't add special effects directly, but keep a note of them so they can be added when fetching values
special = Modifications.specials[modifiers.modifiers[i].name]; special = Modifications.specials[modifiers[i].name];
} else { } else {
// Look up the modifiers to find what we need to do // Look up the modifiers to find what we need to do
const modifierActions = Modifications.modifierActions[modifiers.modifiers[i].name]; const modifierActions = Modifications.modifierActions[i];
const value = modifiers.modifiers[i].value; let value;
if (i === 'OutfittingFieldType_DefenceModifierShieldMultiplier') {
value = modifiers[i].value - 1;
} else if (i === 'OutfittingFieldType_DefenceModifierHealthMultiplier' && blueprint.startsWith('Armour_')) {
value = (modifiers[i].value - module.hullboost) / module.hullboost;
} else if (i === 'OutfittingFieldType_DefenceModifierHealthMultiplier') {
value = modifiers[i].value / module.hullboost;
} else if (i === 'OutfittingFieldType_RateOfFire') {
value = (1 / Math.abs(modifiers[i].value));
} else {
value = modifiers[i].value - 1;
}
// Carry out the required changes // Carry out the required changes
for (const action in modifierActions) { for (const action in modifierActions) {
if (isNaN(modifierActions[action])) { if (isNaN(modifierActions[action])) {
@@ -354,7 +380,7 @@ function _addModifications(module, modifiers, blueprint, grade) {
module.blueprint.special = special; module.blueprint.special = special;
} }
} }
// Need to fix up a few items // Need to fix up a few items
// Shield boosters are treated internally as straight modifiers, so rather than (for example) // Shield boosters are treated internally as straight modifiers, so rather than (for example)
@@ -377,7 +403,7 @@ function _addModifications(module, modifiers, blueprint, grade) {
module.setModValue('thermres', ((module.getModValue('thermres') / 10000) * -1) * 10000); module.setModValue('thermres', ((module.getModValue('thermres') / 10000) * -1) * 10000);
} }
} }
// Shield generator resistance is actually a damage modifier, so needs to be inverted. // Shield generator resistance is actually a damage modifier, so needs to be inverted.
// In addition, the modification is based off the inherent resistance of the module // In addition, the modification is based off the inherent resistance of the module
if (ModuleUtils.isShieldGenerator(module.grp)) { if (ModuleUtils.isShieldGenerator(module.grp)) {
@@ -405,7 +431,7 @@ function _addModifications(module, modifiers, blueprint, grade) {
module.setModValue('thermres', ((1 - (1 - module.thermres) * (1 + module.getModValue('thermres') / 10000)) - module.thermres) * 10000); module.setModValue('thermres', ((1 - (1 - module.thermres) * (1 + module.getModValue('thermres') / 10000)) - module.thermres) * 10000);
} }
} }
// Bulkhead resistance is actually a damage modifier, so needs to be inverted. // Bulkhead resistance is actually a damage modifier, so needs to be inverted.
// In addition, the modification is based off the inherent resistance of the module // In addition, the modification is based off the inherent resistance of the module
if (module.grp == 'bh') { if (module.grp == 'bh') {
@@ -423,7 +449,7 @@ function _addModifications(module, modifiers, blueprint, grade) {
// Bulkhead boost is based off the inherent boost of the module // Bulkhead boost is based off the inherent boost of the module
if (module.grp == 'bh') { if (module.grp == 'bh') {
const alteredBoost = (1 + module.hullboost) * (1 + module.getModValue('hullboost') / 10000) - 1; const alteredBoost = (1 + module.hullboost) * (1 + module.getModValue('hullboost') / 10000) - 1;
module.setModValue('hullboost', (alteredBoost / module.hullboost - 1) * 10000); module.setModValue('hullboost', (alteredBoost / module.hullboost - 1) * 1000);
} }
// Jitter is an absolute number, so we need to divide it by 100 // Jitter is an absolute number, so we need to divide it by 100
@@ -431,11 +457,6 @@ function _addModifications(module, modifiers, blueprint, grade) {
module.setModValue('jitter', module.getModValue('jitter') / 100); module.setModValue('jitter', module.getModValue('jitter') / 100);
} }
// FD uses interval between bursts internally, so we need to translate this to a real rate of fire
if (module.getModValue('rof')) {
module.setModValue('rof', ((1 / (1 + module.getModValue('rof') / 10000)) - 1) * 10000);
}
// Clip size is rounded up so that the result is a whole number // Clip size is rounded up so that the result is a whole number
if (module.getModValue('clip')) { if (module.getModValue('clip')) {
const individual = 1 / (module.clip || 1); const individual = 1 / (module.clip || 1);

View File

@@ -0,0 +1,292 @@
import Ship from '../shipyard/Ship'
import { HARDPOINT_NUM_TO_CLASS, shipModelFromJson } from './CompanionApiUtils'
import { Ships } from 'coriolis-data/dist'
import Module from '../shipyard/Module'
import { Modules } from 'coriolis-data/dist'
import { Modifications } from 'coriolis-data/dist'
import { getBlueprint } from './BlueprintFunctions'
/**
* Obtain a module given its FD Name
* @param {string} fdname the FD Name of the module
* @return {Module} the module
*/
function _moduleFromFdName (fdname) {
if (!fdname) return null
fdname = fdname.toLowerCase()
// Check standard modules
for (const grp in Modules.standard) {
if (Modules.standard.hasOwnProperty(grp)) {
for (const i in Modules.standard[grp]) {
if (Modules.standard[grp][i].symbol && Modules.standard[grp][i].symbol.toLowerCase() === fdname) {
// Found it
return new Module({template: Modules.standard[grp][i]})
}
}
}
}
// Check hardpoint modules
for (const grp in Modules.hardpoints) {
if (Modules.hardpoints.hasOwnProperty(grp)) {
for (const i in Modules.hardpoints[grp]) {
if (Modules.hardpoints[grp][i].symbol && Modules.hardpoints[grp][i].symbol.toLowerCase() === fdname) {
// Found it
return new Module({template: Modules.hardpoints[grp][i]})
}
}
}
}
// Check internal modules
for (const grp in Modules.internal) {
if (Modules.internal.hasOwnProperty(grp)) {
for (const i in Modules.internal[grp]) {
if (Modules.internal[grp][i].symbol && Modules.internal[grp][i].symbol.toLowerCase() === fdname) {
// Found it
return new Module({template: Modules.internal[grp][i]})
}
}
}
}
// Not found
return null
}
/**
* Build a ship from the journal Loadout event JSON
* @param {object} json the Loadout event JSON
* @return {Ship} the built ship
*/
export function shipFromLoadoutJSON (json) {
// Start off building a basic ship
const shipModel = shipModelFromJson(json)
if (!shipModel) {
throw 'No such ship found: "' + json.Ship + '"'
}
const shipTemplate = Ships[shipModel]
let ship = new Ship(shipModel, shipTemplate.properties, shipTemplate.slots)
ship.buildWith(null)
// Initial Ship building, don't do engineering yet.
let opts = [];
for (const module of json.Modules) {
switch (module.Slot) {
// Cargo Hatch.
case 'CargoHatch':
ship.cargoHatch.enabled = module.On
ship.cargoHatch.priority = module.Priority
break
// Add the bulkheads
case 'Armour':
if (module.Item.toLowerCase().endsWith('_armour_grade1')) {
ship.useBulkhead(0, true)
} else if (module.Item.toLowerCase().endsWith('_armour_grade2')) {
ship.useBulkhead(1, true)
} else if (module.Item.toLowerCase().endsWith('_armour_grade3')) {
ship.useBulkhead(2, true)
} else if (module.Item.toLowerCase().endsWith('_armour_mirrored')) {
ship.useBulkhead(3, true)
} else if (module.Item.toLowerCase().endsWith('_armour_reactive')) {
ship.useBulkhead(4, true)
} else {
throw 'Unknown bulkheads "' + module.Item + '"'
}
ship.bulkheads.enabled = true
if (module.Engineering) _addModifications(ship.bulkheads.m, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level)
break
case 'PowerPlant':
const powerplant = _moduleFromFdName(module.Item)
ship.use(ship.standard[0], powerplant, true)
ship.standard[0].enabled = module.On
ship.standard[0].priority = module.Priority
if (module.Engineering) _addModifications(powerplant, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level)
break
case 'MainEngines':
const thrusters = _moduleFromFdName(module.Item)
ship.use(ship.standard[1], thrusters, true)
ship.standard[1].enabled = module.On
ship.standard[1].priority = module.Priority
if (module.Engineering) _addModifications(thrusters, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level)
break
case 'FrameShiftDrive':
const frameshiftdrive = _moduleFromFdName(module.Item)
ship.use(ship.standard[2], frameshiftdrive, true)
ship.standard[2].enabled = module.On
ship.standard[2].priority = module.Priority
if (module.Engineering) _addModifications(frameshiftdrive, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level)
break
case 'LifeSupport':
const lifesupport = _moduleFromFdName(module.Item)
ship.use(ship.standard[3], lifesupport, true)
ship.standard[3].enabled = module.On === true
ship.standard[3].priority = module.Priority
if (module.Engineering) _addModifications(lifesupport, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level)
break
case 'PowerDistributor':
const powerdistributor = _moduleFromFdName(module.Item)
ship.use(ship.standard[4], powerdistributor, true)
ship.standard[4].enabled = module.On
ship.standard[4].priority = module.Priority
if (module.Engineering) _addModifications(powerdistributor, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level)
break
case 'Radar':
const sensors = _moduleFromFdName(module.Item)
ship.use(ship.standard[5], sensors, true)
ship.standard[5].enabled = module.On
ship.standard[5].priority = module.Priority
if (module.Engineering) _addModifications(sensors, module.Engineering.Modifiers, module.Engineering.BlueprintName, module.Engineering.Level)
break
case 'FuelTank':
const fueltank = _moduleFromFdName(module.Item)
ship.use(ship.standard[6], fueltank, true)
ship.standard[6].enabled = true
ship.standard[6].priority = 0
break
default:
}
for (const module of json.Modules) {
if (module.Slot.search(/Hardpoint/) !== -1) {
// Add hardpoints
let hardpoint;
let hardpointClassNum = -1
let hardpointSlotNum = -1
let hardpointArrayNum = 0
for (let i in shipTemplate.slots.hardpoints) {
if (shipTemplate.slots.hardpoints[i] === hardpointClassNum) {
// Another slot of the same class
hardpointSlotNum++
} else {
// The first slot of a new class
hardpointClassNum = shipTemplate.slots.hardpoints[i]
hardpointSlotNum = 1
}
// Now that we know what we're looking for, find it
const hardpointName = HARDPOINT_NUM_TO_CLASS[hardpointClassNum] + 'Hardpoint' + hardpointSlotNum
const hardpointSlot = json.Modules.find(elem => elem.Slot === hardpointName)
if (!hardpointSlot) {
// This can happen with old imports that don't contain new hardpoints
} else if (!hardpointSlot) {
// No module
} else {
hardpoint = _moduleFromFdName(hardpointSlot.Item)
ship.use(ship.hardpoints[hardpointArrayNum], hardpoint, true)
ship.hardpoints[hardpointArrayNum].enabled = hardpointSlot.On
ship.hardpoints[hardpointArrayNum].priority = hardpointSlot.Priority
opts.push({coriolisMod: hardpoint, json: hardpointSlot});
}
hardpointArrayNum++
}
}
if (module.Slot.search(/Slot\d/) !== -1) {
let internalSlotNum = 1
let militarySlotNum = 1
for (let i in shipTemplate.slots.internal) {
const isMilitary = isNaN(shipTemplate.slots.internal[i]) ? shipTemplate.slots.internal[i].name = 'Military' : false
// The internal slot might be a standard or a military slot. Military slots have a different naming system
let internalSlot = null
if (isMilitary) {
const internalName = 'Military0' + militarySlotNum
internalSlot = json.Modules.find(elem => elem.Slot === internalName)
militarySlotNum++
} else {
// Slot numbers are not contiguous so handle skips.
while (internalSlot === null && internalSlotNum < 99) {
// Slot sizes have no relationship to the actual size, either, so check all possibilities
for (let slotsize = 0; slotsize < 9; slotsize++) {
const internalName = 'Slot' + (internalSlotNum <= 9 ? '0' : '') + internalSlotNum + '_Size' + slotsize
if (json.Modules.find(elem => elem.Slot === internalName)) {
internalSlot = json.Modules.find(elem => elem.Slot === internalName);
break
}
}
internalSlotNum++
}
}
if (!internalSlot) {
// This can happen with old imports that don't contain new slots
} else if (!internalSlot) {
// No module
} else {
const internalJson = internalSlot
const internal = _moduleFromFdName(internalJson.Item)
ship.use(ship.internal[i], internal, true)
ship.internal[i].enabled = internalJson.On === true
ship.internal[i].priority = internalJson.Priority
opts.push({coriolisMod: internal, json: internalSlot});
}
}
}
}
}
for (const i of opts) {
if (i.json.Engineering) _addModifications(i.coriolisMod, i.json.Engineering.Modifiers, i.json.Engineering.BlueprintName, i.json.Engineering.Level, i.json.Engineering.ExperimentalEffect)
}
// We don't have any information on it so guess it's priority 5 and disabled
if (!ship.cargoHatch) {
ship.cargoHatch.enabled = false
ship.cargoHatch.priority = 4
}
console.log(ship)
// Now update the ship's codes before returning it
return ship.updatePowerPrioritesString().updatePowerEnabledString().updateModificationsString()
}
/**
* Add the modifications for a module
* @param {Module} module the module
* @param {Object} modifiers the modifiers
* @param {Object} blueprint the blueprint of the modification
* @param {Object} grade the grade of the modification
* @param {Object} specialModifications special modification
*/
function _addModifications (module, modifiers, blueprint, grade, specialModifications) {
if (!modifiers) return
let special
if (specialModifications) {
special = Modifications.specials[specialModifications]
}
for (const i in modifiers) {
// Some special modifications
// Look up the modifiers to find what we need to do
const findMod = val => Object.keys(Modifications.modifierActions).find(elem => elem.toString().toLowerCase().search(val.toString().toLowerCase().replace(/(OutfittingFieldType_|persecond)/igm, '')) >= 0)
const modifierActions = Modifications.modifierActions[findMod(modifiers[i].Label)]
//TODO: Figure out how to scale this value.
if (!!modifiers[i].LessIsGood) {
}
let value = (modifiers[i].Value / modifiers[i].OriginalValue * 100 - 100) * 100;
if (value === Infinity) {
value = modifiers[i].Value * 100;
}
if (modifiers[i].Label.search('Resistance') >= 0) {
value = (modifiers[i].Value * 100) - (modifiers[i].OriginalValue * 100)
}
// Carry out the required changes
for (const action in modifierActions) {
if (isNaN(modifierActions[action])) {
module.setModValue(action, modifierActions[action])
} else {
module.setModValue(action, value)
}
}
}
// Add the blueprint definition, grade and special
if (blueprint) {
module.blueprint = getBlueprint(blueprint, module)
if (grade) {
module.blueprint.grade = Number(grade)
}
if (special) {
module.blueprint.special = special
}
}
}

View File

@@ -55,10 +55,12 @@
<!-- End Piwik Code --> <!-- End Piwik Code -->
<!-- Bugsnag --> <!-- Bugsnag -->
<script <script src="//d2wy8f7a9ursnm.cloudfront.net/v4/bugsnag.min.js"></script>
src="//d2wy8f7a9ursnm.cloudfront.net/bugsnag-3.min.js" <script src="//d2wy8f7a9ursnm.cloudfront.net/bugsnag-plugins/v1/bugsnag-react.min.js"></script>
data-apikey="2382691c622937f28f8fa82a1bfd797a"></script> <script>
window.bugsnagClient = bugsnag('ba9fae819372850fb660755341fa6ef5', {appVersion: window.CORIOLIS_VERSION || undefined})
window.Bugsnag = window.bugsnagClient
</script>
</head> </head>
<body style="background-color:#000;"> <body style="background-color:#000;">
<section id="coriolis"></section> <section id="coriolis"></section>

View File

@@ -18,6 +18,7 @@
@bg: rgba(30,30,30,1); @bg: rgba(30,30,30,1);
@bgBlack: #000; @bgBlack: #000;
@primary-bg: fadeout(darken(@primary, 47%), 15%); @primary-bg: fadeout(darken(@primary, 47%), 15%);
@alt-primary-bg: fadeout(darken(@primary, 42%), 15%); // Lighter brown background
@secondary-bg: fadeout(darken(@secondary, @bgDarken), @bgTransparency); // Brown background @secondary-bg: fadeout(darken(@secondary, @bgDarken), @bgTransparency); // Brown background
@warning-bg: fadeout(darken(@warning, @bgDarken), @bgTransparency); // Dark Red @warning-bg: fadeout(darken(@warning, @bgDarken), @bgTransparency); // Dark Red

View File

@@ -54,6 +54,7 @@ textarea {
width:100%; width:100%;
min-height: 10em; min-height: 10em;
resize: vertical; resize: vertical;
user-select: auto;
margin:2em 0; margin:2em 0;
} }
} }

View File

@@ -54,6 +54,10 @@ tbody tr {
.no-touch &.highlight:hover, .no-touch &.highlighted { .no-touch &.highlight:hover, .no-touch &.highlighted {
background-color: @warning-bg; background-color: @warning-bg;
} }
&.alt {
background-color: @alt-primary-bg;
}
} }
td { td {

View File

@@ -1,28 +1,30 @@
var path = require('path'); const path = require('path')
var exec = require('child_process').exec; const exec = require('child_process').exec
var webpack = require('webpack'); const webpack = require('webpack')
var pkgJson = require('./package'); const HtmlWebpackPlugin = require('html-webpack-plugin')
var HtmlWebpackPlugin = require("html-webpack-plugin"); const ExtractTextPlugin = require('extract-text-webpack-plugin')
var ExtractTextPlugin = require("extract-text-webpack-plugin"); const WebpackNotifierPlugin = require('webpack-notifier')
const pkgJson = require('./package')
function CopyDirPlugin(source, destination) { function CopyDirPlugin(source, destination) {
this.source = source; this.source = source
this.destination = destination; this.destination = destination
}
CopyDirPlugin.prototype.apply = function (compiler) {
compiler.plugin('done', () => {
console.log(compiler.outputPath, this.destination)
exec('cp -r ' + this.source + ' ' + path.join(compiler.outputPath, this.destination))
})
} }
CopyDirPlugin.prototype.apply = function(compiler) {
compiler.plugin('done', function() {
console.log(compiler.outputPath, this.destination);
exec('cp -r ' + this.source + ' ' + path.join(compiler.outputPath, this.destination));
}.bind(this));
};
module.exports = { module.exports = {
devtool: 'eval', devtool: 'source-map',
devServer: { devServer: {
headers: { "Access-Control-Allow-Origin": "*" } headers: {'Access-Control-Allow-Origin': '*'}
}, },
entry: { entry: {
app: [ 'webpack-dev-server/client?http://0.0.0.0:3300', 'webpack/hot/only-dev-server', path.join(__dirname, "src/app/index.js") ], app: ['webpack-dev-server/client?http://0.0.0.0:3300', 'webpack/hot/only-dev-server', path.join(__dirname, 'src/app/index.js')],
lib: ['d3', 'react', 'react-dom', 'classnames', 'fbemitter', 'lz-string'] lib: ['d3', 'react', 'react-dom', 'classnames', 'fbemitter', 'lz-string']
}, },
resolve: { resolve: {
@@ -37,33 +39,34 @@ module.exports = {
plugins: [ plugins: [
new CopyDirPlugin(path.join(__dirname, 'src/.htaccess'), ''), new CopyDirPlugin(path.join(__dirname, 'src/.htaccess'), ''),
new webpack.optimize.CommonsChunkPlugin({ new webpack.optimize.CommonsChunkPlugin({
name: 'lib', name: 'lib',
filename: 'lib.js' filename: 'lib.js'
}), }),
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
inject: false, inject: false,
template: path.join(__dirname, "src/index.ejs"), template: path.join(__dirname, 'src/index.ejs'),
version: pkgJson.version, version: pkgJson.version,
gapiKey: process.env.CORIOLIS_GAPI_KEY || '', gapiKey: process.env.CORIOLIS_GAPI_KEY || ''
}), }),
new ExtractTextPlugin({ new ExtractTextPlugin({
filename: 'app.css', filename: 'app.css',
disable: false, disable: false,
allChunks: true allChunks: true
}), }),
new WebpackNotifierPlugin({alwaysNotify: true}),
new webpack.HotModuleReplacementPlugin(), new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin() new webpack.NoEmitOnErrorsPlugin()
], ],
module: { module: {
rules: [ rules: [
{ test: /\.css$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader'}) }, {test: /\.css$/, loader: ExtractTextPlugin.extract({fallback: 'style-loader', use: 'css-loader'})},
{ test: /\.less$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader!less-loader'}) }, {test: /\.less$/, loader: ExtractTextPlugin.extract({fallback: 'style-loader', use: 'css-loader!less-loader'})},
{ test: /\.(js|jsx)$/, loaders: [ 'babel-loader' ], include: path.join(__dirname, 'src') }, {test: /\.(js|jsx)$/, loaders: ['babel-loader'], include: path.join(__dirname, 'src')},
{ test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff' }, {test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff'},
{ test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff' }, {test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff'},
{ test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/octet-stream' }, {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: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader'},
{ test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=image/svg+xml' } {test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=image/svg+xml'}
] ]
} }
}; }

View File

@@ -1,24 +1,27 @@
var path = require('path'); const path = require('path')
var exec = require('child_process').exec; const exec = require('child_process').exec
var webpack = require('webpack'); const webpack = require('webpack')
var pkgJson = require('./package'); const HtmlWebpackPlugin = require('html-webpack-plugin')
var HtmlWebpackPlugin = require("html-webpack-plugin"); const ExtractTextPlugin = require('extract-text-webpack-plugin')
var ExtractTextPlugin = require("extract-text-webpack-plugin"); const AppCachePlugin = require('appcache-webpack-plugin')
var AppCachePlugin = require('appcache-webpack-plugin'); const {BugsnagSourceMapUploaderPlugin} = require('webpack-bugsnag-plugins')
const pkgJson = require('./package')
function CopyDirPlugin(source, destination) { function CopyDirPlugin (source, destination) {
this.source = source; this.source = source
this.destination = destination; this.destination = destination
}
CopyDirPlugin.prototype.apply = function (compiler) {
compiler.plugin('done', () => {
console.log(compiler.outputPath, this.destination)
exec('cp -r ' + this.source + ' ' + path.join(compiler.outputPath, this.destination))
})
} }
CopyDirPlugin.prototype.apply = function(compiler) {
compiler.plugin('done', function() {
console.log(compiler.outputPath, this.destination);
exec('cp -r ' + this.source + ' ' + path.join(compiler.outputPath, this.destination));
}.bind(this));
};
module.exports = { module.exports = {
cache: true, cache: true,
devtool: 'source-map',
entry: { entry: {
app: ['babel-polyfill', path.resolve(__dirname, 'src/app/index')], app: ['babel-polyfill', path.resolve(__dirname, 'src/app/index')],
lib: ['d3', 'react', 'react-dom', 'classnames', 'fbemitter', 'lz-string'] lib: ['d3', 'react', 'react-dom', 'classnames', 'fbemitter', 'lz-string']
@@ -34,34 +37,39 @@ module.exports = {
}, },
plugins: [ plugins: [
new webpack.optimize.UglifyJsPlugin({ new webpack.optimize.UglifyJsPlugin({
'screw-ie8': true 'screw-ie8': true,
sourceMap: true
}), }),
//new webpack.optimize.CommonsChunkPlugin({ //new webpack.optimize.CommonsChunkPlugin({
// name: 'lib', // name: 'lib',
// filename: 'lib.[chunkhash:6].js' // filename: 'lib.[chunkhash:6].js'
//}), //}),
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
inject: false, inject: false,
appCache: 'coriolis.appcache', appCache: 'coriolis.appcache',
minify: { minify: {
collapseBooleanAttributes: true, collapseBooleanAttributes: true,
collapseWhitespace: true, collapseWhitespace: true,
removeAttributeQuotes: true, removeAttributeQuotes: true,
removeComments: true, removeComments: true,
removeEmptyAttributes: true, removeEmptyAttributes: true,
removeRedundantAttributes: true, removeRedundantAttributes: true,
removeScriptTypeAttributes: true, removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true removeStyleLinkTypeAttributes: true
}, },
template: path.join(__dirname, "src/index.ejs"), template: path.join(__dirname, 'src/index.ejs'),
uaTracking: process.env.CORIOLIS_UA_TRACKING || '', uaTracking: process.env.CORIOLIS_UA_TRACKING || '',
gapiKey: process.env.CORIOLIS_GAPI_KEY || '', gapiKey: process.env.CORIOLIS_GAPI_KEY || '',
version: pkgJson.version version: pkgJson.version
}), }),
new ExtractTextPlugin({ new ExtractTextPlugin({
filename: '[contenthash:6].css', filename: '[contenthash:6].css',
disable: false, disable: false,
allChunks: true allChunks: true
}),
new BugsnagSourceMapUploaderPlugin({
apiKey: 'ba9fae819372850fb660755341fa6ef5',
appVersion: pkgJson.version
}), }),
new CopyDirPlugin(path.join(__dirname, 'src/schemas'), 'schemas'), new CopyDirPlugin(path.join(__dirname, 'src/schemas'), 'schemas'),
new CopyDirPlugin(path.join(__dirname, 'src/images/logo/*'), ''), new CopyDirPlugin(path.join(__dirname, 'src/images/logo/*'), ''),
@@ -75,14 +83,14 @@ module.exports = {
], ],
module: { module: {
rules: [ rules: [
{ test: /\.css$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader'}) }, {test: /\.css$/, loader: ExtractTextPlugin.extract({fallback: 'style-loader', use: 'css-loader'})},
{ test: /\.less$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader',use: 'css-loader!less-loader'}) }, {test: /\.less$/, loader: ExtractTextPlugin.extract({fallback: 'style-loader', use: 'css-loader!less-loader'})},
{ test: /\.(js|jsx)$/, loader: 'babel-loader?cacheDirectory=true', include: path.join(__dirname, 'src') }, {test: /\.(js|jsx)$/, loader: 'babel-loader?cacheDirectory=true', include: path.join(__dirname, 'src')},
{ test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff' }, {test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff'},
{ test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff' }, {test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff'},
{ test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/octet-stream' }, {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: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader'},
{ test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=image/svg+xml' } {test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=image/svg+xml'}
] ]
} }
}; }