Compare commits

...

316 Commits

Author SHA1 Message Date
Colin McLeod
3c8b1f7d6a Adding 2.5% discount 2015-12-18 01:05:49 -08:00
Colin McLeod
62d9749660 Adding agility/maneuverability to shipyard overview 2015-12-13 12:31:06 -08:00
Colin McLeod
7db185e635 Bumping version to 1.10.0 2015-12-13 12:20:56 -08:00
Colin McLeod
e69bdac75c Add Cobra MK IV, FdL power plant update, PV Hangar 2015-12-13 12:19:22 -08:00
Colin McLeod
231f7e9267 Add planetary vechile hanger support 2015-12-13 12:19:22 -08:00
Colin McLeod
2ef44e38b3 Merge pull request #123 from fawick/master
Fix typo in languages.js
2015-12-07 10:31:23 -08:00
Fabian Wickborn
d051829f98 Fix typo in languages.js 2015-12-07 19:16:00 +01:00
Colin McLeod
01e8e71b28 Updating data reference, bumping version to 1.9.4 2015-11-30 23:38:06 -08:00
Colin McLeod
14681aa9fa Update tests to include bulkheads 2015-11-30 22:56:28 -08:00
Colin McLeod
b93572b18d Merge pull request #120 from sf302/master
Heat Sink Launcher utility auto-fill
2015-11-19 16:28:51 -08:00
Kevin Chang
41c4b4243a Remove arg overloading in useUtility 2015-11-16 16:36:15 -08:00
Kevin Chang
f5127c2475 Typo fix 2015-11-16 15:37:55 -08:00
Kevin Chang
db4303d3c8 Add Heat Sink auto-fill given new SCB heat output 2015-11-16 15:35:36 -08:00
Colin McLeod
8bc100714f Fix Viper Mk4 data. Bumping version to 1.9.3 2015-11-14 12:04:55 -08:00
Colin McLeod
fabd370f4a Update serializer test fixtures 2015-11-14 10:59:15 -08:00
Colin McLeod
769c20154d Updating Hull Reinforcement packages. Bumping to 1.9.2 2015-11-14 10:48:47 -08:00
Colin McLeod
2b5edd75cb Fix keelback boost/speed. Bump to 1.9.1 2015-11-14 10:37:38 -08:00
Colin McLeod
1b56d39356 Update tests to support latest data changes 2015-11-14 00:15:59 -08:00
Colin McLeod
8d1d6d63ad Merge pull request #119 from sf302/master
Handle new Bi-Weave Shield Generator
2015-11-13 22:38:26 -08:00
Kevin Chang
a713105878 Handle new Bi-Weave Shield Generator 2015-11-13 16:54:00 -08:00
Colin McLeod
c527a62ce6 Tweak loader 2015-11-12 11:27:56 -08:00
Colin McLeod
16c76b2598 Added EDDB IDs to data. Updating submodule 2015-10-27 12:00:25 -07:00
Colin McLeod
ad134330c4 Fix common -> standard for outfitting page 2015-10-27 12:00:25 -07:00
Colin McLeod
05438daf48 Merge pull request #113 from richardbuckle/fix-112
#112 lower-case 'k' in 'kg/s'
2015-10-25 18:45:33 -08:00
Richard Buckle
afebf68cae #112 lower-case 'k' in 'kg/s' 2015-10-26 01:51:52 +00:00
Colin McLeod
ab4bdf355c Fix submodule reference 2015-10-23 09:44:42 -07:00
Colin McLeod
0f4abd6ace Updating data submodule reference 2015-10-23 09:18:53 -07:00
Colin McLeod
2901c978dc Use HTTPS instead of SSH for submodule 2015-10-23 09:10:01 -07:00
Colin McLeod
21e9dbc381 Adding data through submodule 2015-10-22 20:38:28 -07:00
Colin McLeod
b2ceafa89e removing data folder 2015-10-22 20:37:14 -07:00
Colin McLeod
d8633a8411 Rename common to standard for consistency 2015-10-22 20:19:56 -07:00
Colin McLeod
f4bf09eaab fix discount minus sign placement 2015-10-22 20:19:56 -07:00
Colin McLeod
f0c40aae34 Handle erroneous data better 2015-10-22 20:19:55 -07:00
Colin McLeod
90ed8ed198 error page fix 2015-10-22 20:19:55 -07:00
Colin McLeod
9af6a529dd Adding station icons 2015-10-22 20:19:55 -07:00
Colin McLeod
269dfbdc1d Merge pull request #107 from sf302/master
Reload costs refinements
2015-10-14 00:15:43 -07:00
Kevin Chang
d01cd24b0d Updated comment to reflect changes to fuel logic 2015-10-13 15:58:44 -07:00
Kevin Chang
93ac3b217f Clean up unnecessary fuel costs logic 2015-10-13 15:56:17 -07:00
Colin McLeod
a38d6cf839 Merge pull request #109 from Toxicat/patch-1
Correct bad translation
2015-10-13 13:32:29 -07:00
PanzerKadaver
bd656b46ef Correct bad translation
Correct error reported in #108
2015-10-13 22:29:48 +02:00
Kevin Chang
20cce4dcda More logical limpet ammo display, fuel tied to slider 2015-10-12 20:54:47 -07:00
Kevin Chang
d286dda07f Refinements, limpet ammo display added to reloads 2015-10-12 19:38:33 -07:00
Colin McLeod
45b6dabcd2 Bumping version to 1.8.3 2015-10-10 11:47:46 -07:00
Colin McLeod
d476c58a9c Workaround for UI-router bug for build with slash in the name. Fixes #105 2015-10-09 18:29:04 -07:00
Colin McLeod
e837bb68fb Bumping version to 1.8.2 2015-10-09 15:48:54 -07:00
Colin McLeod
e2adc7bdc4 Tweak AFMU for explorer build 2015-10-09 15:44:10 -07:00
Colin McLeod
22716517c5 Remove A-rated build type, now redundant 2015-10-09 15:23:59 -07:00
Colin McLeod
8b82965c12 Fix section quick-fit menu z-index / overlap 2015-10-09 15:23:43 -07:00
Colin McLeod
65cf975a35 Merge pull request #104 from sf302/master
Hull reinforcement auto-fill, hardpoint clobber behavior tweak
2015-10-09 15:09:10 -07:00
Kevin Chang
1c78fea48f Fix behavior for hull reinforcement max at 5D 2015-10-08 22:51:00 -07:00
Kevin Chang
08f49c8339 Fix SCB internal clobber 2015-10-08 19:29:46 -07:00
Kevin Chang
bed81d26b2 Alter auto-fill clobbering behavior for hardpoints 2015-10-08 19:20:17 -07:00
Kevin Chang
38b13fca27 Add armor autofill, prevent internal fill clobber 2015-10-08 18:06:01 -07:00
Colin McLeod
0869230b13 Fix to standard fit all class B. Closes #103 2015-10-08 15:32:01 -07:00
Colin McLeod
80d4b6b431 fix power bug when swapping disabled components 2015-10-07 20:34:52 -07:00
Colin McLeod
fb7e9136d4 Merge pull request #102 from sf302/master
Additional auto-fill for SCB and other weapons
2015-10-07 20:25:38 -07:00
Colin McLeod
059ff367ff Price changes for 1.4 2015-10-07 20:13:21 -07:00
Kevin Chang
d322e062ad Trimming back down to just laser/MC/cannon fills 2015-10-07 20:09:51 -07:00
Kevin Chang
f807f4222f Less hacks to get the same thing done 2015-10-07 20:06:04 -07:00
Kevin Chang
1d4b046723 Tweaked to reenable slot if previously disabled 2015-10-07 19:51:36 -07:00
Kevin Chang
b9fc114e02 Additional auto-fill for SCB and other weapons 2015-10-07 19:43:39 -07:00
Colin McLeod
50047411c3 Correct Viper boost speed 2015-10-07 17:57:22 -07:00
Colin McLeod
610ded2f83 Fix ammo sorting by qty and unit price 2015-10-07 11:35:36 -07:00
Colin McLeod
2a644e787a Merge pull request #100 from sf302/master
Added new 'Reload Costs' tab for ammo, digit display cleanup
2015-10-07 11:33:05 -07:00
Colin McLeod
90b339e5c3 Correct 50% warning on power band 2015-10-07 11:32:52 -07:00
Colin McLeod
a213ad12d0 lint fix 2015-10-07 02:17:49 -07:00
Colin McLeod
a4b8b942a1 Show warning when Power priority group 1 exceeds 50%. 2015-10-07 02:16:00 -07:00
Colin McLeod
df7ef0fbdb Adding more outiftting sub section menu options 2015-10-07 02:14:45 -07:00
Colin McLeod
f42dc481df Added Outfitting section sub-menu 2015-10-06 22:49:09 -07:00
Colin McLeod
623be748c0 New and improved shipyard/home page 2015-10-06 20:06:13 -07:00
Colin McLeod
35c84ee0f0 Handle rounding erros on priority bands 2015-10-06 20:06:13 -07:00
Colin McLeod
4d84f271be Update tests for ignore auto generated property 2015-10-06 20:06:13 -07:00
Colin McLeod
5458c548fb Detailed discover scanner does not use any power 2015-10-06 20:06:12 -07:00
Colin McLeod
a9be057fe8 Readbility changes for fsd, fuel tank, and ls data 2015-10-06 20:06:12 -07:00
Colin McLeod
564c228d41 Massive refactoring to Ship class 2015-10-06 20:06:12 -07:00
Colin McLeod
3f6875abb6 Add find lightest shield generator 2015-10-06 20:06:12 -07:00
Colin McLeod
a2aa829b45 Add/impromve find compoonent functions 2015-10-06 20:06:12 -07:00
Colin McLeod
08b6ec9e31 Add size map 2015-10-06 20:06:12 -07:00
Colin McLeod
ee99d33275 Bumping version to 1.8.0 2015-10-06 20:06:12 -07:00
Colin McLeod
7b9e8dbc7d Sort ships by actual name not file name 2015-10-06 20:06:12 -07:00
Colin McLeod
44f45e7e93 Handle comparison when build is missing. Closes #96 2015-10-06 20:06:12 -07:00
Colin McLeod
a49f7ec594 Handle special characters in build or comparison name. Closes #101 2015-10-06 20:06:12 -07:00
Colin McLeod
9ee12e4167 Rename DBS file 2015-10-06 20:06:11 -07:00
Kevin Chang
33ad7d909a Fix torpedo ammo cost data 2015-10-05 20:27:22 -07:00
Kevin Chang
e5e29dc6cb Cleaned up lint errors 2015-10-05 20:15:46 -07:00
Kevin Chang
34dd40bcbf Added new 'Reload Costs' tab for ammo, digit display cleanup 2015-10-05 20:08:36 -07:00
Colin McLeod
0e8e9f5cbc Merge pull request #97 from SmokyBird/patch-1
Update fr.js
2015-10-05 16:30:00 -07:00
SmokyBird
d39cbb3ef5 Update fr.js
Finally found the full French translation for the Hull Reinforcement.
2015-10-06 00:47:07 +02:00
Colin McLeod
5470b241f6 Merge pull request #94 from koreldan/master
Minor corrections
2015-09-28 09:24:49 -07:00
enrico
6507c22355 minor corrections 2015-09-27 15:36:11 +02:00
Enrico
96c2f4b3b6 Merge pull request #1 from cmmcleod/master
updating
2015-09-27 15:26:35 +02:00
Colin McLeod
b0c521246e Bumping version to 1.7.3 2015-09-22 11:53:08 -07:00
Colin McLeod
5c0616ad47 Display clip + ammo reserve more intelligently 2015-09-22 11:52:44 -07:00
Colin McLeod
523f37ccc1 Correct Torpedo Pylon ammo reserve 2015-09-22 11:52:13 -07:00
Colin McLeod
5e2768bbf6 Correct Pack-Hound cost 2015-09-22 11:51:56 -07:00
Colin McLeod
61b3e7d47d Corrected Federal Gunship hull cost 2015-09-22 11:51:25 -07:00
Colin McLeod
ed6fc32d76 Correct Shield Cell Bank recharge values 2015-09-22 11:50:00 -07:00
Colin McLeod
4c74675edd Bumping version to 1.7.2 2015-09-22 09:27:39 -07:00
Colin McLeod
d43ee25e71 Use full name for Advanced Plasma Accelerator 2015-09-22 09:27:19 -07:00
Colin McLeod
46f00e0bc7 Lint fixes 2015-09-22 09:14:47 -07:00
Colin McLeod
d3cea71e50 Bumping version to 1.7.1 2015-09-22 09:13:43 -07:00
Colin McLeod
0516a6f54d Use calculated boost speed in comparisons. Fixes #91 2015-09-22 09:13:21 -07:00
Colin McLeod
eb8373f8b4 Line chart UI tweaks 2015-09-22 01:43:54 -07:00
Colin McLeod
202bbbd357 Use power icons for power management 2015-09-22 00:43:55 -07:00
Colin McLeod
b9e404c4da Adding italian number format support 2015-09-21 23:44:24 -07:00
Colin McLeod
e16ce83c03 Adding Spanish support 2015-09-21 23:44:05 -07:00
Colin McLeod
83c266d083 Bumping version to 1.7.0 2015-09-21 21:43:56 -07:00
Colin McLeod
349b8f436c Import/export fixture fixes for FSD Interdictor 2015-09-21 21:43:17 -07:00
Colin McLeod
e9a0a01e14 Lint fixes 2015-09-21 21:42:48 -07:00
Colin McLeod
457b8920f2 Partial Italian translation 2015-09-21 21:00:29 -07:00
Colin McLeod
31b63e9a87 en.js formatting 2015-09-21 21:00:17 -07:00
Colin McLeod
8dc3725b47 Chart UI Tweaks 2015-09-21 20:58:13 -07:00
Colin McLeod
e2096ba9f4 Display calculate boost speed 2015-09-21 20:47:59 -07:00
Colin McLeod
231fcbb3bc Calculate top boost speed 2015-09-21 20:47:31 -07:00
Colin McLeod
75c22de166 Use true base boost speeds 2015-09-21 20:45:44 -07:00
Colin McLeod
d196127392 Improve Shield Cell bank readability 2015-09-20 10:56:39 -07:00
Colin McLeod
fb4dc906aa Empty Spanish translations for now 2015-09-20 10:56:18 -07:00
Colin McLeod
9937ba8039 Merge pull request #93 from koreldan/master
added italian language
2015-09-19 22:10:06 -07:00
enrico
d92722f1c2 added italian language 2015-09-20 01:13:07 +02:00
Colin McLeod
69096d7816 Merge pull request #92 from SmokyBird/patch-1
Update fr.js
2015-09-19 14:48:55 -07:00
SmokyBird
2846827959 Update fr.js
Changed a few translations to keep the real ones, coming from the game.
2015-09-19 14:50:53 +02:00
Colin McLeod
67bd56e692 Top speed display and test tweaks 2015-09-17 22:09:30 -07:00
Colin McLeod
95f5e8e5ae Bumping version to 1.6.0 2015-09-17 01:00:38 -07:00
Colin McLeod
eb52a7548c Improve multi series tooltips for line chart 2015-09-17 01:00:10 -07:00
Colin McLeod
b479b61926 Minor bar chart UI tweak 2015-09-17 00:59:29 -07:00
Colin McLeod
726a08b05b Calculate speed based on Thrusters. Closes #16 2015-09-17 00:59:09 -07:00
Colin McLeod
fc2f76c31c Updating ships and thrusters for speed calculation support 2015-09-17 00:57:31 -07:00
Colin McLeod
839e1a5cbd Removing unused icon 2015-09-17 00:55:26 -07:00
Colin McLeod
12beeffae0 Hack to component select. Closes #89 2015-09-14 10:45:06 -07:00
Colin McLeod
83ad7d9f6c Correct price of Federal Gunship 2015-09-07 12:43:52 -07:00
Colin McLeod
6e65d67f14 Bumping version to 1.5.5 2015-09-05 23:01:19 -07:00
Colin McLeod
a127e2f5a5 Merge pull request #85 from gbiobob/master
Corrections for French localisation
2015-09-05 11:01:13 -07:00
gbiobob
9154b7f38c Corrections for French localisation 2015-09-05 11:13:26 +02:00
Colin McLeod
c2d8cad249 Bumping version to 1.5.4 2015-09-04 17:31:08 -07:00
Colin McLeod
e9ffe5baec Fix to Russian language name 2015-09-04 17:30:41 -07:00
Colin McLeod
fffa325e83 Corrections to French translation 2015-09-04 12:45:14 -07:00
Colin McLeod
ed14ed2bb7 Bumping version to 1.5.2 2015-09-03 12:19:59 -07:00
Colin McLeod
7c9e020b88 Minor french translation correction 2015-09-03 12:10:21 -07:00
Colin McLeod
d711d1519b Correct base shield strength on fed assault and gun ship 2015-09-03 12:07:50 -07:00
Colin McLeod
3361f7e435 Another russian translation correction 2015-09-03 12:01:13 -07:00
Colin McLeod
3a79f99f77 Correct Russian translations 2015-09-03 11:58:29 -07:00
Colin McLeod
ff25b55c1f Lint fix 2015-09-03 00:22:50 -07:00
Colin McLeod
ae6f6b0da1 Bumping version to 1.5.1 2015-09-03 00:21:23 -07:00
Colin McLeod
6dc714371d Update Shield Strength calculation 2015-09-03 00:19:58 -07:00
Colin McLeod
5762b133e5 Fix Orca first interal compartment restrictions 2015-09-03 00:19:30 -07:00
Colin McLeod
50741657a5 Merge pull request #82 from michaelhue/beta-ships
Include v1.4-beta ships
2015-09-02 16:31:23 -07:00
michaelhue
ff9a38f23f Include v1.4-beta ships.
Adds the Federal Assault Ship, Federal Gunship and Imperial Eagle to the ship selection.

Note: Values for `boostEnergy` and `masslock` attributes are currently based on their parent ships. Should be updated as soon as data is available.
2015-09-02 17:48:42 +02:00
Colin McLeod
3b11b31e7c Add all english terms due to angular translate workaround 2015-09-02 01:50:49 -07:00
Colin McLeod
44e5dfb4d4 Lint fix 2015-09-01 20:55:07 -07:00
Colin McLeod
30ea10830c Fix to slider reset event 2015-09-01 20:47:43 -07:00
Colin McLeod
eb0f611d78 Fix slider event 2015-09-01 20:38:28 -07:00
Colin McLeod
96ef192738 Fix max fuel label 2015-09-01 20:38:13 -07:00
Colin McLeod
1970616443 Add cargo hatch priority and status to be included in detailed export 2015-09-01 18:36:57 -07:00
Colin McLeod
aac4c9a872 Fix to slider events 2015-09-01 18:05:35 -07:00
Colin McLeod
aebfb62ac4 Correct Select DOM generation 2015-09-01 18:02:17 -07:00
Colin McLeod
9748043466 Update sensors 2015-09-01 17:59:33 -07:00
Colin McLeod
b6f98e741b UI tweak 2015-09-01 02:53:15 -07:00
Colin McLeod
b513cca4b5 Minor code clean up 2015-09-01 02:49:03 -07:00
Colin McLeod
65f53a3fa4 Fixes for language and scaling 2015-09-01 02:20:05 -07:00
Colin McLeod
bf217e7fdd Updating DE, FR and RU 2015-08-31 17:41:45 -07:00
Colin McLeod
09e646ee95 Power warning when at 100% 2015-08-31 17:39:04 -07:00
Colin McLeod
ab18228131 Further improvement to size ratio 2015-08-31 17:39:04 -07:00
Colin McLeod
164e9f5c8a Another improvement to font-size adjustments 2015-08-31 17:37:04 -07:00
Colin McLeod
faa8759851 More changes for font size adjustment 2015-08-31 17:35:14 -07:00
Colin McLeod
c2a84606a1 Inital commit for font size adjust slider 2015-08-31 17:34:28 -07:00
Colin McLeod
42d51b7612 Merge pull request #81 from Marginal/priorities
Include module status and priority in JSON import and export.
2015-08-31 17:29:54 -07:00
Jonathan Harris
38dc4319c0 Test import/export of module state and priority. 2015-08-30 06:52:44 +01:00
Jonathan Harris
fda966be02 Pass tests. 2015-08-30 06:05:12 +01:00
Jonathan Harris
bf47a81dc1 More cosmetic issues. 2015-08-30 05:29:25 +01:00
Jonathan Harris
eef4e06f29 Fix cosmetic issues. 2015-08-30 05:26:22 +01:00
Jonathan Harris
2d2c2b75e3 Include module status and priority in JSON import and export. 2015-08-30 05:02:59 +01:00
Colin McLeod
0066e7fd40 Bumping version to 1.5.0 2015-08-23 12:40:34 -07:00
Colin McLeod
d596723b7b Major refactor for language support, EN, DE, ES, FR, RU 2015-08-23 12:38:17 -07:00
Colin McLeod
c7269423ed Handle select edge-case 2015-08-20 14:09:07 -07:00
Colin McLeod
ee60e4d043 Fix Diamondback Explorer MLF 2015-08-20 14:08:46 -07:00
Colin McLeod
c98a73c6a8 Bumping version to 1.4.1 2015-08-15 16:35:30 -07:00
Colin McLeod
0116523c63 Merge pull request #75 from sf302/master
Additional refinement to "Optimize Mass" preset
2015-08-14 22:36:17 -07:00
Kevin Chang
c1afa7c385 Additional refinement to "Optimize Mass" preset 2015-08-14 19:16:49 -07:00
Colin McLeod
6630ff8fee Adding another E:D import test case 2015-08-14 11:41:53 -07:00
Colin McLeod
14f303c581 Merge pull request #74 from sf302/master
Adding powerplant capacity warnings
2015-08-14 00:42:50 -07:00
Colin McLeod
0728af14dd Support import of E:D shipyard text exports 2015-08-13 23:22:13 -07:00
Colin McLeod
1edacf3eba Corrected thurster selection and warnings 2015-08-13 23:21:40 -07:00
Colin McLeod
3d6d210563 updating linting params 2015-08-13 23:18:35 -07:00
Colin McLeod
df09da4b0a Remove redundant statements 2015-08-13 23:14:48 -07:00
Colin McLeod
b02de43b50 Updating dependencies 2015-08-13 23:14:33 -07:00
Kevin Chang
1b3ca2f697 Fix lint error 2015-08-13 22:22:46 -07:00
Colin McLeod
886614527f Improved low weight build logic 2015-08-10 15:12:59 -07:00
Colin McLeod
5f05bf0dc5 Lint fix 2015-08-10 15:12:18 -07:00
Colin McLeod
59710ce2cf Adding button for class A oufit 2015-08-10 10:50:46 -07:00
Colin McLeod
b533191bc9 Adding loader for later use 2015-08-10 10:50:16 -07:00
Kevin Chang
4fa1115e8f Extend PD Boost warning to PP Retracted power (TODO: extend to two-stage warning for DEP/RET) 2015-08-06 20:58:11 -07:00
Colin McLeod
be5a069b23 Merge pull request #71 from sf302/master
Add build preset button and correct/improve SCB info
2015-07-30 20:48:17 -07:00
Kevin Chang
80da41c866 Another fix to lint errors 2015-07-30 20:18:33 -07:00
Kevin Chang
d278a7c1fd Correcting CI errors 2015-07-30 20:14:46 -07:00
Kevin Chang
69de209aba A-rated uses largest eligible shield slot; dirty hacks rewritten 2015-07-30 19:50:08 -07:00
Kevin Chang
15616d112f Add per-slot total SCB capacity in MJ 2015-07-30 19:04:52 -07:00
Kevin Chang
95adca5cde Incremented all shield cell bank counts -- "Munitions" tab shows actual cell counts 2015-07-30 18:54:57 -07:00
kchang
82c5460936 Shortcut to A-rated common components and shield generator 2015-07-28 23:21:46 -07:00
Colin McLeod
b850695715 Bumping version to 1.3.1 2015-07-26 22:42:06 -07:00
Colin McLeod
d5af972272 Add 8A pristmatic shield generator 2015-07-26 22:39:13 -07:00
Colin McLeod
8946f9b97c Add component group filtering for Orca special case internal slots 2015-07-21 12:34:35 -07:00
Colin McLeod
348339520d Improve comparison import validation 2015-07-21 12:34:07 -07:00
Colin McLeod
f0bdcd5557 Bumping version to 1.3.0 2015-07-20 13:42:38 -07:00
Colin McLeod
b1ee0e44f3 Linting fixes, update unit test 2015-07-20 13:42:21 -07:00
Colin McLeod
c96e6afbd7 Power Distributor required for Boost. Resolves #17 2015-07-20 13:37:03 -07:00
Colin McLeod
77334341ea Armour value improved by bulkhead 2015-07-20 00:55:51 -07:00
Colin McLeod
5f22743778 Bumping to version 1.2.0 2015-07-19 22:30:30 -07:00
Colin McLeod
03986cb88a Massive refactor for 3rd party import 2015-07-19 21:32:14 -07:00
Colin McLeod
c796adf40d Add Persist.getAll for backup purposes 2015-07-18 16:50:50 -07:00
Colin McLeod
2890ff5537 Add description to export modal 2015-07-18 16:50:03 -07:00
Colin McLeod
a6ba61a2bf Change loadout schema slightly 2015-07-18 14:46:22 -07:00
Colin McLeod
db5e080992 Change meta description 2015-07-18 14:45:36 -07:00
Colin McLeod
63d7f98e2c Fix total jump range calculation bug 2015-07-18 14:45:08 -07:00
Colin McLeod
7997ff6ae9 Correct Beta insurance rate 2015-07-17 09:07:16 -07:00
Colin McLeod
b3126cf6b6 Renaming data test for consistency 2015-07-15 21:11:23 -07:00
Colin McLeod
ab1ea53ce3 Implement export for 3rd Party sites 2015-07-15 16:13:17 -07:00
Colin McLeod
82a87cb653 Adjust select menu size for smaller windows 2015-07-15 15:31:40 -07:00
Colin McLeod
d2fc526039 Don't cachebust JSON files.. 2015-07-14 21:58:27 -07:00
Colin McLeod
88587c6487 Bumping version to 1.1.0 2015-07-14 21:48:11 -07:00
Colin McLeod
4578dbf906 Refactor many variable names, adding detailed json dump and schema 2015-07-14 21:44:12 -07:00
Colin McLeod
cd48ef6f86 Removing ship purpose 2015-07-13 12:33:40 -07:00
Colin McLeod
0f0e67ec9c Adding mass lock factor 2015-07-13 11:08:49 -07:00
Colin McLeod
bbb2a223af Updating price for mining lance 2015-07-13 10:58:05 -07:00
Colin McLeod
5278e52e2f Updating price for Pack-hound 2015-07-13 10:57:52 -07:00
Colin McLeod
e6290abef7 Correcting prices 2015-07-11 00:17:21 -07:00
Colin McLeod
346fee1208 Improve readbility of power distributor and thruster data 2015-07-07 18:29:25 -07:00
Colin McLeod
1b9f5f870e Change component select hover color 2015-07-07 18:29:07 -07:00
Colin McLeod
26b624d1dd Use default right-click action when SHIFT key is held 2015-07-07 15:34:28 -07:00
Colin McLeod
7cbd9732b7 List Utility mounts in alphabetical order 2015-07-07 14:51:23 -07:00
Colin McLeod
44152116b4 Linting fix 2015-07-07 11:30:38 -07:00
Colin McLeod
3ad35992fc Use full names for limpet controllers 2015-07-07 11:20:48 -07:00
Colin McLeod
e963eb24a0 Adding Imperial Hammer rail gun 2015-07-07 11:20:26 -07:00
Colin McLeod
827e2b403c Adding Distrupoter pulse laser 2015-07-07 11:20:07 -07:00
Colin McLeod
0fd4712021 Adding Advanced Plasma Accelerator 2015-07-07 11:19:49 -07:00
Colin McLeod
ae0af05e78 Adding Enforcer Multi-cannon 2015-07-07 11:19:31 -07:00
Colin McLeod
dd00f283e6 Adding Pack-Hound missle rack 2015-07-07 11:19:12 -07:00
Colin McLeod
eddf968629 Adding Mining Lance laser 2015-07-07 11:18:50 -07:00
Colin McLeod
7fdd83ba84 Adding Pacifier frag cannon 2015-07-07 11:18:28 -07:00
Colin McLeod
1bb4f6850e Clean up cannon data 2015-07-07 11:18:05 -07:00
Colin McLeod
f47b931380 Adding Cryptoscrambler burst laser 2015-07-07 11:17:45 -07:00
Colin McLeod
d9f686f0d6 Adding Retributor beam laser 2015-07-07 11:17:25 -07:00
Colin McLeod
73cef20073 Format for readability 2015-07-07 11:17:05 -07:00
Colin McLeod
fd68565d8e Adding prismatic Shield Generators 2015-07-07 11:16:40 -07:00
Colin McLeod
a45d165d33 UI Tweaks 2015-07-06 15:45:56 -07:00
Colin McLeod
904f828d83 Change cargo rack order, remove long name 2015-07-06 11:20:34 -07:00
Colin McLeod
f00420c92f UI Tweaks 2015-07-06 11:20:08 -07:00
Colin McLeod
457705014c Bumping version to 1.0.4 2015-07-03 18:25:54 -07:00
Colin McLeod
6faf3765e0 Fix to scroll to top on iOS 2015-07-03 18:23:19 -07:00
Colin McLeod
4abdce2b70 Fix button wrapping issue on small screens 2015-07-03 15:42:08 -07:00
Colin McLeod
3b44f5fe27 Bumping version 1.0.3 2015-07-03 15:33:47 -07:00
Colin McLeod
7332dc69ed Linting issues 2015-07-03 15:31:52 -07:00
Colin McLeod
381387c04f UI Tweaks, persist cost tab open, revert outfitting order to original 2015-07-03 15:30:49 -07:00
Colin McLeod
e0db9fdfb0 Fix scrolling on iOS 2015-07-03 12:15:35 -07:00
Colin McLeod
a8d66b22af Bumping version to 1.0.2 2015-07-02 20:43:13 -07:00
Colin McLeod
bdc1e622f9 UI Tweaks, scrolling fixes and improvements 2015-07-02 20:42:46 -07:00
Colin McLeod
ad8130ae9b Add missing class 7 & 8 internal fuel tanks 2015-07-02 19:24:52 -07:00
Colin McLeod
394a3bb9f1 Revert to ui-router-extras 0.0.13 due to bug introduced in 0.0.14 2015-07-02 10:41:24 -07:00
Colin McLeod
54907b462c Tweak select look and feel on firefox, safari 2015-07-01 23:41:32 -07:00
Colin McLeod
1350de1910 Empty retrofitting table color fix 2015-06-30 21:55:38 -07:00
Colin McLeod
89d3fd69e1 UI tweaks for mobile 2015-06-30 21:46:05 -07:00
Colin McLeod
7325081ec9 Version 1.0.0 :D 2015-06-30 21:09:19 -07:00
Colin McLeod
680872a302 Retrofitting costs added to outfit page 2015-06-30 21:06:12 -07:00
Colin McLeod
a3c65d6c69 Code comments 2015-06-30 19:25:57 -07:00
Colin McLeod
a189265326 Fix svg click bug in Chrome 2015-06-30 19:25:36 -07:00
Colin McLeod
b447e913ff no need to abbreviate shield details 2015-06-29 16:28:41 -07:00
Colin McLeod
b5a249fb4b Change latest version date format 2015-06-29 16:27:56 -07:00
Colin McLeod
ae081c147e Fix negative power for limpet controllers 2015-06-29 15:42:35 -07:00
Colin McLeod
3ce0d0bdd8 Add dps to outfit page 2015-06-29 15:03:04 -07:00
Colin McLeod
a71abd9fe3 Bumping version to 0.14.1 2015-06-29 14:59:30 -07:00
Colin McLeod
f1d804e3a1 Adding total DPS to outfit page and comparisons 2015-06-29 11:57:29 -07:00
Colin McLeod
aa7479d111 Updating Federal Dropship agility 2015-06-29 10:36:49 -07:00
Colin McLeod
7c23fb3884 Bumping version to 0.14.0 2015-06-26 11:00:46 -07:00
Colin McLeod
b707015d9c Fix power plant toggle power bug 2015-06-26 11:00:11 -07:00
Colin McLeod
10d5611dcd Seperate discounts for ship and components, added discounts for 5,10,15,20,25 percent off 2015-06-25 20:26:22 -07:00
Colin McLeod
9009a2a434 Bumping to 0.13.4, fixing courier bulkhead mass 2015-06-24 13:17:23 -07:00
Colin McLeod
8b98a98faf lint fix 2015-06-23 23:47:27 -07:00
Colin McLeod
44de3e4bbc Minor CSS refactor, outfit page tweak 2015-06-23 23:45:30 -07:00
Colin McLeod
ba2e9a12b0 Tweak chart axis labels 2015-06-23 11:47:23 -07:00
Colin McLeod
57304f55c1 Merge pull request #62 from Maverick-JM/master
Fixes for Windows phone and IE
2015-06-23 11:47:09 -07:00
Maverick
1eea358c35 Typo in the comments :). 2015-06-23 23:10:04 +10:00
Maverick
f671b7c34f Fix for the top menu not working in IE 11 (and probably older IE too). 2015-06-23 23:04:07 +10:00
Maverick
211028d80d Fix for the whole app not working on Windows phones as a Windows phone, this was somewhat vexing :)). 2015-06-23 22:27:24 +10:00
Justin Murtagh
c79359ea2f Merge pull request #6 from cmmcleod/master
Update my fork.
2015-06-23 22:04:34 +10:00
Colin McLeod
93f92da1df Adding line chart, adding speed function 2015-06-19 19:04:45 -07:00
Colin McLeod
25020293ec Fix unique internal component regression bug, add tests, bump to 0.13.3 2015-06-19 10:29:26 -07:00
Colin McLeod
4e7f1d3e8b Updating README and disclaimer text 2015-06-18 16:32:45 -07:00
Colin McLeod
e6ba0a14e8 Minor tweak to slot size position 2015-06-18 15:51:58 -07:00
Colin McLeod
b285a433b2 Bumping version to 0.13.2 2015-06-18 09:52:48 -07:00
Colin McLeod
f19c786f64 Update ship armour stats 2015-06-18 09:52:18 -07:00
Colin McLeod
806e545361 Fix charts in comparison page 2015-06-17 23:32:56 -07:00
Colin McLeod
ae62781d53 Bump version to 0.13.0 2015-06-17 23:17:15 -07:00
Colin McLeod
3abfcf7c95 Tweak chart axis UI 2015-06-17 23:12:27 -07:00
Colin McLeod
dc8b829d8a fix: total range calculation bug 2015-06-17 20:41:54 -07:00
Colin McLeod
353396398b Linting fix 2015-06-17 20:41:11 -07:00
Colin McLeod
bf99b34596 Tweak outfit page charts responsiveness 2015-06-16 15:28:06 -07:00
Colin McLeod
f3af0f3a99 Toggling shield and boosters updates shield strength 2015-06-16 15:27:41 -07:00
Colin McLeod
0fd4a8395e Tweak area chart tooltip 2015-06-16 15:26:47 -07:00
Colin McLeod
cb664003a5 Tweak slider 2015-06-16 15:26:22 -07:00
Colin McLeod
4686f17d18 Strip build should reset bulkheads 2015-06-16 15:26:05 -07:00
Colin McLeod
45c96dc136 Icon tweaks, added feather icon 2015-06-16 15:25:25 -07:00
Colin McLeod
389fdc8dfa Removing unused svg icon 2015-06-15 23:25:42 -07:00
Colin McLeod
b94e6126cd Chart performance tweaks, UI tweaks 2015-06-15 21:46:55 -07:00
Colin McLeod
bee4f7e6bc Fix strip build bug, and update state 2015-06-15 18:18:27 -07:00
Colin McLeod
345b7f5ffe Removing codeship, adding travis build status to readme 2015-06-15 18:08:41 -07:00
Colin McLeod
f1b40eb38c Adding gulp back to package.json 2015-06-15 18:06:09 -07:00
Colin McLeod
f459c26bd7 Locking down npm dependencies, add caching to travis 2015-06-15 18:03:02 -07:00
Colin McLeod
825b678fb0 Total Range chart feature added 2015-06-15 17:43:28 -07:00
Colin McLeod
ce3818f99a Use Travis CI instead of Codeship 2015-06-15 17:32:18 -07:00
Colin McLeod
94e2b60cd1 Changing version link 2015-06-15 17:31:27 -07:00
Colin McLeod
3bbef71a5e Merge pull request #58 from shearn89/strip-ship
Adding in 'Strip Ship' functionality.
2015-06-15 16:26:01 -07:00
Alex Shearn
ca280673d1 Fixing indentation 2015-06-15 22:09:18 +01:00
Alex Shearn
ff477c035a Moving button as per comments 2015-06-15 20:28:15 +01:00
Alex Shearn
1c0b76a8c2 Adding in 'Strip Ship' functionality.
This commit adds a simple button next to the save/reload icons that strips the ship to maximum class, D-rated modules, and no optional modules. Still needs a custom icon! May try to add in future things like 'all cargo' or 'fill empty with...' options.
2015-06-15 20:07:13 +01:00
Colin McLeod
bef741332d Bumping version to 0.12.1 2015-06-15 10:11:34 -07:00
Colin McLeod
f54620ee24 Imperial Courier shield correction 2015-06-15 10:11:12 -07:00
Justin Murtagh
6fb2247dd7 Merge pull request #5 from cmmcleod/master
Merge back post-responsive priority stuff.
2015-06-12 07:12:13 +10:00
159 changed files with 10337 additions and 9971 deletions

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "data"]
path = data
url = https://github.com/cmmcleod/coriolis-data.git

19
.travis.yml Normal file
View File

@@ -0,0 +1,19 @@
language: node_js
notifications:
email: false
sudo: false
node_js:
- "0.12"
cache:
directories:
- node_modules
- bower_components
before_script:
- npm install -g gulp
- npm install -g bower
- bower install
script:
- gulp lint
- gulp build-prod
- gulp test

View File

@@ -1,4 +1,4 @@
[ ![Codeship Status for cmmcleod/coriolis](https://codeship.com/projects/637858c0-f2a5-0132-7af7-5ed004d44c71/status?branch=master)](https://codeship.com/projects/85232) [![Tasks in Ready](https://badge.waffle.io/cmmcleod/coriolis.png?label=ready&title=Ready)](https://waffle.io/cmmcleod/coriolis) [![Tasks in Progress](https://badge.waffle.io/cmmcleod/coriolis.svg?label=in%20progress&title=In%20Progress)](http://waffle.io/cmmcleod/coriolis)
[![Build Status](https://travis-ci.org/cmmcleod/coriolis.svg?branch=master)](https://travis-ci.org/cmmcleod/coriolis) [![Tasks in Ready](https://badge.waffle.io/cmmcleod/coriolis.png?label=ready&title=Ready)](https://waffle.io/cmmcleod/coriolis) [![Tasks in Progress](https://badge.waffle.io/cmmcleod/coriolis.svg?label=in%20progress&title=In%20Progress)](http://waffle.io/cmmcleod/coriolis)
@@ -6,11 +6,11 @@
The Coriolis project was inspired by [E:D Shipyard](http://www.edshipyard.com/) and, of course, [Elite Dangerous](http://www.elitedangerous.com). The ultimate goal of Coriolis is to provide rich features to support in-game play and planning while engaging the E:D community to support its development.
Coriolis was created for non-commercial purposes. It is not endorsed by nor reflects the views or opinions of Frontier Developments.
Coriolis was created using assets and imagery from Elite: Dangerous, with the permission of Frontier Developments plc, for non-commercial purposes. It is not endorsed by nor reflects the views or opinions of Frontier Developments and no employee of Frontier Developments was involved in the making of it.
## Contributing
Please [submit issues](https://github.com/cmmcleod/coriolis/issues), or better yet [pull requests](http://www.elitedangerous.com) for any corrections or additions to the database or the code.
Please [submit issues](https://github.com/cmmcleod/coriolis/issues), or better yet [pull requests](https://github.com/cmmcleod/coriolis/pulls) for any corrections or additions to the database or the code.
### Feature Requests, Suggestions & Bugs
@@ -23,15 +23,16 @@ See the [Developer's Guide](https://github.com/cmmcleod/coriolis/wiki/Developer'
### Ship and Component Database
See [Data wiki](https://github.com/cmmcleod/coriolis/wiki/Database) for details on structure, etc.
See the [Data wiki](https://github.com/cmmcleod/coriolis-data/wiki) for details on structure, etc.
## License
All Data and [associated JSON](https://github.com/cmmcleod/coriolis/tree/master/data) files are intellectual property and copyright of Frontier Developments plc ('Frontier', 'Frontier Developments') and are subject to their
All Data and [associated JSON](https://github.com/cmmcleod/coriolis-data) files are intellectual property and copyright of Frontier Developments plc ('Frontier', 'Frontier Developments') and are subject to their
[terms and conditions](https://www.frontierstore.net/terms-and-conditions/).
The code specificially for Coriolis.io is released under the MIT License.
The code (Javascript, CSS, HTML, and SVG files only) specificially for Coriolis.io is released under the MIT License.
Copyright (c) 2015 Coriolis.io, Colin McLeod
Permission is hereby granted, free of charge, to any person obtaining a copy

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by IcoMoon.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<path d="M16 0c-8.837 0-16 7.163-16 16s7.163 16 16 16 16-7.163 16-16-7.163-16-16-16zM16 29c-7.18 0-13-5.82-13-13s5.82-13 13-13 13 5.82 13 13-5.82 13-13 13z"></path>
<path d="M21 8l-5 5-5-5-3 3 5 5-5 5 3 3 5-5 5 5 3-3-5-5 5-5z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 554 B

28
app/icons/eddb.svg Normal file
View File

@@ -0,0 +1,28 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" height="400" viewBox="0 0 90 32">
<g>
<path d="M19.1,25.2c0.3,0,0.6,0.1,0.7,0.2c0.2,0.1,0.3,0.3,0.4,0.4c0.1,0.2,0.2,0.4,0.2,0.6v3.3c0,0.3-0.1,0.6-0.2,0.7
c-0.1,0.2-0.3,0.3-0.4,0.3c-0.2,0.1-0.4,0.2-0.6,0.1H3.6c-0.3,0-0.6-0.1-0.7-0.2c-0.2-0.1-0.3-0.3-0.3-0.4
c-0.1-0.2-0.2-0.4-0.1-0.6V10.2c0-0.3,0.1-0.5,0.2-0.7C2.7,9.4,2.9,9.3,3,9.2C3.2,9.1,3.4,9,3.6,9h15.5c0.3,0,0.6,0.1,0.7,0.2
c0.2,0.1,0.3,0.3,0.4,0.4c0.1,0.2,0.2,0.4,0.2,0.6V22c0,0.3-0.1,0.6-0.2,0.7c-0.1,0.2-0.3,0.3-0.4,0.3c-0.2,0.1-0.4,0.2-0.6,0.1
h-6.8v-6.8c0.3-0.2,0.6-0.4,0.8-0.7c0.2-0.3,0.3-0.7,0.3-1c0-0.6-0.2-1.1-0.6-1.4c-0.4-0.4-0.9-0.6-1.4-0.6c-0.5,0-1,0.2-1.4,0.6
c-0.4,0.4-0.6,0.9-0.6,1.4c0,0.8,0.3,1.4,1,1.8v8.7H19.1z"/>
<path d="M24.6,29.7V10.2c0-0.2,0-0.4,0.1-0.6c0.1-0.1,0.2-0.3,0.3-0.4C25.3,9.1,25.5,9,25.8,9h5.5c0.2,0,0.4,0.1,0.6,0.2
c0.1,0.1,0.3,0.2,0.4,0.3c0.1,0.1,0.2,0.4,0.2,0.7v13.2c-0.7,0.4-1,1-1,1.8c0,0.5,0.2,1,0.6,1.4c0.4,0.4,0.9,0.6,1.4,0.6
c0.6,0,1.1-0.2,1.4-0.6c0.4-0.4,0.6-0.9,0.6-1.4c0-0.4-0.1-0.8-0.3-1.1c-0.2-0.3-0.4-0.5-0.8-0.7V2.3c0-0.2,0-0.4,0.1-0.6
c0.1-0.1,0.2-0.3,0.3-0.4C35.2,1.1,35.4,1,35.8,1h5.5c0.2,0,0.4,0.1,0.6,0.2c0.1,0.1,0.3,0.2,0.4,0.4c0.1,0.2,0.2,0.4,0.2,0.7v27.4
c0,0.2-0.1,0.4-0.2,0.6c-0.1,0.1-0.2,0.3-0.4,0.4c-0.2,0.1-0.4,0.2-0.7,0.2H25.8c-0.2,0-0.4,0-0.6-0.1c-0.1-0.1-0.3-0.2-0.4-0.3
C24.7,30.3,24.6,30,24.6,29.7z"/>
<path d="M46.9,29.7V10.2c0-0.2,0-0.4,0.1-0.6c0.1-0.1,0.2-0.3,0.3-0.4C47.5,9.1,47.7,9,48.1,9h5.5c0.2,0,0.4,0.1,0.6,0.2
c0.1,0.1,0.3,0.2,0.4,0.3c0.1,0.1,0.2,0.4,0.2,0.7v13.2c-0.7,0.4-1,1-1,1.8c0,0.5,0.2,1,0.6,1.4c0.4,0.4,0.9,0.6,1.4,0.6
c0.6,0,1.1-0.2,1.4-0.6c0.4-0.4,0.6-0.9,0.6-1.4c0-0.4-0.1-0.8-0.3-1.1c-0.2-0.3-0.4-0.5-0.8-0.7V2.3c0-0.2,0-0.4,0.1-0.6
c0.1-0.1,0.2-0.3,0.3-0.4C57.4,1.1,57.7,1,58,1h5.5c0.2,0,0.4,0.1,0.6,0.2c0.1,0.1,0.3,0.2,0.4,0.4c0.1,0.2,0.2,0.4,0.2,0.7v27.4
c0,0.2-0.1,0.4-0.2,0.6c-0.1,0.1-0.2,0.3-0.4,0.4s-0.4,0.2-0.7,0.2H48.1c-0.2,0-0.4,0-0.6-0.1c-0.1-0.1-0.3-0.2-0.4-0.3
C46.9,30.3,46.9,30,46.9,29.7z"/>
<path d="M87,29.7c0,0.3-0.1,0.6-0.2,0.7c-0.1,0.2-0.3,0.3-0.4,0.3c-0.2,0.1-0.4,0.2-0.6,0.1H70.3c-0.3,0-0.6-0.1-0.7-0.2
s-0.3-0.3-0.3-0.4c-0.1-0.2-0.2-0.4-0.1-0.6V2.3c0-0.3,0.1-0.6,0.2-0.7c0.1-0.2,0.3-0.3,0.4-0.4C69.9,1.1,70.1,1,70.3,1h5.5
c0.3,0,0.6,0.1,0.7,0.2c0.2,0.1,0.3,0.3,0.4,0.4c0.1,0.2,0.2,0.4,0.2,0.6v21.2c-0.7,0.4-1,1-1,1.8c0,0.5,0.2,1,0.6,1.4
c0.4,0.4,0.8,0.6,1.4,0.6c0.6,0,1.1-0.2,1.4-0.6c0.4-0.4,0.6-0.9,0.6-1.4c0-0.4-0.1-0.8-0.3-1.1c-0.2-0.3-0.4-0.5-0.8-0.7V10.2
c0-0.3,0.1-0.5,0.2-0.7c0.1-0.1,0.3-0.3,0.4-0.3C79.8,9.1,80,9,80.2,9h5.5c0.3,0,0.6,0.1,0.7,0.2c0.2,0.1,0.3,0.3,0.4,0.4
C87,9.8,87,10,87,10.2V29.7z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -1,6 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by IcoMoon.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<path d="M18 23l3 3 10-10-10-10-3 3 7 7z"></path>
<path d="M14 9l-3-3-10 10 10 10 3-3-7-7z"></path>

Before

Width:  |  Height:  |  Size: 419 B

After

Width:  |  Height:  |  Size: 248 B

3
app/icons/equalizer.svg Normal file
View File

@@ -0,0 +1,3 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 1024 1024">
<path d="M448 128v-16c0-26.4-21.6-48-48-48h-160c-26.4 0-48 21.6-48 48v16h-192v128h192v16c0 26.4 21.6 48 48 48h160c26.4 0 48-21.6 48-48v-16h576v-128h-576zM256 256v-128h128v128h-128zM832 432c0-26.4-21.6-48-48-48h-160c-26.4 0-48 21.6-48 48v16h-576v128h576v16c0 26.4 21.6 48 48 48h160c26.4 0 48-21.6 48-48v-16h192v-128h-192v-16zM640 576v-128h128v128h-128zM448 752c0-26.4-21.6-48-48-48h-160c-26.4 0-48 21.6-48 48v16h-192v128h192v16c0 26.4 21.6 48 48 48h160c26.4 0 48-21.6 48-48v-16h576v-128h-576v-16zM256 896v-128h128v128h-128z"></path>
</svg>

After

Width:  |  Height:  |  Size: 646 B

View File

@@ -1,6 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by IcoMoon.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<path d="M28 0h-28v32h32v-28l-4-4zM16 4h4v8h-4v-8zM28 28h-24v-24h2v10h18v-10h2.343l1.657 1.657v22.343z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 431 B

After

Width:  |  Height:  |  Size: 260 B

3
app/icons/no-power.svg Normal file
View File

@@ -0,0 +1,3 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512">
<path d="M437.020 74.98c-48.353-48.351-112.64-74.98-181.020-74.98s-132.667 26.629-181.020 74.98c-48.351 48.353-74.98 112.64-74.98 181.020s26.629 132.667 74.98 181.020c48.353 48.351 112.64 74.98 181.020 74.98s132.667-26.629 181.020-74.98c48.351-48.353 74.98-112.64 74.98-181.020s-26.629-132.667-74.98-181.020zM448 256c0 41.407-13.177 79.794-35.556 111.19l-267.633-267.634c31.396-22.379 69.782-35.556 111.189-35.556 105.869 0 192 86.131 192 192zM64 256c0-41.407 13.177-79.793 35.556-111.189l267.635 267.634c-31.397 22.378-69.784 35.555-111.191 35.555-105.869 0-192-86.131-192-192z"></path>
</svg>

After

Width:  |  Height:  |  Size: 697 B

3
app/icons/power.svg Normal file
View File

@@ -0,0 +1,3 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512">
<path d="M192 0l-192 256h192l-128 256 448-320h-256l192-192z"></path>
</svg>

After

Width:  |  Height:  |  Size: 178 B

View File

@@ -1,6 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by IcoMoon.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="33" height="33" viewBox="0 0 33 33">
<path d="M32 12h-12l4.485-4.485c-2.267-2.266-5.28-3.515-8.485-3.515s-6.219 1.248-8.485 3.515c-2.266 2.267-3.515 5.28-3.515 8.485s1.248 6.219 3.515 8.485c2.267 2.266 5.28 3.515 8.485 3.515s6.219-1.248 8.485-3.515c0.189-0.189 0.371-0.384 0.546-0.583l3.010 2.634c-2.933 3.349-7.239 5.464-12.041 5.464-8.837 0-16-7.163-16-16s7.163-16 16-16c4.418 0 8.418 1.791 11.313 4.687l4.687-4.687v12z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 713 B

After

Width:  |  Height:  |  Size: 499 B

View File

@@ -0,0 +1,6 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200">
<g>
<rect x="73.001" y="94.017" width="53.997" height="11.945"/>
<path d="M10.324,185.445l89.217,14.348l0.458,0.077l89.677-14.43L200,99.998l-10.338-89.765L100,0.129L10.34,10.233 L-0.001,99.986L10.324,185.445z M193.206,99.986L100,191.108L6.795,99.986L100,8.868L193.206,99.986z M6.82,107.775l87.583,85.624 l-78.983-12.702L6.82,107.775z M184.583,180.692l-78.992,12.712l87.587-85.634L184.583,180.692z M193.745,92.746L105.26,6.245 l79.339,8.938L193.745,92.746z M15.41,15.185L94.736,6.25L6.255,92.751L15.41,15.185z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 642 B

View File

@@ -0,0 +1,7 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200">
<g>
<path d="M100.002,200C155.139,200,200,155.142,200,100.001c0-55.143-44.861-100.002-99.998-100.002 C44.86-0.001-0.002,44.857-0.002,100.001C-0.001,155.142,44.86,200,100.002,200z M100.002,5.574 c52.063,0,94.423,42.359,94.423,94.427c0,52.067-42.361,94.422-94.423,94.422c-52.07,0-94.428-42.358-94.428-94.422 C5.574,47.933,47.933,5.574,100.002,5.574z"/>
<path d="M100.002,148.557c26.771,0,48.558-21.783,48.558-48.555c0-26.771-21.786-48.556-48.558-48.556 c-26.777,0-48.557,21.782-48.557,48.556C51.446,126.778,73.225,148.557,100.002,148.557z M100.002,57.015 c23.699,0,42.986,19.283,42.986,42.986c0,23.7-19.282,42.987-42.986,42.987c-23.705,0-42.991-19.282-42.991-42.987 C57.011,76.298,76.302,57.015,100.002,57.015z"/>
<rect x="73.404" y="93.985" width="53.197" height="12.033"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 912 B

View File

@@ -0,0 +1,6 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200">
<g>
<path d="M100.002,200c55.138,0,99.996-44.861,99.996-100c0-55.141-44.858-100-99.996-100 C44.861,0-0.001,44.857-0.001,100C0,155.139,44.861,200,100.002,200z M100.002,194.424c-35.465,0-66.413-19.663-82.552-48.651 l44.426-23.388c7.704,13.067,21.888,21.884,38.127,21.884c16.054,0,30.096-8.621,37.853-21.446l44.441,23.389 C166.092,174.961,135.282,194.424,100.002,194.424z M100.002,61.306c21.335,0,38.691,17.356,38.691,38.694 c0,21.338-17.364,38.691-38.691,38.691c-21.339,0-38.696-17.354-38.696-38.691C61.307,78.662,78.663,61.306,100.002,61.306z M194.422,100c0,14.802-3.427,28.808-9.521,41.287l-44.447-23.4c2.433-5.477,3.812-11.521,3.812-17.89 c0-23.578-18.539-42.852-41.8-44.145V5.636C153.392,6.956,194.422,48.762,194.422,100z M96.895,5.655v50.233 C73.938,57.491,55.73,76.635,55.73,100c0,6.187,1.286,12.081,3.592,17.434l-44.455,23.402C8.911,128.472,5.571,114.619,5.571,100 C5.577,48.972,46.261,7.297,96.895,5.655z"/>
<rect x="73.403" y="93.983" width="53.196" height="12.032"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,7 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200">
<g>
<path d="M145.137,59.126h4.498v6.995h5.576V46.556h-5.576v6.994h-4.498V16.328h-5.574v57.667h-15.411v14.824h-7.63 v-14.58h-13.044v14.58h-8.295v-14.58H82.138v14.58h-6.573v-14.58H59.072v14.58h-6.573v-14.58H39.458v36.338h13.041V94.391h6.573 v16.186h16.493V94.391h6.573v16.186h13.044V94.391h8.295v16.186h13.044V94.391h7.63v40.457l17.634,17.637h13.185v31.182h5.577 V73.996H145.14v-14.87H145.137z M154.97,146.907h-10.871l-14.376-14.376V79.57h25.247V146.907z"/>
<rect fill="#999999" x="147.703" y="16.328" width="5.572" height="7.345"/>
<rect fill="#999999" x="131.295" y="16.328" width="5.577" height="7.345"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 744 B

View File

@@ -1,6 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by IcoMoon.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="33" height="33" viewBox="0 0 33 33">
<path d="M20 4.581v4.249c1.131 0.494 2.172 1.2 3.071 2.099 1.889 1.889 2.929 4.4 2.929 7.071s-1.040 5.182-2.929 7.071c-1.889 1.889-4.4 2.929-7.071 2.929s-5.182-1.040-7.071-2.929c-1.889-1.889-2.929-4.4-2.929-7.071s1.040-5.182 2.929-7.071c0.899-0.899 1.94-1.606 3.071-2.099v-4.249c-5.783 1.721-10 7.077-10 13.419 0 7.732 6.268 14 14 14s14-6.268 14-14c0-6.342-4.217-11.698-10-13.419zM14 0h4v16h-4z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 723 B

After

Width:  |  Height:  |  Size: 510 B

View File

@@ -5,9 +5,9 @@
<link rel="stylesheet" href="/app.css">
<!-- Standard headers -->
<meta name="description" content="A ship outfitting and comparison tool for Elite Dangerous">
<meta name="description" content="A ship builder, outfitting and comparison tool for Elite Dangerous">
<meta name="mobile-web-app-capable" content="yes">
<meta name="viewport" content="width = device-width, initial-scale = 1.0">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="manifest" href="/images/logo/manifest.json">
<link rel="icon" sizes="152x152 192x192" type="image/png" href="/images/logo/192x192.png">
<link rel="shortcut icon" href="/images/logo/favicon.ico">
@@ -18,7 +18,6 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link rel="apple-touch-icon-precomposed" sizes="180x180" href="/images/logo/apple-touch-icon-precomposed.png">
<link rel="apple-touch-icon" href="/images/logo/apple-touch-icon.png">
<link rel="apple-touch-icon" sizes="180x180" href="/images/logo/apple-touch-icon-180x180.png">
<!-- iPhone, iPod Touch, portrait -->
<link href="/images/splash/320x460.png" media="(device-width: 320px) and (device-height: 480px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 1)" rel="apple-touch-startup-image">
<!-- iPhone, iPod Touch, landscape -->
@@ -57,16 +56,16 @@
<body style="background-color:#000;">
<div style="height: 0; width: 0; overflow:hidden"><%= svgContent %></div>
<shipyard-header></shipyard-header>
<div id="main" ui-view ng-click="bgClicked($event)"></div>
<div id="main" ui-view ng-click="bgClicked($event)" ng-style="{'font-size': sizeRatio + 'em'}"></div>
<div ui-view="modal" ng-click="bgClicked($event)"></div>
<footer>
<div class="right">
<a href="https://github.com/cmmcleod/coriolis" target="_blank" title="Coriolis Github Project">Version <%= version %> - <%= date %></a>
<div class="right cap">
<a href="https://github.com/cmmcleod/coriolis/releases/" target="_blank" title="Coriolis Github Project"><span translate="version"></span> <%= version %> - <%= date %></a>
</div>
<div style="max-width:50%" class="l">
Coriolis Shipyard was created for non-commercial purposes. It is not endorsed by nor reflects the views or opinions of Frontier Developments.
Coriolis was created using assets and imagery from Elite: Dangerous, with the permission of Frontier Developments plc, for non-commercial purposes. It is not endorsed by nor reflects the views or opinions of Frontier Developments and no employee of Frontier Developments was involved in the making of it.
</div>
</footer>

View File

@@ -1,8 +1,14 @@
angular.module('app', ['ui.router', 'ct.ui.router.extras.sticky', 'ui.sortable', 'shipyard', 'ngLodash', 'app.templates'])
.run(['$rootScope', '$location', '$window', '$document', '$state', 'commonArray', 'shipPurpose', 'shipSize', 'hardPointClass', 'GroupMap', 'Persist',
function($rootScope, $location, $window, $doc, $state, CArr, shipPurpose, sz, hpc, GroupMap, Persist) {
angular.module('app', ['ui.router', 'ct.ui.router.extras.sticky', 'ui.sortable', 'shipyard', 'ngLodash', 'app.templates', 'pascalprecht.translate'])
.run(['$rootScope', '$location', '$window', '$document', '$state', '$translate', 'localeFormat', 'Persist', 'Discounts', 'Languages', 'SizeMap',
function($rootScope, $location, $window, $doc, $state, $translate, localeFormat, Persist, Discounts, Languages, SizeMap) {
// App is running as a standalone web app on tablet/mobile
var isStandAlone = $window.navigator.standalone || ($window.external && $window.external.msIsSiteMode && $window.external.msIsSiteMode());
var isStandAlone;
// This was causing issues on Windows phones ($window.external was causing Angular js to throw an exception). Backup is to try this and set isStandAlone to false if this fails.
try {
isStandAlone = $window.navigator.standalone || ($window.external && $window.external.msIsSiteMode && $window.external.msIsSiteMode());
} catch (ex) {
isStandAlone = false;
}
// Redirect any state transition errors to the error controller/state
$rootScope.$on('$stateChangeError', function(e, toState, toParams, fromState, fromParams, error) {
@@ -15,7 +21,6 @@ function($rootScope, $location, $window, $doc, $state, CArr, shipPurpose, sz, hp
$rootScope.prevState = { name: from.name, params: fromParams };
if (to.url) { // Only track states that have a URL
if ($window.ga) {
ga('send', 'pageview', { page: $location.path() });
}
@@ -27,42 +32,50 @@ function($rootScope, $location, $window, $doc, $state, CArr, shipPurpose, sz, hp
}
});
$rootScope.language = {
opts: Languages,
current: Languages[Persist.getLangCode()] ? Persist.getLangCode() : 'en'
};
$rootScope.localeFormat = d3.locale(localeFormat.get($rootScope.language.current));
updateNumberFormat();
// Global Reference variables
$rootScope.CArr = CArr;
$rootScope.SP = shipPurpose;
$rootScope.SZ = sz;
$rootScope.HPC = hpc;
$rootScope.GMAP = GroupMap;
$rootScope.insurance = { opts: [{ name: 'Standard', pct: 0.05 }, { name: 'Alpha', pct: 0.025 }, { name: 'Beta', pct: 0.035 }] };
$rootScope.discounts = { opts: [{ name: 'None', pct: 1 }, { name: 'Founders World - 10%', pct: 0.90 }] };
$rootScope.STATUS = ['', 'DISABLED', 'OFF', 'ON'];
$rootScope.STATUS_CLASS = ['', 'disabled', 'warning', 'secondary-disabled'];
$rootScope.insurance = { opts: [{ name: 'standard', pct: 0.05 }, { name: 'alpha', pct: 0.025 }, { name: 'beta', pct: 0.0375 }] };
$rootScope.discounts = { opts: Discounts };
$rootScope.sizeRatio = Persist.getSizeRatio();
$rootScope.SZM = SizeMap;
$rootScope.title = 'Coriolis';
$rootScope.cName = function(c) {
return c.c ? c.c.name ? c.c.name : GroupMap[c.c.grp] : null;
$rootScope.changeLanguage = function() {
$translate.use($rootScope.language.current);
$rootScope.localeFormat = d3.locale(localeFormat.get($rootScope.language.current));
updateNumberFormat();
$rootScope.$broadcast('languageChanged', $rootScope.language.current);
};
// Formatters
$rootScope.fCrd = d3.format(',.0f');
$rootScope.fPwr = d3.format(',.2f');
$rootScope.fRound = function(d) { return d3.round(d, 2); };
$rootScope.fRound4 = function(d) { return d3.round(d, 4); };
$rootScope.fPct = d3.format('.2%');
$rootScope.f1Pct = d3.format('.1%');
$rootScope.fRPct = d3.format('%');
$rootScope.fTime = function(d) { return Math.floor(d / 60) + ':' + ('00' + Math.floor(d % 60)).substr(-2, 2); };
if (isStandAlone) {
var state = Persist.getState();
// If a previous state has been stored, load that state
if (state && state.name && state.params) {
$state.go(state.name, state.params, { location: 'replace' });
} else {
$state.go('shipyard', null, { location: 'replace' }); // Default to home page
}
function updateNumberFormat() {
var locale = $rootScope.localeFormat;
var fGen = $rootScope.fGen = locale.numberFormat('n');
$rootScope.fCrd = locale.numberFormat(',.0f');
$rootScope.fPwr = locale.numberFormat(',.2f');
$rootScope.fRound = function(d) { return fGen(d3.round(d, 2)); };
$rootScope.fPct = locale.numberFormat('.2%');
$rootScope.f1Pct = locale.numberFormat('.1%');
}
/**
* Returns the name of the component mounted in the specified slot
* @param {Object} slot The slot object
* @return {String} The component name
*/
$rootScope.cName = function(slot) {
return $translate.instant(slot.c ? slot.c.name ? slot.c.name : slot.c.grp : null);
};
// Global Event Listeners
$doc.bind('keyup', function(e) {
if (e.keyCode == 27) { // Escape Key
@@ -88,4 +101,14 @@ function($rootScope, $location, $window, $doc, $state, CArr, shipPurpose, sz, hp
}, false);
}
if (isStandAlone) {
var state = Persist.getState();
// If a previous state has been stored, load that state
if (state && state.name && state.params) {
$state.go(state.name, state.params, { location: 'replace' });
} else {
$state.go('shipyard', null, { location: 'replace' }); // Default to home page
}
}
}]);

View File

@@ -4,6 +4,7 @@
angular.module('app').config(['$provide', '$stateProvider', '$urlRouterProvider', '$locationProvider', 'ShipsDB', function($provide, $stateProvider, $urlRouterProvider, $locationProvider, ships) {
// Use HTML5 push and replace state if possible
$locationProvider.html5Mode({ enabled: true, requireBase: false });
/**
* Set up all states and their routes.
*/
@@ -46,7 +47,7 @@ angular.module('app').config(['$provide', '$stateProvider', '$urlRouterProvider'
// Modal States and views
.state('modal', { abstract: true, views: { 'modal': { templateUrl: 'views/_modal.html', controller: 'ModalController' } } })
.state('modal.about', { views: { 'modal-content': { templateUrl: 'views/modal-about.html' } } })
.state('modal.export', { params: { title: null, data: null, promise: null }, views: { 'modal-content': { templateUrl: 'views/modal-export.html', controller: 'ExportController' } } })
.state('modal.export', { params: { title: null, data: null, promise: null, description: null }, views: { 'modal-content': { templateUrl: 'views/modal-export.html', controller: 'ExportController' } } })
.state('modal.import', { params: { obj: null }, views: { 'modal-content': { templateUrl: 'views/modal-import.html', controller: 'ImportController' } } })
.state('modal.link', { params: { url: null }, views: { 'modal-content': { templateUrl: 'views/modal-link.html', controller: 'LinkController' } } })
.state('modal.delete', { views: { 'modal-content': { templateUrl: 'views/modal-delete.html', controller: 'DeleteController' } } });

View File

@@ -1,4 +1,4 @@
angular.module('app').controller('ComparisonController', ['lodash', '$rootScope', '$filter', '$scope', '$state', '$stateParams', 'Utils', 'ShipFacets', 'ShipsDB', 'Ship', 'Persist', 'Serializer', function(_, $rootScope, $filter, $scope, $state, $stateParams, Utils, ShipFacets, Ships, Ship, Persist, Serializer) {
angular.module('app').controller('ComparisonController', ['lodash', '$rootScope', '$filter', '$scope', '$state', '$stateParams', '$translate', 'Utils', 'ShipFacets', 'ShipsDB', 'Ship', 'Persist', 'Serializer', function(_, $rootScope, $filter, $scope, $state, $stateParams, $translate, Utils, ShipFacets, Ships, Ship, Persist, Serializer) {
$rootScope.title = 'Coriolis - Compare';
$scope.predicate = 'name'; // Sort by ship name as default
$scope.desc = false;
@@ -20,6 +20,11 @@ angular.module('app').controller('ComparisonController', ['lodash', '$rootScope'
$scope.addBuild = function(id, name, code) {
var data = Ships[id]; // Get ship properties
code = code ? code : Persist.builds[id][name]; // Retrieve build code if not passed
if (!code) { // No build found
return;
}
var b = new Ship(id, data.properties, data.slots); // Create a new Ship instance
Serializer.toShip(b, code); // Populate components from code
// Extend ship instance and add properties below
@@ -155,7 +160,7 @@ angular.module('app').controller('ComparisonController', ['lodash', '$rootScope'
return 'Error - ' + err.statusText;
}
);
$state.go('modal.export', { promise: promise, title: 'Forum BBCode' });
$state.go('modal.export', { promise: promise, title: $translate.instant('FORUM') + ' BBCode' });
};
/**
@@ -184,6 +189,10 @@ angular.module('app').controller('ComparisonController', ['lodash', '$rootScope'
$scope.showBuilds = false;
});
$scope.$on('languageChanged', function() {
$scope.tblUpdate = !$scope.tblUpdate; // Simple switch to trigger the table to update
});
/* Initialization */
if ($scope.compareMode) {
if ($scope.name == 'all') {
@@ -226,7 +235,7 @@ angular.module('app').controller('ComparisonController', ['lodash', '$rootScope'
}
}
// Replace fmt with actual format function as defined in rootScope and retain original index
facets.forEach(function(f, i) { f.fmt = $rootScope[f.fmt]; f.index = i; });
facets.forEach(function(f, i) { f.index = i; });
// Remove default facets, mark as active, and add them back in selected order
_.pullAt(facets, defaultFacets).forEach(function(f) { f.active = true; facets.unshift(f); });
$scope.builds = $filter('orderBy')($scope.builds, $scope.predicate, $scope.desc);

View File

@@ -1,11 +1,12 @@
angular.module('app').controller('ExportController', ['$scope', '$stateParams', function($scope, $stateParams) {
$scope.title = $stateParams.title || 'Export';
$scope.description = $stateParams.description;
if ($stateParams.promise) {
$scope.export = 'Generating...';
$stateParams.promise.then(function(data) {
$scope.export = data;
$scope.export = (typeof data === 'object') ? angular.toJson(data, true) : data;
});
} else {
$scope.export = angular.toJson($stateParams.data, true);

View File

@@ -1,92 +1,307 @@
angular.module('app').controller('ImportController', ['$scope', '$stateParams', 'ShipsDB', 'Ship', 'Persist', 'Serializer', function($scope, $stateParams, Ships, Ship, Persist, Serializer) {
$scope.jsonValid = false;
$scope.importData = null;
angular.module('app').controller('ImportController', ['lodash', '$rootScope', '$scope', '$stateParams', 'ShipsDB', 'Ship', 'Components', 'GroupMap', 'Persist', 'Serializer', function(_, $rootScope, $scope, $stateParams, Ships, Ship, Components, GroupMap, Persist, Serializer) {
$scope.importValid = false;
$scope.importString = null;
$scope.errorMsg = null;
$scope.canEdit = true;
$scope.builds = $stateParams.obj || null;
$scope.ships = Ships;
$scope.validateJson = function() {
var importObj = null;
$scope.jsonValid = false;
$scope.errorMsg = null;
$scope.builds = null;
var textBuildRegex = new RegExp('^\\[([\\w \\-]+)\\]\n');
var lineRegex = new RegExp('^([\\dA-Z]{1,2}): (\\d)([A-I])[/]?([FGT])?([SD])? ([\\w\\- ]+)');
var mountMap = { 'H': 4, 'L': 3, 'M': 2, 'S': 1, 'U': 0 };
var standardMap = { 'RB': 0, 'TM': 1, 'FH': 2, 'EC': 3, 'PC': 4, 'SS': 5, 'FS': 6 };
var bhMap = { 'lightweight alloy': 0, 'reinforced alloy': 1, 'military grade composite': 2, 'mirrored surface composite': 3, 'reactive surface composite': 4 };
if (!$scope.importData) { return; }
function isEmptySlot(slot) {
return slot.maxClass == this && slot.c === null;
}
function equalsIgnoreCase(str) {
return str.toLowerCase() == this.toLowerCase();
}
function validateBuild(shipId, code, name) {
var shipData = Ships[shipId];
if (!shipData) {
throw '"' + shipId + '" is not a valid Ship Id!';
}
if (typeof name != 'string' || name.length == 0) {
throw shipData.properties.name + ' build "' + name + '" must be a string at least 1 character long!';
}
if (typeof code != 'string' || code.length < 10) {
throw shipData.properties.name + ' build "' + name + '" is not valid!';
}
try {
Serializer.toShip(new Ship(shipId, shipData.properties, shipData.slots), code);
} catch (e) {
throw shipData.properties.name + ' build "' + name + '" is not valid!';
}
}
function detailedJsonToBuild(detailedBuild) {
var ship;
if (!detailedBuild.name) {
throw 'Build Name missing!';
}
if (!detailedBuild.name.trim()) {
throw 'Build Name must be a string at least 1 character long!';
}
try {
importObj = angular.fromJson($scope.importData);
ship = Serializer.fromDetailedBuild(detailedBuild);
} catch (e) {
$scope.errorMsg = 'Cannot Parse JSON!';
return;
throw detailedBuild.ship + ' Build "' + detailedBuild.name + '": Invalid data';
}
if (typeof importObj != 'object') {
$scope.errorMsg = 'Must be an object!';
return;
}
return { shipId: ship.id, name: detailedBuild.name, code: Serializer.fromShip(ship) };
}
if ((!importObj.builds || !Object.keys(importObj.builds).length)) {
$scope.errorMsg = 'No builds in data';
return;
function importBackup(importData) {
if (importData.builds && typeof importData.builds == 'object') {
for (var shipId in importData.builds) {
for (var buildName in importData.builds[shipId]) {
validateBuild(shipId, importData.builds[shipId][buildName], buildName);
}
}
$scope.builds = importData.builds;
} else {
throw 'builds must be an object!';
}
for (var shipId in importObj.builds) {
var shipData = Ships[shipId];
if (shipData) {
for (var buildName in importObj.builds[shipId]) {
if (typeof importObj.builds[shipId][buildName] != 'string') {
$scope.errorMsg = shipData.properties.name + ' build "' + buildName + '" must be a string!';
return;
}
try {
// Actually build the ship with the code to ensure it's valid
Serializer.toShip(new Ship(shipId, shipData.properties, shipData.slots), importObj.builds[shipId][buildName]);
} catch (e) {
$scope.errorMsg = shipData.properties.name + ' build "' + buildName + '" is not valid!';
return;
if (importData.comparisons) {
for (var compName in importData.comparisons) {
var comparison = importData.comparisons[compName];
for (var i = 0, l = comparison.builds.length; i < l; i++) {
var build = comparison.builds[i];
if (!importData.builds[build.shipId] || !importData.builds[build.shipId][build.buildName]) {
throw build.shipId + ' build "' + build.buildName + '" data is missing!';
}
}
} else {
$scope.errorMsg = '"' + shipId + '"" is not a valid Ship Id!';
return;
}
$scope.builds = importObj.builds;
$scope.comparisons = importData.comparisons;
}
if (importData.discounts instanceof Array && importData.discounts.length == 2) {
$scope.discounts = importData.discounts;
}
if (typeof importData.insurance == 'string' && importData.insurance.length > 3) {
$scope.insurance = importData.insurance;
}
}
function importDetailedArray(importArr) {
var builds = {};
for (var i = 0, l = importArr.length; i < l; i++) {
var build = detailedJsonToBuild(importArr[i]);
if (!builds[build.shipId]) {
builds[build.shipId] = {};
}
builds[build.shipId][build.name] = build.code;
}
$scope.builds = builds;
}
function importTextBuild(buildStr) {
var buildName = textBuildRegex.exec(buildStr)[1].trim();
var shipName = buildName.toLowerCase();
var shipId = null;
for (var sId in Ships) {
if (Ships[sId].properties.name.toLowerCase() == shipName) {
shipId = sId;
break;
}
}
$scope.jsonValid = true;
if (!shipId) { throw 'No such ship found: "' + buildName + '"'; }
var lines = buildStr.split('\n');
var ship = new Ship(shipId, Ships[shipId].properties, Ships[shipId].slots);
ship.buildWith(null);
for (var i = 1; i < lines.length; i++) {
var line = lines[i].trim();
if (!line) { continue; }
if (line.substring(0, 3) == '---') { break; }
var parts = lineRegex.exec(line);
if (!parts) { throw 'Error parsing: "' + line + '"'; }
var typeSize = parts[1];
var cl = parts[2];
var rating = parts[3];
var mount = parts[4];
var missile = parts[5];
var name = parts[6].trim();
var slot, group;
if (isNaN(typeSize)) { // Standard or Hardpoint
if (typeSize.length == 1) { // Hardpoint
var slotClass = mountMap[typeSize];
if (cl > slotClass) { throw cl + rating + ' ' + name + ' exceeds slot size: "' + line + '"'; }
slot = _.find(ship.hardpoints, isEmptySlot, slotClass);
if (!slot) { throw 'No hardpoint slot available for: "' + line + '"'; }
group = _.find(GroupMap, equalsIgnoreCase, name);
var hp = Components.findHardpoint(group, cl, rating, group ? null : name, mount, missile);
if (!hp) { throw 'Unknown component: "' + line + '"'; }
ship.use(slot, hp.id, hp, true);
} else if (typeSize == 'BH') {
var bhId = bhMap[name.toLowerCase()];
if (bhId === undefined) { throw 'Unknown bulkhead: "' + line + '"'; }
ship.useBulkhead(bhId, true);
} else if (standardMap[typeSize] != undefined) {
var standardIndex = standardMap[typeSize];
if (ship.standard[standardIndex].maxClass < cl) { throw name + ' exceeds max class for the ' + ship.name; }
ship.use(ship.standard[standardIndex], cl + rating, Components.standard(standardIndex, cl + rating), true);
} else {
throw 'Unknown component: "' + line + '"';
}
} else {
if (cl > typeSize) { throw cl + rating + ' ' + name + ' exceeds slot size: "' + line + '"'; }
slot = _.find(ship.internal, isEmptySlot, typeSize);
if (!slot) { throw 'No internal slot available for: "' + line + '"'; }
group = _.find(GroupMap, equalsIgnoreCase, name);
var intComp = Components.findInternal(group, cl, rating, group ? null : name);
if (!intComp) { throw 'Unknown component: "' + line + '"'; }
ship.use(slot, intComp.id, intComp);
}
}
var builds = {};
builds[shipId] = {};
builds[shipId]['Imported ' + buildName] = Serializer.fromShip(ship);
$scope.builds = builds;
}
$scope.validateImport = function() {
var importData = null;
var importString = $scope.importString.trim();
$scope.importValid = false;
$scope.errorMsg = null;
$scope.builds = $scope.discounts = $scope.comparisons = $scope.insurance = null;
if (!importString) { return; }
try {
if (textBuildRegex.test(importString)) { // E:D Shipyard build text
importTextBuild(importString);
} else { // JSON Build data
importData = angular.fromJson($scope.importString);
if (!importData || typeof importData != 'object') {
throw 'Must be an object or array!';
}
if (importData instanceof Array) { // Must be detailed export json
importDetailedArray(importData);
} else if (importData.ship && typeof importData.name !== undefined) { // Using JSON from a single ship build export
importDetailedArray([importData]); // Convert to array with singleobject
} else { // Using Backup JSON
importBackup(importData);
}
}
} catch (e) {
$scope.errorMsg = (typeof e == 'string') ? e : 'Cannot Parse the data!';
return;
}
$scope.importValid = true;
};
$scope.hasBuild = function(shipId, name) {
return Persist.getBuild(shipId, name) !== null;
};
$scope.hasComparison = function(name) {
return Persist.getComparison(name) !== null;
};
$scope.process = function() {
var builds = $scope.builds;
for (var shipId in builds) {
for (var buildName in builds[shipId]) {
var code = builds[shipId][buildName];
// Update builds object such that orginal name retained, but can be renamed
builds[shipId][buildName] = {
code: code,
useName: buildName
};
if ($scope.builds) {
var builds = $scope.builds;
for (var shipId in builds) {
for (var buildName in builds[shipId]) {
var code = builds[shipId][buildName];
// Update builds object such that orginal name retained, but can be renamed
builds[shipId][buildName] = {
code: code,
useName: buildName
};
}
}
}
if ($scope.comparisons) {
var comparisons = $scope.comparisons;
for (var name in comparisons) {
comparisons[name].useName = name;
}
}
$scope.processed = true;
};
$scope.import = function() {
var builds = $scope.builds;
for (var shipId in builds) {
for (var buildName in builds[shipId]) {
var build = builds[shipId][buildName];
var name = build.useName.trim();
if (name) {
Persist.saveBuild(shipId, name, build.code);
if ($scope.builds) {
var builds = $scope.builds;
for (var shipId in builds) {
for (var buildName in builds[shipId]) {
var build = builds[shipId][buildName];
var name = build.useName.trim();
if (name) {
Persist.saveBuild(shipId, name, build.code);
}
}
}
}
if ($scope.comparisons) {
var comparisons = $scope.comparisons;
for (var comp in comparisons) {
var comparison = comparisons[comp];
var useName = comparison.useName.trim();
if (useName) {
Persist.saveComparison(useName, comparison.builds, comparison.facets);
}
}
}
if ($scope.discounts) {
$rootScope.discounts.ship = $scope.discounts[0];
$rootScope.discounts.components = $scope.discounts[1];
$rootScope.$broadcast('discountChange');
Persist.setDiscount($scope.discounts);
}
if ($scope.insurance) {
$rootScope.insurance.current = $scope.insurance;
Persist.setInsurance($scope.insurance);
}
$scope.$parent.dismiss();
};

View File

@@ -1,7 +1,8 @@
angular.module('app').controller('OutfitController', ['$window', '$rootScope', '$scope', '$state', '$stateParams', 'ShipsDB', 'Ship', 'Components', 'Serializer', 'Persist', function($window, $rootScope, $scope, $state, $p, Ships, Ship, Components, Serializer, Persist) {
angular.module('app').controller('OutfitController', ['$window', '$rootScope', '$scope', '$state', '$stateParams', '$translate', 'ShipsDB', 'Ship', 'Components', 'Serializer', 'Persist', 'calcTotalRange', 'calcSpeed', function($window, $rootScope, $scope, $state, $p, $translate, Ships, Ship, Components, Serializer, Persist, calcTotalRange, calcSpeed) {
var win = angular.element($window); // Angularized window object for event triggering
var data = Ships[$p.shipId]; // Retrieve the basic ship properties, slots and defaults
var ship = new Ship($p.shipId, data.properties, data.slots); // Create a new Ship instance
var win = angular.element($window); // Angularized window object for event triggering
var retrofitShip = new Ship($p.shipId, data.properties, data.slots); // Create a new Ship for retrofit comparison
// Update the ship instance with the code (if provided) or the 'factory' defaults.
if ($p.code) {
@@ -11,53 +12,116 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
ship.buildWith(data.defaults); // Populate with default components
}
$scope.buildName = $p.bn;
$scope.buildName = $p.bn ? $window.decodeURIComponent($p.bn) : null;
$scope.ships = Ships;
$rootScope.title = ship.name + ($scope.buildName ? ' - ' + $scope.buildName : '');
$scope.ship = ship;
$scope.pp = ship.common[0]; // Power Plant
$scope.th = ship.common[1]; // Thruster
$scope.fsd = ship.common[2]; // Frame Shrift Drive
$scope.ls = ship.common[3]; // Life Support
$scope.pd = ship.common[4]; // Power Distributor
$scope.ss = ship.common[5]; // Sensors
$scope.ft = ship.common[6]; // Fuel Tank
$scope.pp = ship.standard[0]; // Power Plant
$scope.th = ship.standard[1]; // Thruster
$scope.fsd = ship.standard[2]; // Frame Shrift Drive
$scope.ls = ship.standard[3]; // Life Support
$scope.pd = ship.standard[4]; // Power Distributor
$scope.ss = ship.standard[5]; // Sensors
$scope.ft = ship.standard[6]; // Fuel Tank
$scope.hps = ship.hardpoints;
$scope.internal = ship.internal;
$scope.costList = ship.costList;
$scope.powerList = ship.powerList;
$scope.priorityBands = ship.priorityBands;
$scope.availCS = Components.forShip(ship.id);
$scope.availCS = ship.getAvailableComponents();
$scope.selectedSlot = null;
$scope.savedCode = Persist.getBuild(ship.id, $scope.buildName);
$scope.canSave = Persist.isEnabled();
$scope.allBuilds = Persist.builds;
$scope.fuel = 0;
$scope.pwrDesc = false;
$scope.pwrPredicate = 'type';
$scope.retroDesc = false;
$scope.retroPredicate = 'netCost';
$scope.costDesc = true;
$scope.costPredicate = 'c.cost';
$scope.ammoDesc = true;
$scope.ammoPredicate = 'ammoUnitCost';
$scope.costTab = Persist.getCostTab() || 'costs';
if ($scope.savedCode) {
Serializer.toShip(retrofitShip, $scope.savedCode); // Populate components from last save
$scope.retrofitBuild = $scope.buildName;
} else {
retrofitShip.buildWith(data.defaults);
$scope.retrofitBuild = null;
}
ship.applyDiscounts($rootScope.discounts.ship, $rootScope.discounts.components);
retrofitShip.applyDiscounts($rootScope.discounts.ship, $rootScope.discounts.components);
updateRetrofitCosts();
$scope.jrSeries = {
xMin: 0,
xMax: ship.cargoCapacity,
// Slightly higher than actual based bacuse components are excluded
yMax: ship.jumpRangeWithMass(ship.unladenMass),
yMax: ship.unladenRange,
yMin: 0,
func: function(cargo) { // X Axis is Cargo
return ship.jumpRangeWithMass(ship.unladenMass + $scope.fuel + cargo, $scope.fuel);
return ship.getJumpRangeForMass(ship.unladenMass + $scope.fuel + cargo, $scope.fuel);
}
};
$scope.jrChart = {
labels: {
xAxis: {
title: 'Cargo',
title: 'cargo',
unit: 'T'
},
yAxis: {
title: 'Jump Range',
title: 'jump range',
unit: 'LY'
}
},
watch: $scope.fsd
}
};
$scope.trSeries = {
xMin: 0,
xMax: ship.cargoCapacity,
yMax: ship.unladenTotalRange,
yMin: 0,
func: function(cargo) { // X Axis is Cargo
return calcTotalRange(ship.unladenMass + cargo, $scope.fsd.c, $scope.fuel);
}
};
$scope.trChart = {
labels: {
xAxis: {
title: 'cargo',
unit: 'T'
},
yAxis: {
title: 'total range',
unit: 'LY'
}
}
};
$scope.speedSeries = {
xMin: 0,
xMax: ship.cargoCapacity,
yMax: calcSpeed(ship.unladenMass, ship.speed, ship.boost, $scope.th.c, ship.pipSpeed).boost,
yMin: 0,
series: ['boost', '4 Pips', '2 Pips', '0 Pips'],
colors: ['#0088d2', '#ff8c0d', '#D26D00', '#c06400'],
func: function(cargo) { // X Axis is Cargo
return calcSpeed(ship.unladenMass + $scope.fuel + cargo, ship.speed, ship.boost, $scope.th.c, ship.pipSpeed);
}
};
$scope.speedChart = {
labels: {
xAxis: {
title: 'cargo',
unit: 'T'
},
yAxis: {
title: 'speed',
unit: 'm/s'
}
}
};
/**
@@ -85,7 +149,16 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
*/
$scope.select = function(type, slot, e, id) {
e.stopPropagation();
id = id || angular.element(e.target).attr('cpid'); // Get component ID
if (!id) { // Find component id if not passed
var elem = e.target;
while (elem && elem !== e.currentTarget && !elem.getAttribute('cpid')) {
elem = elem.parentElement;
}
if (elem) {
id = elem.getAttribute('cpid');
}
}
if (id) {
if (id == 'empty') {
@@ -93,15 +166,14 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
} else if (type == 'h') {
ship.use(slot, id, Components.hardpoints(id));
} else if (type == 'c') {
ship.use(slot, id, Components.common(ship.common.indexOf(slot), id));
ship.use(slot, id, Components.standard(ship.standard.indexOf(slot), id));
} else if (type == 'i') {
ship.use(slot, id, Components.internal(id));
} else if (type == 'b') {
ship.useBulkhead(id);
}
$scope.selectedSlot = null;
$scope.code = Serializer.fromShip(ship);
updateState();
updateState(Serializer.fromShip(ship));
}
};
@@ -111,11 +183,165 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
$scope.reloadBuild = function() {
if ($scope.buildName && $scope.savedCode) {
Serializer.toShip(ship, $scope.savedCode); // Repopulate with components from last save
$scope.code = $scope.savedCode;
updateState();
updateState($scope.savedCode);
}
};
$scope.resetBuild = function() {
ship.buildWith(data.defaults); // Populate with default components
updateState(null);
};
/**
* Optimize for the lower mass build that can still boost and power the ship
* without power management.
*/
$scope.optimizeMassBuild = function() {
updateState(Serializer.fromShip(ship.optimizeMass()));
};
/**
* Optimize for the lower mass build that can still boost and power the ship
* without power management.
*/
$scope.optimizeStandard = function() {
updateState(Serializer.fromShip(ship.useLightestStandard()));
};
$scope.useStandard = function(rating) {
updateState(Serializer.fromShip(ship.useStandard(rating)));
};
$scope.useHardpoint = function(group, mount, clobber, missile) {
updateState(Serializer.fromShip(ship.useWeapon(group, mount, clobber, missile)));
};
$scope.useUtility = function(group, rating, clobber) {
updateState(Serializer.fromShip(ship.useUtility(group, rating, clobber)));
};
$scope.emptyInternal = function() {
updateState(Serializer.fromShip(ship.emptyInternal()));
};
$scope.emptyHardpoints = function() {
updateState(Serializer.fromShip(ship.emptyWeapons()));
};
$scope.emptyUtility = function() {
updateState(Serializer.fromShip(ship.emptyUtility()));
};
$scope.fillWithCargo = function() {
ship.internal.forEach(function(slot) {
var id = Components.findInternalId('cr', slot.maxClass, 'E');
if (!slot.c) {
ship.use(slot, id, Components.internal(id));
}
});
updateState(Serializer.fromShip(ship));
};
$scope.fillWithCells = function() {
var chargeCap = 0; // Capacity of single activation
ship.internal.forEach(function(slot) {
var id = Components.findInternalId('scb', slot.maxClass, 'A');
if (!slot.c && (!slot.eligible || slot.eligible.scb)) { // Check eligibility because of Orca, don't overwrite generator
ship.use(slot, id, Components.internal(id));
chargeCap += Components.internal(id).recharge;
ship.setSlotEnabled(slot, chargeCap <= ship.shieldStrength); // Don't waste cell capacity on overcharge
}
});
updateState(Serializer.fromShip(ship));
};
$scope.fillWithArmor = function() {
ship.internal.forEach(function(slot) {
var hr = Components.findInternal('hr', Math.min(slot.maxClass, 5), 'D'); // Hull reinforcements top out at 5D
if (!slot.c && hr) {
ship.use(slot, hr.id, hr);
}
});
updateState(Serializer.fromShip(ship));
};
/**
* Fill all internal slots with Cargo Racks, and optmize internal components.
* Hardpoints are not altered.
*/
$scope.optimizeCargo = function() {
ship.internal.forEach(function(slot) {
var id = Components.findInternalId('cr', slot.maxClass, 'E');
ship.use(slot, id, Components.internal(id));
});
ship.useLightestStandard();
updateState(Serializer.fromShip(ship));
};
/**
* Optimize standard and internal components, hardpoints for exploration
*/
$scope.optimizeExplorer = function() {
var intLength = ship.internal.length,
heatSinkCount = 2, // Fit 2 heat sinks if possible
afmUnitCount = 2, // Fit 2 AFM Units if possible
sgSlot,
fuelScoopSlot,
sgId = $scope.availCS.lightestShieldGenerator(ship.hullMass),
sg = Components.internal(sgId);
ship.setSlotEnabled(ship.cargoHatch, false)
.use(ship.internal[--intLength], '2f', Components.internal('2f')) // Advanced Discovery Scanner
.use(ship.internal[--intLength], '2i', Components.internal('2i')); // Detailed Surface Scanner
for (var i = 0; i < intLength; i++) {
var slot = ship.internal[i];
var nextSlot = (i + 1) < intLength ? ship.internal[i + 1] : null;
if (!fuelScoopSlot && (!slot.eligible || slot.eligible.fs)) { // Fit best possible Fuel Scoop
var fuelScoopId = Components.findInternalId('fs', slot.maxClass, 'A');
fuelScoopSlot = slot;
ship.use(fuelScoopSlot, fuelScoopId, Components.internal(fuelScoopId));
ship.setSlotEnabled(fuelScoopSlot, true);
// Mount a Shield generator if possible AND an AFM Unit has been mounted already (Guarantees at least 1 AFM Unit)
} else if (!sgSlot && afmUnitCount < 2 && sg.class <= slot.maxClass && (!slot.eligible || slot.eligible.sg) && (!nextSlot || nextSlot.maxClass < sg.class)) {
sgSlot = slot;
ship.use(sgSlot, sgId, sg);
ship.setSlotEnabled(sgSlot, true);
} else if (afmUnitCount > 0 && (!slot.eligible || slot.eligible.am)) {
afmUnitCount--;
var am = Components.findInternal('am', slot.maxClass, afmUnitCount ? 'B' : 'A');
ship.use(slot, am.id, am);
ship.setSlotEnabled(slot, false); // Disabled power for AFM Unit
} else {
ship.use(slot, null, null);
}
}
ship.hardpoints.forEach(function(s) {
if (s.maxClass == 0 && heatSinkCount) { // Mount up to 2 heatsinks
ship.use(s, '02', Components.hardpoints('02'));
ship.setSlotEnabled(s, heatSinkCount == 2); // Only enable a single Heatsink
heatSinkCount--;
} else {
ship.use(s, null, null);
}
});
if (sgSlot) {
// The SG and Fuel scoop to not need to be powered at the same time
if (sgSlot.c.power > fuelScoopSlot.c.power) { // The Shield generator uses the most power
ship.setSlotEnabled(fuelScoopSlot, false);
} else { // The Fuel scoop uses the most power
ship.setSlotEnabled(sgSlot, false);
}
}
ship.useLightestStandard({ pd: '1D', ppRating: 'A' });
updateState(Serializer.fromShip(ship));
};
/**
* Save the current build. Will replace the saved build if there is one
* for this ship & with the exact name.
@@ -132,7 +358,25 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
if ($scope.code != $scope.savedCode) {
Persist.saveBuild(ship.id, $scope.buildName, $scope.code);
$scope.savedCode = $scope.code;
updateState();
if ($scope.retrofitBuild === $scope.buildName) {
Serializer.toShip(retrofitShip, $scope.code);
}
updateState($scope.code);
}
};
/**
* Export the build to detailed JSON
*/
$scope.exportBuild = function(e) {
e.stopPropagation();
if ($scope.buildName) {
$state.go('modal.export', {
title: $scope.buildName + ' ' + $translate.instant('export'),
description: $translate.instant('PHRASE_EXPORT_DESC'),
data: Serializer.toDetailedBuild($scope.buildName, ship, $scope.code || Serializer.fromShip(ship))
});
}
};
@@ -160,6 +404,15 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
ship.setCostIncluded(item, !item.incCost);
};
/**
* Toggle cost of the selected component for retrofitting comparison
* @param {object} item The component being toggled
*/
$scope.toggleRetrofitCost = function(item) {
retrofitShip.setCostIncluded(item, !item.incCost);
updateRetrofitCosts();
};
/**
* [sortCost description]
* @param {[type]} key [description]
@@ -175,32 +428,40 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
$scope.pwrPredicate = key;
};
$scope.sortRetrofit = function(key) {
$scope.retroDesc = $scope.retroPredicate == key ? !$scope.retroDesc : $scope.retroDesc;
$scope.retroPredicate = key;
};
$scope.sortAmmo = function(key) {
$scope.ammoDesc = $scope.ammoPredicate == key ? !$scope.ammoDesc : $scope.ammoDesc;
$scope.ammoPredicate = key;
};
/**
* Toggle the power on/off for the selected component
* @param {object} item The component being toggled
*/
$scope.togglePwr = function(c) {
ship.setSlotEnabled(c, !c.enabled);
$scope.code = Serializer.fromShip(ship);
updateState();
updateState(Serializer.fromShip(ship));
};
$scope.incPriority = function(c) {
if (ship.changePriority(c, c.priority + 1)) {
$scope.code = Serializer.fromShip(ship);
updateState();
updateState(Serializer.fromShip(ship));
}
};
$scope.decPriority = function(c) {
if (ship.changePriority(c, c.priority - 1)) {
$scope.code = Serializer.fromShip(ship);
updateState();
updateState(Serializer.fromShip(ship));
}
};
$scope.fuelChange = function(fuel) {
$scope.fuel = fuel;
updateAmmoCosts();
win.triggerHandler('render');
};
@@ -212,19 +473,183 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', '
return ship.getSlotStatus(slot, true);
};
$scope.setRetrofitBase = function() {
if ($scope.retrofitBuild) {
Serializer.toShip(retrofitShip, Persist.getBuild(ship.id, $scope.retrofitBuild));
} else {
retrofitShip.buildWith(data.defaults);
}
updateRetrofitCosts();
};
$scope.updateCostTab = function(tab) {
Persist.setCostTab(tab);
$scope.costTab = tab;
};
$scope.ppWarning = function(pp) {
return pp.pGen < ship.powerRetracted;
};
$scope.pdWarning = function(pd) {
return pd.enginecapacity < ship.boostEnergy;
};
// Utilify functions
function updateState() {
function updateState(code) {
$scope.code = code;
$state.go('outfit', { shipId: ship.id, code: $scope.code, bn: $scope.buildName }, { location: 'replace', notify: false });
$scope.jrSeries.xMax = ship.cargoCapacity;
$scope.jrSeries.yMax = ship.jumpRangeWithMass(ship.unladenMass);
$scope.jrSeries.mass = ship.unladenMass;
$scope.speedSeries.xMax = $scope.trSeries.xMax = $scope.jrSeries.xMax = ship.cargoCapacity;
$scope.jrSeries.yMax = ship.unladenRange;
$scope.trSeries.yMax = ship.unladenTotalRange;
$scope.speedSeries.yMax = calcSpeed(ship.unladenMass, ship.speed, ship.boost, $scope.th.c, ship.pipSpeed).boost;
updateRetrofitCosts();
win.triggerHandler('pwrchange');
}
function updateRetrofitCosts() {
var costs = $scope.retrofitList = [];
var total = 0, i, l, item;
if (ship.bulkheads.id != retrofitShip.bulkheads.id) {
item = {
buyClassRating: ship.bulkheads.c.class + ship.bulkheads.c.rating,
buyName: ship.bulkheads.c.name,
sellClassRating: retrofitShip.bulkheads.c.class + retrofitShip.bulkheads.c.rating,
sellName: retrofitShip.bulkheads.c.name,
netCost: ship.bulkheads.discountedCost - retrofitShip.bulkheads.discountedCost,
retroItem: retrofitShip.bulkheads
};
costs.push(item);
if (retrofitShip.bulkheads.incCost) {
total += item.netCost;
}
}
for (var g in { standard: 1, internal: 1, hardpoints: 1 }) {
var retroSlotGroup = retrofitShip[g];
var slotGroup = ship[g];
for (i = 0, l = slotGroup.length; i < l; i++) {
if (slotGroup[i].id != retroSlotGroup[i].id) {
item = { netCost: 0, retroItem: retroSlotGroup[i] };
if (slotGroup[i].id) {
item.buyName = slotGroup[i].c.name || slotGroup[i].c.grp;
item.buyClassRating = slotGroup[i].c.class + slotGroup[i].c.rating;
item.netCost = slotGroup[i].discountedCost;
}
if (retroSlotGroup[i].id) {
item.sellName = retroSlotGroup[i].c.name || retroSlotGroup[i].c.grp;
item.sellClassRating = retroSlotGroup[i].c.class + retroSlotGroup[i].c.rating;
item.netCost -= retroSlotGroup[i].discountedCost;
}
costs.push(item);
if (retroSlotGroup[i].incCost) {
total += item.netCost;
}
}
}
}
$scope.retrofitTotal = total;
updateAmmoCosts();
}
function updateAmmoCosts() {
var costs = $scope.ammoList = [];
var total = 0, i, l, item, q, limpets = 0, srvs = 0, scoop = false;
for (var g in { standard: 1, internal: 1, hardpoints: 1 }) {
var slotGroup = ship[g];
for (i = 0, l = slotGroup.length; i < l; i++) {
if (slotGroup[i].id) {
//special cases needed for SCB, AFMU, and limpet controllers since they don't use standard ammo/clip
q = 0;
switch (slotGroup[i].c.grp) {
case 'fs': //skip fuel calculation if scoop present
scoop = true;
break;
case 'scb':
q = slotGroup[i].c.cells;
break;
case 'am':
q = slotGroup[i].c.ammo;
break;
case 'fx': case 'hb': case 'cc': case 'pc':
limpets = ship.cargoCapacity;
break;
case 'pv':
srvs += slotGroup[i].c.vehicles;
break;
default:
q = slotGroup[i].c.clip + slotGroup[i].c.ammo;
}
//calculate ammo costs only if a cost is specified
if (slotGroup[i].c.ammocost > 0) {
item = {
ammoClassRating: slotGroup[i].c.class + slotGroup[i].c.rating,
ammoName: slotGroup[i].c.name || slotGroup[i].c.grp,
ammoMax: q,
ammoUnitCost: slotGroup[i].c.ammocost,
ammoTotalCost: q * slotGroup[i].c.ammocost
};
costs.push(item);
total += item.ammoTotalCost;
}
}
}
}
//limpets if controllers exist and cargo space available
if (srvs > 0) {
item = {
ammoName: 'SRVs',
ammoMax: srvs,
ammoUnitCost: 6005,
ammoTotalCost: srvs * 6005
};
costs.push(item);
total += item.ammoTotalCost;
}
//limpets if controllers exist and cargo space available
if (limpets > 0) {
item = {
ammoName: 'limpets',
ammoMax: ship.cargoCapacity,
ammoUnitCost: 101,
ammoTotalCost: ship.cargoCapacity * 101
};
costs.push(item);
total += item.ammoTotalCost;
}
//calculate refuel costs if no scoop present
if (!scoop) {
item = {
ammoName: 'fuel',
ammoMax: $scope.fuel,
ammoUnitCost: 50,
ammoTotalCost: $scope.fuel * 50
};
costs.push(item);
total += item.ammoTotalCost;
}
$scope.ammoTotal = total;
}
// Hide any open menu/slot/etc if the background is clicked
$scope.$on('close', function() {
$scope.selectedSlot = null;
});
// Hide any open menu/slot/etc if the background is clicked
$scope.$on('languageChanged', function() {
$scope.selectedSlot = null;
});
// Hide any open menu/slot/etc if the background is clicked
$scope.$on('discountChange', function() {
ship.applyDiscounts($rootScope.discounts.ship, $rootScope.discounts.components);
retrofitShip.applyDiscounts($rootScope.discounts.ship, $rootScope.discounts.components);
updateRetrofitCosts();
});
}]);

View File

@@ -1,4 +1,59 @@
angular.module('app').controller('ShipyardController', ['$rootScope', 'ShipsDB', function($rootScope, ships) {
$rootScope.title = 'Coriolis';
$rootScope.ships = ships;
angular.module('app').controller('ShipyardController', ['$rootScope', '$scope', 'ShipsDB', 'Ship', 'Components', function($rootScope, $scope, ShipsDB, Ship, Components) {
$rootScope.title = 'Coriolis - Shipyard';
$scope.shipPredicate = 'properties.name';
$scope.shipDesc = false;
function countHp(slot) {
this.hp[slot.maxClass]++;
this.hpCount++;
}
function countInt(slot) {
var crEligible = !slot.eligible || slot.eligible.cr;
this.int[slot.maxClass - 1]++; // Subtract 1 since there is no Class 0 Internal compartment
this.intCount++;
this.maxCargo += crEligible ? Components.findInternal('cr', slot.maxClass, 'E').capacity : 0;
}
function shipSummary(shipId, shipData) {
var summary = angular.copy(shipData.properties);
var ship = new Ship(shipId, shipData.properties, shipData.slots);
summary.id = s;
summary.hpCount = 0;
summary.intCount = 0;
summary.maxCargo = 0;
summary.hp = [0, 0, 0, 0, 0]; // Utility, Small, Medium, Large, Huge
summary.int = [0, 0, 0, 0, 0, 0, 0, 0]; // Sizes 1 - 8
// Build Ship
ship.buildWith(shipData.defaults); // Populate with stock/default components
ship.hardpoints.forEach(countHp.bind(summary)); // Count Hardpoints by class
ship.internal.forEach(countInt.bind(summary)); // Count Internal Compartments by class
summary.retailCost = ship.totalCost; // Record Stock/Default/retail cost
ship.optimizeMass({ pd: '1D' }); // Optimize Mass with 1D PD for maximum possible jump range
summary.maxJumpRange = ship.unladenRange; // Record Jump Range
ship.optimizeMass({ th: ship.standard[1].maxClass + 'A' }); // Optmize mass with Max Thrusters
summary.topSpeed = ship.topSpeed;
summary.topBoost = ship.topBoost;
return summary;
}
/* Initialization */
if (!$rootScope.shipsOverview) { // Only generate this once
$rootScope.shipsOverview = [];
for (var s in ShipsDB) {
$scope.shipsOverview.push(shipSummary(s, ShipsDB[s]));
}
}
/**
* Sort ships
* @param {object} key Sort predicate
*/
$scope.sortShips = function(key) {
$scope.shipDesc = $scope.shipPredicate == key ? !$scope.shipDesc : $scope.shipDesc;
$scope.shipPredicate = key;
};
}]);

View File

@@ -1,4 +1,4 @@
angular.module('app').directive('areaChart', ['$window', function($window) {
angular.module('app').directive('areaChart', ['$window', '$translate', function($window, $translate) {
return {
restrict: 'A',
scope: {
@@ -19,7 +19,8 @@ angular.module('app').directive('areaChart', ['$window', function($window) {
xAxis = d3.svg.axis().outerTickSize(0).orient('bottom').tickFormat(d3.format('.2r')),
yAxis = d3.svg.axis().ticks(6).outerTickSize(0).orient('left').tickFormat(fmt),
x = d3.scale.linear(),
y = d3.scale.linear();
y = d3.scale.linear(),
data = [];
// Create chart
var svg = d3.select(element[0]).append('svg');
@@ -46,28 +47,51 @@ angular.module('app').directive('areaChart', ['$window', function($window) {
// Create Y Axis SVG Elements
var yTxt = vis.append('g').attr('class', 'y axis')
.append('text')
.attr('class', 'cap')
.attr('transform', 'rotate(-90)')
.attr('y', -50)
.attr('dy', '.1em')
.style('text-anchor', 'middle')
.text(labels.yAxis.title + ' (' + labels.yAxis.unit + ')');
.text($translate.instant(labels.yAxis.title) + ' (' + $translate.instant(labels.yAxis.unit) + ')');
// Create X Axis SVG Elements
var xLbl = vis.append('g').attr('class', 'x axis');
var xTxt = xLbl.append('text')
.attr('y', 30)
.attr('dy', '.1em')
.style('text-anchor', 'middle')
.text(labels.xAxis.title + ' (' + labels.xAxis.unit + ')');
.text($translate.instant(labels.xAxis.title) + ' (' + $translate.instant(labels.xAxis.unit) + ')');
// Create and Add tooltip
var tip = vis.append('g').style('display', 'none');
tip.append('rect').attr('width', '4em').attr('height', '2em').attr('x', '0.5em').attr('y', '-1em').attr('class', 'tip');
tip.append('rect').attr('width', '4.5em').attr('height', '2em').attr('x', '0.5em').attr('y', '-1em').attr('class', 'tip');
tip.append('circle')
.attr('class', 'marker')
.attr('r', 4);
tip.append('text').attr('class', 'label x').attr('y', '-0.25em');
tip.append('text').attr('class', 'label y').attr('y', '0.85em');
vis.insert('path', ':first-child') // Area/Path to appear behind everything else
.data([data])
.attr('class', 'area')
.attr('fill', 'url(#gradient)')
.attr('d', area)
.on('mouseover', showTip)
.on('mouseout', hideTip)
.on('mousemove', moveTip)
.call(drag);
drag
.on('dragstart', function() {
dragging = true;
moveTip.call(this);
showTip();
})
.on('dragend', function() {
dragging = false;
hideTip();
})
.on('drag', moveTip);
/**
* Watch for changes in the series data (mass changes, etc)
*/
@@ -78,8 +102,9 @@ angular.module('app').directive('areaChart', ['$window', function($window) {
var width = element[0].parentElement.offsetWidth,
height = width * 0.5,
w = width - margin.left - margin.right,
h = height - margin.top - margin.bottom,
data = [];
h = height - margin.top - margin.bottom;
data.length = 0; // Reset Data array
if (series.xMax == series.xMin) {
var yVal = func(series.xMin);
@@ -95,7 +120,7 @@ angular.module('app').directive('areaChart', ['$window', function($window) {
// Update Chart Size
svg.attr('width', width).attr('height', height);
// Update domain and scale for axes;
// Update domain and scale for axes
x.range([0, w]).domain([series.xMin, series.xMax]).clamp(true);
xAxis.scale(x);
xLbl.attr('transform', 'translate(0,' + h + ')');
@@ -106,30 +131,9 @@ angular.module('app').directive('areaChart', ['$window', function($window) {
vis.selectAll('.y.axis').call(yAxis);
vis.selectAll('.x.axis').call(xAxis);
// Remove existing elements
vis.selectAll('path.area').remove();
vis.insert('path', ':first-child') // Area/Path to appear behind everything else
.datum(data)
.attr('class', 'area')
.attr('fill', 'url(#gradient)')
.attr('d', area)
.on('mouseover', showTip)
.on('mouseout', hideTip)
.on('mousemove', moveTip)
.call(drag);
drag
.on('dragstart', function() {
dragging = true;
moveTip.call(this);
showTip();
})
.on('dragend', function() {
dragging = false;
hideTip();
})
.on('drag', moveTip);
vis.selectAll('path.area') // Area/Path to appear behind everything else
.data([data])
.attr('d', area);
}
function showTip() {
@@ -143,12 +147,12 @@ angular.module('app').directive('areaChart', ['$window', function($window) {
}
function moveTip() {
var xPos = d3.mouse(this)[0], x0 = x.invert(xPos), y0 = func(x0), flip = (x0 / x.domain()[1] > 0.75);
var xPos = d3.mouse(this)[0], x0 = x.invert(xPos), y0 = func(x0), flip = (x0 / x.domain()[1] > 0.65);
tip.attr('transform', 'translate(' + x(x0) + ',' + y(y0) + ')');
tip.selectAll('rect').attr('x', flip ? '-4.5em' : '0.5em').style('text-anchor', flip ? 'end' : 'start');
tip.selectAll('text.label').attr('x', flip ? '-1em' : '1em').style('text-anchor', flip ? 'end' : 'start');
tip.select('text.label.x').text(fmtLong(x0) + ' ' + labels.xAxis.unit);
tip.select('text.label.y').text(fmtLong(y0) + ' ' + labels.yAxis.unit);
tip.selectAll('rect').attr('x', flip ? '-5.75em' : '0.5em').style('text-anchor', flip ? 'end' : 'start');
tip.selectAll('text.label').attr('x', flip ? '-2em' : '1em').style('text-anchor', flip ? 'end' : 'start');
tip.select('text.label.x').text(fmtLong(x0) + ' ' + $translate.instant(labels.xAxis.unit));
tip.select('text.label.y').text(fmtLong(y0) + ' ' + $translate.instant(labels.yAxis.unit));
}
scope.$on('$destroy', function() {

View File

@@ -1,4 +1,4 @@
angular.module('app').directive('barChart', ['$window', function($window) {
angular.module('app').directive('barChart', ['$window', '$translate', '$rootScope', function($window, $translate, $rootScope) {
function bName(build) {
return build.buildName + '\n' + build.name;
@@ -6,12 +6,14 @@ angular.module('app').directive('barChart', ['$window', function($window) {
function insertLinebreaks(d) {
var el = d3.select(this);
var words = d.split('\n');
var lines = d.split('\n');
el.text('').attr('y', -6);
for (var i = 0; i < words.length; i++) {
var tspan = el.append('tspan').text(words[i]);
for (var i = 0; i < lines.length; i++) {
var tspan = el.append('tspan').text(lines[i].length > 18 ? lines[i].substring(0, 15) + '...' : lines[i]);
if (i > 0) {
tspan.attr('x', -9).attr('dy', 12);
tspan.attr('x', -9).attr('dy', '1em');
} else {
tspan.attr('class', 'primary');
}
}
}
@@ -25,15 +27,15 @@ angular.module('app').directive('barChart', ['$window', function($window) {
link: function(scope, element) {
var color = d3.scale.ordinal().range([ '#7b6888', '#6b486b', '#3182bd', '#a05d56', '#d0743c']),
labels = scope.facet.lbls,
fmt = scope.facet.fmt,
fmt = null,
unit = null,
properties = scope.facet.props,
unit = scope.facet.unit,
margin = { top: 10, right: 20, bottom: 35, left: 150 },
margin = { top: 10, right: 20, bottom: 40, left: 150 },
y0 = d3.scale.ordinal(),
y1 = d3.scale.ordinal(),
x = d3.scale.linear(),
yAxis = d3.svg.axis().scale(y0).outerTickSize(0).orient('left'),
xAxis = d3.svg.axis().scale(x).ticks(5).outerTickSize(0).orient('bottom').tickFormat(d3.format('.2s'));
xAxis = d3.svg.axis().scale(x).ticks(5).outerTickSize(0).orient('bottom');
// Create chart
var svg = d3.select(element[0]).append('svg');
@@ -43,7 +45,7 @@ angular.module('app').directive('barChart', ['$window', function($window) {
var tip = d3.tip()
.attr('class', 'd3-tip')
.html(function(property, propertyIndex) {
return (labels ? (labels[propertyIndex] + ': ') : '') + fmt(property.value) + ' ' + unit;
return (labels ? ($translate.instant(labels[propertyIndex]) + ': ') : '') + fmt(property.value) + ' ' + unit;
});
vis.call(tip);
@@ -53,25 +55,19 @@ angular.module('app').directive('barChart', ['$window', function($window) {
vis.selectAll('g.y.axis g text').each(insertLinebreaks);
// Create X Axis SVG Elements
var xAxisLbl = vis.append('g')
.attr('class', 'x axis')
.attr('class', 'x axis cap')
.append('text')
.attr('y', 30)
.attr('y', 33)
.attr('dy', '.1em')
.style('text-anchor', 'middle')
.text(scope.facet.title + (unit ? (' (' + unit + ')') : ''));
.style('text-anchor', 'middle');
/**
* Watch for changes in the comparison array (ships added/removed, sorting)
*/
scope.$watchCollection('data', render);
angular.element($window).bind('orientationchange resize render', render);
updateFormats();
function render() {
var data = scope.data,
width = element[0].offsetWidth,
w = width - margin.left - margin.right,
height = 45 + (30 * data.length),
height = 50 + (30 * data.length * $rootScope.sizeRatio),
h = height - margin.top - margin.bottom,
maxVal = d3.max(data, function(d) { return d3.max(properties, function(p) {return d[p]; }); });
@@ -117,6 +113,17 @@ angular.module('app').directive('barChart', ['$window', function($window) {
}
function updateFormats() {
fmt = $rootScope[scope.facet.fmt];
unit = $translate.instant(scope.facet.unit);
xAxisLbl.text($translate.instant(scope.facet.title) + (unit ? (' (' + $translate.instant(unit) + ')') : ''));
xAxis.tickFormat($rootScope.localeFormat.numberFormat('.2s'));
render();
}
angular.element($window).bind('orientationchange resize render', render);
scope.$watchCollection('data', render); // Watch for changes in the comparison array
scope.$on('languageChanged', updateFormats);
scope.$on('$destroy', function() {
angular.element($window).unbind('orientationchange resize render', render);
tip.destroy(); // Remove the tooltip from the DOM

View File

@@ -1,7 +1,7 @@
angular.module('app').directive('comparisonTable', ['$state', function($state) {
angular.module('app').directive('comparisonTable', ['$state', '$translate', '$rootScope', function($state, $translate, $rootScope) {
function tblHeader(facets) {
var r1 = ['<tr class="main"><th rowspan="2" class="prop" prop="name">Ship</th><th rowspan="2" class="prop" prop="buildName">Build</th>'];
var r1 = ['<tr class="main"><th rowspan="2" class="prop" prop="name">', $translate.instant('SHIP'), '</th><th rowspan="2" class="prop" prop="buildName">', $translate.instant('BUILD'), '</th>'];
var r2 = [];
for (var i = 0, l = facets.length; i < l; i++) {
if (facets[i].active) {
@@ -14,11 +14,11 @@ angular.module('app').directive('comparisonTable', ['$state', function($state) {
r1.push(' prop="', p[0], '" class="prop"');
} else {
for (var j = 0; j < pl; j++) {
r2.push('<th prop="', p[j], '" class="prop ', j === 0 ? 'lft' : '', '">', f.lbls[j], '</th>');
r2.push('<th prop="', p[j], '" class="prop ', j === 0 ? 'lft' : '', '">', $translate.instant(f.lbls[j]), '</th>');
}
}
r1.push('>', f.title, '</th>');
r1.push('>', $translate.instant(f.title), '</th>');
}
}
r1.push('</tr><tr>');
@@ -46,7 +46,7 @@ angular.module('app').directive('comparisonTable', ['$state', function($state) {
var f = facets[j];
var p = f.props;
for (var k = 0, pl = p.length; k < pl; k++) {
body.push('<td>', f.fmt(b[p[k]]), '<u> ', f.unit, '</u></td>');
body.push('<td>', $rootScope[f.fmt](b[p[k]]), '<u> ', $translate.instant(f.unit), '</u></td>');
}
}
}

View File

@@ -1,14 +1,14 @@
angular.module('app').directive('componentSelect', function() {
angular.module('app').directive('componentSelect', ['$translate', function($translate) {
// Generting the HTML in this manner is MUCH faster than using an angular template.
function appendGroup(list, opts, cid, mass) {
function appendGroup(list, opts, cid, mass, checkWarning) {
var prevClass = null, prevRating = null;
for (var i = 0; i < opts.length; i++) {
var o = opts[i];
var id = o.id || (o.class + o.rating); // Common components' ID is their class and rating
var id = o.id || (o.class + o.rating); // Standard components' ID is their class and rating
if (i > 0 && opts.length > 3 && o.class != prevClass && (!o.grp || o.rating != prevRating || o.mode)) {
if (i > 0 && opts.length > 3 && o.class != prevClass && (o.rating != prevRating || o.mode) && o.grp != 'pa') {
list.push('<br/>');
}
@@ -18,13 +18,17 @@ angular.module('app').directive('componentSelect', function() {
list.push(' active');
}
list.push((o.maxmass && mass > o.maxmass) ? ' disabled"' : '" cpid="', id, '">');
if (o.mode) {
list.push('<svg cpid="', id, '" class="icon lg"><use xlink:href="#mount-', o.mode, '"></use></svg> ');
if (checkWarning && checkWarning(opts[i])) {
list.push(' warning');
}
list.push(o.class, o.rating);
list.push(((o.maxmass && (mass + (o.mass ? o.mass : 0)) > o.maxmass) ? ' disabled"' : '" cpid="' + id + '"'), '>');
if (o.mode) {
list.push('<svg class="icon lg"><use xlink:href="#mount-', o.mode, '"></use></svg> ');
}
list.push('<span>', o.class, o.rating);
if (o.missile) {
list.push('/' + o.missile);
@@ -32,10 +36,10 @@ angular.module('app').directive('componentSelect', function() {
if (o.name) {
list.push(' ' + o.name);
list.push(' ' + $translate.instant(o.name));
}
list.push('</li>');
list.push('</span></li>');
prevClass = o.class;
prevRating = o.rating;
}
@@ -46,8 +50,9 @@ angular.module('app').directive('componentSelect', function() {
scope: {
opts: '=', // Component Options object
groups: '=', // Groups of Component Options
mass: '=', // Current ship unladen mass
s: '=' // Current Slot
mass: '=', // Current ship mass
s: '=', // Current Slot
warning: '=' // Check warning function
},
link: function(scope, element) {
var list = [];
@@ -55,21 +60,21 @@ angular.module('app').directive('componentSelect', function() {
var component = scope.s.c; // Slot's Current Component (may be null/undefined)
var opts = scope.opts;
var groups = scope.groups;
var mass = scope.mass || 0;
var mass = (scope.mass ? scope.mass : 0) - (component && component.mass ? component.mass : 0); // Mass minus the currently selected component
if (groups) {
// At present time slots with grouped options (Hardpoints and Internal) can be empty
list.push('<div class="empty-c" cpid="empty">EMPTY</div>');
list.push('<div class="empty-c upp" cpid="empty">', $translate.instant('empty'), '</div>');
for (var g in groups) {
var grp = groups[g];
var grpCode = grp[Object.keys(grp)[0]].grp; // Nasty operation to get the grp property of the first/any single component
list.push('<div id="', grpCode, '" class="select-group">', g, '</div><ul>');
appendGroup(list, grp, cid, mass);
list.push('<div id="', grpCode, '" class="select-group cap">', $translate.instant(g), '</div><ul>');
appendGroup(list, grp, cid, mass, scope.warning);
list.push('</ul>');
}
} else {
list.push('<ul>');
appendGroup(list, opts, cid, mass);
appendGroup(list, opts, cid, mass, scope.warning);
list.push('</ul>');
}
@@ -82,4 +87,4 @@ angular.module('app').directive('componentSelect', function() {
}
}
};
});
}]);

View File

@@ -3,10 +3,12 @@ angular.module('app').directive('contextMenu', ['$parse', function($parse) {
var fn = $parse(attrs.contextMenu);
element.bind('contextmenu', function(e) {
scope.$apply(function() {
e.preventDefault();
fn(scope, { $event: e });
});
if (!e.shiftKey) {
scope.$apply(function() {
e.preventDefault();
fn(scope, { $event: e });
});
}
});
};
}]);

View File

@@ -1,4 +1,5 @@
angular.module('app').directive('shipyardHeader', ['lodash', '$rootScope', 'Persist', 'ShipsDB', function(_, $rootScope, Persist, ships) {
angular.module('app').directive('shipyardHeader', ['lodash', '$window', '$rootScope', '$state', 'Persist', 'Serializer', 'ShipsDB', function(_, $window, $rootScope, $state, Persist, Serializer, ships) {
return {
restrict: 'E',
@@ -9,23 +10,15 @@ angular.module('app').directive('shipyardHeader', ['lodash', '$rootScope', 'Pers
scope.ships = ships;
scope.allBuilds = Persist.builds;
scope.buildsList = Object.keys(scope.allBuilds).sort();
scope.allComparisons = Persist.comparisons;
scope.allComparisons = Object.keys(Persist.comparisons).sort();
scope.bs = Persist.state;
var win = angular.element($window); // Angularized window object for event triggering
var insIndex = _.findIndex($rootScope.insurance.opts, 'name', Persist.getInsurance());
var savedDiscounts = Persist.getDiscount() || [1, 1];
$rootScope.insurance.current = $rootScope.insurance.opts[insIndex != -1 ? insIndex : 0];
$rootScope.discounts.current = $rootScope.discounts.opts[Persist.getDiscount() || 0];
// Close menus if a navigation change event occurs
$rootScope.$on('$stateChangeStart', function() {
scope.openedMenu = null;
});
// Listen to close event to close opened menus or modals
$rootScope.$on('close', function() {
scope.openedMenu = null;
$rootScope.showAbout = false;
});
$rootScope.discounts.ship = savedDiscounts[0];
$rootScope.discounts.components = savedDiscounts[1];
/**
* Save selected insurance option
@@ -38,7 +31,34 @@ angular.module('app').directive('shipyardHeader', ['lodash', '$rootScope', 'Pers
* Save selected discount option
*/
scope.updateDiscount = function() {
Persist.setDiscount($rootScope.discounts.opts.indexOf($rootScope.discounts.current));
Persist.setDiscount([$rootScope.discounts.ship, $rootScope.discounts.components]);
$rootScope.$broadcast('discountChange');
};
scope.backup = function(e) {
e.preventDefault();
e.stopPropagation();
scope.openedMenu = null;
$state.go('modal.export', {
title: 'backup',
data: Persist.getAll(),
description: 'PHRASE_BACKUP_DESC'
});
};
scope.detailedExport = function(e) {
e.preventDefault();
e.stopPropagation();
scope.openedMenu = null;
$state.go('modal.export', {
title: 'detailed export',
data: Serializer.toDetailedExport(scope.allBuilds),
description: 'PHRASE_EXPORT_DESC'
});
};
scope.cleanedBuildList = function(shipId) {
return Object.keys(scope.allBuilds[shipId]);
};
scope.openMenu = function(e, menu) {
@@ -52,18 +72,38 @@ angular.module('app').directive('shipyardHeader', ['lodash', '$rootScope', 'Pers
scope.openedMenu = null;
return;
}
if (menu == 'comp') {
scope.allComparisons = Object.keys(Persist.comparisons).sort();
}
scope.openedMenu = menu;
};
scope.about = function(e) {
e.preventDefault();
e.stopPropagation();
// Close menus if a navigation change event occurs
$rootScope.$on('$stateChangeStart', function() {
scope.openedMenu = null;
$rootScope.showAbout = true;
});
// Listen to close event to close opened menus or modals
$rootScope.$on('close', function() {
scope.openedMenu = null;
});
scope.textSizeChange = function(size) {
if (size != $rootScope.sizeRatio) {
$rootScope.sizeRatio = size;
document.getElementById('main').style.fontSize = size + 'em';
Persist.setSizeRatio(size);
win.triggerHandler('resize');
}
};
$rootScope.hideAbout = function() {
$rootScope.showAbout = false;
scope.resetTextSize = function() {
if ($rootScope.sizeRatio != 1) {
scope.textSizeChange(1);
scope.$broadcast('reset', 1);
}
};
scope.$watchCollection('allBuilds', function() {

View File

@@ -0,0 +1,247 @@
angular.module('app').directive('lineChart', ['$window', '$translate', '$rootScope', function($window, $translate, $rootScope) {
var RENDER_POINTS = 20; // Only render 20 points on the graph
return {
restrict: 'A',
scope: {
config: '=',
series: '='
},
link: function(scope, element) {
var seriesConfig = scope.series,
series = seriesConfig.series,
color = d3.scale.ordinal().range(scope.series.colors ? scope.series.colors : ['#ff8c0d']),
config = scope.config,
labels = config.labels,
margin = { top: 15, right: 15, bottom: 35, left: 60 },
fmtLong = null,
func = seriesConfig.func,
drag = d3.behavior.drag(),
dragging = false,
// Define Scales
x = d3.scale.linear(),
y = d3.scale.linear(),
// Define Axes
xAxis = d3.svg.axis().scale(x).outerTickSize(0).orient('bottom'),
yAxis = d3.svg.axis().scale(y).ticks(6).outerTickSize(0).orient('left'),
data = [];
// Create chart
var svg = d3.select(element[0]).append('svg');
var vis = svg.append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
var lines = vis.append('g');
// Define Area
var line = d3.svg.line().y(function(d) { return y(d[1]); });
// Create Y Axis SVG Elements
var yTxt = vis.append('g').attr('class', 'y axis')
.append('text')
.attr('class', 'cap')
.attr('transform', 'rotate(-90)')
.attr('y', -50)
.attr('dy', '.1em')
.style('text-anchor', 'middle');
// Create X Axis SVG Elements
var xLbl = vis.append('g').attr('class', 'x axis');
var xTxt = xLbl.append('text')
.attr('class', 'cap')
.attr('y', 30)
.attr('dy', '.1em')
.style('text-anchor', 'middle');
// xTxt.append('tspan').attr('class', 'metric');
// yTxt.append('tspan').attr('class', 'metric');
// Create and Add tooltip
var tipHeight = 2 + (1.25 * (series ? series.length : 0.75));
var tips = vis.append('g').style('display', 'none').attr('class', 'tooltip');
var markers = vis.append('g').style('display', 'none');
tips.append('rect')
.attr('height', tipHeight + 'em')
.attr('y', (-tipHeight / 2) + 'em')
.attr('class', 'tip');
tips.append('text')
.attr('class', 'label x')
.attr('dy', (-tipHeight / 2) + 'em')
.attr('y', '1.25em');
var background = vis.append('rect') // Background to capture hover/drag
.attr('fill-opacity', 0)
.on('mouseover', showTip)
.on('mouseout', hideTip)
.on('mousemove', moveTip)
.call(drag);
drag
.on('dragstart', function() {
dragging = true;
moveTip.call(this);
showTip();
})
.on('dragend', function() {
dragging = false;
hideTip();
})
.on('drag', moveTip);
updateFormats();
function render() {
var width = element[0].parentElement.offsetWidth,
height = width * 0.5 * $rootScope.sizeRatio,
xMax = seriesConfig.xMax,
xMin = seriesConfig.xMin,
yMax = seriesConfig.yMax,
yMin = seriesConfig.yMin,
w = width - margin.left - margin.right,
h = height - margin.top - margin.bottom,
c, s, val, yVal, delta;
data.length = 0; // Reset Data array
if (seriesConfig.xMax == seriesConfig.xMin) {
line.x(function(d, i) { return i * w; });
} else {
line.x(function(d) { return x(d[0]); });
}
if (series) {
for (s = 0; s < series.length; s++) {
data.push([]);
}
if (xMax == xMin) {
yVal = func(xMin);
for (s = 0; s < series.length; s++) {
data[s].push( [ xMin, yVal[ series[s] ] ], [ 1, yVal[ series[s] ] ]);
}
} else {
delta = (xMax - xMin) / RENDER_POINTS;
val = 0;
for (c = 0; c <= RENDER_POINTS; c++) {
yVal = func(val);
for (s = 0; s < series.length; s++) {
data[s].push([ val, yVal[ series[s] ] ]);
}
val += delta;
}
}
} else {
var seriesData = [];
if (xMax == xMin) {
yVal = func(xMin);
seriesData.push([ xMin, yVal ], [ 1, yVal ]);
} else {
delta = (xMax - xMin) / RENDER_POINTS;
val = 0;
for (c = 0; c <= RENDER_POINTS; c++) {
seriesData.push([val, func(val) ]);
val += delta;
}
}
data.push(seriesData);
}
// Update Chart Size
svg.attr('width', width).attr('height', height);
background.attr('height', h).attr('width', w);
// Update domain and scale for axes
x.range([0, w]).domain([xMin, xMax]).clamp(true);
xLbl.attr('transform', 'translate(0,' + h + ')');
xTxt.attr('x', w / 2);
y.range([h, 0]).domain([yMin, yMax]);
yTxt.attr('x', -h / 2);
vis.selectAll('.y.axis').call(yAxis);
vis.selectAll('.x.axis').call(xAxis);
lines.selectAll('path.line')
.data(data)
.attr('d', line) // Update existing series
.enter() // Add new series
.append('path')
.attr('class', 'line')
.attr('stroke', function(d, i) { return color(i); })
.attr('stroke-width', 2)
.attr('d', line);
tips.selectAll('text.label.y').data(data).enter()
.append('text')
.attr('class', 'label y')
.attr('dy', (-tipHeight / 2) + 'em')
.attr('y', function(d, i) { return 1.25 * (i + 2) + 'em'; });
markers.selectAll('circle.marker').data(data).enter().append('circle').attr('class', 'marker').attr('r', 4);
}
function showTip() {
tips.style('display', null);
markers.style('display', null);
}
function hideTip() {
if (!dragging) {
tips.style('display', 'none');
markers.style('display', 'none');
}
}
function moveTip() {
var xPos = d3.mouse(this)[0],
x0 = x.invert(xPos),
y0 = func(x0),
yTotal = 0,
flip = (x0 / x.domain()[1] > 0.65),
tipWidth = 0,
minTransY = (tips.selectAll('rect').node().getBoundingClientRect().height / 2) - margin.top;
tips.selectAll('text.label.y').text(function(d, i) {
var yVal = series ? y0[series[i]] : y0;
yTotal += yVal;
return (series ? $translate.instant(series[i]) : '') + ' ' + fmtLong(yVal);
}).append('tspan').attr('class', 'metric').text(' ' + $translate.instant(labels.yAxis.unit));
tips.selectAll('text').each(function() {
if (this.getBBox().width > tipWidth) {
tipWidth = Math.ceil(this.getBBox().width);
}
});
tipWidth += 8;
markers.selectAll('circle.marker').attr('cx', x(x0)).attr('cy', function(d, i) { return y(series ? y0[series[i]] : y0); });
tips.selectAll('text.label').attr('x', flip ? -12 : 12).style('text-anchor', flip ? 'end' : 'start');
tips.selectAll('text.label.x').text(fmtLong(x0)).append('tspan').attr('class', 'metric').text(' ' + $translate.instant(labels.xAxis.unit));
tips.attr('transform', 'translate(' + x(x0) + ',' + Math.max(minTransY, y(yTotal / (series ? series.length : 1))) + ')');
tips.selectAll('rect')
.attr('width', tipWidth + 4)
.attr('x', flip ? -tipWidth - 12 : 8)
.style('text-anchor', flip ? 'end' : 'start');
}
function updateFormats() {
xTxt.text($translate.instant(labels.xAxis.title)).append('tspan').attr('class', 'metric').text(' (' + $translate.instant(labels.xAxis.unit) + ')');
yTxt.text($translate.instant(labels.yAxis.title)).append('tspan').attr('class', 'metric').text(' (' + $translate.instant(labels.yAxis.unit) + ')');
fmtLong = $rootScope.localeFormat.numberFormat('.2f');
xAxis.tickFormat($rootScope.localeFormat.numberFormat('.2r'));
yAxis.tickFormat($rootScope.localeFormat.numberFormat('.3r'));
render();
}
angular.element($window).bind('orientationchange resize render', render);
scope.$watchCollection('series', render); // Watch for changes in the series data
scope.$on('languageChanged', updateFormats);
scope.$on('$destroy', function() {
angular.element($window).unbind('orientationchange resize render', render);
});
}
};
}]);

View File

@@ -0,0 +1,9 @@
angular.module('app').directive('loader', function() {
return {
restrict: 'A',
link: function(scope, element) {
element.addClass('loader');
element.html('<svg viewbox="0 0 40 40" width="100%" height="100%"><path d="m5,8l5,8l5,-8z" class="l1 d1" /><path d="m5,8l5,-8l5,8z" class="l1 d2" /><path d="m10,0l5,8l5,-8z" class="l1 d3" /><path d="m15,8l5,-8l5,8z" class="l1 d4" /><path d="m20,0l5,8l5,-8z" class="l1 d5" /><path d="m25,8l5,-8l5,8z" class="l1 d6" /><path d="m25,8l5,8l5,-8z" class="l1 d7" /><path d="m30,16l5,-8l5,8z" class="l1 d8" /><path d="m30,16l5,8l5,-8z" class="l1 d9" /><path d="m25,24l5,-8l5,8z" class="l1 d10" /><path d="m25,24l5,8l5,-8z" class="l1 d11" /><path d="m20,32l5,-8l5,8z" class="l1 d13" /><path d="m15,24l5,8l5,-8z" class="l1 d14" /><path d="m10,32l5,-8l5,8z" class="l1 d15" /><path d="m5,24l5,8l5,-8z" class="l1 d16" /><path d="m5,24l5,-8l5,8z" class="l1 d17" /><path d="m0,16l5,8l5,-8z" class="l1 d18" /><path d="m0,16l5,-8l5,8z" class="l1 d20" /><path d="m10,16l5,-8l5,8z" class="l2 d0" /><path d="m15,8l5,8l5,-8z" class="l2 d3" /><path d="m20,16l5,-8l5,8z" class="l2 d6" /><path d="m20,16l5,8l5,-8z" class="l2 d9" /><path d="m15,24l5,-8l5,8z" class="l2 d12" /><path d="m10,16l5,8l5,-8z" class="l2 d15" /></svg>');
}
};
});

View File

@@ -1,4 +1,4 @@
angular.module('app').directive('powerBands', ['$window', function($window) {
angular.module('app').directive('powerBands', ['$window', '$translate', '$rootScope', function($window, $translate, $rootScope) {
return {
restrict: 'A',
scope: {
@@ -6,72 +6,56 @@ angular.module('app').directive('powerBands', ['$window', function($window) {
available: '='
},
link: function(scope, element) {
var margin = { top: 20, right: 130, bottom: 20, left: 40 },
barHeight = 20,
bands = null,
innerHeight = (barHeight * 2) + 3,
height = innerHeight + margin.top + margin.bottom + 1,
var bands = null,
available = 0,
maxBand,
maxPwr,
deployedSum = 0,
retractedSum = 0,
retBandsSelected = false,
depBandsSelected = false,
wattScale = d3.scale.linear(),
pctScale = d3.scale.linear().domain([0, 1]),
wattFmt = d3.format('.2f'),
pctFmt = d3.format('.1%'),
wattAxis = d3.svg.axis().scale(wattScale).outerTickSize(0).orient('top').tickFormat(d3.format('.2r')),
pctAxis = d3.svg.axis().scale(pctScale).outerTickSize(0).orient('bottom').tickFormat(d3.format('%')),
wattFmt,
pctFmt,
wattAxis = d3.svg.axis().scale(wattScale).outerTickSize(0).orient('top'),
pctAxis = d3.svg.axis().scale(pctScale).outerTickSize(0).orient('bottom'),
// Create chart
svg = d3.select(element[0]).append('svg'),
vis = svg.append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'),
vis = svg.append('g'),
deployed = vis.append('g').attr('class', 'power-band'),
retracted = vis.append('g').attr('class', 'power-band');
svg.on('contextmenu', function() {
if (!d3.event.shiftKey) {
d3.event.preventDefault();
for (var i = 0, l = bands.length; i < l; i++) {
bands[i].retSelected = false;
bands[i].depSelected = false;
}
render();
});
dataChange();
}
});
// Create Y Axis SVG Elements
vis.append('g').attr('class', 'watt axis');
var wattAxisGroup = vis.append('g').attr('class', 'watt axis');
vis.append('g').attr('class', 'pct axis');
vis.append('text').attr('x', -35).attr('y', 16).attr('class', 'primary').text('RET');
vis.append('text').attr('x', -35).attr('y', barHeight + 18).attr('class', 'primary').text('DEP');
var retText = vis.append('text').attr('x', -3).style('text-anchor', 'end').attr('dy', '0.5em').attr('class', 'primary upp');
var depText = vis.append('text').attr('x', -3).style('text-anchor', 'end').attr('dy', '0.5em').attr('class', 'primary upp');
var retLbl = vis.append('text').attr('dy', '0.5em');
var depLbl = vis.append('text').attr('dy', '0.5em');
var retLbl = vis.append('text').attr('y', 16);
var depLbl = vis.append('text').attr('y', barHeight + 18);
updateFormats(true);
// Watch for changes to data and events
scope.$watchCollection('available', render);
angular.element($window).bind('orientationchange resize pwrchange', render);
function render() {
function dataChange() {
bands = scope.bands;
var available = scope.available,
width = element[0].offsetWidth,
w = width - margin.left - margin.right,
maxBand = bands[bands.length - 1],
deployedSum = 0,
retractedSum = 0,
retBandsSelected = false,
depBandsSelected = false,
maxPwr = Math.max(available, maxBand.retractedSum, maxBand.deployedSum);
// Update chart size
svg.attr('width', width).attr('height', height);
// Remove existing elements
retracted.selectAll('rect').remove();
retracted.selectAll('text').remove();
deployed.selectAll('rect').remove();
deployed.selectAll('text').remove();
// Update X & Y Axis
wattScale.range([0, w]).domain([0, maxPwr]).clamp(true);
pctScale.range([0, w]).domain([0, maxPwr / available]).clamp(true);
vis.selectAll('.watt.axis').call(wattAxis);
vis.selectAll('.pct.axis').attr('transform', 'translate(0,' + innerHeight + ')').call(pctAxis);
available = scope.available;
maxBand = bands[bands.length - 1];
deployedSum = 0;
retractedSum = 0;
retBandsSelected = false;
depBandsSelected = false;
maxPwr = Math.max(available, maxBand.retractedSum, maxBand.deployedSum);
for (var b = 0, l = bands.length; b < l; b++) {
if (bands[b].retSelected) {
@@ -84,64 +68,113 @@ angular.module('app').directive('powerBands', ['$window', function($window) {
}
}
updateLabel(retLbl, w, retBandsSelected, retBandsSelected ? retractedSum : maxBand.retractedSum, available);
updateLabel(depLbl, w, depBandsSelected, depBandsSelected ? deployedSum : maxBand.deployedSum, available);
render();
}
function render() {
var size = $rootScope.sizeRatio,
mTop = Math.round(25 * size),
mRight = Math.round(130 * size),
mBottom = Math.round(25 * size),
mLeft = Math.round(45 * size),
barHeight = Math.round(20 * size),
width = element[0].offsetWidth,
innerHeight = (barHeight * 2) + 2,
height = innerHeight + mTop + mBottom,
w = width - mLeft - mRight,
repY = (barHeight / 2),
depY = (barHeight * 1.5) - 1;
// Update chart size
svg.attr('width', width).attr('height', height);
vis.attr('transform', 'translate(' + mLeft + ',' + mTop + ')');
// Remove existing elements
retracted.selectAll('rect').remove();
retracted.selectAll('text').remove();
deployed.selectAll('rect').remove();
deployed.selectAll('text').remove();
wattAxisGroup.selectAll('line.threshold').remove();
// Update X & Y Axis
wattScale.range([0, w]).domain([0, maxPwr]).clamp(true);
pctScale.range([0, w]).domain([0, maxPwr / available]).clamp(true);
wattAxisGroup.call(wattAxis);
vis.selectAll('.pct.axis').attr('transform', 'translate(0,' + innerHeight + ')').call(pctAxis);
var pwrWarningClass = 'threshold' + (bands[0].retractedSum * 2 >= available ? ' exceeded' : '');
vis.select('.pct.axis g:nth-child(6)').selectAll('line, text').attr('class', pwrWarningClass);
wattAxisGroup.append('line')
.attr('x1', pctScale(0.5))
.attr('x2', pctScale(0.5))
.attr('y1', 0)
.attr('y2', innerHeight)
.attr('class', pwrWarningClass);
retText.attr('y', repY);
depText.attr('y', depY);
updateLabel(retLbl, w, repY, retBandsSelected, retBandsSelected ? retractedSum : maxBand.retractedSum, available);
updateLabel(depLbl, w, depY, depBandsSelected, depBandsSelected ? deployedSum : maxBand.deployedSum, available);
retracted.selectAll('rect').data(bands).enter().append('rect')
.attr('height', barHeight)
.attr('width', function(d) { return Math.max(wattScale(d.retracted + d.retOnly) - 1, 0); })
.attr('x', function(d) { return wattScale(d.retractedSum) - wattScale(d.retracted + d.retOnly); })
.attr('width', function(d) { return Math.ceil(Math.max(wattScale(d.retracted + d.retOnly), 0)); })
.attr('x', function(d) { return Math.floor(Math.max(wattScale(d.retractedSum) - wattScale(d.retracted + d.retOnly), 0)); })
.attr('y', 1)
.on('click', function(d) {
d.retSelected = !d.retSelected;
render();
dataChange();
})
.attr('class', function(d) { return getClass(d.retSelected, d.retractedSum, available); });
retracted.selectAll('text').data(bands).enter().append('text')
.attr('x', function(d) { return wattScale(d.retractedSum) - (wattScale(d.retracted + d.retOnly) / 2); })
.attr('y', 15)
.attr('y', repY)
.attr('dy', '0.5em')
.style('text-anchor', 'middle')
.attr('class', 'primary-bg')
.on('click', function(d) {
d.retSelected = !d.retSelected;
render();
dataChange();
})
.text(function(d, i) { return bandText(d.retracted + d.retOnly, i); });
deployed.selectAll('rect').data(bands).enter().append('rect')
.attr('height', barHeight)
.attr('width', function(d) { return Math.max(wattScale(d.deployed + d.retracted) - 1, 0); })
.attr('x', function(d) { return wattScale(d.deployedSum) - wattScale(d.retracted) - wattScale(d.deployed); })
.attr('y', barHeight + 2)
.attr('width', function(d) { return Math.ceil(Math.max(wattScale(d.deployed + d.retracted), 0)); })
.attr('x', function(d) { return Math.floor(Math.max(wattScale(d.deployedSum) - wattScale(d.retracted) - wattScale(d.deployed), 0)); })
.attr('y', barHeight + 1)
.on('click', function(d) {
d.depSelected = !d.depSelected;
render();
dataChange();
})
.attr('class', function(d) { return getClass(d.depSelected, d.deployedSum, available); });
deployed.selectAll('text').data(bands).enter().append('text')
.attr('x', function(d) { return wattScale(d.deployedSum) - ((wattScale(d.retracted) + wattScale(d.deployed)) / 2); })
.attr('y', barHeight + 17)
.attr('y', depY)
.attr('dy', '0.5em')
.style('text-anchor', 'middle')
.attr('class', 'primary-bg')
.on('click', function(d) {
d.depSelected = !d.depSelected;
render();
dataChange();
})
.text(function(d, i) { return bandText(d.deployed + d.retracted, i); });
}
function updateLabel(lbl, width, selected, sum, available) {
function updateLabel(lbl, width, y, selected, sum, avail) {
lbl
.attr('x', width + 5 )
.attr('class', getClass(selected, sum, available))
.text(wattFmt(Math.max(0, sum)) + ' (' + pctFmt(Math.max(0, sum / available)) + ')');
.attr('y', y)
.attr('class', getClass(selected, sum, avail))
.text(wattFmt(Math.max(0, sum)) + ' (' + pctFmt(Math.max(0, sum / avail)) + ')');
}
function getClass(selected, sum, available) {
return selected ? 'secondary' : (sum > available) ? 'warning' : 'primary';
function getClass(selected, sum, avail) {
// Round to avoid floating point precision errors
return selected ? 'secondary' : ((Math.round(sum * 100) / 100) >= avail) ? 'warning' : 'primary';
}
function bandText(val, index) {
@@ -151,6 +184,23 @@ angular.module('app').directive('powerBands', ['$window', function($window) {
return '';
}
function updateFormats(preventRender) {
retText.text($translate.instant('ret'));
depText.text($translate.instant('dep'));
wattFmt = $rootScope.localeFormat.numberFormat('.2f');
pctFmt = $rootScope.localeFormat.numberFormat('.1%');
wattAxis.tickFormat($rootScope.localeFormat.numberFormat('.2r'));
pctAxis.tickFormat($rootScope.localeFormat.numberFormat('%'));
if (!preventRender) {
render();
}
}
// Watch for changes to data and events
angular.element($window).bind('pwrchange', dataChange);
angular.element($window).bind('orientationchange resize', render);
scope.$watchCollection('available', dataChange);
scope.$on('languageChanged', updateFormats);
scope.$on('$destroy', function() {
angular.element($window).unbind('orientationchange resize pwrchange', render);
});

View File

@@ -3,73 +3,83 @@ angular.module('app').directive('slider', ['$window', function($window) {
return {
restrict: 'A',
scope: {
min: '=',
def: '=',
max: '=',
unit: '=',
change: '&onChange'
change: '&onChange',
ignoreResize: '='
},
link: function(scope, element) {
var margin = { top: -10, right: 140, bottom: 0, left: 50 },
height = 40, // Height is fixed
h = height - margin.top - margin.bottom,
var unit = scope.unit,
margin = unit ? { top: -10, right: 145, left: 50 } : { top: 0, right: 10, left: 10 },
height = unit ? 40 : 20, // Height is fixed
h = height - margin.top,
fmt = d3.format('.2f'),
pct = d3.format('.1%'),
unit = scope.unit,
val = scope.max,
def = scope.def !== undefined ? scope.def : scope.max,
val = def,
svg = d3.select(element[0]).append('svg'),
vis = svg.append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'),
xAxis = vis.append('g').attr('class', 'x slider-axis').attr('transform', 'translate(0,' + h / 2 + ')'),
xAxisContainer = vis.append('g').attr('class', 'x slider-axis').attr('transform', 'translate(0,' + h / 2 + ')'),
x = d3.scale.linear(),
xAxis = d3.svg.axis().scale(x).orient('bottom').tickFormat(function(d) { return d + unit; }).tickSize(0).tickPadding(12),
slider = vis.append('g').attr('class', 'slider'),
filled = slider.append('path').attr('class', 'filled').attr('transform', 'translate(0,' + h / 2 + ')'),
brush = d3.svg.brush().x(x).extent([scope.max, scope.max]).on('brush', brushed),
handle = slider.append('circle').attr('class', 'handle').attr('r', '0.6em'),
lbl = slider.append('g').append('text').attr('y', h / 2);
lbl = unit ? slider.append('g').append('text').attr('y', h / 2) : null;
slider.call(brush);
slider.select('.background').attr('height', h);
handle.attr('transform', 'translate(0,' + h / 2 + ')');
function render() {
var width = element[0].offsetWidth, w = width - margin.left - margin.right;
svg.attr('width', width).attr('height', height);
x.domain([scope.min || 0, scope.max]).range([0, w]).clamp(true);
handle.attr('cx', x(val));
if (unit) {
xAxisContainer.call(xAxis.tickValues([0, scope.max / 4, scope.max / 2, (3 * scope.max) / 4, scope.max]));
lbl.attr('x', w + 20);
}
slider.call(brush.extent([val, val]));
drawBrush();
slider.selectAll('.extent,.resize').remove();
}
function brushed() {
val = x.invert(d3.mouse(this)[0]);
brush.extent([val, val]);
scope.change({ val: val });
drawBrush();
}
function drawBrush() {
if (unit) {
lbl.text(fmt(val) + ' ' + unit + ' ' + pct(val / scope.max));
}
handle.attr('cx', x(val));
filled.attr('d', 'M0,0V0H' + x(val) + 'V0');
}
/**
* Watch for changes in the max, window size
*/
scope.$watch('max', function(newMax, oldMax) {
val = newMax * (val / oldMax); // Retain percentage filled
scope.change({ val: val });
render();
});
angular.element($window).bind('orientationchange resize', render);
function render() {
var width = element[0].offsetWidth, w = width - margin.left - margin.right;
svg.attr('width', width).attr('height', height);
x.domain([0, scope.max]).range([0, w]).clamp(true);
handle.attr('cx', x(val));
xAxis
.call(d3.svg.axis()
.scale(x)
.orient('bottom')
.tickFormat(function(d) { return d + unit; })
.tickValues([0, scope.max / 4, scope.max / 2, (3 * scope.max) / 4, scope.max])
.tickSize(0)
.tickPadding(12))
.select('.domain');
lbl.attr('x', w + 20);
slider.call(brush.extent([val, val])).call(brush.event);
slider.selectAll('.extent,.resize').remove();
if (!scope.ignoreResize) {
angular.element($window).bind('orientationchange resize', render);
}
function brushed() {
val = brush.extent()[0];
if (d3.event.sourceEvent) { // not a programmatic event
val = x.invert(d3.mouse(this)[0]);
brush.extent([val, val]);
}
lbl.text(fmt(val) + ' ' + unit + ' ' + pct(val / scope.max));
scope.change({ val: val });
handle.attr('cx', x(val));
filled.attr('d', 'M0,0V0H' + x(val) + 'V0');
}
scope.$on('reset', function(e, resetVal) {
val = resetVal;
drawBrush();
});
scope.$on('$destroy', function() {
angular.element($window).unbind('orientationchange resize render', render);

View File

@@ -3,8 +3,7 @@ angular.module('app').directive('slotHardpoint', ['$rootScope', function($r) {
restrict: 'A',
scope: {
hp: '=',
size: '=',
lbl: '='
size: '='
},
templateUrl: 'views/_slot-hardpoint.html',
link: function(scope) {

View File

@@ -3,7 +3,6 @@ angular.module('app').directive('slotInternal', ['$rootScope', function($r) {
restrict: 'A',
scope: {
c: '=slot',
lbl: '=',
fuel: '='
},
templateUrl: 'views/_slot-internal.html',

View File

@@ -1,7 +1,7 @@
/**
* BBCode Generator functions for embedding in the Elite Dangerous Forums
*/
angular.module('app').factory('Utils', ['$window', '$state', '$http', '$q', function($window, $state, $http, $q) {
angular.module('app').factory('Utils', ['$window', '$state', '$http', '$q', '$translate', '$rootScope', function($window, $state, $http, $q, $translate, $rootScope) {
var shortenAPI = 'https://www.googleapis.com/urlshortener/v1/url?key=';
@@ -24,11 +24,11 @@ angular.module('app').factory('Utils', ['$window', '$state', '$http', '$q', func
p = f.props;
if (p.length == 1) {
l.push('[th][B][COLOR=#FF8C0D]', f.title, '[/COLOR][/B][/th]');
l.push('[th][B][COLOR=#FF8C0D]', $translate.instant(f.title).toUpperCase(), '[/COLOR][/B][/th]');
colCount++;
} else {
for (j = 0; j < p.length; j++) {
l.push('[th][B][COLOR=#FF8C0D]', f.title, '\n', f.lbls[j], '[/COLOR][/B][/th]');
l.push('[th][B][COLOR=#FF8C0D]', $translate.instant(f.title).toUpperCase(), '\n', $translate.instant(f.lbls[j]).toUpperCase(), '[/COLOR][/B][/th]');
colCount++;
}
}
@@ -46,7 +46,7 @@ angular.module('app').factory('Utils', ['$window', '$state', '$http', '$q', func
f = facets[j];
p = f.props;
for (k = 0, pl = p.length; k < pl; k++) {
l.push('[td="align: right"]', f.fmt(b[p[k]]), ' [size=-2]', f.unit, '[/size][/td]');
l.push('[td="align: right"]', $rootScope[f.fmt](b[p[k]]), ' [size=-2]', $translate.instant(f.unit), '[/size][/td]');
}
}
}

220
app/js/i18n/de.js Normal file
View File

@@ -0,0 +1,220 @@
angular.module('app').config(['$translateProvider', 'localeFormatProvider', function($translateProvider, localeFormatProvider) {
// Declare number format settings
localeFormatProvider.addFormat('de', {
decimal: ',',
thousands: '.',
grouping: [3],
currency: ['', ' €'],
dateTime: '%A, der %e. %B %Y, %X',
date: '%d.%m.%Y',
time: '%H:%M:%S',
periods: ['AM', 'PM'], // unused
days: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
shortDays: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'],
months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
shortMonths: ['Jan', 'Feb', 'Mrz', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez']
});
$translateProvider.translations('de', {
PHRASE_EXPORT_DESC: 'Ein detaillierter JSON-Export Ihrer Konfiguration für die Verwendung in anderen Websites und Tools',
'A-Rated': 'A-Klasse',
about: 'Über',
action: 'Aktion',
added: 'Hinzugefügt',
Advanced: 'Verbessert',
'Advanced Discovery Scanner': 'Fortgeschrittener Aufklärungsscanner',
agility: 'Manövrierbarkeit',
ammo: 'Munition',
PHRASE_CONFIRMATION: 'Sind Sie sicher?',
armour: 'Panzerung',
am: 'Automatische Feldwartungs-Einheit',
available: 'Verfügbar',
backup: 'Sicherungsdatei',
'Basic Discovery Scanner': 'Einfacher Aufklärungsscanner',
bl: 'Strahlenlaser',
beta: 'Beta',
bins: 'Behälter',
boost: 'Boost',
build: 'Ausstattung',
'build name': 'Ausstattungsname',
builds: 'Ausstattungen',
bh: 'Rumpfhüllenverstärkung',
ul: 'Salvenlaser',
buy: 'Kaufen',
cancel: 'Abbrechen',
c: 'Kanone',
capital: 'Kapital',
cargo: 'Fracht',
'Cargo Hatch': 'Frachtluke',
cr: 'Frachtgestell',
cs: 'Frachtscanner',
cells: 'Zellen',
'Chaff Launcher': 'Düppel-Werfer',
close: 'Schließen',
cc: 'Krallensteuerung: Sammler',
compare: 'Vergleichen',
'compare all': 'Alles Vergleichen',
comparison: 'Vergleich',
comparisons: 'Vergleiche',
component: 'Komponente',
cost: 'Preis',
costs: 'Kosten',
cm: 'Gegenmaßnahme',
create: 'Erstellen',
'create new': 'Neu Erstellen',
Cytoscrambler: 'Zytostreuer',
damage: 'Schaden',
delete: 'Löschen',
'delete all': 'Alles Löschen',
dep: 'Ausg',
deployed: 'Ausgefahren',
'detailed export': 'Detailierter Export',
'Detailed Surface Scanner': 'Detailoberflächenscanner',
disabled: 'Deaktiviert',
discount: 'Rabatt',
Distruptor: 'Disruptor',
dc: 'Standard-Landecomputer',
done: 'Fertig',
'edit data': 'Bearbeiten',
efficiency: 'Effizienz',
'Electronic Countermeasure': 'Elektronische Gegenmaßnahme',
empty: 'leer',
Enforcer: 'Vollstrecker',
ENG: 'ANT',
'enter name': 'Namen eingeben',
export: 'Export',
fixed: 'Fixiert',
forum: 'Forum',
fc: 'Splitterkanone',
fd: 'Frameshiftantrieb',
ws: 'Frameshift-Sogwolkenscanner',
FSD: 'FSA',
fi: 'FSA-Unterbrecher',
fuel: 'Treibstoff',
fs: 'Treibstoffsammler',
ft: 'Treibstofftank',
fx: 'Krallensteuerung Treibstoffstransfer',
'full tank': 'Tank voll',
Gimballed: 'Kardanisch',
H: 'R',
hardpoints: 'Waffenaufhängungen',
hb: 'Krallen-Steuereinheit (Ladelukenöffner)',
'Heat Sink Launcher': 'Kühlkörperwerfer',
huge: 'Riesig',
hull: 'Hülle',
hr: 'Rumpfhüllenverstärkung (Paket)',
'Imperial Hammer': 'Imperialer Hammer',
import: 'Importieren',
'import all': 'Alles Importieren',
insurance: 'Versicherung',
'Intermediate Discovery Scanner': 'Mittlerer Aufklärungsscanner',
'internal compartments': 'Innenbereichskabine',
'jump range': 'Sprungreichweite',
jumps: 'Sprünge',
kw: 'Tötungsbefehl-Scanner',
L: 'G',
laden: 'Beladen',
language: 'Sprache',
large: 'Groß',
limpets: 'Krallen',
ls: 'Lebenserhaltung',
'Lightweight Alloy': 'Leichte Legierung',
'lock factor': 'Massensperrefaktor',
LS: 'Ls',
LY: 'Lj',
mass: 'Masse',
'max mass': 'maximale Masse',
medium: 'Mittel',
'Military Grade Composite': 'Militär-Komposit',
nl: 'Minenwerfer',
'Mining Lance': 'Lanzenabbaulaser',
ml: 'Abbaulaser',
'Mirrored Surface Composite': 'Gespiegelte-Oberfläche-Komposit',
mr: 'Raketenbatterie',
mc: 'Mehrfachgeschütz',
'net cost': 'Nettokosten',
no: 'Nein',
PHRASE_NO_BUILDS: 'Keine Konfigurationen zum Vergleich ausgewählt!',
PHRASE_NO_RETROCH: 'Keine Umrüständerungen',
none: 'Nichts',
'none created': 'Leer',
off: 'Aus',
on: 'An',
'optimal mass': 'optimale Masse',
'optimize mass': 'Masse optimieren',
overwrite: 'Überschreiben',
Pacifier: 'Friedensstifter',
'Pack-Hound': 'Schwarmwerfer',
PHRASE_IMPORT: 'JSON hier einfügen oder importieren',
pen: 'Durchdr.',
penetration: 'Durchdringung',
permalink: 'Permalink',
pa: 'Plasmabeschleuniger',
'Point Defence': 'Punktverteidigung',
power: 'Energie',
pd: 'Energieverteiler',
pp: 'Kraftwerk',
pri: 'Prio',
priority: 'Priorität',
psg: 'Prismaschildgenerator',
proceed: 'Fortfahren',
pc: 'Krallensteuerung: Erzsucher',
pl: 'Impulslaser',
PWR: 'En',
rg: 'Schienenkanone',
range: 'Reichweite',
rate: 'Rate',
'Reactive Surface Composite': 'Reaktive-Oberfläche-Komposit',
recharge: 'Aufladen',
rf: 'Raffinerie',
'refuel time': 'Auftankzeit',
'Reinforced Alloy': 'Verstärkte Legierung',
reload: 'Aktualisieren',
rename: 'Umbenennen',
repair: 'Reparieren',
reset: 'Zurücksetzen',
ret: 'Eing',
retracted: 'Eingefahren',
'retrofit costs': 'Änderungskosten',
'retrofit from': 'Nachrüsten von',
ROF: 'Kad',
S: 'K',
save: 'Speichern',
sc: 'Scanner',
PHRASE_SELECT_BUILDS: 'Ausstattung zum Vergleich auswählen',
sell: 'Verkaufen',
s: 'Sensoren',
settings: 'Einstellungen',
sb: 'Schild-Booster',
scb: 'Schildzellenbank',
sg: 'Schildgenerator',
shields: 'Schilde',
ship: 'Schiff',
ships: 'Schiffe',
shortened: 'Gekürzt',
size: 'Größe',
skip: 'Überspringen',
small: 'Klein',
speed: 'Geschwindigkeit',
standard: 'Standard',
'Standard Docking Computer': 'Standard-Landecomputer',
Stock: 'Standard',
T: 't',
T_LOAD: 'T-Lad',
'The Retributor': 'Retributor',
t: 'Schubdüsen',
time: 'Dauer',
tp: 'Torpedoaufhängung',
total: 'Gesamt',
'total range': 'Maximale Reichweite',
turret: 'Geschützturm',
type: 'Typ',
U: 'W',
unladen: 'Unbeladen',
PHRASE_UPDATE_RDY: 'Update verfügbar! Klicken zum Aktualisieren',
utility: 'Werkzeug',
'utility mounts': 'Werkzeug-Steckplätze',
WEP: 'WAF',
yes: 'Ja',
PHRASE_BACKUP_DESC: 'Export aller Coriolis-Daten, um sie zu sichern oder oder um sie zu einem anderen Browser/Gerät zu übertragen.'
});
}]);

219
app/js/i18n/en.js Normal file
View File

@@ -0,0 +1,219 @@
angular.module('app').config(['$translateProvider', function($translateProvider) {
$translateProvider.translations('en', {
PHRASE_EXPORT_DESC: 'A detailed JSON export of your build for use in other sites and tools',
'A-Rated': 'A-Rated',
about: 'about',
action: 'action',
added: 'added',
Advanced: 'Advanced',
'Advanced Discovery Scanner': 'Advanced Discovery Scanner',
agility: 'agility',
alpha: 'alpha',
ammo: 'ammo',
PHRASE_CONFIRMATION: 'Are You Sure?',
armour: 'armour',
am: 'Auto Field-Maintenance Unit',
available: 'available',
backup: 'backup',
'Basic Discovery Scanner': 'Basic Discovery Scanner',
bl: 'Beam Laser',
beta: 'beta',
bins: 'bins',
boost: 'boost',
build: 'build',
'build name': 'Build Name',
builds: 'builds',
bh: 'bulkheads',
'bsg': 'Bi-Weave Shield Generator',
ul: 'Burst Laser',
buy: 'buy',
cancel: 'cancel',
c: 'Cannon',
capital: 'capital',
cargo: 'cargo',
'Cargo Hatch': 'Cargo Hatch',
cr: 'Cargo Rack',
cs: 'Cargo Scanner',
cells: 'cells',
'Chaff Launcher': 'Chaff Launcher',
close: 'close',
cc: 'Collector Limpet Controller',
compare: 'compare',
'compare all': 'compare all',
comparison: 'comparison',
comparisons: 'comparisons',
component: 'component',
cost: 'cost',
costs: 'costs',
cm: 'Countermeasure',
CR: 'CR',
create: 'create',
'create new': 'create new',
credits: 'credits',
Cytoscrambler: 'Cytoscrambler',
damage: 'damage',
delete: 'delete',
'delete all': 'delete all',
dep: 'dep',
deployed: 'deployed',
'detailed export': 'detailed export',
'Detailed Surface Scanner': 'Detailed Surface Scanner',
disabled: 'disabled',
discount: 'discount',
Distruptor: 'Distruptor',
dc: 'Docking Computer',
done: 'done',
DPS: 'DPS',
'edit data': 'edit data',
efficiency: 'efficiency',
'Electronic Countermeasure': 'Electronic Countermeasure',
empty: 'empty',
Enforcer: 'Enforcer',
ENG: 'ENG',
'enter name': 'Enter Name',
EPS: 'EPS',
export: 'export',
fixed: 'fixed',
forum: 'forum',
fc: 'Fragment Cannon',
fd: 'Frame Shift Drive',
ws: 'Frame Shift Wake Scanner',
FSD: 'FSD',
fi: 'FSD Interdictor',
fuel: 'fuel',
fs: 'Fuel Scoop',
ft: 'Fuel Tank',
fx: 'Fuel Transfer Limpet Controller',
'full tank': 'full tank',
Gimballed: 'Gimballed',
H: 'H',
hardpoints: 'hardpoints',
hb: 'Hatch Breaker Limpet Controller',
'Heat Sink Launcher': 'Heat Sink Launcher',
huge: 'huge',
hull: 'hull',
hr: 'Hull Reinforcement Package',
'Imperial Hammer': 'Imperial Hammer',
import: 'import',
'import all': 'import all',
insurance: 'insurance',
'Intermediate Discovery Scanner': 'Intermediate Discovery Scanner',
'internal compartments': 'internal compartments',
'jump range': 'jump range',
jumps: 'jumps',
kw: 'Kill Warrant Scanner',
L: 'L',
laden: 'laden',
language: 'language',
large: 'large',
'limpets': 'Limpets',
ls: 'life support',
'Lightweight Alloy': 'Lightweight Alloy',
'lock factor': 'lock factor',
LS: 'Ls',
LY: 'LY',
M: 'M',
'm/s': 'm/s',
mass: 'mass',
max: 'max',
'max mass': 'max mass',
medium: 'medium',
'Military Grade Composite': 'Military Grade Composite',
nl: 'Mine Launcher',
'Mining Lance': 'Mining Lance',
ml: 'Mining Laser',
'Mirrored Surface Composite': 'Mirrored Surface Composite',
mr: 'Missile Rack',
mc: 'Multi-cannon',
'net cost': 'net cost',
no: 'no',
PHRASE_NO_BUILDS: 'No builds added to comparison!',
PHRASE_NO_RETROCH: 'No Retrofitting changes',
none: 'none',
'none created': 'none created',
off: 'off',
on: 'on',
optimal: 'optimal',
'optimal mass': 'optimal mass',
'optimize mass': 'optimize mass',
overwrite: 'overwrite',
Pacifier: 'Pacifier',
'Pack-Hound': 'Pack-Hound',
PHRASE_IMPORT: 'Paste JSON or import here',
pen: 'pen',
penetration: 'penetration',
permalink: 'permalink',
pa: 'Plasma Accelerator',
'Point Defence': 'Point Defence',
power: 'power',
pd: 'power distributor',
pp: 'power plant',
pri: 'pri',
priority: 'priority',
psg: 'Prismatic Shield Generator',
proceed: 'proceed',
pc: 'Prospector Limpet Controller',
pl: 'Pulse Laser',
pv: 'Planetary Vehicle Hangar',
PWR: 'PWR',
rg: 'Rail Gun',
range: 'range',
rate: 'rate',
'Reactive Surface Composite': 'Reactive Surface Composite',
recharge: 'recharge',
rf: 'Refinery',
'refuel time': 'refuel time',
'Reinforced Alloy': 'Reinforced Alloy',
reload: 'reload',
rename: 'rename',
repair: 'repair',
reset: 'reset',
ret: 'ret',
retracted: 'retracted',
'retrofit costs': 'retrofit costs',
'retrofit from': 'retrofit from',
ROF: 'ROF',
S: 'S',
save: 'save',
sc: 'scanner',
PHRASE_SELECT_BUILDS: 'Select Builds to Compare',
sell: 'sell',
s: 'sensors',
settings: 'settings',
sb: 'Shield Booster',
scb: 'Shield Cell Bank',
sg: 'Shield Generator',
shields: 'shields',
ship: 'ship',
ships: 'ships',
shortened: 'shortened',
size: 'size',
skip: 'skip',
small: 'small',
speed: 'speed',
standard: 'standard',
'Standard Docking Computer': 'Standard Docking Computer',
Stock: 'Stock',
SYS: 'SYS',
T: 'T',
T_LOAD: 't-load',
'The Retributor': 'The Retributor',
t: 'thrusters',
time: 'time',
tp: 'Torpedo Pylon',
total: 'total',
'total range': 'total range',
turret: 'turret',
type: 'type',
U: 'U',
unladen: 'unladen',
PHRASE_UPDATE_RDY: 'Update Available! Click to Refresh',
URL: 'URL',
utility: 'utility',
'utility mounts': 'utility mounts',
version: 'version',
WEP: 'WEP',
yes: 'yes',
PHRASE_BACKUP_DESC: 'Backup of all Coriolis data to save or transfer to another browser/device'
});
}]);

212
app/js/i18n/es.js Normal file
View File

@@ -0,0 +1,212 @@
angular.module('app').config(['$translateProvider', 'localeFormatProvider', function($translateProvider, localeFormatProvider) {
// Declare number format settings
localeFormatProvider.addFormat('es', {
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']
});
$translateProvider.translations('es', {
'PHRASE_EXPORT_DESC': 'Una detallada exportaci\u00f3n JSON de tu construcci\u00f3n para usarlo en otros sitios web y herramientas',
'A-Rated': 'Calidad-A',
'about': 'Acerca',
'action': 'Acci\u00f3n',
'added': 'A\u00f1adido',
'Advanced Discovery Scanner': 'Esc\u00e1ner de exploraci\u00f3n avanzado',
'agility': 'Maniobrabilidad',
'alpha': 'Alfa',
'ammo': 'Munici\u00f3n',
'PHRASE_CONFIRMATION': '\u00bfEst\u00e1s seguro?',
'armour': 'Blindaje',
'am': 'Unidad de auto-reparaciones',
'available': 'Disponible',
'backup': 'Reserva',
'Basic Discovery Scanner': 'Esc\u00e1ner de exploraci\u00f3n b\u00e1sico',
'bl': 'L\u00e1ser de haz',
'bins': 'contenedores',
'boost': 'incrementar',
'build': 'Construcci\u00f3n',
'build name': 'Nombre de la construcci\u00f3n',
'builds': 'Construcciones',
'bh': 'mamparos',
'ul': 'Laser de r\u00e1fagas',
'buy': 'Comprar',
'cancel': 'Cancelar',
'c': 'Ca\u00f1\u00f3n',
'capital': 'capital',
'cargo': 'Carga',
'Cargo Hatch': 'Compuerta de carga',
'cr': 'Compartimento de carga',
'cs': 'Esc\u00e1ner de carga',
'cells': 'celdas',
'Chaff Launcher': 'Lanzador de birutas',
'close': 'Cerrar',
'cc': 'Controlador de Drones de Recogida',
'compare': 'Comparar',
'compare all': 'comparar todas',
'comparison': 'Comparativa',
'comparisons': 'Comparativas',
'component': 'Componente',
'cost': 'Coste',
'costs': 'Costes',
'cm': 'Contramedidas',
'create': 'Crear',
'create new': 'Crear nuevo',
'credits': 'Cr\u00e9ditos',
'damage': 'Da\u00f1o',
'delete': 'Borrar',
'delete all': 'Borrar todo',
'dep': 'desp',
'deployed': 'Desplegado',
'detailed export': 'Exportacion detallada',
'Detailed Surface Scanner': 'Escaner de exploraci\u00f3n detallada',
'disabled': 'Desactivado',
'discount': 'Descuento',
'dc': 'Ordenador de aterrizaje',
'done': 'Hecho',
'DPS': 'DPS (Da\u00f1o Por Segundo)',
'edit data': 'Editar datos',
'efficiency': 'Eficiencia',
'Electronic Countermeasure': 'Contramedidas electr\u00f3nicas',
'empty': 'Vac\u00edo',
'ENG': 'MOT',
'enter name': 'Introduce el nombre',
'export': 'exportar',
'fixed': 'fijo',
'forum': 'Foro',
'fc': 'Ca\u00f1\u00f3n de fragmentaci\u00f3n',
'fd': 'Motor de salto',
'ws': 'Esc\u00e1ner de Salto',
'fi': 'Interdictor FSD',
'fuel': 'Combustible',
'fs': 'Recolector de Combustible',
'ft': 'Tanque de combustible',
'fx': 'Sistema de Transferencia de Combustilble',
'full tank': 'Tanque lleno',
'Gimballed': 'Card\u00e1n',
'H': 'E',
'hardpoints': 'Montura de armas',
'hb': 'Controlador de Apertura de Bah\u00eda de Carga',
'Heat Sink Launcher': 'Eyector de Acumulador de Calor',
'huge': 'enorme',
'hull': 'Casco',
'hr': 'Sistema de Casco Reforzado',
'import': 'Importar',
'import all': 'Importar todo',
'insurance': 'Seguro',
'Intermediate Discovery Scanner': 'Esc\u00e1ner de exploraci\u00f3n media',
'internal compartments': 'Compartimentos internos',
'jump range': 'Rango de salto',
'jumps': 'Saltos',
'kw': 'Esc\u00e1ner Detector de Recompensas',
'L': 'G',
'laden': 'Cargada',
'language': 'Idioma',
'large': 'Grande',
'ls': 'Soporte vital',
'Lightweight Alloy': 'Aleaci\u00f3n ligera',
'limpets': 'Drones',
'lock factor': 'factor de bloqueo',
'mass': 'Masa',
'max': 'm\u00e1x',
'max mass': 'Masa m\u00e1xima',
'medium': 'medio',
'Military Grade Composite': 'Blindaje Militar',
'nl': 'Lanzaminas',
'Mining Lance': 'Lanza de miner\u00eda',
'ml': 'L\u00e1ser de miner\u00eda',
'Mirrored Surface Composite': 'Blindaje Reflectante',
'mr': 'Bah\u00eda de Misiles',
'mc': 'Ca\u00f1\u00f3n m\u00faltiple',
'net cost': 'Coste neto',
'PHRASE_NO_BUILDS': '\u00a1No se a\u00f1adieron plantillas para comparaci\u00f3n!',
'PHRASE_NO_RETROCH': 'No hay cambios en los ajutes',
'none': 'Nada',
'none created': 'Nada creado',
'off': 'apagado',
'on': 'encendido',
'optimal': '\u00f3ptimo',
'optimal mass': 'masa \u00f3ptima',
'optimize mass': 'optimizar masa',
'overwrite': 'Sobreescribir',
'PHRASE_IMPORT': 'Pega el JSON o imp\u00f3rtalo aqu\u00ed',
'penetration': 'penetraci\u00f3n',
'permalink': 'enlace permanente',
'pa': 'Acelerador de Plasma',
'Point Defence': 'Punto de Defensa',
'power': 'energ\u00eda',
'pd': 'distribuidor de energ\u00eda',
'pp': 'Planta de Energ\u00eda',
'priority': 'prioridad',
'proceed': 'Proceder',
'pc': 'Controlador de drones de prospecci\u00f3n',
'pl': 'L\u00e1ser de Pulso',
'PWR': 'POT',
'rg': 'Ca\u00f1\u00f3n de Riel',
'range': 'rango',
'rate': 'ratio',
'Reactive Surface Composite': 'Blindaje Reactivo',
'recharge': 'recargar',
'rf': 'Refineria',
'refuel time': 'Tiempo para repostar',
'Reinforced Alloy': 'Armadura reforzada',
'reload': 'Recargar',
'rename': 'Renombrar',
'repair': 'Reparar',
'reset': 'Reiniciar',
'ret': 'PLE',
'retracted': 'plegadas',
'retrofit costs': 'costes de equipamiento',
'retrofit from': 'equipamiento desde',
'ROF': 'RDF',
'S': 'P',
'save': 'guardar',
'sc': 'sc\u00e1ner',
'PHRASE_SELECT_BUILDS': 'Selecciona equipamientos para comparar',
'sell': 'Vender',
's': 'Sensores',
'settings': 'Configuraci\u00f3n',
'sb': 'Potenciador de Escudos',
'scb': 'C\u00e9lula de Energ\u00eda de Escudos',
'sg': 'Generador de escudos',
'shields': 'Escudos',
'ship': 'Nave ',
'ships': 'Naves',
'shortened': 'Abreviado',
'size': 'Tama\u00f1o',
'skip': 'omitir',
'small': 'Peque\u00f1o',
'speed': 'velocidad',
'standard': 'est\u00e1ndar',
'Standard Docking Computer': 'Computador de Atraque Est\u00e1ndar',
'Stock': 'De serie',
'SYS': 'SIS',
'T_LOAD': 'c-t\u00e9rmica',
't': 'Propulsores',
'time': 'Tiempo',
'tp': 'Anclaje de torpedo',
'total': 'Total',
'total range': 'Rango total',
'turret': 'torreta',
'type': 'Tipo',
'unladen': 'Sin carga',
'PHRASE_UPDATE_RDY': 'Actualizacion disponible! Haz click para recargar',
'URL': 'Enlace',
'utility': 'utilidad',
'utility mounts': 'monturas de utilidad',
'version': 'Versi\u00f3n',
'WEP': 'ARM',
'yes': 'si',
'PHRASE_BACKUP_DESC': 'Copia de seguridad de todos los datos de Coriolis para guardarlos o transferirlos a otro navegador\/dispositivo'
});
}]);

200
app/js/i18n/fr.js Normal file
View File

@@ -0,0 +1,200 @@
angular.module('app').config(['$translateProvider', 'localeFormatProvider', function($translateProvider, localeFormatProvider) {
// Declare number format settings
localeFormatProvider.addFormat('fr', {
decimal: ',',
thousands: '.',
grouping: [3],
currency: ['', ' €'],
dateTime: '%A, le %e %B %Y, %X',
date: '%d/%m/%Y',
time: '%H:%M:%S',
periods: ['AM', 'PM'], // unused
days: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'],
shortDays: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'],
months: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'],
shortMonths: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.']
});
$translateProvider.translations('fr', {
PHRASE_EXPORT_DESC: 'Export détaillé en JSON de votre configuration pour utilisation sur d\'autres sites et outils',
'A-Rated': 'Classe-A ',
about: 'à propos',
added: 'ajouté',
Advanced: 'Avancé',
'Advanced Discovery Scanner': 'Détecteur découverte avancé',
agility: 'manœuvrabilité',
ammo: 'munitions',
PHRASE_CONFIRMATION: 'Êtes-vous sûr ?',
armour: 'Armure',
am: 'Unité de maintenance de terrain auto',
available: 'Disponibilité',
backup: 'sauvegarde',
'Basic Discovery Scanner': 'Détecteur découverte simple',
bl: 'Rayon Laser',
bins: 'bennes',
build: 'Configuration',
'build name': 'Nom de la configuration',
builds: 'Configurations',
bh: 'Coque',
ul: 'Laser à rafale',
buy: 'Acheter',
cancel: 'Annuler',
c: 'Canon',
cargo: 'Soute',
'Cargo Hatch': 'Écoutille de soute',
cr: 'Compartiment de soute',
cs: 'Détecteur de cargaison',
cells: 'Cellules',
'Chaff Launcher': 'Lanceur de paillettes',
close: 'fermer',
cc: 'Contrôleur de Collecteur',
compare: 'comparer',
'compare all': 'tout comparer',
comparison: 'comparaison',
comparisons: 'comparaisons',
component: 'composant',
cost: 'coût',
costs: 'coûts',
cm: 'Contre-mesure',
create: 'Créer',
'create new': 'Créer nouveau',
credits: 'crédits',
damage: 'Dégâts',
delete: 'supprimer',
'delete all': 'tout supprimer',
dep: 'depl',
deployed: 'déployé',
'detailed export': 'export détaillé',
'Detailed Surface Scanner': 'Détecteur surface détaillé',
disabled: 'désactivé',
discount: 'réduction',
Distruptor: 'Disrupteur',
dc: 'Ordinateur d\'appontage',
done: 'Valider',
'edit data': 'Editer donnée',
efficiency: 'efficacité',
'Electronic Countermeasure': 'Contre-mesures électroniques',
empty: 'Vide',
'enter name': 'Entrer un nom',
fixed: 'fixé',
fc: 'Canon à fragmentation',
fd: 'Réacteur FSD',
ws: 'Détecteur de sillage FSD',
fi: 'Intercepteur de réacteur FSD',
fuel: 'carburant',
fs: 'Récupérateur de carburant',
ft: 'Réservoir de carburant',
fx: 'Contrôleur de ravitailleur',
'full tank': 'Réservoir plein',
Gimballed: 'Point',
hardpoints: 'Points d\'emport',
hb: 'Contrôle de patelle perce-soute',
'Heat Sink Launcher': 'Éjecteur de dissipateur thermique',
huge: 'Très grand',
hull: 'Coque',
hr: 'Ensemble de mesures permettant de renforcer la coque',
'Imperial Hammer': 'Marteau impérial',
import: 'Importer',
'import all': 'Importer tout',
insurance: 'Assurance',
'Intermediate Discovery Scanner': 'Détecteur découverte intermédiaire',
'internal compartments': 'compartiments internes',
'jump range': 'Distance de saut',
jumps: 'Sauts',
kw: 'Détecteur d\'avis de recherche',
laden: 'chargé',
language: 'Langue',
large: 'large',
ls: 'Systèmes de survie',
'Lightweight Alloy': 'alliage léger',
'limpets': 'Patelles',
'lock factor': 'facteur inhibition de masse',
LS: 'SL',
LY: 'AL',
mass: 'Masse',
'max mass': 'masse max',
'Military Grade Composite': 'Composite militaire',
nl: 'Lance-mines',
'Mining Lance': 'Lance de minage',
ml: 'Laser minier',
'Mirrored Surface Composite': 'Composite à surface miroir',
mr: 'Batterie de missiles',
mc: 'Canon multiple',
'net cost': 'coûts nets',
no: 'non',
PHRASE_NO_BUILDS: 'Aucune configuration ajoutée pour comparaison',
PHRASE_NO_RETROCH: 'Configuration non modifiée',
none: 'aucun',
'none created': 'Rien de créé',
off: 'éteint',
on: 'allumé',
'optimal mass': 'masse optimale',
'optimize mass': 'optimiser masse',
overwrite: 'remplacer',
Pacifier: 'Pacificateur',
PHRASE_IMPORT: 'Coller ici votre JSON à importer',
pen: 'pén.',
penetration: 'pénétration',
permalink: 'lien durable',
pa: 'accélérateur plasma',
'Point Defence': 'Défense ponctuelle',
power: 'énergie',
pd: 'Répartiteur de puissance',
pp: 'Générateur',
priority: 'priorité',
psg: 'générateur de bouclier prisme',
proceed: 'continuer',
pc: 'Contrôleur de prospecteur',
pl: 'Laser à impulsion',
PWR: 'P',
rg: 'Canon électrique',
range: 'portée',
rate: 'cadence',
'Reactive Surface Composite': 'Composite à surface réactive',
recharge: 'recharger',
rf: 'Raffinerie',
'refuel time': 'Temps de remplissage',
'Reinforced Alloy': 'alliage renforcé',
reload: 'recharger',
rename: 'renommer',
repair: 'réparer',
reset: 'Réinitialisation',
ret: 'esc',
retracted: 'escamoté',
'retrofit costs': 'Valeur de rachat',
'retrofit from': 'Racheter de',
ROF: 'cadence',
save: 'sauvegarder',
sc: 'scanner',
PHRASE_SELECT_BUILDS: 'Sélectionner les configurations à comparer',
sell: 'vendre',
s: 'Capteurs',
settings: 'paramètres',
sb: 'Survolteur de bouclier',
scb: 'Réserve de cellules d\'énergie',
sg: 'Générateur de bouclier',
shields: 'boucliers',
ship: 'vaisseau',
ships: 'vaisseaux',
shortened: 'raccourci',
size: 'taille',
skip: 'Suivant',
small: 'petit',
speed: 'vitesse',
'Standard Docking Computer': 'Ordinateur d\'appontage standard',
Stock: 'de base',
T_LOAD: 'Charge thermique',
'The Retributor': 'Le Rétributeur',
t: 'propulseurs',
time: 'temps',
tp: 'Tube lance-torpille',
'total range': 'Distance maximale',
turret: 'tourelle',
unladen: 'Non chargé',
PHRASE_UPDATE_RDY: 'Mise à jour disponible ! Cliquez ici pour mettre à jour',
utility: 'utilitaire',
'utility mounts': 'Support utilitaire',
WEP: 'ARM',
yes: 'oui',
PHRASE_BACKUP_DESC: 'Exportation détaillée des données de Coriolis pour l\'utilisation dans d\'autres sites et outils'
});
}]);

133
app/js/i18n/it.js Normal file
View File

@@ -0,0 +1,133 @@
angular.module('app').config(['$translateProvider', 'localeFormatProvider', function($translateProvider, localeFormatProvider) {
// Declare number format settings
localeFormatProvider.addFormat('es', {
decimal: ',',
thousands: '.',
grouping: [3],
currency: ['€', ''],
dateTime: '%A %e %B %Y, %X',
date: '%d/%m/%Y',
time: '%H:%M:%S',
periods: ['AM', 'PM'], // unused
days: ['Domenica', 'Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato'],
shortDays: ['Dom', 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab'],
months: ['Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre'],
shortMonths: ['Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic']
});
$translateProvider.translations('it', {
PHRASE_EXPORT_DESC: 'Un export dettagliato in formato JSON della tua configurazione per essere usato in altri siti o tools',
'A-Rated': 'Classe A',
about: 'Info su Coriolis',
action: 'azione',
added: 'aggiunto',
Advanced: 'Avanzato',
agility: 'agilità',
ammo: 'munizioni',
PHRASE_CONFIRMATION: 'Sei sicuro ?',
armour: 'armatura',
available: 'disponibile',
bins: 'contenitore',
build: 'configurazione',
'build name': 'Nome Configurazione',
builds: 'configurazioni',
buy: 'compra',
cancel: 'cancella',
cells: 'celle',
close: 'chiudi',
compare: 'confronta',
'compare all': 'confronta tutti',
comparison: 'comparazione',
comparisons: 'comparazioni',
component: 'componente',
cost: 'costo',
costs: 'costi',
cm: 'Contromisure',
create: 'crea',
'create new': 'crea nuovo',
credits: 'crediti',
damage: 'danno',
delete: 'elimina',
'delete all': 'elimina tutto',
dep: 'dep',
deployed: 'deployed',
'detailed export': 'esportazione dettagliata',
disabled: 'disabilita',
discount: 'sconto',
done: 'fatto',
'edit data': 'modifica i dati',
efficiency: 'efficenza',
empty: 'vuoto',
Enforcer: 'Rinforzatore',
'enter name': 'Inserisci un nome',
export: 'esporta',
fixed: 'fissi',
fuel: 'carburante',
'full tank': 'Serbatoio Pieno',
huge: 'enorme',
hull: 'corazza',
import: 'importa',
'import all': 'importa tutto',
insurance: 'assicurazione',
'internal compartments': 'compartimenti interni',
'jump range': 'distanza di salto',
jumps: 'salti',
laden: 'carico',
language: 'lingua',
large: 'largo',
mass: 'massa',
max: 'massimo',
'max mass': 'massa massimale',
medium: 'medio',
'net cost': 'costo netto',
PHRASE_NO_BUILDS: 'nessuna configurazione è stata aggiunta per la comparazione!',
PHRASE_NO_RETROCH: 'Nessun cambiamento di Retrofitting',
none: 'nessuno',
'none created': 'nessuno creato',
optimal: 'ottimale',
'optimal mass': 'massa ottimale',
'optimize mass': 'ottimizza la massa',
overwrite: 'sovrasscrivi',
PHRASE_IMPORT: 'Incolla un JSON o importalo qua',
penetration: 'penetrazione',
power: 'potenza',
priority: 'priorità',
proceed: 'procedi',
range: 'distanza',
rate: 'rateo',
recharge: 'ricarica',
reload: 'ricarica',
rename: 'rinomina',
repair: 'ripara',
reset: 'resetta',
retracted: 'retratti',
'retrofit costs': 'costi di retrofit',
'retrofit from': 'retrofit da',
save: 'salva',
sell: 'vendi',
settings: 'impostazioni',
shields: 'scudi',
ship: 'nave',
ships: 'navi',
shortened: 'accorciato',
size: 'grandezza',
skip: 'salta',
small: 'piccolo',
speed: 'velocità',
Stock: 'appena comprata',
t: 'thrusters',
time: 'tempo',
total: 'totale',
'total range': 'distanza totale',
turret: 'torrette',
type: 'tipo',
unladen: 'scarico',
PHRASE_UPDATE_RDY: 'Aggiornamenti disponibili ! Clicca per Aggiornare',
utility: 'supporti',
'utility mounts': 'supporti di utilità',
version: 'versione',
yes: 'sì',
PHRASE_BACKUP_DESC: 'Esportazione di tutti i dati su Coriolis per salvarli o trasferirli in un altro Browser/dispositivo'
});
}]);

23
app/js/i18n/languages.js Normal file
View File

@@ -0,0 +1,23 @@
angular.module('app').config(['$translateProvider', function($translateProvider) {
$translateProvider
.useSanitizeValueStrategy('escapeParameters')
.useStorage('Persist')
.fallbackLanguage('en') // Use English as default/fallback language
.registerAvailableLanguageKeys(['en', 'de', 'es', 'fr', 'it', 'ru'], {
'en*': 'en',
'de*': 'de',
'es*': 'es',
'fr*': 'fr',
'it*': 'it',
'ru*': 'ru'
})
.determinePreferredLanguage();
}])
.value('Languages', {
en: 'English',
de: 'Deutsch',
it: 'Italiano',
es: 'Español',
fr: 'Français',
ru: 'ру́сский'
});

234
app/js/i18n/ru.js Normal file
View File

@@ -0,0 +1,234 @@
angular.module('app').config(['$translateProvider', 'localeFormatProvider', function($translateProvider, localeFormatProvider) {
// Declare number format settings
localeFormatProvider.addFormat('ru', {
decimal: ',',
thousands: '\xa0',
grouping: [3],
currency: ['', ' руб.'],
dateTime: '%A, %e %B %Y г. %X',
date: '%d.%m.%Y',
time: '%H:%M:%S',
periods: ['AM', 'PM'],
days: ['воскресенье', 'понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота'],
shortDays: ['вс', 'пн', 'вт', 'ср', 'чт', 'пт', 'сб'],
months: ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря'],
shortMonths: ['янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек']
});
$translateProvider.translations('ru', {
PHRASE_EXPORT_DESC: 'Подробный экспорта JSON вашего телосложения для использования в других местах и инструментов',
'A-Rated': 'А-Класса',
about: 'О сайте',
action: 'Действие',
added: 'Добавлено',
Advanced: 'Продвинутый',
'Advanced Discovery Scanner': 'Продвинутый астросканер',
agility: 'Маневренность',
alpha: 'Альфа',
ammo: 'Боекомплект',
PHRASE_CONFIRMATION: 'Вы уверены?',
armour: 'Броня',
am: 'Ремонтный модуль',
available: 'доступно',
backup: 'Резервная копия',
'Basic Discovery Scanner': 'Стандартный исследовательский сканер',
bl: 'Лучевой лазер',
beta: 'Бета',
bins: 'контейнеры',
boost: 'форсаж',
build: 'cборка',
'build name': 'название сборки',
builds: 'cборки',
bh: 'Корпус',
ul: 'Мультиимпульсный лазер',
buy: 'купить',
cancel: 'отменить',
c: 'Пушка',
capital: 'Крупный',
cargo: 'Груз',
'Cargo Hatch': 'Грузовой люк',
cr: 'Грузовой отсек',
cs: 'Сканер груза',
cells: 'Ячейки',
'Chaff Launcher': 'Постановщик помех',
close: 'закрыть',
cc: 'Контроллер "дрон-сборщик"',
compare: 'сравнить ',
'compare all': 'сравнить все',
comparison: 'сравнение',
comparisons: 'сравнения',
component: 'Компонент',
cost: 'Стоимость',
costs: 'Расходы',
cm: 'Контрмеры',
CR: 'кр.',
create: 'создать',
'create new': 'Создать новый',
credits: 'Кредиты',
Cytoscrambler: 'сайтоскрамблер',
damage: 'Урон',
delete: 'Удалить',
'delete all': 'Удалить все',
dep: 'Вып',
deployed: 'Открыты',
'detailed export': 'Подробный экспорт',
'Detailed Surface Scanner': 'Подробный сканер поверхности',
disabled: 'Отключено',
discount: 'Скидка',
Distruptor: 'Дисраптор',
dc: 'Стыковочный компьютер',
done: 'готово',
DPS: 'УВС',
'edit data': 'Редактирование',
efficiency: 'Эффективность',
'Electronic Countermeasure': 'Электронная противомера',
empty: 'пусто',
Enforcer: 'Энфорсер',
ENG: 'ДВГ',
'enter name': 'Введите имя',
EPS: 'ЭВС',
export: 'Экспорт',
fixed: 'Фиксированое',
forum: 'Форум',
fc: 'Осколочное Орудие',
fd: 'Двигатель FSD',
ws: 'FSD Сканнер',
fi: 'Перехватчик FSD',
fuel: 'Топливо',
fs: 'Топливосборщик',
ft: 'Топливный бак',
fx: 'Контроллер Дрона-заправщика',
'full tank': 'Полный бак',
Gimballed: 'Шарнирное',
H: 'O',
hardpoints: 'Орудийные порты',
hb: 'Контроллер "дрон-взломщик"',
'Heat Sink Launcher': 'Теплоотводная ПУ',
huge: 'огромный',
hull: 'Корпус',
hr: 'Набор усиления корпуса',
'Imperial Hammer': 'Имперский Молот',
import: 'импортировать ',
'import all': 'импортировать все',
insurance: 'Страховка',
'Intermediate Discovery Scanner': 'Средний исследовательский сканер',
'internal compartments': 'внутренние отсеки',
'jump range': 'Дальность прыжка',
jumps: 'Прыжков',
kw: 'Полицейский сканер',
L: 'б',
laden: 'Груженый',
language: 'Язык',
large: 'большой',
ls: 'Система жизнеобеспечения',
'Lightweight Alloy': 'Легкий сплав',
'limpets': 'Дроны',
'lock factor': 'Масс. блок',
LS: 'Св.сек',
LY: 'Св.лет',
M: 'С',
'm/s': 'м/с',
mass: 'Масса',
max: 'Макс',
'max mass': 'Максимальная масса',
medium: 'Средний',
'Military Grade Composite': 'Военный композит',
nl: 'Минноукладчик',
'Mining Lance': 'Бурильная сулица',
ml: 'Бурильный лазер',
'Mirrored Surface Composite': 'Зеркальный композит',
mr: 'Ракетная установка',
mc: 'Многоствольное орудие',
'net cost': 'разница в цене',
no: 'Нет',
PHRASE_NO_BUILDS: 'Нечего сравнивать',
PHRASE_NO_RETROCH: 'нет ранних версий сборки\конфигурации',
none: 'ни один',
'none created': 'не создано',
off: 'выкл',
on: 'вкл',
optimal: 'Оптимальный',
'optimal mass': 'Оптимальная масса',
'optimize mass': 'Оптимизировать массу',
overwrite: 'перезаписать',
Pacifier: 'Миротворец',
'Pack-Hound': 'Ракета "Гончая"',
PHRASE_IMPORT: 'Для импорта вставьте код в эту форму',
pen: 'ПБ',
penetration: 'Пробитие',
permalink: 'Постоянная ссылка',
pa: 'Ускоритель плазмы',
'Point Defence': 'Противоракетная защита',
power: 'Мощность',
pd: 'Распределитель энергии',
pp: 'Реактор',
pri: 'Осн',
priority: 'Приоритет',
psg: 'Генератор призматического щита',
proceed: 'продолжить',
pc: 'Контроллер "Дрон-исследователь"',
pl: 'Импульсный лазер',
PWR: 'Эн',
rg: 'Рельсотрон',
range: 'Дальность',
rate: 'скорость',
'Reactive Surface Composite': 'Динамическая защита',
recharge: 'Перезарядка',
rf: 'Переработка',
'refuel time': 'Время дозаправки',
'Reinforced Alloy': 'Усиленный сплав',
reload: 'Перезарядить',
rename: 'Переименовать',
repair: 'Починка',
reset: 'Сброс',
ret: 'Убр.',
retracted: 'Убрано',
'retrofit costs': 'цена модификации',
'retrofit from': 'модификация от',
ROF: 'В/сек',
S: 'М',
save: 'Сохранить',
sc: 'Сканер',
PHRASE_SELECT_BUILDS: 'Выберите конфигурацию для сравнения',
sell: 'Продать',
s: 'Сенсоры',
settings: 'Настройки',
sb: 'Усилитель щита',
scb: 'Батареи перезарядки щита',
sg: 'Генератор щита',
shields: 'Щиты',
ship: 'Корабль',
ships: 'Корабли',
shortened: 'Укороченный',
size: 'размер',
skip: 'пропустить',
small: 'Малый',
speed: 'скорость',
standard: 'Стандартный',
'Standard Docking Computer': 'Стандартный стыковочный компьютер',
Stock: 'Стандартная комплектация',
SYS: 'СИС',
T: 'Т',
T_LOAD: 'Тепл.',
'The Retributor': '"Возмездие"',
t: 'Двигатели',
time: 'Время',
tp: 'Торпедный аппарат',
total: 'Всего',
'total range': 'Общий радиус',
turret: 'Туррель',
type: 'Тип',
U: 'В',
unladen: 'Пустой',
PHRASE_UPDATE_RDY: 'Доступно обновление. Нажмите для обновления.',
URL: 'Ссылка',
utility: 'Вспомогательное',
'utility mounts': 'Вспомогательное оборудование',
version: 'Версия',
WEP: 'ОРУ',
yes: 'Да',
PHRASE_BACKUP_DESC: 'Сохраните все данные перед переносом в другой браузер или устройство'
});
}]);

View File

@@ -0,0 +1,36 @@
angular.module('app').provider('localeFormat', function localeFormatProvider() {
var formats = {
en: {
decimal: '.',
thousands: ',',
grouping: [3],
currency: ['$', ''],
dateTime: '%a %b %e %X %Y',
date: '%m/%d/%Y',
time: '%H:%M:%S',
periods: ['AM', 'PM'],
days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
shortDays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
shortMonths: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
}
};
function LocaleFormat(formatMap) {
this.formatMap = formatMap;
this.get = function(lang) {
return this.formatMap[lang] ? this.formatMap[lang] : this.formatMap.en;
};
}
this.addFormat = function(langCode, formatDetails) {
formats[langCode] = formatDetails;
};
this.$get = [function() {
return new LocaleFormat(formats);
}];
});

View File

@@ -4,6 +4,10 @@
angular.module('app').service('Persist', ['$window', 'lodash', function($window, _) {
var LS_KEY_BUILDS = 'builds';
var LS_KEY_COMPARISONS = 'comparisons';
var LS_KEY_LANG = 'NG_TRANSLATE_LANG_KEY';
var LS_KEY_COST_TAB = 'costTab';
var LS_KEY_INSURANCE = 'insurance';
var LS_KEY_DISCOUNTS = 'discounts';
var localStorage = $window.localStorage;
var buildJson = null;
var comparisonJson = null;
@@ -28,6 +32,22 @@ angular.module('app').service('Persist', ['$window', 'lodash', function($window,
hasBuilds: buildCount > 0,
hasComparisons: Object.keys(this.comparisons).length > 0
};
this.put = function(name, value) {
if (!this.lsEnabled) {
return;
}
localStorage.setItem(name, value);
};
this.get = function(name) {
return this.lsEnabled ? localStorage.getItem(name) : null;
};
this.getLangCode = function() {
return this.lsEnabled ? localStorage.getItem(LS_KEY_LANG) : null;
};
/**
* Persist a ship build in local storage.
*
@@ -117,7 +137,7 @@ angular.module('app').service('Persist', ['$window', 'lodash', function($window,
}
this.comparisons[name] = {
facets: facets,
builds: _.map(builds, function(b) { return { shipId: b.id, buildName: b.buildName }; })
builds: _.map(builds, function(b) { return { shipId: b.id || b.shipId, buildName: b.buildName }; })
};
localStorage.setItem(LS_KEY_COMPARISONS, angular.toJson(this.comparisons));
this.state.hasComparisons = true;
@@ -162,13 +182,23 @@ angular.module('app').service('Persist', ['$window', 'lodash', function($window,
}
};
this.getAll = function() {
var data = {};
data[LS_KEY_BUILDS] = this.builds;
data[LS_KEY_COMPARISONS] = this.comparisons;
data[LS_KEY_INSURANCE] = this.getInsurance();
data[LS_KEY_DISCOUNTS] = this.getDiscount();
return data;
};
/**
* Get the saved insurance type
* @return {string} The name of the saved insurance type of null
*/
this.getInsurance = function() {
if (this.lsEnabled) {
return localStorage.getItem('insurance');
return localStorage.getItem(LS_KEY_INSURANCE);
}
return null;
};
@@ -179,7 +209,7 @@ angular.module('app').service('Persist', ['$window', 'lodash', function($window,
*/
this.setInsurance = function(name) {
if (this.lsEnabled) {
return localStorage.setItem('insurance', name);
return localStorage.setItem(LS_KEY_INSURANCE, name);
}
};
@@ -189,7 +219,7 @@ angular.module('app').service('Persist', ['$window', 'lodash', function($window,
*/
this.setDiscount = function(val) {
if (this.lsEnabled) {
return localStorage.setItem('discount', val);
return localStorage.setItem(LS_KEY_DISCOUNTS, angular.toJson(val));
}
};
@@ -199,14 +229,35 @@ angular.module('app').service('Persist', ['$window', 'lodash', function($window,
*/
this.getDiscount = function() {
if (this.lsEnabled) {
return localStorage.getItem('discount');
return angular.fromJson(localStorage.getItem(LS_KEY_DISCOUNTS));
}
return null;
};
/**
* Persist selected cost tab
* @param {number} val Discount value/amount
*/
this.setCostTab = function(tabName) {
if (this.lsEnabled) {
return localStorage.setItem(LS_KEY_COST_TAB, tabName);
}
};
/**
* Get the saved discount
* @return {number} val Discount value/amount
*/
this.getCostTab = function() {
if (this.lsEnabled) {
return localStorage.getItem(LS_KEY_COST_TAB);
}
return null;
};
/**
* Retrieve the last router state from local storage
* @param {object} state State object containing state name and params
* @return {object} state State object containing state name and params
*/
this.getState = function() {
if (this.lsEnabled) {
@@ -228,6 +279,30 @@ angular.module('app').service('Persist', ['$window', 'lodash', function($window,
}
};
/**
* Retrieve the last router state from local storage
* @return {number} size Ratio
*/
this.getSizeRatio = function() {
if (this.lsEnabled) {
var ratio = localStorage.getItem('sizeRatio');
if (!isNaN(ratio) && ratio > 0.6) {
return ratio;
}
}
return 1;
};
/**
* Save the current size ratio to localstorage
* @param {number} sizeRatio
*/
this.setSizeRatio = function(sizeRatio) {
if (this.lsEnabled) {
localStorage.setItem('sizeRatio', sizeRatio);
}
};
/**
* Check if localStorage is enabled/active
* @return {Boolean} True if localStorage is enabled

View File

@@ -1,7 +1,7 @@
/**
* Service managing seralization and deserialization of models for use in URLs and persistene.
*/
angular.module('app').service('Serializer', ['lodash', function(_) {
angular.module('app').service('Serializer', ['lodash', 'GroupMap', 'MountMap', 'ShipsDB', 'Ship', 'Components', '$state', function(_, GroupMap, MountMap, ShipsDB, Ship, Components, $state) {
/**
* Serializes the ships selected components for all slots to a URL friendly string.
@@ -10,13 +10,13 @@ angular.module('app').service('Serializer', ['lodash', function(_) {
*/
this.fromShip = function(ship) {
var power = {
enabled: [ship.cargoScoop.enabled ? 1 : 0],
priorities: [ship.cargoScoop.priority]
enabled: [ship.cargoHatch.enabled ? 1 : 0],
priorities: [ship.cargoHatch.priority]
};
var data = [
ship.bulkheads.id,
_.map(ship.common, mapGroup, power),
_.map(ship.standard, mapGroup, power),
_.map(ship.hardpoints, mapGroup, power),
_.map(ship.internal, mapGroup, power),
'.',
@@ -32,11 +32,11 @@ angular.module('app').service('Serializer', ['lodash', function(_) {
* Updates an existing ship instance's slots with components determined by the
* code.
*
* @param {Ship} ship The ship instance to be updated
* @param {string} code The string to deserialize
* @param {Ship} ship The ship instance to be updated
* @param {string} dataString The string to deserialize
*/
this.toShip = function(ship, dataString) {
var common = new Array(ship.common.length),
var standard = new Array(ship.standard.length),
hardpoints = new Array(ship.hardpoints.length),
internal = new Array(ship.internal.length),
parts = dataString.split('.'),
@@ -52,16 +52,12 @@ angular.module('app').service('Serializer', ['lodash', function(_) {
priorities = LZString.decompressFromBase64(parts[2].replace(/-/g, '/')).split('');
}
decodeToArray(code, internal, decodeToArray(code, hardpoints, decodeToArray(code, common, 1)));
// get the remaining substring / split into parts for
// - priorities
// - enabled/disabled
decodeToArray(code, internal, decodeToArray(code, hardpoints, decodeToArray(code, standard, 1)));
ship.buildWith(
{
bulkheads: code.charAt(0) * 1,
common: common,
standard: standard,
hardpoints: hardpoints,
internal: internal
},
@@ -70,6 +66,116 @@ angular.module('app').service('Serializer', ['lodash', function(_) {
);
};
this.toDetailedBuild = function(buildName, ship, code) {
var standard = ship.standard,
hardpoints = ship.hardpoints,
internal = ship.internal;
var data = {
$schema: 'http://cdn.coriolis.io/schemas/ship-loadout/2.json#',
name: buildName,
ship: ship.name,
references: [{
name: 'Coriolis.io',
url: $state.href('outfit', { shipId: ship.id, code: code, bn: buildName }, { absolute: true }),
code: code,
shipId: ship.id
}],
components: {
standard: {
bulkheads: ship.bulkheads.c.name,
cargoHatch: { enabled: Boolean(ship.cargoHatch.enabled), priority: ship.cargoHatch.priority + 1 },
powerPlant: { class: standard[0].c.class, rating: standard[0].c.rating, enabled: Boolean(standard[0].enabled), priority: standard[0].priority + 1 },
thrusters: { class: standard[1].c.class, rating: standard[1].c.rating, enabled: Boolean(standard[1].enabled), priority: standard[1].priority + 1 },
frameShiftDrive: { class: standard[2].c.class, rating: standard[2].c.rating, enabled: Boolean(standard[2].enabled), priority: standard[2].priority + 1 },
lifeSupport: { class: standard[3].c.class, rating: standard[3].c.rating, enabled: Boolean(standard[3].enabled), priority: standard[3].priority + 1 },
powerDistributor: { class: standard[4].c.class, rating: standard[4].c.rating, enabled: Boolean(standard[4].enabled), priority: standard[4].priority + 1 },
sensors: { class: standard[5].c.class, rating: standard[5].c.rating, enabled: Boolean(standard[5].enabled), priority: standard[5].priority + 1 },
fuelTank: { class: standard[6].c.class, rating: standard[6].c.rating, enabled: Boolean(standard[6].enabled), priority: standard[6].priority + 1 }
},
hardpoints: _.map(_.filter(hardpoints, function(slot) { return slot.maxClass > 0; }), slotToSchema),
utility: _.map(_.filter(hardpoints, function(slot) { return slot.maxClass === 0; }), slotToSchema),
internal: _.map(internal, slotToSchema)
},
stats: {}
};
for (var stat in ship) {
if (!isNaN(ship[stat])) {
data.stats[stat] = Math.round(ship[stat] * 100) / 100;
}
}
return data;
};
this.fromDetailedBuild = function(detailedBuild) {
var shipId = _.findKey(ShipsDB, { properties: { name: detailedBuild.ship } });
if (!shipId) {
throw 'No such ship: ' + detailedBuild.ship;
}
var comps = detailedBuild.components;
var standard = comps.standard;
var priorities = [ standard.cargoHatch && standard.cargoHatch.priority !== undefined ? standard.cargoHatch.priority - 1 : 0 ];
var enabled = [ standard.cargoHatch && standard.cargoHatch.enabled !== undefined ? standard.cargoHatch.enabled : true ];
var shipData = ShipsDB[shipId];
var ship = new Ship(shipId, shipData.properties, shipData.slots);
var bulkheads = Components.bulkheadIndex(standard.bulkheads);
if (bulkheads < 0) {
throw 'Invalid bulkheads: ' + standard.bulkheads;
}
var standardIds = _.map(
['powerPlant', 'thrusters', 'frameShiftDrive', 'lifeSupport', 'powerDistributor', 'sensors', 'fuelTank'],
function(c) {
if (!standard[c].class || !standard[c].rating) {
throw 'Invalid value for ' + c;
}
priorities.push(standard[c].priority === undefined ? 0 : standard[c].priority - 1);
enabled.push(standard[c].enabled === undefined ? true : standard[c].enabled);
return standard[c].class + standard[c].rating;
}
);
var internal = _.map(comps.internal, function(c) { return c ? Components.findInternalId(c.group, c.class, c.rating, c.name) : 0; });
var hardpoints = _.map(comps.hardpoints, function(c) {
return c ? Components.findHardpointId(c.group, c.class, c.rating, c.name, MountMap[c.mount], c.missile) : 0;
}).concat(_.map(comps.utility, function(c) {
return c ? Components.findHardpointId(c.group, c.class, c.rating, c.name, MountMap[c.mount]) : 0;
}));
// The ordering of these arrays must match the order in which they are read in Ship.buildWith
priorities = priorities.concat(_.map(comps.hardpoints, function(c) { return (!c || c.priority === undefined) ? 0 : c.priority - 1; }),
_.map(comps.utility, function(c) { return (!c || c.priority === undefined) ? 0 : c.priority - 1; }),
_.map(comps.internal, function(c) { return (!c || c.priority === undefined) ? 0 : c.priority - 1; }));
enabled = enabled.concat(_.map(comps.hardpoints, function(c) { return (!c || c.enabled === undefined) ? true : c.enabled * 1; }),
_.map(comps.utility, function(c) { return (!c || c.enabled === undefined) ? true : c.enabled * 1; }),
_.map(comps.internal, function(c) { return (!c || c.enabled === undefined) ? true : c.enabled * 1; }));
ship.buildWith({ bulkheads: bulkheads, standard: standardIds, hardpoints: hardpoints, internal: internal }, priorities, enabled);
return ship;
};
this.toDetailedExport = function(builds) {
var data = [];
for (var shipId in builds) {
for (var buildName in builds[shipId]) {
var code = builds[shipId][buildName];
var shipData = ShipsDB[shipId];
var ship = new Ship(shipId, shipData.properties, shipData.slots);
this.toShip(ship, code);
data.push(this.toDetailedBuild(buildName, ship, code));
}
}
return data;
};
this.fromComparison = function(name, builds, facets, predicate, desc) {
var shipBuilds = [];
@@ -118,4 +224,22 @@ angular.module('app').service('Serializer', ['lodash', function(_) {
return codePos;
}
function slotToSchema(slot) {
if (slot.c) {
var o = { class: slot.c.class, rating: slot.c.rating, enabled: Boolean(slot.enabled), priority: slot.priority + 1, group: GroupMap[slot.c.grp] };
if (slot.c.name) {
o.name = slot.c.name;
}
if (slot.c.mode) {
o.mount = MountMap[slot.c.mode];
}
if (slot.c.missile) {
o.missile = slot.c.missile;
}
return o;
}
return null;
}
}]);

View File

@@ -6,61 +6,138 @@ angular.module('shipyard').factory('ComponentSet', ['lodash', function(_) {
});
}
function ComponentSet(components, mass, maxCommonArr, maxInternal, maxHardPoint) {
function getKey(maxClass, eligible) {
if (eligible) {
return maxClass + Object.keys(eligible).join('-');
}
return maxClass;
}
function ComponentSet(components, mass, maxStandardArr, maxInternal, maxHardPoint) {
this.mass = mass;
this.common = {};
this.standard = {};
this.internal = {};
this.hardpoints = {};
this.hpClass = {};
this.intClass = {};
for (var i = 0; i < components.common.length; i++) {
var max = maxCommonArr[i];
switch (i) {
// Slots where component class must be equal to slot class
case 3: // Life Support
case 5: // Sensors
this.common[i] = filter(components.common[i], max, max, this.mass);
break;
// Other slots can have a component of class lower than the slot class
default:
this.common[i] = filter(components.common[i], max, 0, this.mass);
}
}
this.standard[0] = filter(components.standard[0], maxStandardArr[0], 0, mass); // Power Plant
this.standard[2] = filter(components.standard[2], maxStandardArr[2], 0, mass); // FSD
this.standard[4] = filter(components.standard[4], maxStandardArr[4], 0, mass); // Power Distributor
this.standard[6] = filter(components.standard[6], maxStandardArr[6], 0, mass); // Fuel Tank
// Thrusters, filter components by class only (to show full list of ratings for that class)
var minThrusterClass = _.reduce(components.standard[1], function(minClass, thruster) {
return (thruster.maxmass >= mass && thruster.class < minClass) ? thruster.class : minClass;
}, maxStandardArr[1]);
this.standard[1] = filter(components.standard[1], maxStandardArr[1], minThrusterClass, 0); // Thrusters
// Slots where component class must be equal to slot class
this.standard[3] = filter(components.standard[3], maxStandardArr[3], maxStandardArr[3], 0); // Life Supprt
this.standard[5] = filter(components.standard[5], maxStandardArr[5], maxStandardArr[5], mass); // Sensors
for (var h in components.hardpoints) {
this.hardpoints[h] = filter(components.hardpoints[h], maxHardPoint, 0, this.mass);
this.hardpoints[h] = filter(components.hardpoints[h], maxHardPoint, 0, mass);
}
for (var g in components.internal) {
this.internal[g] = filter(components.internal[g], maxInternal, 0, this.mass);
this.internal[g] = filter(components.internal[g], maxInternal, 0, mass);
}
/**
* Create a memoized function for determining the components that are
* eligible for an internal slot
* @param {integer} c The max class component that can be mounted in the slot
* @param {Object} eligible) The map of eligible internal groups
* @return {object} A map of all eligible components by group
*/
this.getInts = _.memoize(
function(c, eligible) {
var o = {};
for (var key in this.internal) {
if (eligible && !eligible[key]) {
continue;
}
var data = filter(this.internal[key], c, 0, this.mass);
if (data.length) { // If group is not empty
o[key] = data;
}
}
return o;
},
getKey
);
/**
* Create a memoized function for determining the components that are
* eligible for an hardpoint slot
* @param {integer} c The max class component that can be mounted in the slot
* @param {Object} eligible) The map of eligible hardpoint groups
* @return {object} A map of all eligible components by group
*/
this.getHps = _.memoize(
function(c, eligible) {
var o = {};
for (var key in this.hardpoints) {
if (eligible && !eligible[key]) {
continue;
}
var data = filter(this.hardpoints[key], c, c ? 1 : 0, this.mass);
if (data.length) { // If group is not empty
o[key] = data;
}
}
return o;
},
getKey
);
}
ComponentSet.prototype.getHps = function(c) {
if (!this.hpClass[c]) {
var o = this.hpClass[c] = {};
for (var key in this.hardpoints) {
var data = filter(this.hardpoints[key], c, c ? 1 : 0, this.mass);
if (data.length) { // If group is not empty
o[key] = data;
}
ComponentSet.prototype.lightestPowerDist = function(boostEnergy) {
var pds = this.standard[4];
var pd = pds[0];
for (var i = 1; i < pds.length; i++) {
if (pds[i].mass < pd.mass && pds[i].enginecapacity >= boostEnergy) {
pd = pds[i];
}
}
return this.hpClass[c];
return pd.class + pd.rating;
};
ComponentSet.prototype.getInts = function(c) {
if (!this.intClass[c]) {
var o = this.intClass[c] = {};
for (var key in this.internal) {
var data = filter(this.internal[key], c, 0, this.mass);
if (data.length) { // If group is not empty
o[key] = data;
}
ComponentSet.prototype.lightestThruster = function(ladenMass) {
var ths = this.standard[1];
var th = ths[0];
for (var i = 1; i < ths.length; i++) {
if (ths[i].mass < th.mass && ths[i].maxmass >= ladenMass) {
th = ths[i];
}
}
return this.intClass[c];
return th.class + th.rating;
};
ComponentSet.prototype.lightestShieldGenerator = function(hullMass) {
var sg = null;
_.forEach(this.internal.sg, function(s) {
if (sg == null || (s.mass < sg.mass && s.minmass <= hullMass && s.maxmass > hullMass)) {
sg = s;
}
});
return sg.id;
};
ComponentSet.prototype.lightestPowerPlant = function(powerUsed, rating) {
var pps = this.standard[0];
var pp = null;
for (var i = 0; i < pps.length; i++) {
if (pp == null || (pps[i].mass < pp.mass && pps[i].pGen >= powerUsed)) {
pp = pps[i];
}
}
return pp.class + (pp.rating != 'D' || rating == 'A' ? 'A' : 'D'); // Use A rated if C,E
};
return ComponentSet;

View File

@@ -1,4 +1,4 @@
angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', 'calcJumpRange', 'lodash', function(Components, calcShieldStrength, calcJumpRange, _) {
angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', 'calcJumpRange', 'calcTotalRange', 'calcSpeed', 'lodash', 'ArmourMultiplier', function(Components, calcShieldStrength, calcJumpRange, calcTotalRange, calcSpeed, _, ArmourMultiplier) {
/**
* Returns the power usage type of a slot and it's particular component
@@ -8,9 +8,6 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
*/
function powerUsageType(slot, component) {
if (component) {
if (component.retractedOnly) {
return 'retOnly';
}
if (component.passive) {
return 'retracted';
}
@@ -23,36 +20,45 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
*
* @param {string} id Unique ship Id / Key
* @param {object} properties Basic ship properties such as name, manufacturer, mass, etc
* @param {object} slots Collection of slot groups (standard/common, internal, hardpoints) with their max class size.
* @param {object} slots Collection of slot groups (standard/standard, internal, hardpoints) with their max class size.
*/
function Ship(id, properties, slots) {
this.id = id;
this.cargoScoop = { c: Components.cargoScoop(), type: 'SYS' };
this.bulkheads = { incCost: true, maxClass: 8, discount: 1 };
this.cargoHatch = { c: Components.cargoHatch(), type: 'SYS' };
this.bulkheads = { incCost: true, maxClass: 8 };
this.availCS = Components.forShip(id);
for (var p in properties) { this[p] = properties[p]; } // Copy all base properties from shipData
for (var slotType in slots) { // Initialize all slots
var slotGroup = slots[slotType];
var group = this[slotType] = []; // Initialize Slot group (Common, Hardpoints, Internal)
var group = this[slotType] = []; // Initialize Slot group (Standard, Hardpoints, Internal)
for (var i = 0; i < slotGroup.length; i++) {
group.push({ id: null, c: null, incCost: true, maxClass: slotGroup[i], discount: 1 });
if (typeof slotGroup[i] == 'object') {
group.push({ id: null, c: null, incCost: true, maxClass: slotGroup[i].class, eligible: slotGroup[i].eligible });
} else {
group.push({ id: null, c: null, incCost: true, maxClass: slotGroup[i] });
}
}
}
this.c = { incCost: true, discount: 1, c: { name: this.name, cost: this.cost } }; // Make a 'Ship' component similar to other components
// Make a Ship 'slot'/item similar to other slots
this.c = { incCost: true, type: 'SHIP', discountedCost: this.hullCost, c: { name: this.name, cost: this.hullCost } };
this.costList = _.union(this.internal, this.common, this.hardpoints);
this.costList = _.union(this.internal, this.standard, this.hardpoints);
this.costList.push(this.bulkheads); // Add The bulkheads
this.costList.unshift(this.c); // Add the ship itself to the list
this.powerList = _.union(this.internal, this.hardpoints);
this.powerList.unshift(this.cargoScoop);
this.powerList.unshift(this.common[1]); // Add Thrusters
this.powerList.unshift(this.common[5]); // Add Sensors
this.powerList.unshift(this.common[4]); // Add Power Distributor
this.powerList.unshift(this.common[3]); // Add Life Support
this.powerList.unshift(this.common[2]); // Add FSD
this.powerList.unshift(this.common[0]); // Add Power Plant
this.powerList.unshift(this.cargoHatch);
this.powerList.unshift(this.standard[1]); // Add Thrusters
this.powerList.unshift(this.standard[5]); // Add Sensors
this.powerList.unshift(this.standard[4]); // Add Power Distributor
this.powerList.unshift(this.standard[3]); // Add Life Support
this.powerList.unshift(this.standard[2]); // Add FSD
this.powerList.unshift(this.standard[0]); // Add Power Plant
this.shipCostMultiplier = 1;
this.componentCostMultiplier = 1;
this.priorityBands = [
{ deployed: 0, retracted: 0, retOnly: 0 },
@@ -63,16 +69,101 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
];
}
//*********//
// GETTERS //
//*********//
Ship.prototype.getAvailableComponents = function() {
return this.availCS;
};
Ship.prototype.getSlotStatus = function(slot, deployed) {
if (!slot.c) { // Empty Slot
return 0; // No Status (Not possible to be active in this state)
} else if (!slot.enabled) {
return 1; // Disabled
} else if (deployed) {
return this.priorityBands[slot.priority].deployedSum >= this.powerAvailable ? 2 : 3; // Offline : Online
// Active hardpoints have no retracted status
} else if ((slot.cat === 1 && !slot.c.passive)) {
return 0; // No Status (Not possible to be active in this state)
}
return this.priorityBands[slot.priority].retractedSum >= this.powerAvailable ? 2 : 3; // Offline : Online
};
/**
* Calculate jump range using the installed FSD and the
* specified mass which can be more or less than ships actual mass
* @param {number} mass Mass in tons
* @param {number} fuel Fuel available in tons
* @return {number} Jump range in Light Years
*/
Ship.prototype.getJumpRangeForMass = function(mass, fuel) {
return calcJumpRange(mass, this.standard[2].c, fuel);
};
/**
* Find an internal slot that has an installed component of the specific group.
*
* @param {string} group Component group/type
* @return {number} The index of the slot in ship.internal
*/
Ship.prototype.findInternalByGroup = function(group) {
var index;
if (group == 'sg' || group == 'psg' || group == 'bsg') {
index = _.findIndex(this.internal, function(slot) {
return slot.c && (slot.c.grp == 'sg' || slot.c.grp == 'psg' || slot.c.grp == 'bsg');
});
} else {
index = _.findIndex(this.internal, function(slot) {
return slot.c && slot.c.grp == group;
});
}
if (index !== -1) {
return this.internal[index];
}
return null;
};
//**********************//
// Mutate / Update Ship //
//**********************//
/**
* Recalculate all item costs and total based on discounts.
* @param {number} shipCostMultiplier Ship cost multiplier discount (e.g. 0.9 === 10% discount)
* @param {number} componentCostMultiplier Component cost multiplier discount (e.g. 0.75 === 25% discount)
*/
Ship.prototype.applyDiscounts = function(shipCostMultiplier, componentCostMultiplier) {
var total = 0;
var costList = this.costList;
for (var i = 0, l = costList.length; i < l; i++) {
var item = costList[i];
if (item.c && item.c.cost) {
item.discountedCost = item.c.cost * (item.type == 'SHIP' ? shipCostMultiplier : componentCostMultiplier);
if (item.incCost) {
total += item.discountedCost;
}
}
}
this.shipCostMultiplier = shipCostMultiplier;
this.componentCostMultiplier = componentCostMultiplier;
this.totalCost = total;
return this;
};
/**
* Builds/Updates the ship instance with the components[comps] passed in.
* @param {object} comps Collection of components used to build the ship
*/
Ship.prototype.buildWith = function(comps, priorities, enabled) {
var internal = this.internal,
common = this.common,
standard = this.standard,
hps = this.hardpoints,
bands = this.priorityBands,
cl = common.length,
cl = standard.length,
i, l;
// Reset Cumulative stats
@@ -80,15 +171,16 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
this.cargoCapacity = 0;
this.ladenMass = 0;
this.armourAdded = 0;
this.armourMultiplier = 1;
this.shieldMultiplier = 1;
this.totalCost = this.cost;
this.unladenMass = this.mass;
this.armourTotal = this.armour;
this.totalCost = this.c.incCost ? this.c.discountedCost : 0;
this.unladenMass = this.hullMass;
this.totalDps = 0;
this.bulkheads.c = null;
this.useBulkhead(comps.bulkheads || 0, true);
this.cargoScoop.priority = priorities ? priorities[0] * 1 : 0;
this.cargoScoop.enabled = enabled ? enabled[0] * 1 : true;
this.useBulkhead(comps && comps.bulkheads ? comps.bulkheads : 0, true);
this.cargoHatch.priority = priorities ? priorities[0] * 1 : 0;
this.cargoHatch.enabled = enabled ? enabled[0] * 1 : true;
for (i = 0, l = this.priorityBands.length; i < l; i++) {
this.priorityBands[i].deployed = 0;
@@ -96,31 +188,36 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
this.priorityBands[i].retOnly = 0;
}
if (this.cargoScoop.enabled) {
bands[this.cargoScoop.priority].retracted += this.cargoScoop.c.power;
if (this.cargoHatch.enabled) {
bands[this.cargoHatch.priority].retracted += this.cargoHatch.c.power;
}
for (i = 0; i < cl; i++) {
common[i].cat = 0;
common[i].enabled = enabled ? enabled[i + 1] * 1 : true;
common[i].priority = priorities ? priorities[i + 1] * 1 : 0;
common[i].type = 'SYS';
common[i].c = common[i].id = null; // Resetting 'old' component if there was one
this.use(common[i], comps.common[i], Components.common(i, comps.common[i]), true);
standard[i].cat = 0;
standard[i].enabled = enabled ? enabled[i + 1] * 1 : true;
standard[i].priority = priorities && priorities[i + 1] ? priorities[i + 1] * 1 : 0;
standard[i].type = 'SYS';
standard[i].c = standard[i].id = null; // Resetting 'old' component if there was one
standard[i].discountedCost = 0;
if (comps) {
this.use(standard[i], comps.standard[i], Components.standard(i, comps.standard[i]), true);
}
}
common[1].type = 'ENG'; // Thrusters
common[2].type = 'ENG'; // FSD
standard[1].type = 'ENG'; // Thrusters
standard[2].type = 'ENG'; // FSD
cl++; // Increase accounts for Cargo Scoop
for (i = 0, l = hps.length; i < l; i++) {
hps[i].cat = 1;
hps[i].enabled = enabled ? enabled[cl + i] * 1 : true;
hps[i].priority = priorities ? priorities[cl + i] * 1 : 0;
hps[i].priority = priorities && priorities[cl + i] ? priorities[cl + i] * 1 : 0;
hps[i].type = hps[i].maxClass ? 'WEP' : 'SYS';
hps[i].c = hps[i].id = null; // Resetting 'old' component if there was one
hps[i].discountedCost = 0;
if (comps.hardpoints[i] !== 0) {
if (comps && comps.hardpoints[i] !== 0) {
this.use(hps[i], comps.hardpoints[i], Components.hardpoints(comps.hardpoints[i]), true);
}
}
@@ -130,28 +227,223 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
for (i = 0, l = internal.length; i < l; i++) {
internal[i].cat = 2;
internal[i].enabled = enabled ? enabled[cl + i] * 1 : true;
internal[i].priority = priorities ? priorities[cl + i] * 1 : 0;
internal[i].priority = priorities && priorities[cl + i] ? priorities[cl + i] * 1 : 0;
internal[i].type = 'SYS';
internal[i].id = internal[i].c = null; // Resetting 'old' component if there was one
internal[i].discountedCost = 0;
if (comps.internal[i] !== 0) {
if (comps && comps.internal[i] !== 0) {
this.use(internal[i], comps.internal[i], Components.internal(comps.internal[i]), true);
}
}
// Update aggragated stats
this.updatePower();
this.updateJumpStats();
this.updateShieldStrength();
if (comps) {
this.updatePower()
.updateJumpStats()
.updateShieldStrength()
.updateTopSpeed();
}
return this;
};
Ship.prototype.useBulkhead = function(index, preventUpdate) {
var oldBulkhead = this.bulkheads.c;
this.bulkheads.id = index;
this.bulkheads.c = Components.bulkheads(this.id, index);
this.updateStats(this.bulkheads, this.bulkheads.c, oldBulkhead, preventUpdate);
Ship.prototype.emptyHardpoints = function() {
for (var i = this.hardpoints.length; i--; ) {
this.use(this.hardpoints[i], null, null);
}
return this;
};
Ship.prototype.emptyInternal = function() {
for (var i = this.internal.length; i--; ) {
this.use(this.internal[i], null, null);
}
return this;
};
Ship.prototype.emptyUtility = function() {
for (var i = this.hardpoints.length; i--; ) {
if (!this.hardpoints[i].maxClass) {
this.use(this.hardpoints[i], null, null);
}
}
return this;
};
Ship.prototype.emptyWeapons = function() {
for (var i = this.hardpoints.length; i--; ) {
if (this.hardpoints[i].maxClass) {
this.use(this.hardpoints[i], null, null);
}
}
return this;
};
/**
* Optimize for the lower mass build that can still boost and power the ship
* without power management.
* @param {object} c Standard Component overrides
*/
Ship.prototype.optimizeMass = function(c) {
return this.emptyHardpoints().emptyInternal().useLightestStandard(c);
};
Ship.prototype.setCostIncluded = function(item, included) {
if (item.incCost != included && item.c) {
this.totalCost += included ? item.discountedCost : -item.discountedCost;
}
item.incCost = included;
return this;
};
Ship.prototype.setSlotEnabled = function(slot, enabled) {
if (slot.enabled != enabled) { // Enabled state is changing
slot.enabled = enabled;
if (slot.c) {
this.priorityBands[slot.priority][powerUsageType(slot, slot.c)] += enabled ? slot.c.power : -slot.c.power;
if (slot.c.grp == 'sg' || slot.c.grp == 'psg' || slot.c.grp == 'bsg') {
this.updateShieldStrength();
} else if (slot.c.grp == 'sb') {
this.shieldMultiplier += slot.c.shieldmul * (enabled ? 1 : -1);
this.updateShieldStrength();
} else if (slot.c.dps) {
this.totalDps += slot.c.dps * (enabled ? 1 : -1);
}
this.updatePower();
}
}
return this;
};
/**
* Updates the ship's cumulative and aggregated stats based on the component change.
*/
Ship.prototype.updateStats = function(slot, n, old, preventUpdate) {
var powerChange = slot == this.standard[0];
if (old) { // Old component now being removed
switch (old.grp) {
case 'ft':
this.fuelCapacity -= old.capacity;
break;
case 'cr':
this.cargoCapacity -= old.capacity;
break;
case 'hr':
this.armourAdded -= old.armouradd;
break;
case 'sb':
this.shieldMultiplier -= slot.enabled ? old.shieldmul : 0;
break;
}
if (slot.incCost && old.cost) {
this.totalCost -= old.cost * this.componentCostMultiplier;
}
if (old.power && slot.enabled) {
this.priorityBands[slot.priority][powerUsageType(slot, old)] -= old.power;
powerChange = true;
if (old.dps) {
this.totalDps -= old.dps;
}
}
this.unladenMass -= old.mass || 0;
}
if (n) {
switch (n.grp) {
case 'ft':
this.fuelCapacity += n.capacity;
break;
case 'cr':
this.cargoCapacity += n.capacity;
break;
case 'hr':
this.armourAdded += n.armouradd;
break;
case 'sb':
this.shieldMultiplier += slot.enabled ? n.shieldmul : 0;
break;
}
if (slot.incCost && n.cost) {
this.totalCost += n.cost * this.componentCostMultiplier;
}
if (n.power && slot.enabled) {
this.priorityBands[slot.priority][powerUsageType(slot, n)] += n.power;
powerChange = true;
if (n.dps) {
this.totalDps += n.dps;
}
}
this.unladenMass += n.mass || 0;
}
this.ladenMass = this.unladenMass + this.cargoCapacity + this.fuelCapacity;
this.armour = this.armourAdded + Math.round(this.baseArmour * this.armourMultiplier);
if (!preventUpdate) {
if (powerChange) {
this.updatePower();
}
this.updateTopSpeed();
this.updateJumpStats();
this.updateShieldStrength();
}
return this;
};
Ship.prototype.updatePower = function() {
var bands = this.priorityBands;
var prevRetracted = 0, prevDeployed = 0;
for (var i = 0, l = bands.length; i < l; i++) {
var band = bands[i];
prevRetracted = band.retractedSum = prevRetracted + band.retracted + band.retOnly;
prevDeployed = band.deployedSum = prevDeployed + band.deployed + band.retracted;
}
this.powerAvailable = this.standard[0].c.pGen;
this.powerRetracted = prevRetracted;
this.powerDeployed = prevDeployed;
return this;
};
Ship.prototype.updateTopSpeed = function() {
var speeds = calcSpeed(this.unladenMass + this.fuelCapacity, this.speed, this.boost, this.standard[1].c, this.pipSpeed);
this.topSpeed = speeds['4 Pips'];
this.topBoost = speeds.boost;
return this;
};
Ship.prototype.updateShieldStrength = function() {
var sgSlot = this.findInternalByGroup('sg'); // Find Shield Generator slot Index if any
this.shieldStrength = sgSlot && sgSlot.enabled ? calcShieldStrength(this.hullMass, this.baseShieldStrength, sgSlot.c, this.shieldMultiplier) : 0;
return this;
};
/**
* Jump Range and total range calculations
*/
Ship.prototype.updateJumpStats = function() {
var fsd = this.standard[2].c; // Frame Shift Drive;
this.unladenRange = calcJumpRange(this.unladenMass + fsd.maxfuel, fsd, this.fuelCapacity); // Include fuel weight for jump
this.fullTankRange = calcJumpRange(this.unladenMass + this.fuelCapacity, fsd, this.fuelCapacity); // Full Tanke
this.ladenRange = calcJumpRange(this.ladenMass, fsd, this.fuelCapacity);
this.unladenTotalRange = calcTotalRange(this.unladenMass, fsd, this.fuelCapacity);
this.ladenTotalRange = calcTotalRange(this.unladenMass + this.cargoCapacity, fsd, this.fuelCapacity);
this.maxJumpCount = Math.ceil(this.fuelCapacity / fsd.maxfuel);
return this;
};
/**
* Update a slot with a the component if the id is different from the current id for this slot.
* Has logic handling components that you may only have 1 of (Shield Generator or Refinery).
@@ -164,48 +456,122 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
Ship.prototype.use = function(slot, id, component, preventUpdate) {
if (slot.id != id) { // Selecting a different component
// Slot is an internal slot, is not being emptied, and the selected component group/type must be of unique
if (slot.cat != 2 && component && _.includes(['sg', 'rf', 'fs'], component.grp)) {
if (slot.cat == 2 && component && _.includes(['bsg', 'psg', 'sg', 'rf', 'fs'], component.grp)) {
// Find another internal slot that already has this type/group installed
var similarSlot = this.findInternalByGroup(component.grp);
// If another slot has an installed component with of the same type
if (similarSlot && similarSlot !== slot) {
this.updateStats(similarSlot, null, similarSlot.c, true); // Update stats but don't trigger a global update
if (!preventUpdate && similarSlot && similarSlot !== slot) {
this.updateStats(similarSlot, null, similarSlot.c);
similarSlot.id = similarSlot.c = null; // Empty the slot
similarSlot.discountedCost = 0;
}
}
var oldComponent = slot.c;
slot.id = id;
slot.c = component;
slot.discountedCost = (component && component.cost) ? component.cost * this.componentCostMultiplier : 0;
this.updateStats(slot, component, oldComponent, preventUpdate);
}
};
/**
* Calculate jump range using the installed FSD and the
* specified mass which can be more or less than ships actual mass
* @param {number} mass Mass in tons
* @param {number} fuel Fuel available in tons
* @return {number} Jump range in Light Years
*/
Ship.prototype.jumpRangeWithMass = function(mass, fuel) {
return calcJumpRange(mass, this.common[2].c, fuel);
return this;
};
/**
* Find an internal slot that has an installed component of the specific group.
*
* @param {string} group Component group/type
* @return {number} The index of the slot in ship.internal
* [useBulkhead description]
* @param {[type]} index [description]
* @param {[type]} preventUpdate [description]
* @return {[type]} [description]
*/
Ship.prototype.findInternalByGroup = function(group) {
var index = _.findIndex(this.internal, function(slot) {
return slot.c && slot.c.grp == group;
});
if (index !== -1) {
return this.internal[index];
Ship.prototype.useBulkhead = function(index, preventUpdate) {
var oldBulkhead = this.bulkheads.c;
this.bulkheads.id = index;
this.bulkheads.c = Components.bulkheads(this.id, index);
this.bulkheads.discountedCost = this.bulkheads.c.cost * this.componentCostMultiplier;
this.armourMultiplier = ArmourMultiplier[index];
this.updateStats(this.bulkheads, this.bulkheads.c, oldBulkhead, preventUpdate);
return this;
};
/**
* [useStandard description]
* @param {[type]} rating [description]
* @return {[type]} [description]
*/
Ship.prototype.useStandard = function(rating) {
for (var i = this.standard.length - 1; i--; ) { // All except Fuel Tank
var id = this.standard[i].maxClass + rating;
this.use(this.standard[i], id, Components.standard(i, id));
}
return null;
return this;
};
/**
* Use the lightest standard components unless otherwise specified
* @param {object} c Component overrides
*/
Ship.prototype.useLightestStandard = function(c) {
c = c || {};
var standard = this.standard,
pd = c.pd || this.availCS.lightestPowerDist(this.boostEnergy), // Find lightest Power Distributor that can still boost;
fsd = c.fsd || standard[2].maxClass + 'A',
ls = c.ls || standard[3].maxClass + 'D',
s = c.s || standard[5].maxClass + 'D',
updated;
this.useBulkhead(0)
.use(standard[2], fsd, Components.standard(2, fsd)) // FSD
.use(standard[3], ls, Components.standard(3, ls)) // Life Support
.use(standard[5], s, Components.standard(5, s)) // Sensors
.use(standard[4], pd, Components.standard(4, pd)); // Power Distributor
// Thrusters and Powerplant must be determined after all other components are mounted
// Loop at least once to determine absolute lightest PD and TH
do {
updated = false;
// Find lightest Thruster that still works for the ship at max mass
var th = c.th || this.availCS.lightestThruster(this.ladenMass);
if (th != standard[1].id) {
this.use(standard[1], th, Components.standard(1, th));
updated = true;
}
// Find lightest Power plant that can power the ship
var pp = c.pp || this.availCS.lightestPowerPlant(Math.max(this.powerRetracted, this.powerDeployed), c.ppRating);
if (pp != standard[0].id) {
this.use(standard[0], pp, Components.standard(0, pp));
updated = true;
}
} while (updated);
return this;
};
Ship.prototype.useUtility = function(group, rating, name, clobber) {
var component = Components.findHardpoint(group, 0, rating, name);
for (var i = this.hardpoints.length; i--; ) {
if ((clobber || !this.hardpoints[i].c) && !this.hardpoints[i].maxClass) {
this.use(this.hardpoints[i], component.id, component);
}
}
return this;
};
Ship.prototype.useWeapon = function(group, mount, clobber, missile) {
var hps = this.hardpoints;
for (var i = hps.length; i--; ) {
if (hps[i].maxClass) {
var size = hps[i].maxClass, component;
do {
component = Components.findHardpoint(group, size, null, null, mount, missile);
if ((clobber || !hps[i].c) && component) {
this.use(hps[i], component.id, component);
break;
}
} while (!component && (--size > 0));
}
}
return this;
};
/**
@@ -230,153 +596,5 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength',
return false;
};
Ship.prototype.setCostIncluded = function(item, included) {
if (item.incCost != included && item.c) {
this.totalCost += included ? item.c.cost : -item.c.cost;
}
item.incCost = included;
};
Ship.prototype.setSlotEnabled = function(slot, enabled) {
if (slot.enabled != enabled && slot.c) { // Enabled state is changing
this.priorityBands[slot.priority][powerUsageType(slot, slot.c)] += enabled ? slot.c.power : -slot.c.power;
this.updatePower();
}
slot.enabled = enabled;
};
Ship.prototype.getSlotStatus = function(slot, deployed) {
if (!slot.c) { // Empty Slot
return 0; // No Status (Not possible)
} else if (!slot.enabled) {
return 1; // Disabled
} else if (deployed && !slot.c.retractedOnly) { // Certain component (e.g. Detaild Surface scanner) are power only while retracted
return this.priorityBands[slot.priority].deployedSum > this.powerAvailable ? 2 : 3; // Offline : Online
// Active hardpoints have no retracted status
} else if ((deployed && slot.c.retractedOnly) || (slot.cat === 1 && !slot.c.passive)) {
return 0; // No Status (Not possible)
}
return this.priorityBands[slot.priority].retractedSum > this.powerAvailable ? 2 : 3; // Offline : Online
};
/**
* Updates the ship's cumulative and aggregated stats based on the component change.
*/
Ship.prototype.updateStats = function(slot, n, old, preventUpdate) {
var powerChange = slot == this.common[0];
if (old) { // Old component now being removed
switch (old.grp) {
case 'ft':
this.fuelCapacity -= old.capacity;
break;
case 'cr':
this.cargoCapacity -= old.capacity;
break;
case 'hr':
this.armourAdded -= old.armouradd;
break;
case 'sb':
this.shieldMultiplier -= old.shieldmul;
break;
}
if (slot.incCost && old.cost) {
this.totalCost -= old.cost;
}
if (old.power && slot.enabled) {
this.priorityBands[slot.priority][powerUsageType(slot, old)] -= old.power;
powerChange = true;
}
this.unladenMass -= old.mass || 0;
}
if (n) {
switch (n.grp) {
case 'ft':
this.fuelCapacity += n.capacity;
break;
case 'cr':
this.cargoCapacity += n.capacity;
break;
case 't':
this.maxMass = n.maxmass;
break;
case 'hr':
this.armourAdded += n.armouradd;
break;
case 'sb':
this.shieldMultiplier += n.shieldmul;
break;
}
if (slot.incCost && n.cost) {
this.totalCost += n.cost;
}
if (n.power && slot.enabled) {
this.priorityBands[slot.priority][powerUsageType(slot, n)] += n.power;
powerChange = true;
}
this.unladenMass += n.mass || 0;
}
this.ladenMass = this.unladenMass + this.cargoCapacity + this.fuelCapacity;
this.armourTotal = this.armourAdded + this.armour;
if (!preventUpdate) {
if (powerChange) {
this.updatePower();
}
this.updateJumpStats();
this.updateShieldStrength();
}
};
Ship.prototype.updatePower = function() {
var bands = this.priorityBands;
var prevRetracted = 0, prevDeployed = 0;
for (var i = 0, l = bands.length; i < l; i++) {
var band = bands[i];
prevRetracted = band.retractedSum = prevRetracted + band.retracted + band.retOnly;
prevDeployed = band.deployedSum = prevDeployed + band.deployed + band.retracted;
}
this.powerAvailable = this.common[0].c.pGen;
this.powerRetracted = prevRetracted;
this.powerDeployed = prevDeployed;
};
Ship.prototype.updateShieldStrength = function() {
var sgSlot = this.findInternalByGroup('sg'); // Find Shield Generator slot Index if any
this.shieldStrength = sgSlot ? calcShieldStrength(this.mass, this.shields, sgSlot.c, this.shieldMultiplier) : 0;
};
/**
* Jump Range and total range calculations
*/
Ship.prototype.updateJumpStats = function() {
var fsd = this.common[2].c; // Frame Shift Drive;
var fuelRemaining = this.fuelCapacity % fsd.maxfuel; // Fuel left after making N max jumps
var jumps = this.fuelCapacity / fsd.maxfuel;
this.unladenRange = calcJumpRange(this.unladenMass + fsd.maxfuel, fsd, this.fuelCapacity); // Include fuel weight for jump
this.fullTankRange = calcJumpRange(this.unladenMass + this.fuelCapacity, fsd, this.fuelCapacity); // Full Tanke
this.ladenRange = calcJumpRange(this.ladenMass, fsd, this.fuelCapacity);
this.maxJumpCount = Math.ceil(jumps); // Number of full fuel jumps + final jump to empty tank
// Going backwards, start with the last jump using the remaining fuel
this.unladenTotalRange = fuelRemaining > 0 ? calcJumpRange(this.unladenMass + fuelRemaining, fsd, fuelRemaining) : 0;
this.ladenTotalRange = fuelRemaining > 0 ? calcJumpRange(this.unladenMass + this.cargoCapacity + fuelRemaining, fsd, fuelRemaining) : 0;
// For each max fuel jump, calculate the max jump range based on fuel left in the tank
for (var j = 0, l = Math.floor(jumps); j < l; j++) {
fuelRemaining += fsd.maxfuel;
this.unladenTotalRange += calcJumpRange(this.unladenMass + fuelRemaining, fsd);
this.ladenTotalRange += calcJumpRange(this.unladenMass + this.cargoCapacity + fuelRemaining, fsd);
}
};
return Ship;
}]);

View File

@@ -7,21 +7,20 @@
* @requires ngLodash
*/
angular.module('shipyard', ['ngLodash'])
// Create 'angularized' references to DB.This will aid testing
// Create 'angularized' references to DB. This will aid testing
.constant('ShipsDB', DB.ships)
.constant('ComponentsDB', DB.components)
.value('commonArray', [
'Power Plant',
'Thrusters',
'Frame Shift Drive',
'Life Support',
'Power Distributor',
'Sensors',
'Fuel Tank'
.constant('ArmourMultiplier', [
1, // Lightweight
1.4, // Reinforced
1.945, // Military
1.945, // Mirrored
1.945 // Reactive
])
// Map to lookup group labels/names for component grp
.value('GroupMap', {
// Common
.constant('SizeMap', ['', 'small', 'medium', 'large', 'capital'])
// Map to lookup group labels/names for component grp, used for JSON Serialization
.constant('GroupMap', {
// Standard
pp: 'Power Plant',
t: 'Thrusters',
fsd: 'Frame Shift Drive',
@@ -32,19 +31,22 @@ angular.module('shipyard', ['ngLodash'])
// Internal
fs: 'Fuel Scoop',
sc: 'Scanners',
am: 'Auto Field-Maint. Unit',
cr: 'Cargo Racks',
fi: 'FSD Interdictor',
hb: 'Hatch Breaker Limpet Ctrl',
sc: 'Scanner',
am: 'Auto Field-Maintenance Unit',
cr: 'Cargo Rack',
fi: 'Frame Shift Drive Interdictor',
hb: 'Hatch Breaker Limpet Controller',
hr: 'Hull Reinforcement Package',
rf: 'Refinery',
scb: 'Shield Cell Bank',
sg: 'Shield Generator',
psg: 'Prismatic Shield Generator',
bsg: 'Bi-Weave Shield Generator',
dc: 'Docking Computer',
fx: 'Fuel Transfer Limpet Ctrl',
pc: 'Prospector Limpet Ctrl',
cc: 'Collector Limpet Ctrl',
fx: 'Fuel Transfer Limpet Controller',
pc: 'Prospector Limpet Controller',
cc: 'Collector Limpet Controller',
pv: 'Planetary Vehicle Hangar',
// Hard Points
bl: 'Beam Laser',
@@ -65,106 +67,112 @@ angular.module('shipyard', ['ngLodash'])
sb: 'Shield Booster',
tp: 'Torpedo Pylon'
})
.value('shipPurpose', {
mp: 'Multi Purpose',
fr: 'Freighter',
ex: 'Explorer',
co: 'Combat',
pa: 'Passenger Transport'
.constant('MountMap', {
'F': 'Fixed',
'G': 'Gimballed',
'T': 'Turret',
'Fixed': 'F',
'Gimballed': 'G',
'Turret': 'T'
})
.value('shipSize', [
'N/A',
'Small',
'Medium',
'Large',
'Capital'
])
.value('hardPointClass', [
'Utility',
'Small',
'Medium',
'Large',
'Huge'
])
/**
* Array of all Ship properties (facets) organized into groups
* used for ship comparisons.
*
* @type {Array}
*/
.value('ShipFacets', [
.constant('ShipFacets', [
{ // 0
title: 'Agility',
title: 'agility',
props: ['agility'],
unit: '',
fmt: 'fCrd'
},
{ // 1
title: 'Speed',
props: ['speed', 'boost'],
lbls: ['Thrusters', 'Boost'],
title: 'speed',
props: ['topSpeed', 'topBoost'],
lbls: ['thrusters', 'boost'],
unit: 'm/s',
fmt: 'fRound'
fmt: 'fCrd'
},
{ // 2
title: 'Armour',
props: ['armourTotal'],
title: 'armour',
props: ['armour'],
unit: '',
fmt: 'fCrd'
},
{ // 3
title: 'Shields',
title: 'shields',
props: ['shieldStrength'],
unit: 'MJ',
fmt: 'fRound'
},
{ // 4
title: 'Jump Range',
title: 'jump range',
props: ['unladenRange', 'fullTankRange', 'ladenRange'],
lbls: ['Max', 'Full Tank', 'Laden'],
lbls: ['max', 'full tank', 'laden'],
unit: 'LY',
fmt: 'fRound'
},
{ // 5
title: 'Mass',
title: 'mass',
props: ['unladenMass', 'ladenMass'],
lbls: ['Unladen', 'Laden'],
lbls: ['unladen', 'laden'],
unit: 'T',
fmt: 'fRound'
},
{ // 6
title: 'Cargo',
title: 'cargo',
props: ['cargoCapacity'],
unit: 'T',
fmt: 'fRound'
},
{ // 7
title: 'Fuel',
title: 'fuel',
props: ['fuelCapacity'],
unit: 'T',
fmt: 'fRound'
},
{ // 8
title: 'Power',
title: 'power',
props: ['powerRetracted', 'powerDeployed', 'powerAvailable'],
lbls: ['Retracted', 'Deployed', 'Available'],
lbls: ['retracted', 'deployed', 'available'],
unit: 'MW',
fmt: 'fPwr'
},
{ // 9
title: 'Cost',
title: 'cost',
props: ['totalCost'],
unit: 'CR',
fmt: 'fCrd'
},
{ // 10
title: 'Total Range',
title: 'total range',
props: ['unladenTotalRange', 'ladenTotalRange'],
lbls: ['Unladen', 'Laden'],
lbls: ['unladen', 'laden'],
unit: 'LY',
fmt: 'fRound'
},
{ // 11
title: 'DPS',
props: ['totalDps'],
lbls: ['DPS'],
unit: '',
fmt: 'fRound'
}
])
/**
* Set of all available / theoretical discounts
*/
.constant('Discounts', {
'0%': 1,
'2.5%': 0.975,
'5%': 0.95,
'10%': 0.90,
'15%': 0.85,
'20%': 0.80,
'25%': 0.75
})
/**
* Calculate the maximum single jump range based on mass and a specific FSD
*
@@ -175,11 +183,31 @@ angular.module('shipyard', ['ngLodash'])
*/
.value('calcJumpRange', function(mass, fsd, fuel) {
return Math.pow(Math.min(fuel === undefined ? fsd.maxfuel : fuel, fsd.maxfuel) / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass;
})
/**
* Calculate the total range based on mass and a specific FSD, and all fuel available
*
* @param {number} mass Mass of a ship: laden, unlanden, partially laden, etc
* @param {object} fsd The FDS object/component with maxfuel, fuelmul, fuelpower, optmass
* @param {number} fuel The total fuel available
* @return {number} Distance in Light Years
*/
.value('calcTotalRange', function(mass, fsd, fuel) {
var fuelRemaining = fuel % fsd.maxfuel; // Fuel left after making N max jumps
var jumps = Math.floor(fuel / fsd.maxfuel);
mass += fuelRemaining;
// Going backwards, start with the last jump using the remaining fuel
var totalRange = fuelRemaining > 0 ? Math.pow(fuelRemaining / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass : 0;
// For each max fuel jump, calculate the max jump range based on fuel mass left in the tank
for (var j = 0; j < jumps; j++) {
mass += fsd.maxfuel;
totalRange += Math.pow(fsd.maxfuel / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass;
}
return totalRange;
})
/**
* Calculate the a ships shield strength based on mass, shield generator and shield boosters used.
*
* @private
* @param {number} mass Current mass of the ship
* @param {number} shields Base Shield strength MJ for ship
* @param {object} sg The shield generator used
@@ -187,17 +215,41 @@ angular.module('shipyard', ['ngLodash'])
* @return {number} Approximate shield strengh in MJ
*/
.value('calcShieldStrength', function(mass, shields, sg, multiplier) {
if (!sg) {
return 0;
}
if (mass <= sg.minmass) {
var opt;
if (mass < sg.minmass) {
return shields * multiplier * sg.minmul;
}
if (mass > sg.maxmass) {
return shields * multiplier * sg.maxmul;
}
if (mass < sg.optmass) {
return shields * multiplier * (sg.minmul + (mass - sg.minmass) / (sg.optmass - sg.minmass) * (sg.optmul - sg.minmul));
opt = (sg.optmass - mass) / (sg.optmass - sg.minmass);
opt = 1 - Math.pow(1 - opt, 0.87);
return shields * multiplier * ((opt * sg.minmul) + ((1 - opt) * sg.optmul));
} else {
opt = (sg.optmass - mass) / (sg.maxmass - sg.optmass);
opt = -1 + Math.pow(1 + opt, 2.425);
return shields * multiplier * ( (-1 * opt * sg.maxmul) + ((1 + opt) * sg.optmul) );
}
if (mass < sg.maxmass) {
return shields * multiplier * (sg.optmul + (mass - sg.optmass) / (sg.maxmass - sg.optmass) * (sg.maxmul - sg.optmul));
}
return shields * multiplier * sg.maxmul;
})
/**
* Calculate the a ships speed based on mass, and thrusters.
*
* @param {number} mass Current mass of the ship
* @param {number} baseSpeed Base speed m/s for ship
* @param {number} baseBoost Base boost speed m/s for ship
* @param {object} thrusters The Thrusters used
* @param {number} pipSpeed Speed pip multiplier
* @return {object} Approximate speed by pips
*/
.value('calcSpeed', function(mass, baseSpeed, baseBoost, thrusters, pipSpeed) {
var multiplier = mass > thrusters.maxmass ? 0 : ((1 - thrusters.M) + (thrusters.M * Math.pow(3 - (2 * Math.max(0.5, mass / thrusters.optmass)), thrusters.P)));
var speed = baseSpeed * multiplier;
return {
'0 Pips': speed * (1 - (pipSpeed * 4)),
'2 Pips': speed * (1 - (pipSpeed * 2)),
'4 Pips': speed,
'boost': baseBoost * multiplier
};
});

View File

@@ -1,11 +1,17 @@
angular.module('shipyard').service('Components', ['lodash', 'ComponentsDB', 'ShipsDB', 'ComponentSet', function(_, C, Ships, ComponentSet) {
angular.module('shipyard').service('Components', ['lodash', 'ComponentsDB', 'ShipsDB', 'ComponentSet', 'GroupMap', function(_, C, Ships, ComponentSet, GroupMap) {
this.cargoScoop = function() {
var GrpNameToCodeMap = {};
for (var grp in GroupMap) {
GrpNameToCodeMap[GroupMap[grp]] = grp;
}
this.cargoHatch = function() {
return { name: 'Cargo Hatch', class: 1, rating: 'H', power: 0.6 };
};
this.common = function(typeIndex, componentId) {
return C.common[typeIndex][componentId];
this.standard = function(typeIndex, componentId) {
return C.standard[typeIndex][componentId];
};
this.hardpoints = function(id) {
@@ -32,6 +38,119 @@ angular.module('shipyard').service('Components', ['lodash', 'ComponentsDB', 'Shi
return null;
};
/**
* Finds an internal Component based on Class, Rating, Group and/or name.
* At least one ofGroup name or unique component name must be provided
*
* @param {string} groupName [Optional] Full name or abbreviated name for component group
* @param {integer} clss Component Class
* @param {string} rating Component Rating
* @param {string} name [Optional] Long/unique name for component -e.g. 'Advanced Discover Scanner'
* @return {String} The id of the component if found, null if not found
*/
this.findInternal = function(groupName, clss, rating, name) {
var groups = {};
if (groupName) {
if (C.internal[groupName]) {
groups[groupName] = C.internal[groupName];
} else {
var grpCode = GrpNameToCodeMap[groupName];
if (grpCode && C.internal[grpCode]) {
groups[grpCode] = C.internal[grpCode];
}
}
} else if (name) {
groups = C.internal;
}
for (var g in groups) {
var group = groups[g];
for (var i = 0, l = group.length; i < l; i++) {
if (group[i].class == clss && group[i].rating == rating && ((!name && !group[i].name) || group[i].name == name)) {
return group[i];
}
}
}
return null;
};
/**
* Finds an internal Component ID based on Class, Rating, Group and/or name.
* At least one ofGroup name or unique component name must be provided
*
* @param {string} groupName [Optional] Full name or abbreviated name for component group
* @param {integer} clss Component Class
* @param {string} rating Component Rating
* @param {string} name [Optional] Long/unique name for component -e.g. 'Advanced Discover Scanner'
* @return {String} The id of the component if found, null if not found
*/
this.findInternalId = function(groupName, clss, rating, name) {
var i = this.findInternal(groupName, clss, rating, name);
return i ? i.id : 0;
};
/**
* Finds a hardpoint Component based on Class, Rating, Group and/or name.
* At least one ofGroup name or unique component name must be provided
*
* @param {string} groupName [Optional] Full name or abbreviated name for component group
* @param {integer} clss Component Class
* @param {string} rating [Optional] Component Rating
* @param {string} name [Optional] Long/unique name for component -e.g. 'Heat Sink Launcher'
* @param {string} mode Mount mode/type - [F]ixed, [G]imballed, [T]urret
* @param {string} missile [Optional] Missile type - [D]umbfire, [S]eeker
* @return {String} The id of the component if found, null if not found
*/
this.findHardpoint = function(groupName, clss, rating, name, mode, missile) {
var groups = {};
if (groupName) {
if (C.hardpoints[groupName]) {
groups[groupName] = C.hardpoints[groupName];
} else {
var grpCode = GrpNameToCodeMap[groupName];
if (grpCode && C.hardpoints[grpCode]) {
groups[grpCode] = C.hardpoints[grpCode];
}
}
} else if (name) {
groups = C.hardpoints;
}
for (var g in groups) {
var group = groups[g];
for (var i = 0, l = group.length; i < l; i++) {
if (group[i].class == clss && (!rating || group[i].rating == rating) && group[i].mode == mode
&& ((!name && !group[i].name) || group[i].name == name)
&& ((!missile && !group[i].missile) || group[i].missile == missile)
) {
return group[i];
}
}
}
return null;
};
/**
* Finds a hardpoint Component ID based on Class, Rating, Group and/or name.
* At least one of Group name or unique component name must be provided
*
* @param {string} groupName [Optional] Full name or abbreviated name for component group
* @param {integer} clss Component Class
* @param {string} rating Component Rating
* @param {string} name [Optional] Long/unique name for component -e.g. 'Heat Sink Launcher'
* @param {string} mode Mount mode/type - [F]ixed, [G]imballed, [T]urret
* @param {string} missile [Optional] Missile type - [D]umbfire, [S]eeker
* @return {String} The id of the component if found, null if not found
*/
this.findHardpointId = function(groupName, clss, rating, name, mode, missile) {
var h = this.findHardpoint(groupName, clss, rating, name, mode, missile);
return h ? h.id : 0;
};
/**
* Looks up the bulkhead component for a specific ship and bulkhead
* @param {string} shipId Unique ship Id/Key
@@ -42,6 +161,10 @@ angular.module('shipyard').service('Components', ['lodash', 'ComponentsDB', 'Shi
return C.bulkheads[shipId][bulkheadsId];
};
this.bulkheadIndex = function(bulkheadName) {
return ['Lightweight Alloy', 'Reinforced Alloy', 'Military Grade Composite', 'Mirrored Surface Composite', 'Reactive Surface Composite'].indexOf(bulkheadName);
};
/**
* Creates a new ComponentSet that contains all available components
* that the specified ship is eligible to use.
@@ -51,7 +174,8 @@ angular.module('shipyard').service('Components', ['lodash', 'ComponentsDB', 'Shi
*/
this.forShip = function(shipId) {
var ship = Ships[shipId];
return new ComponentSet(C, ship.properties.mass + 5, ship.slots.common, ship.slots.internal[0], ship.slots.hardpoints[0]);
var maxInternal = isNaN(ship.slots.internal[0]) ? ship.slots.internal[0].class : ship.slots.internal[0];
return new ComponentSet(C, ship.minMassFilter || ship.properties.hullMass + 5, ship.slots.standard, maxInternal, ship.slots.hardpoints[0]);
};
}]);

View File

@@ -19,10 +19,15 @@
@import 'buttons';
@import 'error';
@import 'sortable';
@import 'loader';
html, body {
height: 100%;
width: 100%;
text-rendering: optimizeLegibility;
overflow-x: hidden;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
body {
@@ -32,6 +37,8 @@ body {
padding: 0;
font-family: @fStandard;
letter-spacing: 0.05em;
overflow-x: hidden;
-webkit-overflow-scrolling: touch;
}
div, a, li {
@@ -40,7 +47,9 @@ div, a, li {
#main {
margin: 0;
padding: 0.5em 0;
padding: 0.5em 0.5em;
width: 100%;
box-sizing: border-box;
min-height: 90%;
clear: both;
text-align: center;
@@ -78,6 +87,14 @@ div, a, li {
text-align: center;
}
.cap {
text-transform: capitalize;
}
.upp {
text-transform: uppercase;
}
.scroll-x {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
@@ -108,6 +125,7 @@ h3 {
u { // Unit (Mj, Km, etc)
font-size: 0.8em;
text-decoration: none;
text-transform: none;
}
a, a:visited {

View File

@@ -5,7 +5,9 @@ button {
fill: @primary;
}
border: none;
text-transform: capitalize;
font-family: @fStandard;
font-size: 0.75em;
vertical-align: middle;
padding: 0.5em;
cursor: pointer;

View File

@@ -2,7 +2,7 @@
font-size: 0.8em;
padding: 0.25em 0.5em;
background: @primary-disabled;
text-transform: capitalize;
color: @primary-bg;
pointer-events: none;
}

View File

@@ -1,11 +1,9 @@
.chart {
.user-select-none();
display: inline-block;
margin: 0;
cursor: default;
overflow: hidden;
width: 33%;
box-sizing: border-box;
@@ -23,6 +21,7 @@
&[ng-click] {
cursor: pointer;
}
}
}
@@ -40,12 +39,14 @@ svg {
fill: @primary-disabled;
}
&.y {
text tspan:first-child {
fill: @primary;
}
}
}
.label {
text-transform: capitalize;
}
.metric {
text-transform: none;
}
.marker {
@@ -61,7 +62,6 @@ svg {
fill: @bgBlack;
stroke: @secondary;
stroke-width: 1px;
font-size: 0.75em
}
}

View File

@@ -66,3 +66,7 @@
color: @warning-disabled;
fill: @warning-disabled;
}
.bg-warning-disabled {
background-color: @warning-disabled;
}

View File

@@ -29,6 +29,7 @@
height: 100%;
display: inline-block;
padding: 0.3em;
font-size: 1em;
vertical-align: middle;
border: none;
border-right: 1px solid @primary-disabled;

View File

@@ -39,6 +39,7 @@ header {
}
.smallTablet({
position: static;
position: initial;
});
}
@@ -49,6 +50,7 @@ header {
padding : 0 1em;
cursor: pointer;
color: @warning;
text-transform: capitalize;
// Less than 600px screen width: hide text
&.disabled {
@@ -63,7 +65,7 @@ header {
.menu-item-label {
margin-left: 1em;
.largePhone({
.smallTablet({
display: none;
});
}
@@ -83,6 +85,19 @@ header {
-webkit-overflow-scrolling: touch;
max-height: 500px;
&::-webkit-scrollbar {
width: 0.5em;
}
&::-webkit-scrollbar-track {
background-color: transparent;
}
&::-webkit-scrollbar-thumb {
background-color: @warning-disabled;
}
.smallTablet({
max-height: 400px;
left: 0;

38
app/less/loader.less Normal file
View File

@@ -0,0 +1,38 @@
@keyframes outer {
0% { opacity: 0.3; }
20% { opacity: 1; }
100% { opacity: 0.3; }
}
@keyframes inner {
0% { opacity: 0.4; }
20% { opacity: 1; }
100% { opacity: 0.4; }
}
@animationTime: 1000ms;
@outerTriangles: 19;
@animationDelay: @animationTime / @outerTriangles;
.loader {
path {
stroke: #000;
stroke-width: 0;
opacity: 0;
}
}
.l1 { animation: outer @animationTime linear infinite; }
.l2 { animation: inner @animationTime linear infinite; }
.mixin-loop (@i) when (@i > 0) {
.d@{i} {
opacity: @i / @outerTriangles;
animation-delay: @i * @animationDelay;
}
.mixin-loop(@i - 1);
}
.mixin-loop(@outerTriangles);

View File

@@ -51,6 +51,32 @@
transform: scaleX(-1); /* standard */
}
.section-menu {
position: relative;
z-index: 0;
&.selected {
z-index: 1;
h1 {
background-color: @primary;
}
}
h1 {
cursor: pointer;
.icon {
float: right;
margin: 0.1em 0.3em 0 0;
}
}
.select {
box-sizing: border-box;
left: 0;
}
}
#build {
float: right;
line-height: 2em;
@@ -59,7 +85,7 @@
input {
background: none;
line-height: 1.3em;
width: 20em;
width: 15em;
font-size: 0.9em;
box-sizing: border-box;
display: inline-block;
@@ -71,16 +97,17 @@
color: @primary;
}
.largePhone({
width: 70%;
.smallTablet({
width: 60%;
});
.medPhone({
.largePhone({
width: 100%;
});
}
.largePhone({
.smallTablet({
float: left;
clear: left;
width: 100%;
@@ -99,6 +126,12 @@
text-overflow: ellipsis;
}
.optional-hide {
.largePhone({
display: none;
});
}
table.total {
width: 100%;
@@ -113,6 +146,26 @@ table.total {
}
}
.tabs {
width: 100%;
box-sizing: border-box;
margin-bottom: 1px;
&, th {
border-collapse: collapse;
color: @primary-disabled;
background-color: @primary-bg;
border: 1px solid @primary-disabled;
padding-top: 1px;
}
.active {
color: @primary-bg;
background-color: @primary-disabled;
}
}
.group {
width: 25%;
padding: 0.5em 0.2em;
@@ -122,11 +175,6 @@ table.total {
.user-select-none();
cursor: default;
[ng-click] {
cursor: pointer;
}
h1 {
font-family: @fStandard;
color: @bgBlack;
@@ -139,11 +187,6 @@ table.total {
font-weight: normal;
}
tbody tr:hover {
background-color: @warning-bg;
}
.smallTablet({
width: 50%;
});
@@ -152,7 +195,7 @@ table.total {
width: 100%;
});
&.dbl {
&.half {
width: 50%;
.tablet({
@@ -162,22 +205,54 @@ table.total {
});
.smallTablet({
overflow-x: auto;
-webkit-overflow-scrolling: touch;
width: 100% !important;
});
}
&.third {
width: 33%;
.smallTablet({
width: 100% !important;
});
}
.smallScreen({
.axis.x {
g.tick:nth-child(2n + 1) text {
display: none;
}
}
});
}
.power-band {
text, rect {
cursor: pointer;
}
rect {
stroke-width: 1px;
stroke: #000;
}
}
svg g {
.threshold {
stroke: @secondary-disabled !important;
fill: @secondary-disabled !important;
&.exceeded {
stroke: @warning !important;
fill: @warning !important;
}
}
}
#componentPriority {
.tablet({
text.primary, text.warning, text.primary-bg {
text.primary, text.warning, text.primary-bg, text.secondary {
font-size: 0.8em;
}
@@ -219,9 +294,6 @@ table.total {
&:nth-child(3) {
display: none;
}
&:nth-child(2) {
font-size: 0.7em;
}
}
});

View File

@@ -32,3 +32,9 @@
@rules();
}
}
.smallScreen(@rules) {
@media only screen and /*(min-width: 601px) and */(max-width: 1400px) {
@rules();
}
}

View File

@@ -1,3 +1,27 @@
select {
.border-radius(0);
cursor: pointer;
background: none;
color: @primary-disabled;
font-family: @fStandard;
font-size: 1em;
background-color: transparent;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
padding: 0.1em 0.5em;
outline:none;
border: 0;
&:focus {
outline:none;
}
&::-moz-focus-inner {
border: 0;
}
}
.select {
color: @primary-disabled;
position: absolute;
@@ -5,85 +29,112 @@
padding: 0.5em 0;
width: 100%;
margin: 0;
max-height: 300px;
max-height: 400px;
overflow-y: auto;
overflow-x: hidden;
z-index: 0;
-webkit-overflow-scrolling: touch;
background-color: @bg;
border: 1px solid @primary;
white-space: nowrap;
text-align: center;
.tablet({
max-height: 300px;
});
&::-webkit-scrollbar {
width: 0.5em;
}
&::-webkit-scrollbar-track {
background-color: transparent;
border-left: 1px solid @primary;
}
&::-webkit-scrollbar-thumb {
background-color: @primary-disabled;
}
.select-group {
white-space: nowrap;
line-height: 1.5em;
text-align: left;
margin: 0.5em 0;
padding-left: 5px;
border-top: 1px solid @primary-disabled;
border-bottom: 1px solid @primary-disabled;
overflow: hidden;
text-overflow: ellipsis;
}
.empty-c, .c, .lc {
cursor: pointer;
@optionSpacing: 2em;
.empty-c, .c, .lc {
white-space: nowrap;
text-align: center;
cursor: pointer;
line-height:@optionSpacing;
color: @primary-disabled;
stroke-width: 1em;
stroke-width: 0.5em;
stroke: @primary-disabled;
&:hover {
color: @warning;
stroke: @warning;
border-color: @primary;
color: @primary;
stroke: @primary;
}
}
.lc, .c {
border:1px solid @primary-disabled;
padding: 0.1em 0.25em;
margin: 0.3em;
&.warning {
border-color: @warning-disabled;
color: @warning-disabled;
stroke: @warning-disabled;
&:hover {
border-color: @warning;
color: @warning;
stroke: @warning;
}
}
&.disabled {
cursor: not-allowed;
border-color: @disabled;
color: @disabled;
stroke: @disabled;
}
&.active {
border-color: @secondary;
color: @secondary;
stroke: @secondary;
}
}
@optionSpacing: 2em;
.lc {
line-height:@optionSpacing;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
text-transform: capitalize;
}
.empty-c {
line-height:@optionSpacing;
text-align: center;
}
.c {
border:1px solid @primary-disabled;
display: inline-block;
padding: 0.1em;
margin: 0.3em;
width: 2em;
line-height: @optionSpacing;
text-align: center;
}
&:hover {
border:1px solid @warning;
}
&.disabled {
border:1px solid @disabled;
}
&.active {
border:1px solid @secondary;
}
span {
vertical-align: middle;
}
ul {
display: inline-block;
text-align: left;
min-width: 15em;
min-width: 16em;
max-width: 100%;
margin: 0 auto;
padding: 0;
list-style: none;
@@ -91,7 +142,7 @@
&.hardpoint {
.c {
width: 4.4em;
width: 4.5em;
padding: 0.1em 0.2em;
}
ul {

View File

@@ -41,3 +41,58 @@
cursor: crosshair;
}
}
input[type=range] {
-webkit-appearance: none;
border: 1px solid @bgBlack;
/*required for proper track sizing in FF*/
width: 300px;
&::-moz-range-track, &::-webkit-slider-runnable-track {
width: 300px;
height: 5px;
background: @primary;
border: none;
border-radius: 3px;
}
&::-moz-range-thumb, &::-webkit-slider-thumb {
-webkit-appearance: none;
border: none;
height: 1em;
width: 1em;
border-radius: 50%;
background: @primary;
}
&:focus {
outline: none;
}
/*hide the outline behind the border*/
&:-moz-focusring{
outline: 1px solid @bgBlack;
outline-offset: -1px;
}
&::-ms-track {
width: 300px;
height: 5px;
background: transparent;
border-color: transparent;
border-width: 6px 0;
color: transparent;
}
&::-ms-fill-lower {
background: @primary;
border-radius: 10px;
}
&::-ms-fill-upper {
background: @primary;
border-radius: 10px;
}
&::-ms-thumb {
border: none;
height: 16px;
width: 16px;
border-radius: 50%;
background: goldenrod;
}
}

View File

@@ -24,11 +24,19 @@
text-transform: none;
}
.name {
overflow: hidden;
white-space: nowrap;
max-width: 80%;
text-overflow: ellipsis;
}
.cb {
overflow: hidden;
}
.l {
text-transform: capitalize;
margin-right: 0.8em;
}
@@ -44,9 +52,11 @@
border-right: 1px solid @primary-disabled;
box-sizing: border-box;
padding-top: 0.2em;
padding-left: 0.05em;
}
.empty {
text-transform: uppercase;
font-size: 1.3em;
color: lighten(@primary-bg, 12%);
text-align: center;

View File

@@ -8,6 +8,10 @@ table {
color: @primary;
text-decoration: none;
}
[ng-click] {
cursor: pointer;
}
}
thead {
@@ -43,7 +47,6 @@ thead {
}
}
tbody tr {
&.tr {
@@ -55,6 +58,12 @@ tbody tr {
}
}
&.highlight {
&:hover {
background-color: @warning-bg;
}
}
td {
line-height: 1.4em;
padding: 0 0.3em;

View File

@@ -0,0 +1,281 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://cdn.coriolis.io/schemas/ship-loadout/1-draft.json#",
"title": "Ship Loadout",
"type": "object",
"description": "The details for a specific ship build/loadout",
"required": ["name", "ship", "components"],
"properties": {
"name": {
"description": "The name of the build/loadout",
"type": "string",
"minLength": 2
},
"ship": {
"description": "The full display name of the ship",
"type": "string",
"minimum": 3
},
"manufacturer": {
"description": "The ship manufacturer",
"type": "string"
},
"references" : {
"description": "3rd Party references and/or links to this build/loadout",
"type": "array",
"items": {
"type": "object",
"required": ["name","url"],
"additionalProperties": true,
"properties": {
"name": {
"description": "The name of the 3rd party, .e.g 'Coriolis.io' or 'E:D Shipyard'",
"type": "string"
},
"url": {
"description": "The link/url to the 3rd party referencing this build/loadout",
"type": "string"
}
}
}
},
"components": {
"description": "The components used by this build",
"type": "object",
"additionalProperties": false,
"required": ["standard", "internal", "hardpoints", "utility"],
"properties": {
"standard": {
"description": "The set of standard components across all ships",
"type": "object",
"additionalProperties": false,
"required": ["bulkheads", "powerPlant", "thrusters", "frameShiftDrive", "lifeSupport", "powerDistributor", "sensors", "fuelTank"],
"properties": {
"bulkheads": {
"enum": ["Lightweight Alloy", "Reinforced Alloy", "Military Grade Composite", "Mirrored Surface Composite", "Reactive Surface Composite"]
},
"powerPlant": {
"required": ["class", "rating"],
"properties": {
"class": { "type": "integer", "minimum": 2, "maximum": 8 },
"rating": { "$ref": "#/definitions/standardRatings" }
}
},
"thrusters": {
"required": ["class", "rating"],
"properties": {
"class": { "type": "integer", "minimum": 2, "maximum": 8 },
"rating": { "$ref": "#/definitions/standardRatings" }
}
},
"frameShiftDrive": {
"required": ["class", "rating"],
"properties": {
"class": { "type": "integer", "minimum": 2, "maximum": 8 },
"rating": { "$ref": "#/definitions/standardRatings" }
}
},
"lifeSupport": {
"required": ["class", "rating"],
"properties": {
"class": { "type": "integer", "minimum": 1, "maximum": 6 },
"rating": { "$ref": "#/definitions/standardRatings" }
}
},
"powerDistributor": {
"required": ["class", "rating"],
"properties": {
"class": { "type": "integer", "minimum": 1, "maximum": 8 },
"rating": { "$ref": "#/definitions/standardRatings" }
}
},
"sensors": {
"required": ["class", "rating"],
"properties": {
"class": { "type": "integer", "minimum": 1, "maximum": 8 },
"rating": { "$ref": "#/definitions/standardRatings" }
}
},
"fuelTank": {
"required": ["class", "rating"],
"properties": {
"class": { "type": "integer", "minimum": 1, "maximum": 6 },
"rating": { "$ref": "#/definitions/standardRatings" }
}
}
}
},
"internal": {
"type": "array",
"items": {
"type": ["object", "null"],
"required": ["class", "rating", "group"],
"properties" : {
"class": { "type": "integer", "minimum": 1, "maximum": 8 },
"rating": { "$ref": "#/definitions/standardRatings" },
"group": {
"description": "The group of the component, e.g. 'Shield Generator', or 'Cargo Rack'",
"type": "string"
},
"name": {
"description": "The name identifying the component (if applicable), e.g. 'Advance Discovery Scanner', or 'Detailed Surface Scanner'",
"type": "string"
}
}
},
"minItems": 3
},
"hardpoints": {
"type": "array",
"items": {
"type": ["object", "null"],
"required": ["class", "rating", "group", "mount"],
"properties" : {
"class": { "type": "integer", "minimum": 1, "maximum": 4 },
"rating": { "$ref": "#/definitions/allRatings" },
"mount": { "type": "string", "enum": ["Fixed", "Gimballed", "Turret"] },
"group": {
"description": "The group of the component, e.g. 'Beam Laser', or 'Missile Rack'",
"type": "string"
},
"name": {
"description": "The name identifing the component (if applicable), e.g. 'Retributor', or 'Mining Lance'",
"type": "string"
}
}
},
"minItems": 1
},
"utility": {
"type": "array",
"items": {
"type": ["object", "null"],
"required": ["class", "rating", "group"],
"properties" : {
"class": { "type": "integer", "minimum": 0, "maximum": 0 },
"rating": { "$ref": "#/definitions/allRatings" },
"group": {
"description": "The group of the component, e.g. 'Shield Booster', or 'Kill Warrant Scanner'",
"type": "string"
},
"name": {
"description": "The name identifing the component (if applicable), e.g. 'Point Defence', or 'Electronic Countermeasure'",
"type": "string"
}
}
},
"minItems": 1
}
}
},
"stats": {
"description": "Optional statistics from the build",
"type": "object",
"additionalProperties": true,
"properties": {
"agility": {
"type": "integer",
"minimum": 0
},
"armour": {
"description": "Sum of base armour + any hull reinforcements",
"type": "integer",
"minimum": 1
},
"armourAdded":{
"description": "Armour added through Hull reinforcement",
"type": "integer",
"minimum": 1
},
"baseShieldStrength": {
"type": "integer",
"minimum": 1
},
"baseArmour": {
"type": "integer",
"minimum": 1
},
"boost": {
"description": "Maximum boost speed of the ships (4 pips, straight-line)",
"type": "number",
"minimum": 1
},
"cargoCapacity": {
"type": "integer",
"minimum": 0
},
"class": {
"description": "Ship Class/Size [Small, Medium, Large]",
"enum": [1,2,3]
},
"dps": {
"description": "Cumulative DPS based on the in-game 1-10 statistic",
"type": "integer",
"minimum": 0
},
"hullCost": {
"description": "Cost of the ship's hull",
"type": "integer",
"minimum": 1
},
"hullMass": {
"description": "Mass of the Ship hull only",
"type": "number",
"minimum": 1
},
"fuelCapacity": {
"type": "integer",
"minimum": 1
},
"fullTankRange": {
"description": "Single Jump range with a full tank (unladenMass + fuel)",
"type": "number",
"minimum": 0
},
"ladenMass": {
"description": "Mass of the Ship + fuel + cargo (hull + all components + fuel tank + cargo capacity)",
"type": "number",
"minimum": 1
},
"ladenRange": {
"description": "Single Jump range with full cargo load, see ladenMass",
"type": "number",
"minimum": 0
},
"masslock": {
"description": "Mass Lock Factor of the Ship",
"type": "integer",
"minimum": 1
},
"shieldStrength": {
"description": "Shield strengh in Mega Joules (Mj)",
"type": "number",
"minimum": 0
},
"speed": {
"description": "Maximum speed of the ships (4 pips, straight-line)",
"type": "number",
"minimum": 1
},
"totalCost": {
"type": "integer",
"minimum": 1
},
"unladenRange": {
"description": "Single Jump range when unladen, see unladenMass",
"type": "number",
"minimum": 0
},
"unladenMass": {
"description": "Mass of the Ship (hull + all components)",
"type": "number",
"minimum": 1
}
}
}
},
"definitions": {
"standardRatings": { "enum": ["A", "B", "C", "D", "E"] },
"allRatings": { "enum": ["A", "B", "C", "D", "E", "F", "I" ] }
}
}

View File

@@ -0,0 +1,308 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://cdn.coriolis.io/schemas/ship-loadout/2.json#",
"title": "Ship Loadout",
"type": "object",
"description": "The details for a specific ship build/loadout",
"required": ["name", "ship", "components"],
"properties": {
"name": {
"description": "The name of the build/loadout",
"type": "string",
"minLength": 2
},
"ship": {
"description": "The full display name of the ship",
"type": "string",
"minimum": 3
},
"manufacturer": {
"description": "The ship manufacturer",
"type": "string"
},
"references" : {
"description": "3rd Party references and/or links to this build/loadout",
"type": "array",
"items": {
"type": "object",
"required": ["name","url"],
"additionalProperties": true,
"properties": {
"name": {
"description": "The name of the 3rd party, .e.g 'Coriolis.io' or 'E:D Shipyard'",
"type": "string"
},
"url": {
"description": "The link/url to the 3rd party referencing this build/loadout",
"type": "string"
}
}
}
},
"components": {
"description": "The components used by this build",
"type": "object",
"additionalProperties": false,
"required": ["standard", "internal", "hardpoints", "utility"],
"properties": {
"standard": {
"description": "The set of standard components across all ships",
"type": "object",
"additionalProperties": false,
"required": ["bulkheads", "powerPlant", "thrusters", "frameShiftDrive", "lifeSupport", "powerDistributor", "sensors", "fuelTank", "cargoHatch"],
"properties": {
"bulkheads": {
"enum": ["Lightweight Alloy", "Reinforced Alloy", "Military Grade Composite", "Mirrored Surface Composite", "Reactive Surface Composite"]
},
"cargoHatch": {
"required": ["enabled", "priority"],
"properties": {
"enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 }
}
},
"powerPlant": {
"required": ["class", "rating", "enabled", "priority"],
"properties": {
"class": { "type": "integer", "minimum": 2, "maximum": 8 },
"rating": { "$ref": "#/definitions/standardRatings" },
"enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 }
}
},
"thrusters": {
"required": ["class", "rating", "enabled", "priority"],
"properties": {
"class": { "type": "integer", "minimum": 2, "maximum": 8 },
"rating": { "$ref": "#/definitions/standardRatings" },
"enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 }
}
},
"frameShiftDrive": {
"required": ["class", "rating", "enabled", "priority"],
"properties": {
"class": { "type": "integer", "minimum": 2, "maximum": 8 },
"rating": { "$ref": "#/definitions/standardRatings" },
"enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 }
}
},
"lifeSupport": {
"required": ["class", "rating", "enabled", "priority"],
"properties": {
"class": { "type": "integer", "minimum": 1, "maximum": 6 },
"rating": { "$ref": "#/definitions/standardRatings" },
"enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 }
}
},
"powerDistributor": {
"required": ["class", "rating", "enabled", "priority"],
"properties": {
"class": { "type": "integer", "minimum": 1, "maximum": 8 },
"rating": { "$ref": "#/definitions/standardRatings" },
"enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 }
}
},
"sensors": {
"required": ["class", "rating", "enabled", "priority"],
"properties": {
"class": { "type": "integer", "minimum": 1, "maximum": 8 },
"rating": { "$ref": "#/definitions/standardRatings" },
"enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 }
}
},
"fuelTank": {
"required": ["class", "rating", "enabled", "priority"],
"properties": {
"class": { "type": "integer", "minimum": 1, "maximum": 6 },
"rating": { "$ref": "#/definitions/standardRatings" },
"enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 }
}
}
}
},
"internal": {
"type": "array",
"items": {
"type": ["object", "null"],
"required": ["class", "rating", "enabled", "priority", "group"],
"properties" : {
"class": { "type": "integer", "minimum": 1, "maximum": 8 },
"rating": { "$ref": "#/definitions/standardRatings" },
"enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 },
"group": {
"description": "The group of the component, e.g. 'Shield Generator', or 'Cargo Rack'",
"type": "string"
},
"name": {
"description": "The name identifying the component (if applicable), e.g. 'Advance Discovery Scanner', or 'Detailed Surface Scanner'",
"type": "string"
}
}
},
"minItems": 3
},
"hardpoints": {
"type": "array",
"items": {
"type": ["object", "null"],
"required": ["class", "rating", "enabled", "priority", "group", "mount"],
"properties" : {
"class": { "type": "integer", "minimum": 1, "maximum": 4 },
"rating": { "$ref": "#/definitions/allRatings" },
"enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 },
"mount": { "type": "string", "enum": ["Fixed", "Gimballed", "Turret"] },
"group": {
"description": "The group of the component, e.g. 'Beam Laser', or 'Missile Rack'",
"type": "string"
},
"name": {
"description": "The name identifing the component (if applicable), e.g. 'Retributor', or 'Mining Lance'",
"type": "string"
}
}
},
"minItems": 1
},
"utility": {
"type": "array",
"items": {
"type": ["object", "null"],
"required": ["class", "rating", "enabled", "priority", "group"],
"properties" : {
"class": { "type": "integer", "minimum": 0, "maximum": 0 },
"rating": { "$ref": "#/definitions/allRatings" },
"enabled": { "type": "boolean" },
"priority": { "type": "integer", "minimum": 1, "maximum": 5 },
"group": {
"description": "The group of the component, e.g. 'Shield Booster', or 'Kill Warrant Scanner'",
"type": "string"
},
"name": {
"description": "The name identifing the component (if applicable), e.g. 'Point Defence', or 'Electronic Countermeasure'",
"type": "string"
}
}
},
"minItems": 1
}
}
},
"stats": {
"description": "Optional statistics from the build",
"type": "object",
"additionalProperties": true,
"properties": {
"agility": {
"type": "integer",
"minimum": 0
},
"armour": {
"description": "Sum of base armour + any hull reinforcements",
"type": "integer",
"minimum": 1
},
"armourAdded":{
"description": "Armour added through Hull reinforcement",
"type": "integer",
"minimum": 1
},
"baseShieldStrength": {
"type": "integer",
"minimum": 1
},
"baseArmour": {
"type": "integer",
"minimum": 1
},
"boost": {
"description": "Maximum boost speed of the ships (4 pips, straight-line)",
"type": "number",
"minimum": 1
},
"cargoCapacity": {
"type": "integer",
"minimum": 0
},
"class": {
"description": "Ship Class/Size [Small, Medium, Large]",
"enum": [1,2,3]
},
"dps": {
"description": "Cumulative DPS based on the in-game 1-10 statistic",
"type": "integer",
"minimum": 0
},
"hullCost": {
"description": "Cost of the ship's hull",
"type": "integer",
"minimum": 1
},
"hullMass": {
"description": "Mass of the Ship hull only",
"type": "number",
"minimum": 1
},
"fuelCapacity": {
"type": "integer",
"minimum": 1
},
"fullTankRange": {
"description": "Single Jump range with a full tank (unladenMass + fuel)",
"type": "number",
"minimum": 0
},
"ladenMass": {
"description": "Mass of the Ship + fuel + cargo (hull + all components + fuel tank + cargo capacity)",
"type": "number",
"minimum": 1
},
"ladenRange": {
"description": "Single Jump range with full cargo load, see ladenMass",
"type": "number",
"minimum": 0
},
"masslock": {
"description": "Mass Lock Factor of the Ship",
"type": "integer",
"minimum": 1
},
"shieldStrength": {
"description": "Shield strengh in Mega Joules (Mj)",
"type": "number",
"minimum": 0
},
"speed": {
"description": "Maximum speed of the ships (4 pips, straight-line)",
"type": "number",
"minimum": 1
},
"totalCost": {
"type": "integer",
"minimum": 1
},
"unladenRange": {
"description": "Single Jump range when unladen, see unladenMass",
"type": "number",
"minimum": 0
},
"unladenMass": {
"description": "Mass of the Ship (hull + all components)",
"type": "number",
"minimum": 1
}
}
}
},
"definitions": {
"standardRatings": { "enum": ["A", "B", "C", "D", "E"] },
"allRatings": { "enum": ["A", "B", "C", "D", "E", "F", "I" ] }
}
}

View File

@@ -1,5 +1,5 @@
<div id="app-update" ng-show="appCacheUpdate">
<a href="#" onclick="window.location.reload()">Update Available! Click to Refresh</a>
<a href="#" onclick="window.location.reload()">{{ 'PHRASE_UPDATE_RDY' | translate }}</a>
</div>
<header>
@@ -7,8 +7,8 @@
<div class="l menu">
<div class="menu-header" ng-class="{selected: openedMenu=='s'}" ng-click="openMenu($event,'s')">
<svg class="icon warning"><use xlink:href="#rocket"></use></svg><span class="menu-item-label"> Ships</span>
</div>
<svg class="icon warning"><use xlink:href="#rocket"></use></svg><span class="menu-item-label"> {{'ships' | translate}}</span>
</div>
<div class="menu-list dbl no-wrap" ng-if="openedMenu=='s'">
<a class="block" ng-repeat="(shipId,ship) in ships" ui-sref-active="active" ui-sref="outfit({shipId:shipId, code:null, bn:null})">{{::ship.properties.name}}</a>
</div>
@@ -16,14 +16,14 @@
<div class="l menu">
<div class="menu-header" ng-class="{selected: openedMenu=='b', disabled: !bs.hasBuilds}" ng-click="openMenu($event,'b')">
<svg class="icon warning" ng-class="{'warning-disabled': !bs.hasBuilds}"><use xlink:href="#hammer"></use></svg><span class="menu-item-label"> Builds</span>
<svg class="icon warning" ng-class="{'warning-disabled': !bs.hasBuilds}"><use xlink:href="#hammer"></use></svg><span class="menu-item-label"> {{'builds' | translate}}</span>
</div>
<div class="menu-list" ng-if="openedMenu=='b'" ng-click="$event.stopPropagation();">
<div class="dbl" >
<div><ul ng-repeat="shipId in buildsList">
{{ships[shipId].properties.name}}
<li ng-repeat="(name, build) in allBuilds[shipId]">
<a ui-sref-active="active" class="name" ui-sref="outfit({shipId:shipId, code:build, bn:name})" ng-bind="name"></a>
<li ng-repeat="(i, name) in cleanedBuildList(shipId)">
<a ui-sref-active="active" class="name" ui-sref="outfit({shipId:shipId, code:allBuilds[shipId][name], bn:name})" ng-bind="name"></a>
</li>
</ul></div>
</div>
@@ -32,39 +32,59 @@
<div class="l menu">
<div class="menu-header" ng-class="{selected: openedMenu=='comp', disabled: !bs.hasBuilds}" ng-click="openMenu($event,'comp')">
<svg class="icon warning" ng-class="{'warning-disabled': !bs.hasBuilds}"><use xlink:href="#stats-bars"></use></svg><span class="menu-item-label"> Compare</span>
</div>
<svg class="icon warning" ng-class="{'warning-disabled': !bs.hasBuilds}"><use xlink:href="#stats-bars"></use></svg><span class="menu-item-label"> {{'compare' | translate}}</span>
</div>
<div class="menu-list" ng-if="openedMenu=='comp'" ng-click="$event.stopPropagation();" style="white-space: nowrap;">
<span ng-if="!bs.hasComparisons">None Created</span>
<a ng-repeat="(name, comp) in allComparisons" ui-sref-active="active" class="block name" ui-sref="compare({name:name})" ng-bind="name"></a>
<span class="cap" ng-if="!bs.hasComparisons" translate="none created"></span>
<a ng-repeat="(i, name) in allComparisons" ui-sref-active="active" class="block name" ui-sref="compare({name:name})" ng-bind="name"></a>
<hr />
<a ui-sref="compare({name: 'all'})" class="block">Compare All</a>
<a ui-sref="compare({name: null})" class="block">Create New</a>
<a ui-sref="compare({name: 'all'})" class="block cap" translate="compare all"></a>
<a ui-sref="compare({name: null})" class="block cap" translate="create new"></a>
</div>
</div>
<div class="r menu">
<div class="menu-header" ng-class="{selected: openedMenu=='settings'}" ng-click="openMenu($event,'settings')">
<svg class="icon xl warning"><use xlink:href="#cogs"></use></svg><span class="menu-item-label"> Settings</span>
<svg class="icon xl warning"><use xlink:href="#cogs"></use></svg><span class="menu-item-label"> {{'settings' | translate}}</span>
</div>
<div class="menu-list no-wrap" ng-if="openedMenu=='settings'" ng-click="$event.stopPropagation();">
<div class="menu-list no-wrap cap" ng-if="openedMenu=='settings'" ng-click="$event.stopPropagation();">
<ul>
Insurance
<li><select ng-model="insurance.current" ng-options="ins.name for (i,ins) in insurance.opts" ng-change="updateInsurance()"></select></li>
{{'language' | translate}}
<li><select class="cap" ng-model="language.current" ng-options="langCode as langName for (langCode,langName) in language.opts" ng-change="changeLanguage()"></select></li>
</ul><br>
<ul>
Discount
<li><select ng-model="discounts.current" ng-options="d.name for (i,d) in discounts.opts" ng-change="updateDiscount()"></select></li>
{{'insurance' | translate}}
<li><select class="cap" ng-model="insurance.current" ng-options="ins.name | translate for (i,ins) in insurance.opts" ng-change="updateInsurance()"></select></li>
</ul><br>
<ul>
{{'ship' | translate}} {{'discount' | translate}}
<li><select class="cap" ng-model="discounts.ship" ng-options="i for (i,d) in discounts.opts" ng-change="updateDiscount()"></select></li>
</ul><br>
<ul>
{{'component' | translate}} {{'discount' | translate}}
<li><select class="cap" ng-model="discounts.components" ng-options="i for (i,d) in discounts.opts" ng-change="updateDiscount()"></select></li>
</ul>
<hr />
<ul>
Builds & Comparisons
<li><a href="#" class="block" ui-sref="modal.export({data: {builds: allBuilds}})">Export</a></li>
<li><a href="#" class="block" ui-sref="modal.import">Import</a></li>
<li><a href="#" class="block" ui-sref="modal.delete">Delete All</a></li>
{{'builds' | translate}} & {{'comparisons' | translate}}
<li><a href="#" class="block" ng-click="backup($event)" translate="backup"></a></li>
<li><a href="#" class="block" ng-click="detailedExport($event)" translate="detailed export"></a></li>
<li><a href="#" class="block" ui-sref="modal.import" translate="import"></a></li>
<li><a href="#" class="block" ui-sref="modal.delete" translate="delete all"></a></li>
</ul>
<hr />
<a href="#" ui-sref="modal.about" class="block">About</a>
<table style="width: 300px;background-color:transparent">
<tr>
<td style="width: 20px"><u>A</u></td>
<td slider min="0.65" def="sizeRatio" max="1.2" on-change="textSizeChange(val)" ignore-resize="true"></td>
<td style="width: 20px"><span style="font-size: 30px">A</span></td>
</tr>
<tr>
<td></td><td style="text-align:center" class="primary-disabled cap" ng-click="resetTextSize()" translate="reset"></td><td></td>
</tr>
</table>
<hr />
<a href="#" ui-sref="modal.about" class="block" translate="about"></a>
</div>
</div>

View File

@@ -1,17 +1,17 @@
<div class="sz">{{::['U','S','M','L','H'][hp.maxClass]}}</div>
<div class="empty" ng-if="!hp.c">EMPTY</div>
<div class="sz">{{['U','S','M','L','H'][hp.maxClass] | translate}}</div>
<div class="empty" ng-if="!hp.c" translate="empty"></div>
<div ng-if="hp.c">
{{hp.c.class}}{{hp.c.rating}}<span ng-if="hp.c.mode">/{{hp.c.mode}}{{hp.c.missile}}</span> {{hp.c.name || lbl}}
{{hp.c.class}}{{hp.c.rating}}<span ng-if="hp.c.mode">/{{hp.c.mode}}{{hp.c.missile}}</span> {{hp.c.name || hp.c.grp | translate}}
<div class="r">{{hp.c.mass}} <u>T</u></div>
<div class="cb">
<div class="l" ng-if="hp.c.damage">Damage: {{hp.c.damage}} <span ng-if="hp.c.ssdam">({{$r.fCrd(hp.c.ssdam)}} <u>Mj</u>)</span></div>
<div class="l" ng-if="hp.c.dps">DPS: {{hp.c.dps}} <span ng-if="hp.c.mjdps">({{$r.fCrd(hp.c.mjdps)}} <u>Mj</u>)</span></div>
<div class="l" ng-if="hp.c.thermload">T-Load: {{hp.c.thermload}}</div>
<div class="l" ng-if="hp.c.type">Type: {{hp.c.type}}</div>
<div class="l" ng-if="hp.c.rof">ROF: {{hp.c.rof}}<u>/s</u></div>
<div class="l" ng-if="hp.c.armourpen">Pen: {{hp.c.armourpen}}</div>
<div class="l" ng-if="hp.c.damage">{{'damage' | translate}}: {{hp.c.damage}} <span ng-if="hp.c.ssdam">({{$r.fCrd(hp.c.ssdam)}} <u>MJ</u>)</span></div>
<div class="l" ng-if="hp.c.dps">{{'DPS' | translate}}: {{hp.c.dps}} <span ng-if="hp.c.mjdps">({{$r.fCrd(hp.c.mjdps)}} <u>MJ</u>)</span></div>
<div class="l" ng-if="hp.c.thermload">{{'T_LOAD' | translate}}: {{hp.c.thermload}}</div>
<div class="l" ng-if="hp.c.type">{{'type' | translate}}: {{hp.c.type}}</div>
<div class="l" ng-if="hp.c.rof">{{'ROF' | translate}}: {{hp.c.rof}}<u>/s</u></div>
<div class="l" ng-if="hp.c.armourpen">{{'pen' | translate}}: {{hp.c.armourpen}}</div>
<div class="l" ng-if="hp.c.shieldmul">+{{$r.fRPct(hp.c.shieldmul)}}</div>
<div class="l" ng-if="hp.c.range">{{hp.c.range}} <u>KM</u></div>
<div class="l" ng-if="hp.c.ammo">Ammo: {{$r.fCrd(hp.c.clip)}}/{{$r.fCrd(hp.c.ammo)}}</div>
<div class="l" ng-if="hp.c.range">{{hp.c.range}} <u>km</u></div>
<div class="l" ng-if="hp.c.ammo >= 0">{{'ammo' | translate}}: {{$r.fCrd(hp.c.clip)}}+{{$r.fCrd(hp.c.ammo)}}</div>
</div>
</div>

View File

@@ -1,22 +1,23 @@
<div class="sz" ng-bind="c.maxClass"></div>
<div class="empty" ng-if="!c.c">EMPTY</div>
<div class="empty" ng-if="!c.c" translate="empty"></div>
<div ng-if="c.c">
{{c.c.class}}{{c.c.rating}} {{c.c.name || lbl}}
<div class="r">{{c.c.mass || c.c.capacity || '0'}} <u>T</u></div>
<div class="l name">{{c.c.class}}{{c.c.rating}} {{c.c.name || c.c.grp | translate}}</div>
<div class="r">{{c.c.mass || c.c.capacity || '0'}} <u translate="T"></u></div>
<div class="cb"></div>
<div class="l" ng-if="c.c.optmass">Opt: {{c.c.optmass}} <u>T</u></div>
<div class="l" ng-if="c.c.maxmass">Max: {{c.c.maxmass}} <u>T</u></div>
<div class="l" ng-if="c.c.bins">{{c.c.bins}} <u>Bins</u></div>
<div class="l" ng-if="c.c.rate">Rate: {{c.c.rate}} <u>Kg/s</u>&nbsp;&nbsp;&nbsp;Refuel Time: {{$r.fTime(fuel * 1000 / c.c.rate)}}</div>
<div class="l" ng-if="c.c.ammo">Ammo: {{c.c.ammo}}</div>
<div class="l" ng-if="c.c.cells">Cells: {{c.c.cells}}</div>
<div class="l" ng-if="c.c.recharge">Recharge: {{c.c.recharge}} <u>MJ</u></div>
<div class="l" ng-if="c.c.repair">Repair: {{c.c.repair}}</div>
<div class="l" ng-if="c.c.range">Range {{c.c.range}} <u>km</u></div>
<div class="l" ng-if="c.c.time">Time: {{$r.fTime(c.c.time)}}</div>
<div class="l" ng-if="c.c.maximum">Max: {{(c.c.maximum)}}</div>
<div class="l" ng-if="c.c.rangeLS">{{c.c.rangeLS}} <u>LS</u></div>
<div class="l" ng-if="c.c.rangeLS === null"><svg class="icon"><use xlink:href="#infinite"></use></svg> <u>LS</u></div>
<div class="l" ng-if="c.c.rangeRating">Range: {{c.c.rangeRating}}</div>
<div class="l" ng-if="c.c.armouradd">+{{c.c.armouradd}} <u>Armour</u></div>
</div>
<div class="l" ng-if="c.c.optmass">{{'optimal mass' | translate}}: {{c.c.optmass}} <u translate="T"></u></div>
<div class="l" ng-if="c.c.maxmass">{{'max mass' | translate}}: {{c.c.maxmass}} <u translate="T"></u></div>
<div class="l" ng-if="c.c.bins">{{c.c.bins}} <u translate="bins"></u></div>
<div class="l" ng-if="c.c.rate">{{'rate' | translate}}: {{c.c.rate}} <u>kg/s</u>&nbsp;&nbsp;&nbsp;{{'refuel time' | translate}}: {{$r.fTime(fuel * 1000 / c.c.rate)}}</div>
<div class="l" ng-if="c.c.vehicles">{{'vehicles' | translate}}: {{c.c.vehicles}}</div>
<div class="l" ng-if="c.c.ammo">{{'ammo' | translate}}: {{$r.fCrd(c.c.ammo)}}</div>
<div class="l" ng-if="c.c.cells">{{'cells' | translate}}: {{c.c.cells}}</div>
<div class="l" ng-if="c.c.recharge">{{'recharge' | translate}}: {{c.c.recharge}} <u>MJ</u>&nbsp;&nbsp;&nbsp;{{'total' | translate}}: {{c.c.cells * c.c.recharge}} <u>MJ</u></div>
<div class="l" ng-if="c.c.repair">{{'repair' | translate}}: {{c.c.repair}}</div>
<div class="l" ng-if="c.c.range">{{'range' | translate}} {{c.c.range}} <u>km</u></div>
<div class="l" ng-if="c.c.time">{{'time' | translate}}: {{$r.fTime(c.c.time)}}</div>
<div class="l" ng-if="c.c.maximum">{{'max' | translate}}: {{(c.c.maximum)}}</div>
<div class="l" ng-if="c.c.rangeLS">{{c.c.rangeLS}} <u translate="LS"></u></div>
<div class="l" ng-if="c.c.rangeLS === null"><svg class="icon"><use xlink:href="#infinite"></use></svg> <u translate="LS"></u></div>
<div class="l" ng-if="c.c.rangeRating">{{'range' | translate}}: {{c.c.rangeRating}}</div>
<div class="l" ng-if="c.c.armouradd">+{{c.c.armouradd}} <u translate="armour"></u></div>
</div>

View File

@@ -26,4 +26,4 @@
<p>Help keep the lights on! Donations will be used to cover costs of running and maintaining Coriolis. Thanks for helping!</p>
<button class="r dismiss" ng-click="dismiss()">Close</button>
<button class="r dismiss cap" ng-click="dismiss()" translate="close"></button>

View File

@@ -1,4 +1,4 @@
<h2>Delete All</h2>
<p style="text-align:center;">Are you sure?</p>
<button class="l" ng-click="deleteAll()">Yes</button>
<button class="r" ng-click="dismiss()">No</button>
<h2 translate="delete all"></h2>
<p style="text-align:center;" translate="PHRASE_CONFIRMATION"></p>
<button class="l cap" ng-click="deleteAll()" translate="yes"></button>
<button class="r cap" ng-click="dismiss()" translate="no"></button>

View File

@@ -1,5 +1,6 @@
<h2 ng-bind="title"></h2>
<h2 ng-bind="title | translate"></h2>
<div ng-if="description" ng-bind="description | translate"></div>
<div>
<textarea class="cb json" ng-click="onTextClick($event)" ng-bind="export"></textarea>
</div>
<button class="r dismiss" ng-click="dismiss()">Close</button>
<button class="r dismiss cap" ng-click="dismiss()" translate="close"></button>

View File

@@ -1,26 +1,46 @@
<h2>Import</h2>
<h2 translate="import"></h2>
<div ng-show="!processed">
<textarea class="cb json" ng-model="importData" ng-change="validateJson()" placeholder="Paste JSON Here"></textarea>
<button class="l" ng-click="process()" ng-disabled="!jsonValid">Proceed</button>
<textarea class="cb json" ng-model="importString" ng-change="validateImport()" placeholder="{{'PHRASE_IMPORT' | translate}}"></textarea>
<button class="l cap" ng-click="process()" ng-disabled="!importValid" translate="proceed"></button>
<div class="l warning" style="margin-left:3em;">{{errorMsg}}</div>
</div>
<div ng-show="processed">
<table class="l" style="overflow:hidden;margin: 1em 0;">
<thead><tr><th>Ship</th><th>Build Name</th><th>Action</th></tr></thead>
<table class="l" style="overflow:hidden;margin: 1em 0; width: 100%;">
<thead>
<tr>
<th style="text-align:left" translate="ship"></th>
<th style="text-align:left" translate="build name"></th>
<th translate="action"></th>
</tr>
</thead>
<tbody ng-repeat="(shipId,shipBuilds) in builds">
<tr class="cb" ng-repeat="(buildName, b) in shipBuilds">
<td>{{ships[shipId].properties.name}}</td>
<td><input type="text" ng-model="b.useName"/></td>
<td ng-class="{warning: hasBuild(shipId, b.useName) == true, disabled: b.useName == ''}">
<span ng-show="b.useName">{{ hasBuild(shipId, b.useName)? 'Overwrite' : 'Create' }}</span>
<span ng-show="b.useName == ''">Skip</span>
<td style="text-align:center" ng-class="{warning: hasBuild(shipId, b.useName) == true, disabled: b.useName == ''}">
<span ng-show="b.useName" translate="{{ hasBuild(shipId, b.useName)? 'overwrite' : 'create' }}"></span>
<span ng-show="b.useName == ''" translate="skip"></span>
</td>
</tr>
</tbody>
</table>
<button class="cl l" ng-click="import()"><svg class="icon"><use xlink:href="#download"></use></svg> Import</button>
<button class="l" style="margin-left: 2em;" ng-click="processed = false" ng-show="canEdit">Edit JSON</button>
<table class="l" style="overflow:hidden;margin: 1em 0; width: 100%;" ng-if="comparisons">
<thead><tr><th style="text-align:left" translate="comparison"></th><th translate="action"></th></tr></thead>
<tbody>
<tr class="cb" ng-repeat="(name, comparison) in comparisons">
<td><input type="text" ng-model="comparison.useName"/></td>
<td style="text-align:center" ng-class="{warning: hasComparison(comparison.useName) == true, disabled: comparison.useName == ''}">
<span ng-show="comparison.useName" translate="{{ hasComparison(comparison.useName)? 'overwrite' : 'create' }}"></span>
<span ng-show="comparison.useName == ''" translate="skip"></span>
</td>
</tr>
</tbody>
</table>
<button class="cl l" ng-click="import()"><svg class="icon"><use xlink:href="#download"></use></svg> {{'import' | translate}}</button>
<button class="l cap" style="margin-left: 2em;" ng-click="processed = false" ng-show="canEdit" translate="edit data"></button>
</div>
<button class="r dismiss" ng-click="dismiss()">Cancel</button>
<button class="r dismiss cap" ng-click="dismiss()" translate="cancel"></button>

View File

@@ -1,9 +1,9 @@
<h2>Permalink</h2>
<h2 translate="permalink"></h2>
<br>
<h3>URL</h3>
<h3 translate="URL"></h3>
<input ng-model="url" size="40" ng-click="onTextClick($event)">
<br><br>
<h3>Shortened</h3>
<h3 translate="shortened"></h3>
<input ng-model="shortenedUrl" size="25" ng-click="onTextClick($event)">
<br><br>
<button class="r dismiss" ng-click="dismiss()">Close</button>
<button class="r dismiss cap" ng-click="dismiss()" translate="close"></button>

View File

@@ -1,37 +1,37 @@
<table id="comparison">
<tr ng-show="compareMode">
<td class="head">Comparison</td>
<td class="head" translate="comparison"></td>
<td>
<input ng-model="name" ng-change="nameChange()" placeholder="Enter Comparison Name" maxlength="50" />
<input ng-model="name" ng-change="nameChange()" placeholder="{{'enter name' | translate}}" maxlength="50" />
<button ng-click="save()" ng-disabled="!name || name == 'all' || saved">
<svg class="icon lg "><use xlink:href="#floppy-disk"></use></svg><span class="button-lbl"> Save</span>
<svg class="icon lg "><use xlink:href="#floppy-disk"></use></svg><span class="button-lbl"> {{'save' | translate}}</span>
</button>
<button ng-click="delete()" ng-disabled="name == 'all' || !saved"><svg class="icon lg warning "><use xlink:href="#bin"></use></svg></button>
<button ng-click="selectBuilds(true, $event)">
<svg class="icon lg "><use xlink:href="#rocket"></use></svg><span class="button-lbl"> Builds</span>
<svg class="icon lg "><use xlink:href="#rocket"></use></svg><span class="button-lbl"> {{'builds' | translate}}</span>
</button>
<button class="r" ng-click="permalink($event)" ng-disabled="builds.length == 0">
<svg class="icon lg "><use xlink:href="#link"></use></svg><span class="button-lbl"> Permalink</span>
<svg class="icon lg "><use xlink:href="#link"></use></svg><span class="button-lbl"> {{'permalink' | translate}}</span>
</button>
<button class="r" ng-click="embed($event)" ng-disabled="builds.length == 0">
<svg class="icon lg "><use xlink:href="#embed"></use></svg><span class="button-lbl"> Forum</span>
<svg class="icon lg "><use xlink:href="#embed"></use></svg><span class="button-lbl"> {{'forum' | translate}}</span>
</button>
</td>
</tr>
<tr ng-show="!compareMode">
<td class="head">Comparison</td>
<td class="head" translate="comparison"></td>
<td>
<h3 ng-bind="name"></h3>
<button class="r" ui-sref="modal.import({obj:importObj})"><svg class="icon lg "><use xlink:href="#download"></use></svg> Import Builds</button>
<button class="r" ui-sref="modal.import({obj:importObj})"><svg class="icon lg "><use xlink:href="#download"></use></svg> {{'import' | translate}}</button>
</td>
</tr>
<tr>
<td class="head">Compare</td>
<td class="head" translate="compare"></td>
<td>
<ul id="facet-container" as-sortable="facetSortOpts" ng-model="facets" class="sortable" update="tblUpdate">
<li ng-repeat="(i,f) in facets" as-sortable-item class="facet" ng-class="{active: f.active}" ng-click="toggleFacet(i)">
<div as-sortable-item-handle>&#x2194; <span ng-bind="f.title"></span></div>
<div as-sortable-item-handle>&#x2194; <span ng-bind="f.title | translate"></span></div>
</li>
</ul>
</td>
@@ -43,15 +43,15 @@
</div>
<div ng-repeat="f in facets | filter:{active:true}" ng-if="builds.length > 0" class="chart" bar-chart facet="f" data="builds">
<h3 ng-click="sort(f.props[0])" >{{f.title}}</h3>
<h3 ng-click="sort(f.props[0])" >{{f.title | translate}}</h3>
</div>
<div class="modal-bg" ng-show="showBuilds" ng-click="selectBuilds(false, $event)">
<div class="modal" ui-view="modal-content" ng-click="$event.stopPropagation()">
<h3>Select Builds to Compare</h3>
<h3 translate="PHRASE_SELECT_BUILDS"></h3>
<div id="build-select">
<table>
<thead><tr><th colspan="2">Available</th></tr></thead>
<thead><tr><th colspan="2" translate="available"></th></tr></thead>
<tbody>
<tr ng-repeat="b in unusedBuilds | orderBy:'name'" ng-click="addBuild(b.id, b.buildName)">
<td class="tl" ng-bind="b.name"></td><td class="tl" ng-bind="b.buildName"></td>
@@ -60,7 +60,7 @@
</table>
<h1></h1>
<table>
<thead><tr><th colspan="2">Added</th></tr></thead>
<thead><tr><th colspan="2" translate="added"></th></tr></thead>
<tbody>
<tr ng-repeat="b in builds | orderBy:'name'" ng-click="removeBuild(b.id, b.buildName)">
<td class="tl" ng-bind="b.name"></td><td class="tl" ng-bind="b.buildName"></td>
@@ -69,6 +69,6 @@
</table>
</div>
<br>
<button class="r dismiss" ng-click="selectBuilds(false, $event)">Done</button>
<button class="r dismiss cap" ng-click="selectBuilds(false, $event)" translate="done"></button>
</div>
</div>

View File

@@ -15,7 +15,7 @@
<div ng-if="path" >Path:<br>{{path}}</div>
<div ng-if="type">Error:<br>{{type}}</div>
<div ng-if="errorMessage">Message:<pre>{{errorMessage}}</pre></div>
<div ng-if="details">Details:<br><pre>{{details}}<pre></div>
<div ng-if="details">Details:<br><pre>{{details}}</pre></div>
</div>
</div>
</div>

View File

@@ -3,18 +3,21 @@
<div id="overview">
<h1 ng-bind="ship.name"></h1>
<div id="build">
<input ng-model="buildName" ng-change="bnChange()" placeholder="Enter Build Name" maxsize="50" />
<input ng-model="buildName" ng-change="bnChange()" placeholder="{{'enter name' | translate}}" maxsize="50" />
<button ng-click="saveBuild()" ng-disabled="!buildName || savedCode && code == savedCode || !canSave">
<svg class="icon lg "><use xlink:href="#floppy-disk"></use></svg><span class="button-lbl">Save</span>
<svg class="icon lg "><use xlink:href="#floppy-disk"></use></svg><span class="button-lbl" translate="save"></span>
</button>
<button ng-click="reloadBuild()" ng-disabled="!savedCode || code == savedCode">
<svg class="icon lg"><use xlink:href="#spinner11"></use></svg><span class="button-lbl">Reload</span>
<svg class="icon lg"><use xlink:href="#spinner11"></use></svg><span class="button-lbl" translate="reload"></span>
</button>
<button class="danger" ng-click="deleteBuild()" ng-disabled="!savedCode">
<svg class="icon lg"><use xlink:href="#bin"></use></svg>
</button>
<button ui-sref="outfit({shipId: ship.id,code:null, bn: buildName})" ng-disabled="!code">
<svg class="icon lg"><use xlink:href="#switch"></use></svg><span class="button-lbl">Reset</span>
<button ng-click="resetBuild()" ng-disabled="!code">
<svg class="icon lg"><use xlink:href="#switch"></use></svg><span class="button-lbl" translate="reset"></span>
</button>
<button ng-click="exportBuild($event)" ng-disabled="!buildName">
<svg class="icon lg"><use xlink:href="#download"></use></svg><span class="button-lbl" translate="export"></span>
</button>
</div>
</div>
@@ -23,160 +26,252 @@
<table id="summaryTable">
<thead>
<tr class="main">
<th rowspan="2">Size</th>
<th rowspan="2">Agility</th>
<th rowspan="2">Speed</th>
<th rowspan="2">Boost</th>
<th rowspan="2">Armour</th>
<th rowspan="2">Shields</th>
<th colspan="2">Mass</th>
<th rowspan="2">Cargo</th>
<th rowspan="2">Fuel</th>
<th colspan="3">Jump Range</th>
<th colspan="3">Total Range</th>
<th rowspan="2" translate="size"></th>
<th rowspan="2" translate="agility"></th>
<th rowspan="2" ng-class="{'bg-warning-disabled': th.c.maxmass < ship.ladenMass}" translate="speed"></th>
<th rowspan="2" ng-class="{'bg-warning-disabled': (pd.c.enginecapacity < ship.boostEnergy || th.c.maxmass < ship.ladenMass)}" translate="boost"></th>
<th rowspan="2" translate="DPS"></th>
<th rowspan="2" translate="armour"></th>
<th rowspan="2" translate="shields"></th>
<th colspan="3" translate="mass"></th>
<th rowspan="2" translate="cargo"></th>
<th rowspan="2" translate="fuel"></th>
<th colspan="3" translate="jump range"></th>
<th colspan="3" translate="total range"></th>
<th rowspan="2" translate="lock factor"></th>
</tr>
<tr>
<th class="lft">Unladen</th>
<th>Laden</th>
<th class="lft">Max</th>
<th>Full Tank</th>
<th>Laden</th>
<th class="lft">Jumps</th>
<th>Unladen</th>
<th>Laden</th>
<th class="lft" translate="hull"></th>
<th translate="unladen"></th>
<th translate="laden"></th>
<th class="lft" translate="max"></th>
<th translate="full tank"></th>
<th translate="laden"></th>
<th class="lft" translate="jumps"></th>
<th translate="unladen"></th>
<th translate="laden"></th>
</tr>
</thead>
<tbody>
<tr>
<td ng-bind="SZ[ship.class]"></td>
<td class="cap" ng-bind="SZM[ship.class] | translate"></td>
<td>{{ship.agility}}/10</td>
<td>{{fRound(ship.speed)}} <u>m/s</u></td>
<td>{{fRound(ship.boost)}} <u>m/s</u></td>
<td>{{ship.armourTotal}} <span ng-if="ship.armourAdded">({{ship.armour}} + {{ship.armourAdded}})</span></td>
<td>{{fRound(ship.shieldStrength)}} <u>MJ</u> <span ng-if="ship.shieldMultiplier > 1">({{fRPct(ship.shieldMultiplier)}})</span></td>
<td>{{fRound(ship.unladenMass)}} <u>T</u></td>
<td>{{fRound(ship.ladenMass)}} <u>T</u></td>
<td>{{fRound(ship.cargoCapacity)}} <u>T</u></td>
<td>{{fRound(ship.fuelCapacity)}} <u>T</u></td>
<td>{{fRound(ship.unladenRange)}} <u>LY</u></td>
<td>{{fRound(ship.fullTankRange)}} <u>LY</u></td>
<td>{{fRound(ship.ladenRange)}} <u>LY</u></td>
<td>
<span ng-if="th.c.maxmass >= ship.ladenMass">{{fCrd(ship.topSpeed)}} <u translate>m/s</u></span>
<span class="warning" ng-if="th.c.maxmass < ship.ladenMass">0 <svg class="icon"><use xlink:href="#warning"></use></svg></span>
</td>
<td>
<span ng-if="pd.c.enginecapacity >= ship.boostEnergy && th.c.maxmass >= ship.ladenMass">{{fCrd(ship.topBoost)}} <u translate>m/s</u></span>
<span class="warning" ng-if="pd.c.enginecapacity < ship.boostEnergy || th.c.maxmass < ship.ladenMass">0
<svg class="icon"><use xlink:href="#warning"></use></svg>
</span>
</td>
<td>{{fRound(ship.totalDps)}}</td>
<td>
{{fCrd(ship.armour)}}
<span ng-if="ship.armourAdded || ship.armourMultiplier > 1">
(<span ng-if="ship.armourMultiplier > 1">{{fRPct(ship.armourMultiplier)}}</span><span ng-if="ship.armourAdded && ship.armourMultiplier > 1">&nbsp;</span><span ng-if="ship.armourAdded">+ {{ship.armourAdded}}</span>)
</span>
</td>
<td>{{fCrd(ship.shieldStrength)}} <u translate>MJ</u> <span ng-if="ship.shieldMultiplier > 1 && ship.shieldStrength > 0">({{fRPct(ship.shieldMultiplier)}})</span></td>
<td>{{ship.hullMass}} <u translate>T</u></td>
<td>{{fRound(ship.unladenMass)}} <u translate>T</u></td>
<td>{{fRound(ship.ladenMass)}} <u translate>T</u></td>
<td>{{fRound(ship.cargoCapacity)}} <u translate>T</u></td>
<td>{{fRound(ship.fuelCapacity)}} <u translate>T</u></td>
<td>{{fRound(ship.unladenRange)}} <u translate>LY</u></td>
<td>{{fRound(ship.fullTankRange)}} <u translate>LY</u></td>
<td>{{fRound(ship.ladenRange)}} <u translate>LY</u></td>
<td>{{fRound(ship.maxJumpCount)}}</td>
<td>{{fRound(ship.unladenTotalRange)}} <u>LY</u></td>
<td>{{fRound(ship.ladenTotalRange)}} <u>LY</u></td>
<td>{{fRound(ship.unladenTotalRange)}} <u translate>LY</u></td>
<td>{{fRound(ship.ladenTotalRange)}} <u translate>LY</u></td>
<td ng-bind="ship.masslock"></td>
</tr>
</tbody>
</table>
</div>
<div id="standard" class="group">
<h1>Standard</h1>
<div class="section-menu" ng-class="{selected: selectedSlot=='standard'}" context-menu="optimizeStandard()" ng-click="selectSlot($event, 'standard')">
<h1>
{{'standard' | translate}}
<svg class="icon"><use xlink:href="#equalizer"></use></svg>
</h1>
<div class="select" ng-if="selectedSlot=='standard'">
<ul>
<li class="lc" ng-click="optimizeStandard()" translate="Optimize"></li>
<li class="c" ng-click="useStandard('E')">E</li>
<li class="c" ng-click="useStandard('D')">D</li>
<li class="c" ng-click="useStandard('C')">C</li>
<li class="c" ng-click="useStandard('B')">B</li>
<li class="c" ng-click="useStandard('A')">A</li>
</ul>
<div class="select-group cap" translate="builds / roles"></div>
<ul>
<li class="lc" ng-click="optimizeCargo()" translate="Trader"></li>
<li class="lc" ng-click="optimizeExplorer()" translate="Explorer"></li>
</ul>
</div>
</div>
<div class="slot" ng-click="selectSlot($event, ship.bulkheads)" ng-class="{selected: selectedSlot==ship.bulkheads}">
<div class="details">
<div class="sz"><span>8</span></div>
<div class="l">Bulkheads</div>
<div class="r">{{ship.bulkheads.c.mass}} <u>T</u></div>
<div class="cl l">{{ship.bulkheads.c.name}}</div>
<div class="l cap" translate="bh"></div>
<div class="r">{{ship.bulkheads.c.mass}} <u translate>T</u></div>
<div class="cl l">{{ship.bulkheads.c.name | translate}}</div>
</div>
<div class="select" ng-if="selectedSlot==ship.bulkheads" ng-click="select('b',ship.bulkheads,$event)">
<ul>
<li class="lc" ng-class="{active: ship.bulkheads.id=='0'}" cpid="0">Lightweight Alloy</li>
<li class="lc" ng-class="{active: ship.bulkheads.id=='1'}" cpid="1">Reinforced Alloy</li>
<li class="lc" ng-class="{active: ship.bulkheads.id=='2'}" cpid="2">Military Grade Composite</li>
<li class="lc" ng-class="{active: ship.bulkheads.id=='3'}" cpid="3">Mirrored Surface Composite</li>
<li class="lc" ng-class="{active: ship.bulkheads.id=='4'}" cpid="4">Reactive Surface Composite</li>
<li class="lc" ng-class="{active: ship.bulkheads.id=='0'}" cpid="0" translate="Lightweight Alloy"></li>
<li class="lc" ng-class="{active: ship.bulkheads.id=='1'}" cpid="1" translate="Reinforced Alloy"></li>
<li class="lc" ng-class="{active: ship.bulkheads.id=='2'}" cpid="2" translate="Military Grade Composite"></li>
<li class="lc" ng-class="{active: ship.bulkheads.id=='3'}" cpid="3" translate="Mirrored Surface Composite"></li>
<li class="lc" ng-class="{active: ship.bulkheads.id=='4'}" cpid="4" translate="Reactive Surface Composite"></li>
</ul>
</div>
</div>
<div class="slot" ng-click="selectSlot($event, pp)" ng-class="{selected: selectedSlot==pp}">
<div class="details">
<div class="details" ng-class="{warning: pp.c.pGen < ship.powerRetracted}">
<div class="sz">{{::pp.maxClass}}</div>
<div class="l">{{pp.id}} Power Plant</div>
<div class="r">{{pp.c.mass}} <u>T</u></div>
<div class="l">{{pp.id}} {{'pp' | translate}}</div>
<div class="r">{{pp.c.mass}} <u translate>T</u></div>
<div class="cb"></div>
<div class="l">Efficiency: {{pp.c.eff}}</div>
<div class="l">Power: {{pp.c.pGen}} <u>MW</u></div>
<div class="l cap">{{'efficiency' | translate}}: {{pp.c.eff}}</div>
<div class="l cap">{{'power' | translate}}: {{pp.c.pGen}} <u translate>MW</u></div>
</div>
<div component-select class="select" s="pp" opts="availCS.common[0]" ng-if="selectedSlot==pp" ng-click="select('c',pp,$event)"></div>
<div component-select class="select" s="pp" warning="ppWarning" opts="availCS.standard[0]" ng-if="selectedSlot==pp" ng-click="select('c',pp,$event)"></div>
</div>
<div class="slot" ng-click="selectSlot($event, th)" ng-class="{selected: selectedSlot==th}">
<div class="details">
<div class="details" ng-class="{'warning': th.c.maxmass < ship.ladenMass}">
<div class="sz">{{::th.maxClass}}</div>
<div class="l">{{th.id}} Thrusters</div>
<div class="r">{{th.c.mass}} <u>T</u></div>
<div class="l">{{th.id}} {{'t' | translate}}</div>
<div class="r">{{th.c.mass}} <u translate>T</u></div>
<div class="cb"></div>
<div class="l">Optimal Mass: {{th.c.optmass}} <u>T</u></div>
<div class="l">Max Mass: {{th.c.maxmass}} <u>T</u></div>
<div class="l">{{'optimal mass' | translate}}: {{th.c.optmass}} <u translate>T</u></div>
<div class="l">{{'max mass' | translate}}: {{th.c.maxmass}} <u translate>T</u></div>
</div>
<div component-select class="select" s="th" mass="ship.unladenMass" opts="availCS.common[1]" ng-if="selectedSlot==th" ng-click="select('c',th,$event)"></div>
<div component-select class="select" s="th" mass="ship.ladenMass" opts="availCS.standard[1]" ng-if="selectedSlot==th" ng-click="select('c',th,$event)"></div>
</div>
<div class="slot" ng-click="selectSlot($event, fsd)" ng-class="{selected: selectedSlot==fsd}">
<div class="details">
<div class="sz">{{::fsd.maxClass}}</div>
<div class="l">{{fsd.id}} Frame Shift Drive</div>
<div class="r cr">{{fsd.c.mass}} <u>T</u></div>
<div class="l">{{fsd.id}} {{'fd' | translate}}</div>
<div class="r cr">{{fsd.c.mass}} <u translate>T</u></div>
<div class="cb"></div>
<div class="l">Optimal Mass: {{fsd.c.optmass}} <u>T</u></div>
<div class="l">Max Fuel: {{fsd.c.maxfuel}} <u>T</u></div>
<div class="l cap">{{'optimal mass' | translate}}: {{fsd.c.optmass}} <u translate>T</u></div>
<div class="l cap">{{'max' | translate}} {{'fuel' | translate}}: {{fsd.c.maxfuel}} <u translate>T</u></div>
</div>
<div component-select class="select" s="fsd" opts="availCS.common[2]" ng-if="selectedSlot==fsd" ng-click="select('c',fsd,$event)"></div>
<div component-select class="select" s="fsd" opts="availCS.standard[2]" ng-if="selectedSlot==fsd" ng-click="select('c',fsd,$event)"></div>
</div>
<div class="slot" ng-click="selectSlot($event, ls)" ng-class="{selected: selectedSlot==ls}">
<div class="details">
<div class="sz">{{::ls.maxClass}}</div>
<div class="l">{{ls.id}} Life Support</div>
<div class="r">{{ls.c.mass}} <u>T</u></div>
<div class="l">{{ls.id}} {{'ls' | translate}}</div>
<div class="r">{{ls.c.mass}} <u translate>T</u></div>
<div class="cb"></div>
<div class="l">Time: {{fTime(ls.c.time)}}</div>
<div class="l cap">{{'time' | translate}}: {{fTime(ls.c.time)}}</div>
</div>
<div component-select class="select" s="ls" opts="availCS.common[3]" ng-if="selectedSlot==ls" ng-click="select('c',ls,$event)"></div>
<div component-select class="select" s="ls" opts="availCS.standard[3]" ng-if="selectedSlot==ls" ng-click="select('c',ls,$event)"></div>
</div>
<div class="slot" ng-click="selectSlot($event, pd)" ng-class="{selected: selectedSlot==pd}">
<div class="details">
<div class="details" ng-class="{warning: pd.c.enginecapacity < ship.boostEnergy}">
<div class="sz">{{::pd.maxClass}}</div>
<div class="l">{{pd.id}} Power Distributor</div>
<div class="r">{{pd.c.mass}} <u>T</u></div>
<div class="l">{{pd.id}} {{'pd' | translate}}</div>
<div class="r">{{pd.c.mass}} <u translate>T</u></div>
<div class="cb"></div>
<div class="l">WEP: {{pd.c.weaponcapacity}} <u>MJ</u> / {{pd.c.weaponrecharge}} <u>MW</u></div>
<div class="l">SYS: {{pd.c.systemcapacity}} <u>MJ</u> / {{pd.c.systemrecharge}} <u>MW</u></div>
<div class="l">ENG: {{pd.c.enginecapacity}} <u>MJ</u> / {{pd.c.enginerecharge}} <u>MW</u></div>
<div class="l">{{'WEP' | translate}}: {{pd.c.weaponcapacity}} <u translate>MJ</u> / {{pd.c.weaponrecharge}} <u translate>MW</u></div>
<div class="l">{{'SYS' | translate}}: {{pd.c.systemcapacity}} <u translate>MJ</u> / {{pd.c.systemrecharge}} <u translate>MW</u></div>
<div class="l">{{'ENG' | translate}}: {{pd.c.enginecapacity}} <u translate>MJ</u> / {{pd.c.enginerecharge}} <u translate>MW</u></div>
</div>
<div component-select class="select" s="pd" opts="availCS.common[4]" ng-if="selectedSlot==pd" ng-click="select('c',pd,$event)"></div>
<div component-select class="select" s="pd" warning="pdWarning" opts="availCS.standard[4]" ng-if="selectedSlot==pd" ng-click="select('c',pd,$event)"></div>
</div>
<div class="slot" ng-click="selectSlot($event, ss)" ng-class="{selected: selectedSlot==ss}">
<div class="details">
<div class="sz">{{::ss.maxClass}}</div>
<div class="l">{{ss.id}} Sensors</div>
<div class="r">{{ss.c.mass}} <u>T</u></div>
<div class="l">{{ss.id}} {{'s' | translate}}</div>
<div class="r">{{ss.c.mass}} <u translate>T</u></div>
<div class="cb"></div>
<div class="l">Range: {{ss.c.range}} <u>km</u></div>
<div class="l cap">{{'range' | translate}}: {{ss.c.range}} <u translate>km</u></div>
</div>
<div component-select class="select" s="ss" opts="availCS.common[5]" ng-if="selectedSlot==ss" ng-click="select('c',ss,$event)"></div>
<div component-select class="select" s="ss" opts="availCS.standard[5]" ng-if="selectedSlot==ss" ng-click="select('c',ss,$event)"></div>
</div>
<div class="slot" ng-click="selectSlot($event, ft)" ng-class="{selected: selectedSlot==ft}">
<div class="details">
<div class="sz">{{::ft.maxClass}}</div>
<div class="l">{{ft.id}} Fuel Tank</div>
<div class="r">{{ft.c.capacity}} <u>T</u></div>
<div class="l">{{ft.id}} {{'ft' | translate}}</div>
<div class="r">{{ft.c.capacity}} <u translate>T</u></div>
</div>
<div component-select class="select" s="ft" opts="availCS.common[6]" ng-if="selectedSlot==ft" ng-click="select('c',ft,$event)"></div>
<div component-select class="select" s="ft" opts="availCS.standard[6]" ng-if="selectedSlot==ft" ng-click="select('c',ft,$event)"></div>
</div>
</div>
<div id="internal" class="group">
<h1>Internal Compartments</h1>
<div class="section-menu" ng-class="{selected: selectedSlot=='internal'}" context-menu="emptyInternal()" ng-click="selectSlot($event, 'internal')">
<h1>
{{'internal compartments' | translate}}
<svg class="icon"><use xlink:href="#equalizer"></use></svg>
</h1>
<div class="select" ng-if="selectedSlot=='internal'">
<ul>
<li class="lc" ng-click="emptyInternal()" translate="empty all"></li>
<li class="lc" ng-click="fillWithCargo()" translate="cargo"></li>
<li class="lc" ng-click="fillWithCells()" translate="scb"></li>
<li class="lc" ng-click="fillWithArmor()" translate="hr"></li>
</ul>
</div>
</div>
<div class="slot" ng-repeat="i in ship.internal" ng-click="selectSlot($event, i)" context-menu="select('i', i, $event, 'empty')" ng-class="{selected: selectedSlot==i}">
<div slot-internal class="details" slot="i" lbl="GMAP[i.c.grp]" fuel="ship.fuelCapacity"></div>
<div slot-internal class="details" slot="i" fuel="ship.fuelCapacity"></div>
<div class="select" ng-if="selectedSlot==i" ng-click="select('i',i,$event)">
<div component-select s="i" groups="availCS.getInts(i.maxClass)"></div>
<div component-select s="i" groups="availCS.getInts(i.maxClass, i.eligible)"></div>
</div>
</div>
</div>
<div id="hardpoints" class="group">
<h1>HardPoints</h1>
<div class="section-menu" ng-class="{selected: selectedSlot=='hardpoints'}" context-menu="emptyHardpoints()" ng-click="selectSlot($event, 'hardpoints')">
<h1>
{{'hardpoints' | translate}}
<svg class="icon"><use xlink:href="#equalizer"></use></svg>
</h1>
<div class="select hardpoint" ng-if="selectedSlot=='hardpoints'">
<ul>
<li class="lc" ng-click="emptyHardpoints()" translate="empty all"></li>
</ul>
<div class="select-group cap" translate="pl"></div>
<ul>
<li class="c" ng-click="useHardpoint('pl','F')"><svg class="icon lg"><use xlink:href="#mount-F"></use></svg></li>
<li class="c" ng-click="useHardpoint('pl','G')"><svg class="icon lg"><use xlink:href="#mount-G"></use></svg></li>
<li class="c" ng-click="useHardpoint('pl','T')"><svg class="icon lg"><use xlink:href="#mount-T"></use></svg></li>
</ul>
<div class="select-group cap" translate="ul"></div>
<ul>
<li class="c" ng-click="useHardpoint('ul','F')"><svg class="icon lg"><use xlink:href="#mount-F"></use></svg></li>
<li class="c" ng-click="useHardpoint('ul','G')"><svg class="icon lg"><use xlink:href="#mount-G"></use></svg></li>
<li class="c" ng-click="useHardpoint('ul','T')"><svg class="icon lg"><use xlink:href="#mount-T"></use></svg></li>
</ul>
<div class="select-group cap" translate="bl"></div>
<ul>
<li class="c" ng-click="useHardpoint('bl','F')"><svg class="icon lg"><use xlink:href="#mount-F"></use></svg></li>
<li class="c" ng-click="useHardpoint('bl','G')"><svg class="icon lg"><use xlink:href="#mount-G"></use></svg></li>
<li class="c" ng-click="useHardpoint('bl','T')"><svg class="icon lg"><use xlink:href="#mount-T"></use></svg></li>
</ul>
<div class="select-group cap" translate="mc"></div>
<ul>
<li class="c" ng-click="useHardpoint('mc','F')"><svg class="icon lg"><use xlink:href="#mount-F"></use></svg></li>
<li class="c" ng-click="useHardpoint('mc','G')"><svg class="icon lg"><use xlink:href="#mount-G"></use></svg></li>
<li class="c" ng-click="useHardpoint('mc','T')"><svg class="icon lg"><use xlink:href="#mount-T"></use></svg></li>
</ul>
<div class="select-group cap" translate="c"></div>
<ul>
<li class="c" ng-click="useHardpoint('c','F')"><svg class="icon lg"><use xlink:href="#mount-F"></use></svg></li>
<li class="c" ng-click="useHardpoint('c','G')"><svg class="icon lg"><use xlink:href="#mount-G"></use></svg></li>
<li class="c" ng-click="useHardpoint('c','T')"><svg class="icon lg"><use xlink:href="#mount-T"></use></svg></li>
</ul>
</div>
</div>
<div class="slot" ng-repeat="h in ship.hardpoints | filter:{maxClass: '!0'}" ng-click="selectSlot($event, h)" context-menu="select('h', h, $event, 'empty')" ng-class="{selected: selectedSlot==h}">
<div slot-hardpoint class="details" hp="h" size="HPC[h.maxClass]" lbl="GMAP[h.c.grp]"></div>
<div slot-hardpoint class="details" hp="h" size="HPC[h.maxClass]"></div>
<div class="select" ng-class="{hardpoint: h.maxClass > 0}" ng-if="selectedSlot==h" ng-click="select('h',h,$event)">
<div component-select s="h" groups="availCS.getHps(h.maxClass)"></div>
</div>
@@ -184,32 +279,54 @@
</div>
<div id="utility" class="group">
<h1>Utility Mounts</h1>
<div class="section-menu" ng-class="{selected: selectedSlot=='utility'}" context-menu="emptyUtility()" ng-click="selectSlot($event, 'utility')">
<h1>
{{'utility mounts' | translate}}
<svg class="icon"><use xlink:href="#equalizer"></use></svg>
</h1>
<div class="select" ng-if="selectedSlot=='utility'">
<ul>
<li class="lc" ng-click="emptyUtility()" translate="empty all"></li>
</ul>
<div class="select-group cap" translate="sb"></div>
<ul>
<li class="c" ng-click="useUtility('sb','E')">E</li>
<li class="c" ng-click="useUtility('sb','D')">D</li>
<li class="c" ng-click="useUtility('sb','C')">C</li>
<li class="c" ng-click="useUtility('sb','B')">B</li>
<li class="c" ng-click="useUtility('sb','A')">A</li>
</ul>
<div class="select-group cap" translate="Heat Sink Launcher"></div>
<ul>
<li class="lc" ng-click="useUtility('cm',null,'Heat Sink Launcher')" translate="Heat Sink Launcher"></li>
</ul>
</div>
</div>
<div class="slot" ng-repeat="h in ship.hardpoints | filter:{maxClass: '0'}" ng-click="selectSlot($event, h)" context-menu="select('h', h, $event, 'empty')" ng-class="{selected: selectedSlot==h}">
<div slot-hardpoint class="details" hp="h" size="HPC[h.maxClass]" lbl="GMAP[h.c.grp]"></div>
<div slot-hardpoint class="details" hp="h" size="HPC[h.maxClass]"></div>
<div class="select" ng-class="{hardpoint: h.maxClass > 0}" ng-if="selectedSlot==h" ng-click="select('h',h,$event)">
<div component-select s="h" groups="availCS.getHps(h.maxClass)"></div>
</div>
</div>
</div>
<div class="group dbl" id="componentPriority">
<div class="group half" id="componentPriority">
<table style="width:100%">
<thead>
<tr class="main">
<th colspan="2" class="sortable le" ng-click="sortPwr(cName)">Component</th>
<th style="width:3em;" class="sortable" ng-click="sortPwr('type')">Type</th>
<th style="width:4em;" class="sortable" ng-click="sortPwr('priority')">Pri</th>
<th colspan="2" class="sortable" ng-click="sortPwr('c.power')">Pwr</th>
<th style="width:3em;" class="sortable" ng-click="sortPwr(statusRetracted)">Ret</th>
<th style="width:3em;" class="sortable" ng-click="sortPwr(statusDeployed)">Dep</th>
<th colspan="2" class="sortable le" ng-click="sortPwr(cName)" translate="COMPONENT"></th>
<th style="width:3em;" class="sortable" ng-click="sortPwr('type')" translate="TYPE"></th>
<th style="width:4em;" class="sortable" ng-click="sortPwr('priority')" translate="PRI"></th>
<th colspan="2" class="sortable" ng-click="sortPwr('c.power')" translate="PWR"></th>
<th style="width:3em;" class="sortable" ng-click="sortPwr(statusRetracted)" translate="ret"></th>
<th style="width:3em;" class="sortable" ng-click="sortPwr(statusDeployed)" translate="dep"></th>
</tr>
</thead>
<tbody>
<tr>
<td ng-click="togglePwr(c)">{{pp.c.class}}{{pp.c.rating}}</td>
<td class="le shorten">Power Plant</td>
<td><u>SYS</u></td>
<td>{{pp.c.class}}{{pp.c.rating}}</td>
<td class="le shorten cap" translate="pp"></td>
<td><u translate="SYS"></u></td>
<td>1</td>
<td class="ri">{{fPwr(pp.c.pGen)}}</td>
<td class="ri"><u>100%</u></td>
@@ -217,57 +334,169 @@
<td></td>
</tr>
<tr><td style="line-height:0;" colspan="8"><hr style="margin: 0 0 3px;background: #ff8c0d;border: 0;height: 1px;" /></td></tr>
<tr ng-repeat="c in powerList | orderBy:pwrPredicate:pwrDesc" ng-if="c.c.power" ng-class="{disabled:!c.enabled}">
<tr class="highlight" ng-repeat="c in powerList | orderBy:pwrPredicate:pwrDesc" ng-if="c.c.power" ng-class="{disabled:!c.enabled}">
<td style="width:1em;" ng-click="togglePwr(c)">{{c.c.class}}{{c.c.rating}}</td>
<td class="le shorten" ng-click="togglePwr(c)" ng-bind="cName(c)"></td>
<td ng-click="togglePwr(c)"><u ng-bind="c.type"></u></td>
<td class="le shorten cap" ng-click="togglePwr(c)" ng-bind="cName(c)"></td>
<td ng-click="togglePwr(c)"><u ng-bind="c.type | translate"></u></td>
<td><span ng-click="decPriority(c)" class="flip">&#9658;</span> {{c.priority + 1}} <span ng-click="incPriority(c)">&#9658;</span></td>
<td class="ri" style="width:3.25em;">{{fPwr(c.c.power)}}</td>
<td class="ri" style="width:3em;"><u>{{f1Pct(c.c.power/ship.powerAvailable)}}</u></td>
<td ng-if="!c.enabled" class="disabled" colspan="2">DISABLED</td>
<td ng-if="c.enabled" ng-class="STATUS_CLASS[statusRetracted(c)]">{{STATUS[statusRetracted(c)]}}</td>
<td ng-if="c.enabled" ng-class="STATUS_CLASS[statusDeployed(c)]">{{STATUS[statusDeployed(c)]}}</td>
<td class="ri" style="width:3.25em;" ng-click="togglePwr(c)">{{fPwr(c.c.power)}}</td>
<td class="ri" style="width:3em;" ng-click="togglePwr(c)"><u>{{f1Pct(c.c.power/ship.powerAvailable)}}</u></td>
<td ng-if="!c.enabled" class="disabled upp" colspan="2" translate="disabled" ng-click="togglePwr(c)"></td>
<td class="upp" ng-if="c.enabled" ng-click="togglePwr(c)">
<svg class="icon secondary-disabled" ng-if="statusRetracted(c) == 3"><use xlink:href="#power"><title class="cap">{{'on' | translate}}</title></use></svg>
<svg class="icon warning" ng-if="statusRetracted(c) == 2"><use xlink:href="#no-power"><title class="cap">{{'off' | translate}}</title></use></svg>
<span class="disabled" translate="disabled" ng-if="statusRetracted(c) == 1"></span>
</td>
<td class="upp" ng-if="c.enabled" ng-click="togglePwr(c)">
<svg class="icon secondary-disabled" ng-if="statusDeployed(c) == 3"><use xlink:href="#power"><title class="cap">{{'on' | translate}}</title></use></svg>
<svg class="icon warning" ng-if="statusDeployed(c) == 2"><use xlink:href="#no-power"><title class="cap">{{'off' | translate}}</title></use></svg>
<span class="disabled" translate="disabled" ng-if="statusDeployed(c) == 1"></span>
</td>
</tr>
</tbody>
</table>
<div style="margin-top: 1em" power-bands bands="priorityBands" available="ship.powerAvailable"></div>
</div>
<div class="group dbl">
<table style="width:100%">
<div class="group half">
<table class="tabs">
<thead>
<tr class="main">
<th colspan="2" class="sortable le" ng-click="sortCost(cName)">Component</th>
<th class="sortable le" ng-click="sortCost('c.cost')">Credits</th>
<tr>
<th style="width:34%" ng-class="{active: costTab == 'ammo'}" ng-click="updateCostTab('ammo')" translate="reload costs"></th>
<th style="width:33%" ng-class="{active: costTab == 'retrofit'}" ng-click="updateCostTab('retrofit')" translate="retrofit costs"></th>
<th style="width:33%" ng-class="{active: costTab == 'costs'}" ng-click="updateCostTab('costs')" translate="costs"></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="c in costList | orderBy:costPredicate:costDesc" ng-if="c.c.cost > 0" ng-class="{disabled:!c.incCost}">
<td class="toggleable" style="width:1em;" ng-click="toggleCost(c)">{{c.c.class}}{{c.c.rating}}</td>
<td class="le toggleable shorten" ng-bind="cName(c)" ng-click="toggleCost(c)"></td>
<td class="ri toggleable" ng-click="toggleCost(c)">{{fCrd(discounts.current.pct * c.c.cost)}} <u>CR</u></td>
</tr>
</tbody>
</table>
<table class="total">
<div ng-if="costTab == 'costs'">
<table style="width:100%">
<thead>
<tr class="main">
<th colspan="2" class="sortable le" ng-click="sortCost(cName)">
{{'component' | translate}}
<u class="optional-hide" ng-if="discounts.ship < 1">[{{'ship' | translate }} -{{fRPct(1 - discounts.ship)}}]</u>
<u class="optional-hide" ng-if="discounts.components < 1">[{{'components' | translate}} -{{fRPct(1 - discounts.components)}}]</u>
</th>
<th class="sortable le" ng-click="sortCost('discountedCost')" translate="credits"></th>
</tr>
</thead>
<tbody>
<tr class="highlight" ng-repeat="item in costList | orderBy:costPredicate:costDesc" ng-if="item.c.cost > 0" ng-class="{disabled:!item.incCost}">
<td class="toggleable" style="width:1em;" ng-click="toggleCost(item)">{{item.c.class}}{{item.c.rating}}</td>
<td class="le toggleable shorten cap" ng-click="toggleCost(item)">{{cName(item)}}</td>
<td class="ri toggleable" ng-click="toggleCost(item)">{{fCrd(item.discountedCost)}} <u translate>CR</u></td>
</tr>
</tbody>
</table>
<table class="total">
<tr class="ri">
<td class="lbl">Total</td>
<td>{{fCrd(ship.totalCost * discounts.current.pct)}} <u>CR</u></td>
<td class="lbl" translate="total"></td>
<td>{{fCrd(ship.totalCost)}} <u translate>CR</u></td>
</tr>
<tr class="ri">
<td class="lbl">Insurance</td>
<td>{{fCrd(ship.totalCost * discounts.current.pct * insurance.current.pct)}} <u>CR</u></td>
<td class="lbl" translate="insurance"></td>
<td>{{fCrd(ship.totalCost * insurance.current.pct)}} <u translate>CR</u></td>
</tr>
</table>
</table>
</div>
<div ng-if="costTab == 'retrofit'">
<div class="scroll-x">
<table style="width:100%">
<thead>
<tr class="main">
<th colspan="2" class="sortable le" ng-click="sortRetrofit('sellName | translate')" translate="sell"></th>
<th colspan="2" class="sortable le" ng-click="sortRetrofit('buyName | translate')" translate="buy"></th>
<th class="sortable le" ng-click="sortRetrofit('netCost')">
{{'net cost' | translate}} <u class="optional-hide" ng-if="discounts.components < 1">[-{{fRPct(1 - discounts.components)}}]</u>
</th>
</tr>
</thead>
<tbody>
<tr ng-if="!retrofitList || retrofitList.length == 0">
<td colspan="5" style="padding: 3em 0;" translate="PHRASE_NO_RETROCH"></td>
</tr>
<tr class="highlight" ng-repeat="item in retrofitList | orderBy:retroPredicate:retroDesc" ng-click="toggleRetrofitCost(item.retroItem)" ng-class="{disabled: !item.retroItem.incCost}">
<td style="width:1em;">{{item.sellClassRating}}</td>
<td class="le shorten cap">{{item.sellName | translate}}</td>
<td style="width:1em;">{{item.buyClassRating}}</td>
<td class="le shorten cap">{{item.buyName | translate}}</td>
<td class="ri" ng-class="item.retroItem.incCost ? item.netCost > 0 ? 'warning' : 'secondary-disabled' : 'disabled'">{{ fCrd(item.netCost)}} <u translate>CR</u></td>
</tr>
</tbody>
</table>
</div>
<table class="total">
<tr class="ri">
<td class="lbl" translate="cost"></td>
<td colspan="2" ng-class="retrofitTotal > 0 ? 'warning' : 'secondary-disabled'">{{fCrd(retrofitTotal)}} <u translate>CR</u></td>
</tr>
<tr class="ri">
<td class="lbl cap" translate="retrofit from"></td>
<td class="cen" style="border-right:none;width: 1em;"><u class="primary-disabled">&#9662;</u></td>
<td style="border-left:none;padding:0;">
<select style="width: 100%;padding: 0" ng-model="$parent.retrofitBuild" ng-change="setRetrofitBase()" ng-options="name as name for (name, build) in allBuilds[ship.id]">
<option value="">{{'Stock' | translate}}</option>
</select>
</td>
</tr>
</table>
</div>
<div ng-if="costTab == 'ammo'">
<div class="scroll-x">
<table style="width:100%">
<thead>
<tr class="main">
<th colspan="2" class="sortable le" ng-click="sortAmmo('ammoName | translate')" translate="component"></th>
<th colspan="1" class="sortable le" ng-click="sortAmmo('ammoMax')" translate="quantity"></th>
<th colspan="1" class="sortable le" ng-click="sortAmmo('ammoUnitCost')" translate="unit cost"></th>
<th class="sortable le" ng-click="sortAmmo('ammoTotalCost')">
{{'total cost' | translate}} <u class="optional-hide" ng-if="discounts.ammo < 1">-[{{fRPct(1 - discounts.ammo)}}]</u>
</th>
</tr>
</thead>
<tbody>
<tr class="highlight" ng-repeat="item in ammoList | orderBy:ammoPredicate:ammoDesc">
<td style="width:1em;">{{item.ammoClassRating}}</td>
<td class="le shorten cap">{{item.ammoName | translate}}</td>
<td class="ri">{{fCrd(item.ammoMax)}}</td>
<td class="ri">{{fCrd(item.ammoUnitCost)}} <u translate>CR</u></td>
<td class="ri">{{fCrd(item.ammoTotalCost)}} <u translate>CR</u></td>
</tr>
</tbody>
</table>
</div>
<table class="total">
<tr class="ri">
<td class="lbl" translate="total"></td>
<td>{{fCrd(ammoTotal)}} <u translate>CR</u></td>
</tr>
</table>
</div>
</div>
<div class="group dbl">
<h1>Jump Range</h1>
<div class="cen">
<div area-chart config="jrChart" series="jrSeries"></div>
<div slider max="ship.fuelCapacity" unit="'T'" on-change="::fuelChange(val)" style="position:relative; margin: 0 auto;">
<div class="group third">
<h1 translate="jump range"></h1>
<div line-chart config="jrChart" series="jrSeries"></div>
</div>
<div class="group third">
<h1 translate="total range"></h1>
<div line-chart config="trChart" series="trSeries"></div>
</div>
<div class="group third">
<h1 translate="speed"></h1>
<div line-chart config="speedChart" series="speedSeries"></div>
</div>
<div class="group half">
<div slider max="ship.fuelCapacity" unit="'T'" on-change="::fuelChange(val)" style="position:relative; margin: 0 auto;">
<svg class="icon xl primary-disabled" style="position:absolute;height: 100%;"><use xlink:href="#fuel"></use></svg>
</div>
</div>
</div>

View File

@@ -1,9 +1,89 @@
<div id="shipyard">
<a ui-sref="outfit({shipId:id})" class="ship" ng-repeat="(id,s) in ships">
<h2 ng-bind="s.properties.name"></h2>
<div class="subtitle">
<small ng-bind="s.properties.manufacturer"></small>
</div>
{{fCrd(s.retailCost)}} <u>CR</u>
</a>
<div class="scroll-x">
<table align="center" style="font-size:0.85em;white-space:nowrap">
<thead>
<tr class="main">
<th rowspan="2" class="sortable le" ng-click="sortShips('name')" translate="ship"></th>
<th rowspan="2" class="sortable" ng-click="sortShips('manufacturer')" translate="manufacturer"></th>
<th rowspan="2" class="sortable" ng-click="sortShips('class')" translate="size"></th>
<th rowspan="2" class="sortable" ng-click="sortShips('agility')" translate="agility"></th>
<th colspan="4" translate="base"></th>
<th colspan="4" translate="max"></th>
<th colspan="5" class="sortable" ng-click="sortShips('hpCount')" translate="hardpoints"></th>
<th colspan="8" class="sortable" ng-click="sortShips('intCount')" translate="internal compartments"></th>
<th rowspan="2" class="sortable" ng-click="sortShips('hullMass')" translate="hull"></th>
<th rowspan="2" class="sortable" ng-click="sortShips('masslock')" translate="MLF"></th>
<th rowspan="2" class="sortable" ng-click="sortShips('retailCost')" translate="cost"></th>
</tr>
<tr>
<!-- Base -->
<th class="sortable lft" ng-click="sortShips('speed')" translate="speed"></th>
<th class="sortable" ng-click="sortShips('boost')" translate="boost"></th>
<th class="sortable" ng-click="sortShips('baseArmour')" translate="armour"></th>
<th class="sortable" ng-click="sortShips('baseShieldStrength')" translate="shields"></th>
<!-- Max -->
<th class="sortable lft" ng-click="sortShips('topSpeed')" translate="speed"></th>
<th class="sortable " ng-click="sortShips('topBoost')" translate="boost"></th>
<th class="sortable " ng-click="sortShips('maxJumpRange')" translate="jump"></th>
<th class="sortable" ng-click="sortShips('maxCargo')" translate="cargo"></th>
<!-- Hardpoints -->
<th class="sortable lft" ng-click="sortShips('hp[1]')" translate="S"></th>
<th class="sortable" ng-click="sortShips('hp[2]')" translate="M"></th>
<th class="sortable" ng-click="sortShips('hp[3]')" translate="L"></th>
<th class="sortable" ng-click="sortShips('hp[4]')" translate="H"></th>
<th class="sortable" ng-click="sortShips('hp[0]')" translate="U"></th>
<!-- Internal -->
<th class="sortable lft" ng-click="sortShips('int[0]')" translate="1"></th>
<th class="sortable" ng-click="sortShips('int[1]')" translate="2"></th>
<th class="sortable" ng-click="sortShips('int[2]')" translate="3"></th>
<th class="sortable" ng-click="sortShips('int[3]')" translate="4"></th>
<th class="sortable" ng-click="sortShips('int[4]')" translate="5"></th>
<th class="sortable" ng-click="sortShips('int[5]')" translate="6"></th>
<th class="sortable" ng-click="sortShips('int[6]')" translate="7"></th>
<th class="sortable" ng-click="sortShips('int[7]')" translate="8"></th>
</tr>
</thead>
<tbody>
<tr class="highlight" ng-repeat="s in shipsOverview | orderBy:shipPredicate:shipDesc">
<td class="le"><a ui-sref="outfit({shipId: s.id})" ng-bind="s.name"></a></td>
<td class="le" ng-bind="s.manufacturer"></td>
<!-- Pad Size -->
<td class="cap" ng-bind="SZM[s.class] | translate"></td>
<td class="ri" ng-bind="s.agility"></td>
<!-- Base -->
<td class="ri">{{fCrd(s.speed)}} <u translate>m/s</u></td>
<td class="ri">{{fCrd(s.boost)}} <u translate>m/s</u></td>
<td class="ri" ng-bind="s.baseArmour"></td>
<td class="ri">{{fCrd(s.baseShieldStrength)}} <u translate>Mj</u></td>
<!-- Max -->
<td class="ri">{{fCrd(s.topSpeed)}} <u translate>m/s</u></td>
<td class="ri">{{fCrd(s.topBoost)}} <u translate>m/s</u></td>
<td class="ri">{{fRound(s.maxJumpRange)}} <u translate>LY</u></td>
<td class="ri">{{fCrd(s.maxCargo)}} <u translate>T</u></td>
<!-- Hardpoints -->
<td ng-bind="s.hp[1]" ng-class="{disabled: !s.hp[1]}"></td>
<td ng-bind="s.hp[2]" ng-class="{disabled: !s.hp[2]}"></td>
<td ng-bind="s.hp[3]" ng-class="{disabled: !s.hp[3]}"></td>
<td ng-bind="s.hp[4]" ng-class="{disabled: !s.hp[4]}"></td>
<td ng-bind="s.hp[0]" ng-class="{disabled: !s.hp[0]}"></td>
<!-- Internal -->
<td ng-bind="s.int[0]" ng-class="{disabled: !s.int[0]}"></td>
<td ng-bind="s.int[1]" ng-class="{disabled: !s.int[1]}"></td>
<td ng-bind="s.int[2]" ng-class="{disabled: !s.int[2]}"></td>
<td ng-bind="s.int[3]" ng-class="{disabled: !s.int[3]}"></td>
<td ng-bind="s.int[4]" ng-class="{disabled: !s.int[4]}"></td>
<td ng-bind="s.int[5]" ng-class="{disabled: !s.int[5]}"></td>
<td ng-bind="s.int[6]" ng-class="{disabled: !s.int[6]}"></td>
<td ng-bind="s.int[7]" ng-class="{disabled: !s.int[7]}"></td>
<!-- Other Stats -->
<td class="ri">{{fCrd(s.hullMass)}} <u translate>T</u></td>
<td class="ri" ng-bind="s.masslock"></td>
<td class="ri">{{fCrd(s.retailCost)}} <u translate>CR</u></td>
</tr>
</tbody>
</table>
</div>
</div>

View File

@@ -21,12 +21,13 @@
"dependencies": {
"d3": "~3.5.5",
"ng-lodash": "~0.2.0",
"ui-router-extras": "~0.0.13",
"ui-router-extras": "0.0.13",
"angular-ui-router": "^0.2.15",
"d3-tip": "~0.6.7",
"ng-sortable": "~1.2.1",
"lz-string": "~1.4.3",
"angular": "~1.4.0"
"lz-string": "~1.4.4",
"angular": "~1.4.0",
"angular-translate": "~2.7.2"
},
"overrides": {
"angular": {
@@ -35,6 +36,9 @@
"angular-ui-router": {
"main": "release/angular-ui-router.min.js"
},
"angular-translate": {
"main": "angular-translate.min.js"
},
"d3": {
"main": "d3.min.js"
},

1
data Submodule

Submodule data added at bb316e77b2

View File

@@ -1,742 +0,0 @@
{
"sidewinder": [
{
"name": "Lightweight Alloy",
"class": 1,
"rating": "I",
"cost": 0,
"mass": 0
},
{
"name": "Reinforced Alloy",
"class": 1,
"rating": "I",
"cost": 25600,
"mass": 2
},
{
"name": "Military Grade Composite",
"class": 1,
"rating": "I",
"cost": 80320,
"mass": 4
},
{
"name": "Mirrored Surface Composite",
"class": 1,
"rating": "I",
"cost": 132064,
"mass": 4
},
{
"name": "Reactive Surface Composite",
"class": 1,
"rating": "I",
"cost": 139424,
"mass": 4
}
],
"diamondback": [
{
"name": "Lightweight Alloy",
"class": 1,
"rating": "I",
"cost": 0,
"mass": 0
},
{
"name": "Reinforced Alloy",
"class": 1,
"rating": "I",
"cost": 225700,
"mass": 13
},
{
"name": "Military Grade Composite",
"class": 1,
"rating": "I",
"cost": 507900,
"mass": 26
},
{
"name": "Mirrored Surface Composite",
"class": 1,
"rating": "I",
"cost": 1185100,
"mass": 26
},
{
"name": "Reactive Surface Composite",
"class": 1,
"rating": "I",
"cost": 1330100,
"mass": 26
}
],
"diamondback_explorer": [
{
"name": "Lightweight Alloy",
"class": 1,
"rating": "I",
"cost": 0,
"mass": 0
},
{
"name": "Reinforced Alloy",
"class": 1,
"rating": "I",
"cost": 800000,
"mass": 23
},
{
"name": "Military Grade Composite",
"class": 1,
"rating": "I",
"cost": 1800000,
"mass": 47
},
{
"name": "Mirrored Surface Composite",
"class": 1,
"rating": "I",
"cost": 4200000,
"mass": 26
},
{
"name": "Reactive Surface Composite",
"class": 1,
"rating": "I",
"cost": 4714000,
"mass": 47
}
],
"imperial_courier": [
{
"name": "Lightweight Alloy",
"class": 1,
"rating": "I",
"cost": 0,
"mass": 0
},
{
"name": "Reinforced Alloy",
"class": 1,
"rating": "I",
"cost": 1017200,
"mass": 21
},
{
"name": "Military Grade Composite",
"class": 1,
"rating": "I",
"cost": 2288600,
"mass": 42
},
{
"name": "Mirrored Surface Composite",
"class": 1,
"rating": "I",
"cost": 5408800,
"mass": 42
},
{
"name": "Reactive Surface Composite",
"class": 1,
"rating": "I",
"cost": 5993700,
"mass": 42
}
],
"cobra_mk_iii": [
{
"name": "Lightweight Alloy",
"class": 1,
"rating": "I",
"cost": 0,
"mass": 0
},
{
"name": "Reinforced Alloy",
"class": 1,
"rating": "I",
"cost": 151887,
"mass": 14
},
{
"name": "Military Grade Composite",
"class": 1,
"rating": "I",
"cost": 341746,
"mass": 27
},
{
"name": "Mirrored Surface Composite",
"class": 1,
"rating": "I",
"cost": 797407,
"mass": 27
},
{
"name": "Reactive Surface Composite",
"class": 1,
"rating": "I",
"cost": 894995,
"mass": 27
}
],
"imperial_clipper": [
{
"name": "Lightweight Alloy",
"class": 1,
"rating": "I",
"cost": 0,
"mass": 0
},
{
"name": "Reinforced Alloy",
"class": 1,
"rating": "I",
"cost": 8918344,
"mass": 30
},
{
"name": "Military Grade Composite",
"class": 1,
"rating": "I",
"cost": 20066274,
"mass": 60
},
{
"name": "Mirrored Surface Composite",
"class": 1,
"rating": "I",
"cost": 47423294,
"mass": 60
},
{
"name": "Reactive Surface Composite",
"class": 1,
"rating": "I",
"cost": 52551342,
"mass": 60
}
],
"federal_dropship": [
{
"name": "Lightweight Alloy",
"class": 1,
"rating": "I",
"cost": 0,
"mass": 0
},
{
"name": "Reinforced Alloy",
"class": 1,
"rating": "I",
"cost": 7925682,
"mass": 44
},
{
"name": "Military Grade Composite",
"class": 1,
"rating": "I",
"cost": 17832784,
"mass": 87
},
{
"name": "Mirrored Surface Composite",
"class": 1,
"rating": "I",
"cost": 42144814,
"mass": 87
},
{
"name": "Reactive Surface Composite",
"class": 1,
"rating": "I",
"cost": 46702081,
"mass": 87
}
],
"python": [
{
"name": "Lightweight Alloy",
"class": 1,
"rating": "I",
"cost": 0,
"mass": 0
},
{
"name": "Reinforced Alloy",
"class": 1,
"rating": "I",
"cost": 22791271,
"mass": 26
},
{
"name": "Military Grade Composite",
"class": 1,
"rating": "I",
"cost": 51280361,
"mass": 53
},
{
"name": "Mirrored Surface Composite",
"class": 1,
"rating": "I",
"cost": 121192586,
"mass": 53
},
{
"name": "Reactive Surface Composite",
"class": 1,
"rating": "I",
"cost": 134297567,
"mass": 53
}
],
"anaconda": [
{
"name": "Lightweight Alloy",
"class": 1,
"rating": "I",
"cost": 0,
"mass": 0
},
{
"name": "Reinforced Alloy",
"class": 1,
"rating": "I",
"cost": 58787780,
"mass": 30
},
{
"name": "Military Grade Composite",
"class": 1,
"rating": "I",
"cost": 132272505,
"mass": 60
},
{
"name": "Mirrored Surface Composite",
"class": 1,
"rating": "I",
"cost": 312604021,
"mass": 60
},
{
"name": "Reactive Surface Composite",
"class": 1,
"rating": "I",
"cost": 346406995,
"mass": 60
}
],
"eagle": [
{
"name": "Lightweight Alloy",
"class": 1,
"rating": "I",
"cost": 0,
"mass": 0
},
{
"name": "Reinforced Alloy",
"class": 1,
"rating": "I",
"cost": 26880,
"mass": 4
},
{
"name": "Military Grade Composite",
"class": 1,
"rating": "I",
"cost": 90048,
"mass": 8
},
{
"name": "Mirrored Surface Composite",
"class": 1,
"rating": "I",
"cost": 140089,
"mass": 8
},
{
"name": "Reactive Surface Composite",
"class": 1,
"rating": "I",
"cost": 150393,
"mass": 8
}
],
"viper": [
{
"name": "Lightweight Alloy",
"class": 1,
"rating": "I",
"cost": 0,
"mass": 0
},
{
"name": "Reinforced Alloy",
"class": 1,
"rating": "I",
"cost": 57172,
"mass": 5
},
{
"name": "Military Grade Composite",
"class": 1,
"rating": "I",
"cost": 128637,
"mass": 9
},
{
"name": "Mirrored Surface Composite",
"class": 1,
"rating": "I",
"cost": 304014,
"mass": 9
},
{
"name": "Reactive Surface Composite",
"class": 1,
"rating": "I",
"cost": 336888,
"mass": 9
}
],
"vulture": [
{
"name": "Lightweight Alloy",
"class": 1,
"rating": "I",
"cost": 0,
"mass": 0
},
{
"name": "Reinforced Alloy",
"class": 1,
"rating": "I",
"cost": 1970246,
"mass": 17
},
{
"name": "Military Grade Composite",
"class": 1,
"rating": "I",
"cost": 4433054,
"mass": 35
},
{
"name": "Mirrored Surface Composite",
"class": 1,
"rating": "I",
"cost": 10476783,
"mass": 35
},
{
"name": "Reactive Surface Composite",
"class": 1,
"rating": "I",
"cost": 11609675,
"mass": 35
}
],
"fer_de_lance": [
{
"name": "Lightweight Alloy",
"class": 1,
"rating": "I",
"cost": 0,
"mass": 0
},
{
"name": "Reinforced Alloy",
"class": 1,
"rating": "I",
"cost": 20626816,
"mass": 19
},
{
"name": "Military Grade Composite",
"class": 1,
"rating": "I",
"cost": 46410336,
"mass": 38
},
{
"name": "Mirrored Surface Composite",
"class": 1,
"rating": "I",
"cost": 109683094,
"mass": 38
},
{
"name": "Reactive Surface Composite",
"class": 1,
"rating": "I",
"cost": 121543513,
"mass": 38
}
],
"hauler": [
{
"name": "Lightweight Alloy",
"class": 1,
"rating": "I",
"cost": 0,
"mass": 0
},
{
"name": "Reinforced Alloy",
"class": 1,
"rating": "I",
"cost": 42176,
"mass": 1
},
{
"name": "Military Grade Composite",
"class": 1,
"rating": "I",
"cost": 185047,
"mass": 2
},
{
"name": "Mirrored Surface Composite",
"class": 1,
"rating": "I",
"cost": 270295,
"mass": 2
},
{
"name": "Reactive Surface Composite",
"class": 1,
"rating": "I",
"cost": 282421,
"mass": 2
}
],
"type_6_transporter": [
{
"name": "Lightweight Alloy",
"class": 1,
"rating": "I",
"cost": 0,
"mass": 0
},
{
"name": "Reinforced Alloy",
"class": 1,
"rating": "I",
"cost": 418378,
"mass": 12
},
{
"name": "Military Grade Composite",
"class": 1,
"rating": "I",
"cost": 941350,
"mass": 23
},
{
"name": "Mirrored Surface Composite",
"class": 1,
"rating": "I",
"cost": 2224725,
"mass": 23
},
{
"name": "Reactive Surface Composite",
"class": 1,
"rating": "I",
"cost": 2465292,
"mass": 23
}
],
"type_7_transport": [
{
"name": "Lightweight Alloy",
"class": 1,
"rating": "I",
"cost": 0,
"mass": 0
},
{
"name": "Reinforced Alloy",
"class": 1,
"rating": "I",
"cost": 6988901,
"mass": 32
},
{
"name": "Military Grade Composite",
"class": 1,
"rating": "I",
"cost": 15725027,
"mass": 63
},
{
"name": "Mirrored Surface Composite",
"class": 1,
"rating": "I",
"cost": 37163481,
"mass": 63
},
{
"name": "Reactive Surface Composite",
"class": 1,
"rating": "I",
"cost": 41182099,
"mass": 63
}
],
"type_9_heavy": [
{
"name": "Lightweight Alloy",
"class": 1,
"rating": "I",
"cost": 0,
"mass": 0
},
{
"name": "Reinforced Alloy",
"class": 1,
"rating": "I",
"cost": 30622336,
"mass": 75
},
{
"name": "Military Grade Composite",
"class": 1,
"rating": "I",
"cost": 68900257,
"mass": 150
},
{
"name": "Mirrored Surface Composite",
"class": 1,
"rating": "I",
"cost": 162834275,
"mass": 150
},
{
"name": "Reactive Surface Composite",
"class": 1,
"rating": "I",
"cost": 180442119,
"mass": 150
}
],
"adder": [
{
"name": "Lightweight Alloy",
"class": 1,
"rating": "I",
"cost": 0,
"mass": 0
},
{
"name": "Reinforced Alloy",
"class": 1,
"rating": "I",
"cost": 35123,
"mass": 3
},
{
"name": "Military Grade Composite",
"class": 1,
"rating": "I",
"cost": 79027,
"mass": 5
},
{
"name": "Mirrored Surface Composite",
"class": 1,
"rating": "I",
"cost": 186767,
"mass": 5
},
{
"name": "Reactive Surface Composite",
"class": 1,
"rating": "I",
"cost": 206963,
"mass": 5
}
],
"asp": [
{
"name": "Lightweight Alloy",
"class": 1,
"rating": "I",
"cost": 0,
"mass": 0
},
{
"name": "Reinforced Alloy",
"class": 1,
"rating": "I",
"cost": 2664461,
"mass": 21
},
{
"name": "Military Grade Composite",
"class": 1,
"rating": "I",
"cost": 5995038,
"mass": 42
},
{
"name": "Mirrored Surface Composite",
"class": 1,
"rating": "I",
"cost": 14168273,
"mass": 42
},
{
"name": "Reactive Surface Composite",
"class": 1,
"rating": "I",
"cost": 15700338,
"mass": 42
}
],
"orca": [
{
"name": "Lightweight Alloy",
"class": 1,
"rating": "I",
"cost": 0,
"mass": 0
},
{
"name": "Reinforced Alloy",
"class": 1,
"rating": "I",
"cost": 19415954,
"mass": 21
},
{
"name": "Military Grade Composite",
"class": 1,
"rating": "I",
"cost": 43685898,
"mass": 87
},
{
"name": "Mirrored Surface Composite",
"class": 1,
"rating": "I",
"cost": 103244339,
"mass": 87
},
{
"name": "Reactive Surface Composite",
"class": 1,
"rating": "I",
"cost": 114408513,
"mass": 87
}
]
}

View File

@@ -1,302 +0,0 @@
{
"6E": {
"grp": "fsd",
"class": 6,
"rating": "E",
"cost": 199747,
"mass": 40,
"power": 0.4,
"optmass": 960,
"maxfuel": 5.3,
"fuelmul": 0.011,
"fuelpower": 2.6
},
"6D": {
"grp": "fsd",
"class": 6,
"rating": "D",
"cost": 599242,
"mass": 16,
"power": 0.45,
"optmass": 1080,
"maxfuel": 5.3,
"fuelmul": 0.01,
"fuelpower": 2.6
},
"6C": {
"grp": "fsd",
"class": 6,
"rating": "C",
"cost": 1797726,
"mass": 40,
"power": 0.5,
"optmass": 1200,
"maxfuel": 5.3,
"fuelmul": 0.008,
"fuelpower": 2.6
},
"6B": {
"grp": "fsd",
"class": 6,
"rating": "B",
"cost": 5393177,
"mass": 64,
"power": 0.63,
"optmass": 1500,
"maxfuel": 6.6,
"fuelmul": 0.01,
"fuelpower": 2.6
},
"6A": {
"grp": "fsd",
"class": 6,
"rating": "A",
"cost": 16179531,
"mass": 40,
"power": 0.75,
"optmass": 1800,
"maxfuel": 8,
"fuelmul": 0.012,
"fuelpower": 2.6
},
"5E": {
"grp": "fsd",
"class": 5,
"rating": "E",
"cost": 63013,
"mass": 20,
"power": 0.32,
"optmass": 560,
"maxfuel": 3.3,
"fuelmul": 0.011,
"fuelpower": 2.45
},
"5D": {
"grp": "fsd",
"class": 5,
"rating": "D",
"cost": 189036,
"mass": 8,
"power": 0.36,
"optmass": 630,
"maxfuel": 3.3,
"fuelmul": 0.01,
"fuelpower": 2.45
},
"5C": {
"grp": "fsd",
"class": 5,
"rating": "C",
"cost": 567106,
"mass": 20,
"power": 0.4,
"optmass": 700,
"maxfuel": 3.3,
"fuelmul": 0.008,
"fuelpower": 2.45
},
"5B": {
"grp": "fsd",
"class": 5,
"rating": "B",
"cost": 1701318,
"mass": 32,
"power": 0.5,
"optmass": 875,
"maxfuel": 4.1,
"fuelmul": 0.01,
"fuelpower": 2.45
},
"5A": {
"grp": "fsd",
"class": 5,
"rating": "A",
"cost": 5103953,
"mass": 20,
"power": 0.6,
"optmass": 1050,
"maxfuel": 5,
"fuelmul": 0.012,
"fuelpower": 2.45
},
"4E": {
"grp": "fsd",
"class": 4,
"rating": "E",
"cost": 19878,
"mass": 10,
"power": 0.24,
"optmass": 280,
"maxfuel": 2,
"fuelmul": 0.011,
"fuelpower": 2.3
},
"4D": {
"grp": "fsd",
"class": 4,
"rating": "D",
"cost": 59633,
"mass": 4,
"power": 0.27,
"optmass": 315,
"maxfuel": 2,
"fuelmul": 0.01,
"fuelpower": 2.3
},
"4C": {
"grp": "fsd",
"class": 4,
"rating": "C",
"cost": 178898,
"mass": 10,
"power": 0.3,
"optmass": 350,
"maxfuel": 2,
"fuelmul": 0.008,
"fuelpower": 2.3
},
"4B": {
"grp": "fsd",
"class": 4,
"rating": "B",
"cost": 536693,
"mass": 16,
"power": 0.38,
"optmass": 438,
"maxfuel": 2.5,
"fuelmul": 0.01,
"fuelpower": 2.3
},
"4A": {
"grp": "fsd",
"class": 4,
"rating": "A",
"cost": 1610080,
"mass": 10,
"power": 0.45,
"optmass": 525,
"maxfuel": 3,
"fuelmul": 0.012,
"fuelpower": 2.3
},
"3E": {
"grp": "fsd",
"class": 3,
"rating": "E",
"cost": 6271,
"mass": 5,
"power": 0.24,
"optmass": 80,
"maxfuel": 1.2,
"fuelmul": 0.011,
"fuelpower": 2.15
},
"3D": {
"grp": "fsd",
"class": 3,
"rating": "D",
"cost": 18812,
"mass": 2,
"power": 0.27,
"optmass": 90,
"maxfuel": 1.2,
"fuelmul": 0.01,
"fuelpower": 2.15
},
"3C": {
"grp": "fsd",
"class": 3,
"rating": "C",
"cost": 56435,
"mass": 5,
"power": 0.3,
"optmass": 100,
"maxfuel": 1.2,
"fuelmul": 0.008,
"fuelpower": 2.15
},
"3B": {
"grp": "fsd",
"class": 3,
"rating": "B",
"cost": 169304,
"mass": 8,
"power": 0.38,
"optmass": 125,
"maxfuel": 1.5,
"fuelmul": 0.01,
"fuelpower": 2.15
},
"3A": {
"grp": "fsd",
"class": 3,
"rating": "A",
"cost": 507912,
"mass": 5,
"power": 0.45,
"optmass": 150,
"maxfuel": 1.8,
"fuelmul": 0.012,
"fuelpower": 2.15
},
"2E": {
"grp": "fsd",
"class": 2,
"rating": "E",
"cost": 1978,
"mass": 2.5,
"power": 0.16,
"optmass": 48,
"maxfuel": 0.6,
"fuelmul": 0.011,
"fuelpower": 2
},
"2D": {
"grp": "fsd",
"class": 2,
"rating": "D",
"cost": 5934,
"mass": 1,
"power": 0.18,
"optmass": 54,
"maxfuel": 0.6,
"fuelmul": 0.01,
"fuelpower": 2
},
"2C": {
"grp": "fsd",
"class": 2,
"rating": "C",
"cost": 17803,
"mass": 2.5,
"power": 0.2,
"optmass": 60,
"maxfuel": 0.6,
"fuelmul": 0.008,
"fuelpower": 2
},
"2B": {
"grp": "fsd",
"class": 2,
"rating": "B",
"cost": 53408,
"mass": 4,
"power": 0.25,
"optmass": 75,
"maxfuel": 0.8,
"fuelmul": 0.01,
"fuelpower": 2
},
"2A": {
"grp": "fsd",
"class": 2,
"rating": "A",
"cost": 160224,
"mass": 2.5,
"power": 0.3,
"optmass": 90,
"maxfuel": 0.9,
"fuelmul": 0.012,
"fuelpower": 2
}
}

View File

@@ -1,44 +0,0 @@
{
"1C": {
"grp": "ft",
"class": 1,
"rating": "C",
"cost": 1000,
"capacity": 2
},
"2C": {
"grp": "ft",
"class": 2,
"rating": "C",
"cost": 3750,
"capacity": 4
},
"3C": {
"grp": "ft",
"class": 3,
"rating": "C",
"cost": 7063,
"capacity": 8
},
"4C": {
"grp": "ft",
"class": 4,
"rating": "C",
"cost": 24734,
"capacity": 16
},
"5C": {
"grp": "ft",
"class": 5,
"rating": "C",
"cost": 97754,
"capacity": 32
},
"6C": {
"grp": "ft",
"class": 6,
"rating": "C",
"cost": 341577,
"capacity": 64
}
}

View File

@@ -1,272 +0,0 @@
{
"6E": {
"grp": "ls",
"class": 6,
"rating": "E",
"cost": 88978,
"mass": 40,
"power": 0.64,
"time": 300
},
"6D": {
"grp": "ls",
"class": 6,
"rating": "D",
"cost": 222444,
"mass": 16,
"power": 0.72,
"time": 450
},
"6C": {
"grp": "ls",
"class": 6,
"rating": "C",
"cost": 556110,
"mass": 40,
"power": 0.8,
"time": 600
},
"6B": {
"grp": "ls",
"class": 6,
"rating": "B",
"cost": 1390275,
"mass": 64,
"power": 0.88,
"time": 900
},
"6A": {
"grp": "ls",
"class": 6,
"rating": "A",
"cost": 3475688,
"mass": 40,
"power": 0.96,
"time": 1500
},
"5E": {
"grp": "ls",
"class": 5,
"rating": "E",
"cost": 31778,
"mass": 20,
"power": 0.57,
"time": 300
},
"5D": {
"grp": "ls",
"class": 5,
"rating": "D",
"cost": 79444,
"mass": 8,
"power": 0.64,
"time": 450
},
"5C": {
"grp": "ls",
"class": 5,
"rating": "C",
"cost": 198611,
"mass": 20,
"power": 0.71,
"time": 600
},
"5B": {
"grp": "ls",
"class": 5,
"rating": "B",
"cost": 496527,
"mass": 32,
"power": 0.78,
"time": 900
},
"5A": {
"grp": "ls",
"class": 5,
"rating": "A",
"cost": 1241317,
"mass": 20,
"power": 0.85,
"time": 1500
},
"4E": {
"grp": "ls",
"class": 4,
"rating": "E",
"cost": 11349,
"mass": 10,
"power": 0.5,
"time": 300
},
"4D": {
"grp": "ls",
"class": 4,
"rating": "D",
"cost": 28373,
"mass": 4,
"power": 0.56,
"time": 450
},
"4C": {
"grp": "ls",
"class": 4,
"rating": "C",
"cost": 70932,
"mass": 10,
"power": 0.62,
"time": 600
},
"4B": {
"grp": "ls",
"class": 4,
"rating": "B",
"cost": 177331,
"mass": 16,
"power": 0.68,
"time": 900
},
"4A": {
"grp": "ls",
"class": 4,
"rating": "A",
"cost": 443328,
"mass": 10,
"power": 0.74,
"time": 1500
},
"3E": {
"grp": "ls",
"class": 3,
"rating": "E",
"cost": 4053,
"mass": 5,
"power": 0.42,
"time": 300
},
"3D": {
"grp": "ls",
"class": 3,
"rating": "D",
"cost": 10133,
"mass": 2,
"power": 0.48,
"time": 450
},
"3C": {
"grp": "ls",
"class": 3,
"rating": "C",
"cost": 25333,
"mass": 5,
"power": 0.53,
"time": 600
},
"3B": {
"grp": "ls",
"class": 3,
"rating": "B",
"cost": 63333,
"mass": 8,
"power": 0.58,
"time": 900
},
"3A": {
"grp": "ls",
"class": 3,
"rating": "A",
"cost": 158331,
"mass": 5,
"power": 0.64,
"time": 1500
},
"2E": {
"grp": "ls",
"class": 2,
"rating": "E",
"cost": 1448,
"mass": 2.5,
"power": 0.37,
"time": 300
},
"2D": {
"grp": "ls",
"class": 2,
"rating": "D",
"cost": 3619,
"mass": 1,
"power": 0.41,
"time": 450
},
"2C": {
"grp": "ls",
"class": 2,
"rating": "C",
"cost": 9048,
"mass": 2.5,
"power": 0.46,
"time": 600
},
"2B": {
"grp": "ls",
"class": 2,
"rating": "B",
"cost": 22619,
"mass": 4,
"power": 0.51,
"time": 900
},
"2A": {
"grp": "ls",
"class": 2,
"rating": "A",
"cost": 56547,
"mass": 2.5,
"power": 0.55,
"time": 1500
},
"1E": {
"grp": "ls",
"class": 1,
"rating": "E",
"cost": 517,
"mass": 1.3,
"power": 0.32,
"time": 300
},
"1D": {
"grp": "ls",
"class": 1,
"rating": "D",
"cost": 1293,
"mass": 0.5,
"power": 0.36,
"time": 450
},
"1C": {
"grp": "ls",
"class": 1,
"rating": "C",
"cost": 3231,
"mass": 1.3,
"power": 0.4,
"time": 600
},
"1B": {
"grp": "ls",
"class": 1,
"rating": "B",
"cost": 8078,
"mass": 2,
"power": 0.44,
"time": 900
},
"1A": {
"grp": "ls",
"class": 1,
"rating": "A",
"cost": 20195,
"mass": 1.3,
"power": 0.48,
"time": 1500
}
}

View File

@@ -1,562 +0,0 @@
{
"8E": {
"grp": "pd",
"class": 8,
"rating": "E",
"cost": 697584,
"mass": 160,
"power": 0.64,
"weaponcapacity": 48,
"weaponrecharge": 4.8,
"enginecapacity": 32,
"enginerecharge": 3.2,
"systemcapacity": 32,
"systemrecharge": 3.2
},
"8D": {
"grp": "pd",
"class": 8,
"rating": "D",
"cost": 1743961,
"mass": 64,
"power": 0.72,
"weaponcapacity": 54,
"weaponrecharge": 5.4,
"enginecapacity": 36,
"enginerecharge": 3.6,
"systemcapacity": 36,
"systemrecharge": 3.6
},
"8C": {
"grp": "pd",
"class": 8,
"rating": "C",
"cost": 4359903,
"mass": 160,
"power": 0.8,
"weaponcapacity": 60,
"weaponrecharge": 6,
"enginecapacity": 40,
"enginerecharge": 4,
"systemcapacity": 40,
"systemrecharge": 4
},
"8B": {
"grp": "pd",
"class": 8,
"rating": "B",
"cost": 10899756,
"mass": 256,
"power": 0.88,
"weaponcapacity": 66,
"weaponrecharge": 6.6,
"enginecapacity": 44,
"enginerecharge": 4.4,
"systemcapacity": 44,
"systemrecharge": 4.4
},
"8A": {
"grp": "pd",
"class": 8,
"rating": "A",
"cost": 27249391,
"mass": 160,
"power": 0.96,
"weaponcapacity": 72,
"weaponrecharge": 7.2,
"enginecapacity": 48,
"enginerecharge": 4.8,
"systemcapacity": 48,
"systemrecharge": 4.8
},
"7E": {
"grp": "pd",
"class": 7,
"rating": "E",
"cost": 249137,
"mass": 80,
"power": 0.59,
"weaponcapacity": 41,
"weaponrecharge": 4.1,
"enginecapacity": 27,
"enginerecharge": 2.6,
"systemcapacity": 27,
"systemrecharge": 2.6
},
"7D": {
"grp": "pd",
"class": 7,
"rating": "D",
"cost": 622843,
"mass": 32,
"power": 0.67,
"weaponcapacity": 46,
"weaponrecharge": 4.6,
"enginecapacity": 31,
"enginerecharge": 3,
"systemcapacity": 31,
"systemrecharge": 3
},
"7C": {
"grp": "pd",
"class": 7,
"rating": "C",
"cost": 1557108,
"mass": 80,
"power": 0.74,
"weaponcapacity": 51,
"weaponrecharge": 5.1,
"enginecapacity": 34,
"enginerecharge": 3.3,
"systemcapacity": 34,
"systemrecharge": 3.3
},
"7B": {
"grp": "pd",
"class": 7,
"rating": "B",
"cost": 3892770,
"mass": 128,
"power": 0.81,
"weaponcapacity": 56,
"weaponrecharge": 5.6,
"enginecapacity": 37,
"enginerecharge": 3.6,
"systemcapacity": 37,
"systemrecharge": 3.6
},
"7A": {
"grp": "pd",
"class": 7,
"rating": "A",
"cost": 9731925,
"mass": 80,
"power": 0.89,
"weaponcapacity": 61,
"weaponrecharge": 6.1,
"enginecapacity": 41,
"enginerecharge": 4,
"systemcapacity": 41,
"systemrecharge": 4
},
"6E": {
"grp": "pd",
"class": 6,
"rating": "E",
"cost": 88978,
"mass": 40,
"power": 0.54,
"weaponcapacity": 34,
"weaponrecharge": 3.4,
"enginecapacity": 23,
"enginerecharge": 2.2,
"systemcapacity": 23,
"systemrecharge": 2.2
},
"6D": {
"grp": "pd",
"class": 6,
"rating": "D",
"cost": 222444,
"mass": 16,
"power": 0.61,
"weaponcapacity": 38,
"weaponrecharge": 3.9,
"enginecapacity": 26,
"enginerecharge": 2.4,
"systemcapacity": 26,
"systemrecharge": 2.4
},
"6C": {
"grp": "pd",
"class": 6,
"rating": "C",
"cost": 556110,
"mass": 40,
"power": 0.68,
"weaponcapacity": 42,
"weaponrecharge": 4.3,
"enginecapacity": 29,
"enginerecharge": 2.7,
"systemcapacity": 29,
"systemrecharge": 2.7
},
"6B": {
"grp": "pd",
"class": 6,
"rating": "B",
"cost": 1390275,
"mass": 64,
"power": 0.75,
"weaponcapacity": 46,
"weaponrecharge": 4.7,
"enginecapacity": 32,
"enginerecharge": 3,
"systemcapacity": 32,
"systemrecharge": 3
},
"6A": {
"grp": "pd",
"class": 6,
"rating": "A",
"cost": 3475688,
"mass": 40,
"power": 0.82,
"weaponcapacity": 50,
"weaponrecharge": 5.2,
"enginecapacity": 35,
"enginerecharge": 3.2,
"systemcapacity": 35,
"systemrecharge": 3.2
},
"5E": {
"grp": "pd",
"class": 5,
"rating": "E",
"cost": 31778,
"mass": 20,
"power": 0.5,
"weaponcapacity": 27,
"weaponrecharge": 2.9,
"enginecapacity": 19,
"enginerecharge": 1.7,
"systemcapacity": 19,
"systemrecharge": 1.7
},
"5D": {
"grp": "pd",
"class": 5,
"rating": "D",
"cost": 79444,
"mass": 8,
"power": 0.56,
"weaponcapacity": 31,
"weaponrecharge": 3.2,
"enginecapacity": 22,
"enginerecharge": 1.9,
"systemcapacity": 22,
"systemrecharge": 1.9
},
"5C": {
"grp": "pd",
"class": 5,
"rating": "C",
"cost": 198611,
"mass": 20,
"power": 0.62,
"weaponcapacity": 34,
"weaponrecharge": 3.6,
"enginecapacity": 24,
"enginerecharge": 2.1,
"systemcapacity": 24,
"systemrecharge": 2.1
},
"5B": {
"grp": "pd",
"class": 5,
"rating": "B",
"cost": 496527,
"mass": 32,
"power": 0.68,
"weaponcapacity": 37,
"weaponrecharge": 4,
"enginecapacity": 26,
"enginerecharge": 2.3,
"systemcapacity": 26,
"systemrecharge": 2.3
},
"5A": {
"grp": "pd",
"class": 5,
"rating": "A",
"cost": 1241317,
"mass": 20,
"power": 0.74,
"weaponcapacity": 41,
"weaponrecharge": 4.3,
"enginecapacity": 29,
"enginerecharge": 2.5,
"systemcapacity": 29,
"systemrecharge": 2.5
},
"4E": {
"grp": "pd",
"class": 4,
"rating": "E",
"cost": 11349,
"mass": 10,
"power": 0.45,
"weaponcapacity": 22,
"weaponrecharge": 2.3,
"enginecapacity": 15,
"enginerecharge": 1.3,
"systemcapacity": 15,
"systemrecharge": 1.3
},
"4D": {
"grp": "pd",
"class": 4,
"rating": "D",
"cost": 28373,
"mass": 4,
"power": 0.5,
"weaponcapacity": 24,
"weaponrecharge": 2.6,
"enginecapacity": 17,
"enginerecharge": 1.4,
"systemcapacity": 17,
"systemrecharge": 1.4
},
"4C": {
"grp": "pd",
"class": 4,
"rating": "C",
"cost": 70932,
"mass": 10,
"power": 0.56,
"weaponcapacity": 27,
"weaponrecharge": 2.9,
"enginecapacity": 19,
"enginerecharge": 1.6,
"systemcapacity": 19,
"systemrecharge": 1.6
},
"4B": {
"grp": "pd",
"class": 4,
"rating": "B",
"cost": 177331,
"mass": 16,
"power": 0.62,
"weaponcapacity": 30,
"weaponrecharge": 3.2,
"enginecapacity": 21,
"enginerecharge": 1.8,
"systemcapacity": 21,
"systemrecharge": 1.8
},
"4A": {
"grp": "pd",
"class": 4,
"rating": "A",
"cost": 443328,
"mass": 10,
"power": 0.67,
"weaponcapacity": 32,
"weaponrecharge": 3.5,
"enginecapacity": 23,
"enginerecharge": 1.9,
"systemcapacity": 23,
"systemrecharge": 1.9
},
"3E": {
"grp": "pd",
"class": 3,
"rating": "E",
"cost": 4053,
"mass": 5,
"power": 0.4,
"weaponcapacity": 16,
"weaponrecharge": 1.8,
"enginecapacity": 12,
"enginerecharge": 0.9,
"systemcapacity": 12,
"systemrecharge": 0.9
},
"3D": {
"grp": "pd",
"class": 3,
"rating": "D",
"cost": 10133,
"mass": 2,
"power": 0.45,
"weaponcapacity": 18,
"weaponrecharge": 2.1,
"enginecapacity": 14,
"enginerecharge": 1,
"systemcapacity": 14,
"systemrecharge": 1
},
"3C": {
"grp": "pd",
"class": 3,
"rating": "C",
"cost": 25333,
"mass": 5,
"power": 0.5,
"weaponcapacity": 20,
"weaponrecharge": 2.3,
"enginecapacity": 15,
"enginerecharge": 1.1,
"systemcapacity": 15,
"systemrecharge": 1.1
},
"3B": {
"grp": "pd",
"class": 3,
"rating": "B",
"cost": 63333,
"mass": 8,
"power": 0.55,
"weaponcapacity": 22,
"weaponrecharge": 2.5,
"enginecapacity": 17,
"enginerecharge": 1.2,
"systemcapacity": 17,
"systemrecharge": 1.2
},
"3A": {
"grp": "pd",
"class": 3,
"rating": "A",
"cost": 158331,
"mass": 5,
"power": 0.6,
"weaponcapacity": 24,
"weaponrecharge": 2.8,
"enginecapacity": 18,
"enginerecharge": 1.3,
"systemcapacity": 18,
"systemrecharge": 1.3
},
"2E": {
"grp": "pd",
"class": 2,
"rating": "E",
"cost": 1448,
"mass": 2.5,
"power": 0.36,
"weaponcapacity": 12,
"weaponrecharge": 1.4,
"enginecapacity": 10,
"enginerecharge": 0.6,
"systemcapacity": 10,
"systemrecharge": 0.6
},
"2D": {
"grp": "pd",
"class": 2,
"rating": "D",
"cost": 3619,
"mass": 1,
"power": 0.41,
"weaponcapacity": 14,
"weaponrecharge": 1.6,
"enginecapacity": 11,
"enginerecharge": 0.6,
"systemcapacity": 11,
"systemrecharge": 0.6
},
"2C": {
"grp": "pd",
"class": 2,
"rating": "C",
"cost": 9048,
"mass": 2.5,
"power": 0.45,
"weaponcapacity": 15,
"weaponrecharge": 1.8,
"enginecapacity": 12,
"enginerecharge": 0.7,
"systemcapacity": 12,
"systemrecharge": 0.7
},
"2B": {
"grp": "pd",
"class": 2,
"rating": "B",
"cost": 22619,
"mass": 4,
"power": 0.5,
"weaponcapacity": 17,
"weaponrecharge": 2,
"enginecapacity": 13,
"enginerecharge": 0.8,
"systemcapacity": 13,
"systemrecharge": 0.8
},
"2A": {
"grp": "pd",
"class": 2,
"rating": "A",
"cost": 56547,
"mass": 2.5,
"power": 0.54,
"weaponcapacity": 18,
"weaponrecharge": 2.2,
"enginecapacity": 14,
"enginerecharge": 0.8,
"systemcapacity": 14,
"systemrecharge": 0.8
},
"1E": {
"grp": "pd",
"class": 1,
"rating": "E",
"cost": 517,
"mass": 1.3,
"power": 0.32,
"weaponcapacity": 10,
"weaponrecharge": 1.2,
"enginecapacity": 8,
"enginerecharge": 0.4,
"systemcapacity": 8,
"systemrecharge": 0.4
},
"1D": {
"grp": "pd",
"class": 1,
"rating": "D",
"cost": 1293,
"mass": 0.5,
"power": 0.36,
"weaponcapacity": 11,
"weaponrecharge": 1.4,
"enginecapacity": 9,
"enginerecharge": 0.5,
"systemcapacity": 9,
"systemrecharge": 0.5
},
"1C": {
"grp": "pd",
"class": 1,
"rating": "C",
"cost": 3231,
"mass": 1.3,
"power": 0.4,
"weaponcapacity": 12,
"weaponrecharge": 1.5,
"enginecapacity": 10,
"enginerecharge": 0.5,
"systemcapacity": 10,
"systemrecharge": 0.5
},
"1B": {
"grp": "pd",
"class": 1,
"rating": "B",
"cost": 8078,
"mass": 2,
"power": 0.44,
"weaponcapacity": 13,
"weaponrecharge": 1.7,
"enginecapacity": 11,
"enginerecharge": 0.6,
"systemcapacity": 11,
"systemrecharge": 0.6
},
"1A": {
"grp": "pd",
"class": 1,
"rating": "A",
"cost": 20195,
"mass": 1.3,
"power": 0.48,
"weaponcapacity": 14,
"weaponrecharge": 1.8,
"enginecapacity": 12,
"enginerecharge": 0.6,
"systemcapacity": 12,
"systemrecharge": 0.6
}
}

View File

@@ -1,317 +0,0 @@
{
"8E": {
"grp": "pp",
"class": 8,
"rating": "E",
"cost": 2007241,
"mass": 160,
"pGen": 24,
"eff": "F"
},
"8D": {
"grp": "pp",
"class": 8,
"rating": "D",
"cost": 6021722,
"mass": 64,
"pGen": 27,
"eff": "D"
},
"8C": {
"grp": "pp",
"class": 8,
"rating": "C",
"cost": 18065165,
"mass": 80,
"pGen": 30,
"eff": "C"
},
"8B": {
"grp": "pp",
"class": 8,
"rating": "B",
"cost": 54195495,
"mass": 128,
"pGen": 33,
"eff": "C"
},
"8A": {
"grp": "pp",
"class": 8,
"rating": "A",
"cost": 162586486,
"mass": 80,
"pGen": 36,
"eff": "B"
},
"7E": {
"grp": "pp",
"class": 7,
"rating": "E",
"cost": 633199,
"mass": 80,
"pGen": 20,
"eff": "F"
},
"7D": {
"grp": "pp",
"class": 7,
"rating": "D",
"cost": 1899597,
"mass": 32,
"pGen": 22.5,
"eff": "D"
},
"7C": {
"grp": "pp",
"class": 7,
"rating": "C",
"cost": 5698790,
"mass": 40,
"pGen": 25,
"eff": "C"
},
"7B": {
"grp": "pp",
"class": 7,
"rating": "B",
"cost": 17096371,
"mass": 64,
"pGen": 27.5,
"eff": "C"
},
"7A": {
"grp": "pp",
"class": 7,
"rating": "A",
"cost": 51289112,
"mass": 40,
"pGen": 30,
"eff": "B"
},
"6E": {
"grp": "pp",
"class": 6,
"rating": "E",
"cost": 199747,
"mass": 40,
"pGen": 16.8,
"eff": "F"
},
"6D": {
"grp": "pp",
"class": 6,
"rating": "D",
"cost": 599242,
"mass": 16,
"pGen": 18.9,
"eff": "D"
},
"6C": {
"grp": "pp",
"class": 6,
"rating": "C",
"cost": 1797726,
"mass": 20,
"pGen": 21,
"eff": "C"
},
"6B": {
"grp": "pp",
"class": 6,
"rating": "B",
"cost": 5393177,
"mass": 32,
"pGen": 23.1,
"eff": "C"
},
"6A": {
"grp": "pp",
"class": 6,
"rating": "A",
"cost": 16179531,
"mass": 20,
"pGen": 25.2,
"eff": "B"
},
"5E": {
"grp": "pp",
"class": 5,
"rating": "E",
"cost": 63012,
"mass": 20,
"pGen": 13.6,
"eff": "F"
},
"5D": {
"grp": "pp",
"class": 5,
"rating": "D",
"cost": 189035,
"mass": 8,
"pGen": 15.3,
"eff": "D"
},
"5C": {
"grp": "pp",
"class": 5,
"rating": "C",
"cost": 567106,
"mass": 10,
"pGen": 17,
"eff": "C"
},
"5B": {
"grp": "pp",
"class": 5,
"rating": "B",
"cost": 1701318,
"mass": 16,
"pGen": 18.7,
"eff": "C"
},
"5A": {
"grp": "pp",
"class": 5,
"rating": "A",
"cost": 5103953,
"mass": 10,
"pGen": 20.4,
"eff": "B"
},
"4E": {
"grp": "pp",
"class": 4,
"rating": "E",
"cost": 19878,
"mass": 10,
"pGen": 10.4,
"eff": "F"
},
"4D": {
"grp": "pp",
"class": 4,
"rating": "D",
"cost": 59633,
"mass": 4,
"pGen": 11.7,
"eff": "D"
},
"4C": {
"grp": "pp",
"class": 4,
"rating": "C",
"cost": 178898,
"mass": 5,
"pGen": 13,
"eff": "C"
},
"4B": {
"grp": "pp",
"class": 4,
"rating": "B",
"cost": 536693,
"mass": 8,
"pGen": 14.3,
"eff": "C"
},
"4A": {
"grp": "pp",
"class": 4,
"rating": "A",
"cost": 1610080,
"mass": 5,
"pGen": 15.6,
"eff": "B"
},
"3E": {
"grp": "pp",
"class": 3,
"rating": "E",
"cost": 6271,
"mass": 5,
"pGen": 8,
"eff": "F"
},
"3D": {
"grp": "pp",
"class": 3,
"rating": "D",
"cost": 18812,
"mass": 2,
"pGen": 9,
"eff": "D"
},
"3C": {
"grp": "pp",
"class": 3,
"rating": "C",
"cost": 56435,
"mass": 2.5,
"pGen": 10,
"eff": "C"
},
"3B": {
"grp": "pp",
"class": 3,
"rating": "B",
"cost": 169304,
"mass": 4,
"pGen": 11,
"eff": "C"
},
"3A": {
"grp": "pp",
"class": 3,
"rating": "A",
"cost": 507912,
"mass": 2.5,
"pGen": 12,
"eff": "B"
},
"2E": {
"grp": "pp",
"class": 2,
"rating": "E",
"cost": 1978,
"mass": 2.5,
"pGen": 6.4,
"eff": "F"
},
"2D": {
"grp": "pp",
"class": 2,
"rating": "D",
"cost": 5934,
"mass": 1,
"pGen": 7.2,
"eff": "D"
},
"2C": {
"grp": "pp",
"class": 2,
"rating": "C",
"cost": 17803,
"mass": 1.3,
"pGen": 8,
"eff": "C"
},
"2B": {
"grp": "pp",
"class": 2,
"rating": "B",
"cost": 53408,
"mass": 2,
"pGen": 8.8,
"eff": "C"
},
"2A": {
"grp": "pp",
"class": 2,
"rating": "A",
"cost": 160224,
"mass": 1.3,
"pGen": 9.6,
"eff": "B"
}
}

View File

@@ -1,317 +0,0 @@
{
"8E": {
"grp": "s",
"class": 8,
"rating": "E",
"cost": 697584,
"mass": 160,
"power": 0.55,
"range": 5
},
"8D": {
"grp": "s",
"class": 8,
"rating": "D",
"cost": 1743961,
"mass": 64,
"power": 0.62,
"range": 6
},
"8C": {
"grp": "s",
"class": 8,
"rating": "C",
"cost": 4359903,
"mass": 160,
"power": 0.69,
"range": 6
},
"8B": {
"grp": "s",
"class": 8,
"rating": "B",
"cost": 10899756,
"mass": 256,
"power": 1.14,
"range": 7
},
"8A": {
"grp": "s",
"class": 8,
"rating": "A",
"cost": 27249391,
"mass": 160,
"power": 2.07,
"range": 8
},
"6E": {
"grp": "s",
"class": 6,
"rating": "E",
"cost": 88978,
"mass": 40,
"power": 0.4,
"range": 5
},
"6D": {
"grp": "s",
"class": 6,
"rating": "D",
"cost": 222444,
"mass": 16,
"power": 0.45,
"range": 5
},
"6C": {
"grp": "s",
"class": 6,
"rating": "C",
"cost": 556110,
"mass": 40,
"power": 0.5,
"range": 6
},
"6B": {
"grp": "s",
"class": 6,
"rating": "B",
"cost": 1390275,
"mass": 64,
"power": 0.83,
"range": 7
},
"6A": {
"grp": "s",
"class": 6,
"rating": "A",
"cost": 3475688,
"mass": 40,
"power": 1.5,
"range": 7
},
"5E": {
"grp": "s",
"class": 5,
"rating": "E",
"cost": 31778,
"mass": 20,
"power": 0.33,
"range": 4.5
},
"5D": {
"grp": "s",
"class": 5,
"rating": "D",
"cost": 79444,
"mass": 8,
"power": 0.37,
"range": 5
},
"5C": {
"grp": "s",
"class": 5,
"rating": "C",
"cost": 198611,
"mass": 20,
"power": 0.41,
"range": 5.5
},
"5B": {
"grp": "s",
"class": 5,
"rating": "B",
"cost": 496527,
"mass": 32,
"power": 0.68,
"range": 6
},
"5A": {
"grp": "s",
"class": 5,
"rating": "A",
"cost": 1241317,
"mass": 20,
"power": 1.23,
"range": 6.5
},
"4E": {
"grp": "s",
"class": 4,
"rating": "E",
"cost": 11349,
"mass": 10,
"power": 0.27,
"range": 4
},
"4D": {
"grp": "s",
"class": 4,
"rating": "D",
"cost": 28373,
"mass": 4,
"power": 0.31,
"range": 5
},
"4C": {
"grp": "s",
"class": 4,
"rating": "C",
"cost": 70932,
"mass": 10,
"power": 0.34,
"range": 6
},
"4B": {
"grp": "s",
"class": 4,
"rating": "B",
"cost": 177331,
"mass": 16,
"power": 0.56,
"range": 6
},
"4A": {
"grp": "s",
"class": 4,
"rating": "A",
"cost": 443328,
"mass": 10,
"power": 1.02,
"range": 7
},
"3E": {
"grp": "s",
"class": 3,
"rating": "E",
"cost": 4053,
"mass": 5,
"power": 0.22,
"range": 4
},
"3D": {
"grp": "s",
"class": 3,
"rating": "D",
"cost": 10133,
"mass": 2,
"power": 0.25,
"range": 4.5
},
"3C": {
"grp": "s",
"class": 3,
"rating": "C",
"cost": 25333,
"mass": 5,
"power": 0.28,
"range": 5
},
"3B": {
"grp": "s",
"class": 3,
"rating": "B",
"cost": 63333,
"mass": 8,
"power": 0.46,
"range": 5.5
},
"3A": {
"grp": "s",
"class": 3,
"rating": "A",
"cost": 158331,
"mass": 5,
"power": 0.84,
"range": 6
},
"2E": {
"grp": "s",
"class": 2,
"rating": "E",
"cost": 1448,
"mass": 2.5,
"power": 0.18,
"range": 4
},
"2D": {
"grp": "s",
"class": 2,
"rating": "D",
"cost": 3619,
"mass": 1,
"power": 0.21,
"range": 4.5
},
"2C": {
"grp": "s",
"class": 2,
"rating": "C",
"cost": 9048,
"mass": 2.5,
"power": 0.23,
"range": 5
},
"2B": {
"grp": "s",
"class": 2,
"rating": "B",
"cost": 22619,
"mass": 4,
"power": 0.38,
"range": 5.5
},
"2A": {
"grp": "s",
"class": 2,
"rating": "A",
"cost": 56547,
"mass": 2.5,
"power": 0.69,
"range": 6
},
"1E": {
"grp": "s",
"class": 1,
"rating": "E",
"cost": 517,
"mass": 1.3,
"power": 0.16,
"range": 4
},
"1D": {
"grp": "s",
"class": 1,
"rating": "D",
"cost": 1293,
"mass": 0.5,
"power": 0.18,
"range": 4.5
},
"1C": {
"grp": "s",
"class": 1,
"rating": "C",
"cost": 3231,
"mass": 1.3,
"power": 0.2,
"range": 5
},
"1B": {
"grp": "s",
"class": 1,
"rating": "B",
"cost": 8078,
"mass": 2,
"power": 0.33,
"range": 5.5
},
"1A": {
"grp": "s",
"class": 1,
"rating": "A",
"cost": 20195,
"mass": 1.3,
"power": 0.6,
"range": 6
}
}

View File

@@ -1,302 +0,0 @@
{
"7E": {
"grp": "t",
"class": 7,
"rating": "E",
"cost": 633199,
"mass": 80,
"power": 6.08,
"optmass": 1440,
"maxmass": 2160
},
"7D": {
"grp": "t",
"class": 7,
"rating": "D",
"cost": 1899597,
"mass": 32,
"power": 6.84,
"optmass": 1620,
"maxmass": 2430
},
"7C": {
"grp": "t",
"class": 7,
"rating": "C",
"cost": 5698790,
"mass": 80,
"power": 7.6,
"optmass": 1800,
"maxmass": 2700
},
"7B": {
"grp": "t",
"class": 7,
"rating": "B",
"cost": 17096371,
"mass": 128,
"power": 8.36,
"optmass": 1980,
"maxmass": 2970
},
"7A": {
"grp": "t",
"class": 7,
"rating": "A",
"cost": 51289112,
"mass": 80,
"power": 9.12,
"optmass": 2160,
"maxmass": 3240
},
"6E": {
"grp": "t",
"class": 6,
"rating": "E",
"cost": 199747,
"mass": 40,
"power": 5.04,
"optmass": 960,
"maxmass": 1440
},
"6D": {
"grp": "t",
"class": 6,
"rating": "D",
"cost": 599242,
"mass": 16,
"power": 5.67,
"optmass": 1080,
"maxmass": 1620
},
"6C": {
"grp": "t",
"class": 6,
"rating": "C",
"cost": 1797726,
"mass": 40,
"power": 6.3,
"optmass": 1200,
"maxmass": 1800
},
"6B": {
"grp": "t",
"class": 6,
"rating": "B",
"cost": 5393177,
"mass": 64,
"power": 6.93,
"optmass": 1320,
"maxmass": 1980
},
"6A": {
"grp": "t",
"class": 6,
"rating": "A",
"cost": 16179531,
"mass": 40,
"power": 7.56,
"optmass": 1440,
"maxmass": 2160
},
"5E": {
"grp": "t",
"class": 5,
"rating": "E",
"cost": 63012,
"mass": 20,
"power": 4.08,
"optmass": 560,
"maxmass": 840
},
"5D": {
"grp": "t",
"class": 5,
"rating": "D",
"cost": 189035,
"mass": 8,
"power": 4.59,
"optmass": 630,
"maxmass": 945
},
"5C": {
"grp": "t",
"class": 5,
"rating": "C",
"cost": 567106,
"mass": 20,
"power": 5.1,
"optmass": 700,
"maxmass": 1050
},
"5B": {
"grp": "t",
"class": 5,
"rating": "B",
"cost": 1701318,
"mass": 32,
"power": 5.61,
"optmass": 770,
"maxmass": 1155
},
"5A": {
"grp": "t",
"class": 5,
"rating": "A",
"cost": 5103953,
"mass": 20,
"power": 6.12,
"optmass": 840,
"maxmass": 1260
},
"4E": {
"grp": "t",
"class": 4,
"rating": "E",
"cost": 19878,
"mass": 10,
"power": 3.82,
"optmass": 280,
"maxmass": 420
},
"4D": {
"grp": "t",
"class": 4,
"rating": "D",
"cost": 59633,
"mass": 4,
"power": 3.69,
"optmass": 315,
"maxmass": 473
},
"4C": {
"grp": "t",
"class": 4,
"rating": "C",
"cost": 178898,
"mass": 10,
"power": 4.1,
"optmass": 350,
"maxmass": 525
},
"4B": {
"grp": "t",
"class": 4,
"rating": "B",
"cost": 536693,
"mass": 16,
"power": 4.51,
"optmass": 385,
"maxmass": 578
},
"4A": {
"grp": "t",
"class": 4,
"rating": "A",
"cost": 1610080,
"mass": 10,
"power": 4.92,
"optmass": 420,
"maxmass": 630
},
"3E": {
"grp": "t",
"class": 3,
"rating": "E",
"cost": 6271,
"mass": 5,
"power": 2.48,
"optmass": 80,
"maxmass": 120
},
"3D": {
"grp": "t",
"class": 3,
"rating": "D",
"cost": 18812,
"mass": 2,
"power": 2.79,
"optmass": 90,
"maxmass": 135
},
"3C": {
"grp": "t",
"class": 3,
"rating": "C",
"cost": 56435,
"mass": 5,
"power": 3.1,
"optmass": 100,
"maxmass": 150
},
"3B": {
"grp": "t",
"class": 3,
"rating": "B",
"cost": 169304,
"mass": 8,
"power": 3.41,
"optmass": 110,
"maxmass": 165
},
"3A": {
"grp": "t",
"class": 3,
"rating": "A",
"cost": 507912,
"mass": 5,
"power": 3.72,
"optmass": 120,
"maxmass": 180
},
"2E": {
"grp": "t",
"class": 2,
"rating": "E",
"cost": 1978,
"mass": 2.5,
"power": 2,
"optmass": 48,
"maxmass": 72
},
"2D": {
"grp": "t",
"class": 2,
"rating": "D",
"cost": 5934,
"mass": 1,
"power": 2.25,
"optmass": 54,
"maxmass": 81
},
"2C": {
"grp": "t",
"class": 2,
"rating": "C",
"cost": 17803,
"mass": 2.5,
"power": 2.5,
"optmass": 60,
"maxmass": 90
},
"2B": {
"grp": "t",
"class": 2,
"rating": "B",
"cost": 53408,
"mass": 4,
"power": 2.75,
"optmass": 66,
"maxmass": 99
},
"2A": {
"grp": "t",
"class": 2,
"rating": "A",
"cost": 160224,
"mass": 2.5,
"power": 3,
"optmass": 72,
"maxmass": 108
}
}

View File

@@ -1,166 +0,0 @@
{
"Beam Lasers" : [
{
"id": "0u",
"grp": "bl",
"class": 3,
"rating": "C",
"cost": 1177600,
"mass": 8,
"power": 1.8,
"mode": "F",
"type": "T",
"damage": 6,
"armourpen": "A",
"rof": null,
"dps": 5,
"mjdps" : 30.33,
"mjeps" : 5.65,
"thermload": 5
},
{
"id": "0v",
"grp": "bl",
"class": 3,
"rating": "C",
"cost": 2396160,
"mass": 8,
"power": 1.78,
"mode": "G",
"type": "T",
"damage": 6,
"armourpen": "A",
"rof": null,
"dps": 4,
"mjdps" : 24.00,
"mjeps" : 5.59,
"thermload": 6
},
{
"id": "0o",
"grp": "bl",
"class": 3,
"rating": "D",
"cost": 19399600,
"mass": 8,
"power": 1.68,
"mode": "T",
"type": "T",
"damage": 5,
"armourpen": "A",
"rof": null,
"dps": 4,
"mjdps" : 14.44,
"mjeps" : 3.54,
"thermload": 4
},
{
"id": "0r",
"grp": "bl",
"class": 2,
"rating": "D",
"cost": 299520,
"mass": 4,
"power": 1.12,
"mode": "F",
"type": "T",
"damage": 5,
"armourpen": "A",
"rof": null,
"dps": 4,
"mjdps" : 19.38,
"mjeps" : 3.42,
"thermload": 4
},
{
"id": "0s",
"grp": "bl",
"class": 2,
"rating": "D",
"cost": 500600,
"mass": 4,
"power": 1.1,
"mode": "G",
"type": "T",
"damage": 5,
"armourpen": "A",
"rof": null,
"dps": 4,
"mjdps" : 13.85,
"mjeps" : 3.26,
"thermload": 4
},
{
"id": "0t",
"grp": "bl",
"class": 2,
"rating": "E",
"cost": 2099900,
"mass": 4,
"power": 1.03,
"mode": "T",
"type": "T",
"damage": 4,
"armourpen": "A",
"rof": null,
"dps": 3,
"mjdps" : 8.95,
"mjeps" : 2.10,
"thermload": 3
},
{
"id": "10",
"grp": "bl",
"class": 1,
"rating": "E",
"cost": 37430,
"mass": 2,
"power": 0.69,
"mode": "F",
"type": "T",
"damage": 4,
"armourpen": "A",
"rof": null,
"dps": 3,
"mjdps" : 11.61,
"mjeps" : 2.16,
"thermload": 3
},
{
"id": "0p",
"grp": "bl",
"class": 1,
"rating": "E",
"cost": 74650,
"mass": 2,
"power": 0.67,
"mode": "G",
"type": "T",
"damage": 4,
"armourpen": "A",
"rof": null,
"dps": 3,
"mjdps" : 8.70,
"mjeps" : 2.05,
"thermload": 3
},
{
"id": "0q",
"grp": "bl",
"class": 1,
"rating": "F",
"cost": 500000,
"mass": 2,
"power": 0.63,
"mode": "T",
"type": "T",
"damage": 3,
"armourpen": "A",
"rof": null,
"dps": 3,
"mjdps" : 5.49,
"mjeps" : 1.29,
"thermload": 2
}
]
}

View File

@@ -1,166 +0,0 @@
{
"Burst Lasers": [
{
"id": "14",
"grp": "ul",
"class": 3,
"rating": "D",
"cost": 140400,
"mass": 8,
"power": 1.66,
"mode": "F",
"type": "T",
"damage": 4,
"armourpen": "B",
"rof": 1,
"dps": 4,
"mjdps" : 24.97,
"mjeps" : 3.52,
"ssdam" : 27.85,
"thermload": 1
},
{
"id": "15",
"grp": "ul",
"class": 3,
"rating": "E",
"cost": 281600,
"mass": 8,
"power": 1.65,
"mode": "G",
"type": "T",
"damage": 3,
"armourpen": "A",
"rof": 1.2,
"dps": 4,
"mjdps" : 18.56,
"mjeps" : 3.27,
"ssdam" : 18.56,
"thermload": 1
},
{
"id": "16",
"grp": "ul",
"class": 3,
"rating": "E",
"cost": 800400,
"mass": 8,
"power": 1.57,
"mode": "T",
"type": "T",
"damage": 3,
"armourpen": "A",
"rof": 0.9,
"dps": 4,
"mjdps" : 8.78,
"mjeps" : 1.69,
"ssdam" : 9.45,
"thermload": 1
},
{
"id": "7h",
"grp": "ul",
"class":2,
"rating":"E",
"cost": 23000,
"mass": 4,
"power":1.05,
"mode":"F",
"type":"T",
"damage": 3,
"armourpen":"A",
"rof":1.3,
"dps": 4,
"thermload": 1
},
{
"id": "7i",
"grp": "ul",
"class":2,
"rating":"F",
"cost": 48500,
"mass": 4,
"power":1.04,
"mode":"G",
"type":"T",
"damage": 3,
"armourpen":"A",
"rof":1.5,
"dps": 4,
"thermload": 1
},
{
"id": "7j",
"grp": "ul",
"class":2,
"rating":"F",
"cost": 162800,
"mass": 4,
"power":0.98,
"mode":"T",
"type":"T",
"damage": 2,
"armourpen":"A",
"rof":1.1,
"dps": 3,
"thermload": 1
},
{
"id": "11",
"grp": "ul",
"class": 1,
"rating": "F",
"cost": 4400,
"mass": 2,
"power": 0.65,
"mode": "F",
"type": "T",
"damage": 2,
"armourpen": "A",
"rof": 1.6,
"dps": 3,
"mjdps" : 9.94,
"mjeps" : 1.40,
"ssdam" : 6.45,
"thermload": 1
},
{
"id": "12",
"grp": "ul",
"class": 1,
"rating": "G",
"cost": 8600,
"mass": 2,
"power": 0.64,
"mode": "G",
"type": "T",
"damage": 2,
"armourpen": "A",
"rof": 1.7,
"dps": 3,
"mjdps" : 7.95,
"mjeps" : 1.40,
"ssdam" : 4.53,
"thermload": 1
},
{
"id": "13",
"grp": "ul",
"class": 1,
"rating": "G",
"cost": 52800,
"mass": 2,
"power": 0.6,
"mode": "T",
"type": "T",
"damage": 1,
"armourpen": "B",
"rof": 1.3,
"dps": 2,
"mjdps" : 2.98,
"mjeps" : 0.63,
"ssdam" : 2.24,
"thermload": 1
}
]
}

View File

@@ -1,235 +0,0 @@
{
"Cannons": [
{
"id": "1q",
"grp": "c",
"class": 4,
"rating": "B",
"cost": 2700800,
"mass": 16,
"power": 0.92,
"mode": "F",
"type": "K",
"damage": 9,
"armourpen": "A",
"rof": 0.4,
"dps": 5,
"thermload": 2,
"grp": "c",
"clip": 5,
"mjdps": 8.13,
"ssdam" : 37.13,
"ammo": 100
},
{
"id": "1r",
"grp": "c",
"class": 4,
"rating": "B",
"cost": 5401600,
"mass": 16,
"power": 1.03,
"mode": "G",
"type": "K",
"damage": 8,
"armourpen": "A",
"rof": 0.4,
"dps": 4,
"thermload": 2,
"grp": "c",
"clip": 5,
"mjdps": 10.97,
"ssdam" : 30.94,
"ammo": 100
},
{
"id": "1n",
"grp": "c",
"class": 3,
"rating": "C",
"cost": 675200,
"mass": 8,
"power": 0.67,
"mode": "F",
"type": "K",
"damage": 7,
"armourpen": "A",
"rof": 0.4,
"dps": 4,
"thermload": 2,
"grp": "c",
"clip": 5,
"mjdps": 8.13,
"ssdam" : 22.28,
"ammo": 100
},
{
"id": "1o",
"grp": "c",
"class": 3,
"rating": "C",
"cost": 1350400,
"mass": 8,
"power": 0.75,
"mode": "G",
"type": "K",
"damage": 7,
"armourpen": "A",
"rof": 0.4,
"dps": 4,
"thermload": 1,
"grp": "c",
"clip": 5,
"mjdps" : 7.95,
"ssdam" : 21.04,
"ammo": 100
},
{
"id": "1p",
"grp": "c",
"class": 3,
"rating": "D",
"cost": 16204800,
"mass": 8,
"power": 0.64,
"mode": "T",
"type": "K",
"damage": 6,
"armourpen": "A",
"rof": 0.3,
"dps": 4,
"thermload": 1,
"grp": "c",
"clip": 5,
"mjdps" : 3.58,
"ssdam" : 12.38,
"ammo": 100
},
{
"id": "1k",
"grp": "c",
"class": 2,
"rating": "D",
"cost": 168430,
"mass": 4,
"power": 0.49,
"mode": "F",
"type": "K",
"damage": 6,
"armourpen": "A",
"rof": 0.5,
"dps": 4,
"thermload": 1,
"grp": "c",
"clip": 5,
"mjdps" : 6.00,
"ssdam" : 15.47,
"ammo": 100
},
{
"id": "1l",
"grp": "c",
"class": 2,
"rating": "D",
"cost": 337600,
"mass": 4,
"power": 0.54,
"mode": "G",
"type": "K",
"damage": 6,
"armourpen": "A",
"rof": 0.5,
"dps": 3,
"thermload": 1,
"grp": "c",
"clip": 5,
"mjdps" : 6.24,
"ssdam" : 15.47,
"ammo": 100
},
{
"id": "1m",
"grp": "c",
"class": 2,
"rating": "E",
"cost": 4051200,
"mass": 4,
"power": 0.45,
"mode": "T",
"type": "K",
"damage": 5,
"armourpen": "A",
"rof": 0.3,
"dps": 3,
"thermload": 1,
"grp": "c",
"clip": 5,
"mjdps" : 2.41,
"ssdam" : 7.74,
"ammo": 100
},
{
"id": "1h",
"grp": "c",
"class": 1,
"rating": "D",
"cost": 21100,
"mass": 2,
"power": 0.34,
"mode": "F",
"type": "K",
"damage": 5,
"armourpen": "A",
"rof": 0.5,
"dps": 3,
"thermload": 1,
"grp": "c",
"clip": 5,
"mjdps" : 4.00,
"ssdam" : 9.59,
"ammo": 100
},
{
"id": "1i",
"grp": "c",
"class": 1,
"rating": "E",
"cost": 42200,
"mass": 2,
"power": 0.38,
"mode": "G",
"type": "K",
"damage": 5,
"armourpen": "A",
"rof": 0.5,
"dps": 3,
"thermload": 1,
"grp": "c",
"clip": 5,
"mjdps" : 3.80,
"ssdam" : 8.97,
"ammo": 100
},
{
"id": "1j",
"grp": "c",
"class": 1,
"rating": "F",
"cost": 506400,
"mass": 2,
"power": 0.32,
"mode": "T",
"type": "K",
"damage": 4,
"armourpen": "A",
"rof": 0.4,
"dps": 3,
"thermload": 1,
"grp": "c",
"clip": 5,
"mjdps" : 1.35,
"ssdam" : 4.13,
"ammo": 100
}
]
}

View File

@@ -1,59 +0,0 @@
{
"Cargo Scanners": [
{
"id": "0d",
"grp": "cs",
"class": 0,
"rating": "E",
"cost": 13544,
"mass": 1.3,
"power": 0.2,
"range": 2,
"time": 10
},
{
"id": "0c",
"grp": "cs",
"class": 0,
"rating": "D",
"cost": 40633,
"mass": 1.3,
"power": 0.4,
"range": 2.5,
"time": 10
},
{
"id": "0b",
"grp": "cs",
"class": 0,
"rating": "C",
"cost": 121899,
"mass": 1.3,
"power": 0.8,
"range": 3,
"time": 10
},
{
"id": "0a",
"grp": "cs",
"class": 0,
"rating": "B",
"cost": 365698,
"mass": 1.3,
"power": 1.6,
"range": 3.5,
"time": 10
},
{
"id": "09",
"grp": "cs",
"class": 0,
"rating": "A",
"cost": 1097095,
"mass": 1.3,
"power": 3.2,
"range": 4,
"time": 10
}
]
}

View File

@@ -1,63 +0,0 @@
{
"Countermeasures": [
{
"id": "00",
"grp": "cm",
"name": "Chaff Launcher",
"class": 0,
"rating": "I",
"cost": 8500,
"mass": 1.3,
"power": 0.2,
"passive": 1,
"armourpen": "F",
"thermload": 2,
"clip": 1,
"ammo": 10
},
{
"id": "01",
"grp": "cm",
"name": "Electronic Countermeasure",
"class": 0,
"rating": "F",
"cost": 12500,
"mass": 1.3,
"power": 0.2,
"range": 3,
"chargeup": 4,
"activepower": 4,
"cooldown": 10
},
{
"id": "02",
"grp": "cm",
"name": "Heat Sink Launcher",
"class": 0,
"rating": "I",
"cost": 3500,
"mass": 1.3,
"power": 0.2,
"passive": 1,
"armourpen": "F",
"thermload": 0,
"clip": 1,
"ammo": 3
},
{
"id": "03",
"grp": "cm",
"name": "Point Defence",
"class": 0,
"rating": "I",
"cost": 18546,
"mass": 0.5,
"power": 0.2,
"passive": 1,
"armourpen": "F",
"thermload": 1,
"clip": 50,
"ammo": 10000
}
]
}

View File

@@ -1,190 +0,0 @@
{
"Fragment Cannons": [
{
"id": "1t",
"grp": "fc",
"class": 3,
"rating": "C",
"cost": 1167360,
"mass": 8,
"power": 1.02,
"mode": "F",
"type": "K",
"damage": 3,
"armourpen": "A",
"rof": 4.5,
"dps": 10,
"thermload": 1,
"grp": "fc",
"clip": 3,
"mjdps": 15.19,
"ssdam" : 28.36,
"ammo": 30
},
{
"id": "1u",
"grp": "fc",
"class": 3,
"rating": "C",
"cost": 1751040,
"mass": 8,
"power": 1.55,
"mode": "G",
"type": "K",
"damage": 3,
"armourpen": "A",
"rof": 4.8,
"dps": 10,
"thermload": 1,
"grp": "fc",
"clip": 3,
"mjdps" : 12.77,
"ssdam" : 23.21,
"ammo": 30
},
{
"id": "1v",
"grp": "fc",
"class": 3,
"rating": "C",
"cost": 5836800,
"mass": 8,
"power": 1.29,
"mode": "T",
"type": "K",
"damage": 2,
"armourpen": "A",
"rof": 3.3,
"dps": 9,
"thermload": 1,
"grp": "fc",
"clip": 3,
"mjdps" : 6.85,
"ssdam" : 12.89,
"ammo": 30
},
{
"id": "1s",
"grp": "fc",
"class": 2,
"rating": "A",
"cost": 291840,
"mass": 4,
"power": 0.74,
"mode": "F",
"type": "K",
"damage": 3,
"armourpen": "A",
"rof": 5,
"dps": 9,
"thermload": 1,
"grp": "fc",
"clip": 3,
"mjdps" : 9.50,
"ssdam" : 18.05,
"ammo": 30
},
{
"id": "7e",
"grp": "fc",
"class": 2,
"rating": "D",
"cost": 437800,
"mass": 4,
"power": 1.03,
"mode": "G",
"type": "K",
"damage": 2,
"armourpen": "A",
"rof": 5.3,
"dps": 9,
"thermload": 1,
"grp": "fc",
"clip": 3,
"ammo": 30
},
{
"id": "7f",
"grp": "fc",
"class": 2,
"rating": "D",
"cost": 1459200,
"mass": 4,
"power": 0.79,
"mode": "T",
"type": "K",
"damage": 2,
"armourpen": "A",
"rof": 3.7,
"dps": 9,
"thermload": 1,
"grp": "fc",
"clip": 3,
"ammo": 30
},
{
"id": "20",
"grp": "fc",
"class": 1,
"rating": "E",
"cost": 36000,
"mass": 2,
"power": 0.45,
"mode": "F",
"type": "K",
"damage": 2,
"armourpen": "A",
"rof": 5.5,
"dps": 8,
"thermload": 1,
"grp": "fc",
"clip": 3,
"mjdps" : 5.53,
"ssdam" : 10.31,
"ammo": 30
},
{
"id": "21",
"grp": "fc",
"class": 1,
"rating": "E",
"cost": 54720,
"mass": 2,
"power": 0.59,
"mode": "G",
"type": "K",
"damage": 2,
"armourpen": "A",
"rof": 5.8,
"dps": 7,
"thermload": 1,
"grp": "fc",
"clip": 3,
"mjdps" : 3.58,
"ssdam" : 6.45,
"ammo": 30
},
{
"id": "22",
"grp": "fc",
"class": 1,
"rating": "E",
"cost": 182400,
"mass": 2,
"power": 0.42,
"mode": "T",
"type": "K",
"damage": 1,
"armourpen": "A",
"rof": 4,
"dps": 6,
"thermload": 1,
"grp": "fc",
"clip": 3,
"mjdps" : 2.11,
"ssdam" : 3.87,
"ammo": 30
}
]
}

View File

@@ -1,59 +0,0 @@
{
"Frame Shift Wake Scanners": [
{
"id": "0i",
"grp": "ws",
"class": 0,
"rating": "E",
"cost": 13544,
"mass": 1.3,
"power": 0.2,
"range": 2,
"time": 10
},
{
"id": "0h",
"grp": "ws",
"class": 0,
"rating": "D",
"cost": 40633,
"mass": 1.3,
"power": 0.4,
"range": 2.5,
"time": 10
},
{
"id": "0g",
"grp": "ws",
"class": 0,
"rating": "C",
"cost": 121899,
"mass": 1.3,
"power": 0.8,
"range": 3,
"time": 10
},
{
"id": "0f",
"grp": "ws",
"class": 0,
"rating": "B",
"cost": 365698,
"mass": 1.3,
"power": 1.6,
"range": 3.5,
"time": 10
},
{
"id": "0e",
"grp": "ws",
"class": 0,
"rating": "A",
"cost": 1097095,
"mass": 1.3,
"power": 3.2,
"range": 4,
"time": 10
}
]
}

View File

@@ -1,59 +0,0 @@
{
"Kill Warrant Scanners": [
{
"id": "0n",
"grp": "kw",
"class": 0,
"rating": "E",
"cost": 13544,
"mass": 1.3,
"power": 0.2,
"range": 2,
"time": 10
},
{
"id": "0m",
"grp": "kw",
"class": 0,
"rating": "D",
"cost": 40633,
"mass": 1.3,
"power": 0.4,
"range": 2.5,
"time": 10
},
{
"id": "0l",
"grp": "kw",
"class": 0,
"rating": "C",
"cost": 121899,
"mass": 1.3,
"power": 0.8,
"range": 3,
"time": 10
},
{
"id": "0k",
"grp": "kw",
"class": 0,
"rating": "B",
"cost": 365698,
"mass": 1.3,
"power": 1.6,
"range": 3.5,
"time": 10
},
{
"id": "0j",
"grp": "kw",
"class": 0,
"rating": "A",
"cost": 1097095,
"mass": 1.3,
"power": 3.2,
"range": 4,
"time": 10
}
]
}

View File

@@ -1,34 +0,0 @@
{
"Mine Launchers": [
{
"id": "2j",
"grp": "nl",
"class": 1,
"rating": "I",
"cost": 24260,
"mass": 2,
"power": 0.4,
"mode": "F",
"type": "E",
"armourpen": "C",
"thermload": 2,
"clip": 1,
"ammo": 24
},
{
"id": "2k",
"grp": "nl",
"class": 2,
"rating": "I",
"cost": 294080,
"mass": 4,
"power": 0.4,
"mode": "F",
"type": "E",
"armourpen": "C",
"thermload": 3,
"clip": 3,
"ammo": 24
}
]
}

View File

@@ -1,34 +0,0 @@
{
"Mining Lasers": [
{
"id": "2l",
"grp": "ml",
"class": 1,
"rating": "D",
"cost": 6800,
"mass": 2,
"power": 0.5,
"mode": "F",
"armourpen": "D",
"thermload": 3,
"grp": "ml",
"clip": 1,
"ammo": 1
},
{
"id": "2m",
"grp": "ml",
"class": 2,
"rating": "D",
"cost": 22576,
"mass": 2,
"power": 0.75,
"mode": "F",
"armourpen": "D",
"thermload": 5,
"grp": "ml",
"clip": 1,
"ammo": 1
}
]
}

View File

@@ -1,92 +0,0 @@
{
"Missile Racks": [
{
"id": "2f",
"grp": "mr",
"class": 2,
"rating": "B",
"cost": 240400,
"mass": 4,
"power": 1.2,
"mode": "F",
"type": "E",
"damage": 7,
"armourpen": "F",
"rof": 2.5,
"dps": 8,
"thermload": 3,
"grp": "mr",
"clip": 12,
"ammo": 24,
"mjdps": 1.72,
"ssdam" : 3.87,
"missile": "D"
},
{
"id": "2g",
"grp": "mr",
"class": 2,
"rating": "B",
"cost": 512400,
"mass": 4,
"power": 1.2,
"mode": "F",
"type": "E",
"damage": 6,
"armourpen": "F",
"rof": 0.3,
"dps": 3,
"thermload": 3,
"grp": "mr",
"clip": 6,
"ammo": 18,
"mjdps": 0.57,
"ssdam" : 2.58,
"missile": "S"
},
{
"id": "2d",
"grp": "mr",
"class": 1,
"rating": "B",
"cost": 32175,
"mass": 2,
"power": 0.4,
"mode": "F",
"type": "E",
"damage": 7,
"armourpen": "F",
"rof": 2.5,
"dps": 8,
"thermload": 3,
"grp": "mr",
"clip": 8,
"ammo": 16,
"mjdps": 1.63,
"ssdam" : 3.87,
"missile": "D"
},
{
"id": "2e",
"grp": "mr",
"class": 1,
"rating": "B",
"cost": 72600,
"mass": 2,
"power": 0.6,
"mode": "F",
"type": "E",
"damage": 6,
"armourpen": "F",
"rof": 0.3,
"dps": 3,
"thermload": 3,
"grp": "mr",
"clip": 6,
"ammo": 6,
"mjdps": 0.57,
"ssdam" : 2.58,
"missile": "S"
}
]
}

Some files were not shown because too many files have changed in this diff Show More