From 16832e02dda2ab99d3566c9243060a6c8e37d066 Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Mon, 22 Dec 2014 16:36:04 -0800 Subject: [PATCH] Step 1 in converting to a Backbone-based website --- .gitignore | 2 + Gruntfile.coffee | 116 + dist/css/main.css | 219 + dist/css/main.css.map | 7 + dist/css/mocha.css | 270 + {html => dist}/data/applied_energetics.json | 0 {html => dist}/data/buildcraft.json | 0 {html => dist}/data/gravisuite.json | 0 {html => dist}/data/industrial_craft.json | 0 {html => dist}/data/more_blocks.json | 0 {html => dist}/data/thermal_expansion.json | 0 {html => dist}/data/vanilla.json | 0 dist/fonts/press_start.ttf | Bin 0 -> 24708 bytes dist/images/bedrock.png | Bin 0 -> 1398 bytes dist/images/bookshelf.png | Bin 0 -> 610 bytes dist/images/dirt.png | Bin 0 -> 1138 bytes dist/images/grass_side.png | Bin 0 -> 1429 bytes dist/images/ice.png | Bin 0 -> 206 bytes dist/images/stone_brick.png | Bin 0 -> 860 bytes dist/images/stone_brick_light.png | Bin 0 -> 9246 bytes dist/images/wordmark.png | Bin 0 -> 36148 bytes dist/images/workbench_front.png | Bin 0 -> 801 bytes dist/images/workbench_top.png | Bin 0 -> 1012 bytes dist/index.html | 75 + dist/js/backbone.js | 1608 +++ dist/js/chai.js | 4800 +++++++++ dist/js/d3.js | 9470 +++++++++++++++++ dist/js/jade.js | 238 + dist/js/jquery.js | 9205 ++++++++++++++++ dist/js/main.js | 1079 ++ dist/js/mocha.js | 6069 +++++++++++ dist/js/test.js | 788 ++ dist/js/underscore.js | 1415 +++ dist/js/views.js | 32 + dist/js/when.js | 2364 ++++ dist/src/css/main.scss | 152 + dist/src/css/mixins.scss | 26 + dist/src/css/reset.scss | 75 + dist/src/css/templates/index.scss | 8 + dist/src/css/templates/recipe_books.scss | 28 + dist/src/css/templates/recipe_catalog.scss | 28 + dist/test.html | 70 + httpd.conf | 16 - package.json | 40 + scripts/server | 2 +- src/css/main.scss | 152 + src/css/mixins.scss | 26 + src/css/reset.scss | 75 + src/css/templates/index.scss | 8 + src/css/templates/recipe_catalog.scss | 28 + src/data/applied_energetics.json | 333 + src/data/buildcraft.json | 256 + src/data/gravisuite.json | 67 + src/data/industrial_craft.json | 904 ++ src/data/more_blocks.json | 123 + src/data/thermal_expansion.json | 211 + src/data/vanilla.json | 564 + src/fonts/press_start.ttf | Bin 0 -> 24708 bytes src/images/bedrock.png | Bin 0 -> 1398 bytes src/images/bookshelf.png | Bin 0 -> 610 bytes src/images/dirt.png | Bin 0 -> 1138 bytes src/images/grass_side.png | Bin 0 -> 1429 bytes src/images/ice.png | Bin 0 -> 206 bytes src/images/stone_brick.png | Bin 0 -> 860 bytes src/images/stone_brick_light.png | Bin 0 -> 9246 bytes src/images/wordmark.png | Bin 0 -> 36148 bytes src/images/workbench_front.png | Bin 0 -> 801 bytes src/images/workbench_top.png | Bin 0 -> 1012 bytes src/pages/includes/_footer.jade | 33 + src/pages/includes/_google_analytics.jade | 15 + src/pages/includes/_header.jade | 12 + src/pages/index.jade | 15 + src/pages/layouts/basic.jade | 33 + src/pages/test.jade | 20 + src/scripts/constants.coffee | 24 + .../controllers/base_controller.coffee | 77 + .../landing_page_controller.coffee | 25 + .../recipe_catalog_controller.coffee | 16 + src/scripts/crafting_guide_router.coffee | 57 + src/scripts/logger.coffee | 87 + src/scripts/main.coffee | 20 + src/scripts/models/base_model.coffee | 28 + src/scripts/models/item.coffee | 19 + src/scripts/models/landing_page.coffee | 17 + src/scripts/models/parser_versions/v1.coffee | 81 + src/scripts/models/recipe.coffee | 17 + src/scripts/models/recipe_book.coffee | 38 + src/scripts/models/recipe_book_parser.coffee | 26 + src/scripts/models/recipe_catalog.coffee | 54 + src/scripts/views.js | 32 + src/templates/landing_page.jade | 10 + src/templates/recipe_catalog.jade | 19 + src/templates/test.jade | 8 + test/parser_versions/v1.test.coffee | 124 + test/test.coffee | 27 + 95 files changed, 41866 insertions(+), 17 deletions(-) create mode 100644 Gruntfile.coffee create mode 100644 dist/css/main.css create mode 100644 dist/css/main.css.map create mode 100644 dist/css/mocha.css rename {html => dist}/data/applied_energetics.json (100%) rename {html => dist}/data/buildcraft.json (100%) rename {html => dist}/data/gravisuite.json (100%) rename {html => dist}/data/industrial_craft.json (100%) rename {html => dist}/data/more_blocks.json (100%) rename {html => dist}/data/thermal_expansion.json (100%) rename {html => dist}/data/vanilla.json (100%) create mode 100644 dist/fonts/press_start.ttf create mode 100644 dist/images/bedrock.png create mode 100644 dist/images/bookshelf.png create mode 100644 dist/images/dirt.png create mode 100644 dist/images/grass_side.png create mode 100644 dist/images/ice.png create mode 100644 dist/images/stone_brick.png create mode 100644 dist/images/stone_brick_light.png create mode 100644 dist/images/wordmark.png create mode 100644 dist/images/workbench_front.png create mode 100644 dist/images/workbench_top.png create mode 100644 dist/index.html create mode 100644 dist/js/backbone.js create mode 100644 dist/js/chai.js create mode 100644 dist/js/d3.js create mode 100644 dist/js/jade.js create mode 100644 dist/js/jquery.js create mode 100644 dist/js/main.js create mode 100644 dist/js/mocha.js create mode 100644 dist/js/test.js create mode 100644 dist/js/underscore.js create mode 100644 dist/js/views.js create mode 100644 dist/js/when.js create mode 100644 dist/src/css/main.scss create mode 100644 dist/src/css/mixins.scss create mode 100644 dist/src/css/reset.scss create mode 100644 dist/src/css/templates/index.scss create mode 100644 dist/src/css/templates/recipe_books.scss create mode 100644 dist/src/css/templates/recipe_catalog.scss create mode 100644 dist/test.html delete mode 100644 httpd.conf create mode 100644 package.json create mode 100644 src/css/main.scss create mode 100644 src/css/mixins.scss create mode 100644 src/css/reset.scss create mode 100644 src/css/templates/index.scss create mode 100644 src/css/templates/recipe_catalog.scss create mode 100644 src/data/applied_energetics.json create mode 100644 src/data/buildcraft.json create mode 100644 src/data/gravisuite.json create mode 100644 src/data/industrial_craft.json create mode 100644 src/data/more_blocks.json create mode 100644 src/data/thermal_expansion.json create mode 100644 src/data/vanilla.json create mode 100644 src/fonts/press_start.ttf create mode 100755 src/images/bedrock.png create mode 100755 src/images/bookshelf.png create mode 100755 src/images/dirt.png create mode 100755 src/images/grass_side.png create mode 100755 src/images/ice.png create mode 100755 src/images/stone_brick.png create mode 100755 src/images/stone_brick_light.png create mode 100644 src/images/wordmark.png create mode 100755 src/images/workbench_front.png create mode 100755 src/images/workbench_top.png create mode 100644 src/pages/includes/_footer.jade create mode 100644 src/pages/includes/_google_analytics.jade create mode 100644 src/pages/includes/_header.jade create mode 100644 src/pages/index.jade create mode 100644 src/pages/layouts/basic.jade create mode 100644 src/pages/test.jade create mode 100644 src/scripts/constants.coffee create mode 100644 src/scripts/controllers/base_controller.coffee create mode 100644 src/scripts/controllers/landing_page_controller.coffee create mode 100644 src/scripts/controllers/recipe_catalog_controller.coffee create mode 100644 src/scripts/crafting_guide_router.coffee create mode 100644 src/scripts/logger.coffee create mode 100644 src/scripts/main.coffee create mode 100644 src/scripts/models/base_model.coffee create mode 100644 src/scripts/models/item.coffee create mode 100644 src/scripts/models/landing_page.coffee create mode 100644 src/scripts/models/parser_versions/v1.coffee create mode 100644 src/scripts/models/recipe.coffee create mode 100644 src/scripts/models/recipe_book.coffee create mode 100644 src/scripts/models/recipe_book_parser.coffee create mode 100644 src/scripts/models/recipe_catalog.coffee create mode 100644 src/scripts/views.js create mode 100644 src/templates/landing_page.jade create mode 100644 src/templates/recipe_catalog.jade create mode 100644 src/templates/test.jade create mode 100644 test/parser_versions/v1.test.coffee create mode 100644 test/test.coffee diff --git a/.gitignore b/.gitignore index e43b0f988..4f83dfc29 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ .DS_Store +.sass-cache +node_modules diff --git a/Gruntfile.coffee b/Gruntfile.coffee new file mode 100644 index 000000000..7fc0fe10a --- /dev/null +++ b/Gruntfile.coffee @@ -0,0 +1,116 @@ +### +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +######################################################################################################################## + +module.exports = (grunt)-> + + grunt.loadTasks tasks for tasks in grunt.file.expand './node_modules/grunt-*/tasks' + + grunt.config.init + browserify: + main: + options: + ignore: ['jade'] + transform: ['coffeeify'] + browserifyOptions: + debug: false + extensions: ['.coffee'] + files: + './dist/js/main.js': ['./src/scripts/main.coffee'] + test: + options: + transform: ['coffeeify'] + browserifyOptions: + debug: true + extensions: ['.coffee'] + files: + './dist/js/test.js': ['./test/test.coffee'] + when: + options: + browserifyOptions: + debug: false + standalone: 'w' + files: + './dist/js/when.js': ['./node_modules/when/when.js'] + + clean: + dist: ['./dist'] + + copy: + data: + files: [expand:true, cwd:'./src/data', src:'**/*.json', dest:'./dist/data'] + fonts: + files: [expand:true, cwd:'./src/fonts', src:'**/*.ttf', dest:'./dist/fonts'] + images: + files: [expand:true, cwd:'./src/images/', src:['**/*.png', '**/*.jpg'], dest:'./dist/images'] + mocha_styles: + files: + './dist/css/mocha.css': ['./node_modules/mocha/mocha.css'] + scripts: + files: + './dist/js/backbone.js': ['./node_modules/backbone/backbone.js'] + './dist/js/chai.js': ['./node_modules/chai/chai.js'] + './dist/js/jade.js': ['./node_modules/jade/runtime.js'] + './dist/js/jquery.js': ['./node_modules/jquery/dist/jquery.js'] + './dist/js/mocha.js': ['./node_modules/mocha/mocha.js'] + './dist/js/underscore.js': ['./node_modules/backbone/node_modules/underscore/underscore.js'] + styles: + files: [expand:true, cwd:'./src/css', src:'**/*.scss', dest:'./dist/src/css'] + + jade: + pages: + options: + pretty: true + files: [ + expand: true + cwd: './src/pages' + src: '*.jade' + dest: './dist' + ext: '.html' + ] + + templates: + options: + client: true + node: true + pretty: true + processName: (f)-> + f = f.replace './src/templates/', '' + f = f.replace '_view', '' + f = f.replace '.jade', '' + f = f.replace /\//g, '_' + return f + files: + './src/scripts/views.js': ['./src/templates/**/*.jade'] + + sass: + main: + files: + './dist/css/main.css': ['./src/css/main.scss'] + + watch: + fonts: + files: ['./src/fonts/**/*'] + tasks: ['copy:fonts'] + images: + files: ['./src/images/**/*'] + tasks: ['copy:images'] + browserify: + files: ['./src/scripts/**/*.coffee', './test/**/*.coffee'] + tasks: ['browserify'] + pages: + files: ['./src/pages/**/*.jade'] + tasks: ['jade:pages'] + templates: + files: ['./src/templates/**/*.jade'] + tasks: ['jade:templates', 'browserify:main'] + sass: + files: ['./src/css/**/*.scss'] + tasks: ['sass', 'copy:styles'] + + grunt.registerTask 'default', 'build' + + grunt.registerTask 'build', ['copy', 'sass', 'jade', 'browserify'] diff --git a/dist/css/main.css b/dist/css/main.css new file mode 100644 index 000000000..81de61d13 --- /dev/null +++ b/dist/css/main.css @@ -0,0 +1,219 @@ +/* +Crafting Guide - main.scss + +Copyright (c) 2014 by Redwood Labs +All rights reserved. +*/ +/* +Crafting Guide - mixins.scss + +Copyright (c) 2014 by Redwood Labs +All rights reserved. +*/ +a, abbr, acronym, address, applet, article, aside, audio, b, big, blockquote, body, canvas, caption, center, cite, code, dd, del, details, dfn, dialog, div, dl, dt, em, embed, fieldset, figcaption, figure, font, footer, form, h1, h2, h3, h4, h5, h6, header, hgroup, hr, html, i, iframe, img, ins, kbd, label, legend, li, mark, menu, meter, nav, object, ol, output, p, pre, progress, q, rp, rt, ruby, s, samp, section, small, span, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, time, tr, tt, u, ul, var, video, xmp { + border: 0; + margin: 0; + padding: 0; + font-size: 100%; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; } + +html, body { + height: 100%; } + +article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { + display: block; } + +b, strong { + font-weight: bold; } + +img { + color: transparent; + vertical-align: middle; + -ms-interpolation-mode: bicubic; } + +ol, ul { + list-style: none; } + +li { + display: list-item; } + +table { + border-collapse: collapse; + border-spacing: 0; } + +th, td, caption { + font-weight: normal; + vertical-align: top; + text-align: left; } + +q { + quotes: none; } + +q:before, q:after { + content: ''; + content: none; } + +sub, sup, small { + font-size: 75%; } + +sub, sup { + line-height: 0; + position: relative; + vertical-align: baseline; } + +sub { + bottom: -0.25em; } + +sup { + top: -0.5em; } + +svg { + overflow: hidden; } + +@font-face { + font-family: 'PressStart'; + font-style: normal; + font-weight: 400; + src: url("/fonts/press_start.ttf") format("truetype"); } +body { + background: #AAC9FF url("/images/ice.png"); + font-size: 10px; } + +h1 { + margin-bottom: 1em; } + h1 * { + display: inline; } + h1 img { + position: relative; + height: 10em; + width: 10em; + margin-right: 1em; + vertical-align: bottom; } + h1 p { + font-family: PressStart; + font-size: 3em; + position: relative; + top: -0.5em; } + +h2 { + margin-bottom: 1em; } + h2 * { + display: inline; } + h2 img { + position: relative; + height: 7.5em; + width: 7.5em; + margin-right: 1em; + vertical-align: bottom; } + h2 p { + font-family: PressStart; + font-size: 2em; + position: relative; + top: -0.25em; } + +.centered { + text-align: center; } + +.content { + background: rgba(230, 230, 230, 0.9); + box-shadow: 10px 10px 20px #666; + margin: 2em auto; + max-width: 96em; + position: relative; + width: 100%; } + +.view__footer { + background: #3D1D09; + color: white; + margin-top: 2em; } + .view__footer a { + color: white; } + .view__footer .divider { + position: relative; + height: 3.2em; + width: 100%; + clear: both; } + .view__footer .divider.top { + background: #906647 url("/images/grass_side.png"); } + .view__footer .left, .view__footer .center, .view__footer .right { + position: relative; + width: 33%; + float: left; + padding: 2em; } + .view__footer .left p, .view__footer .center p, .view__footer .right p { + font-family: sans-serif; + font-size: 1.25em; + padding-bottom: 1.0em; } + .view__footer .left p:last-child, .view__footer .center p:last-child, .view__footer .right p:last-child { + padding-bottom: 0; } + .view__footer .left h2, .view__footer .center h2, .view__footer .right h2 { + padding-bottom: 1.0em; } + .view__footer .left h2 p, .view__footer .center h2 p, .view__footer .right h2 p { + font-family: PressStart; + font-size: 1.5em; } + .view__footer .divider.bottom { + background: #0A0A0A url("/images/bedrock.png"); } + +.view__header { + background: #D9D9D9 url("/images/stone_brick_light.png"); + position: relative; + height: 10em; + margin: 5em 0 2em 0; } + .view__header h1 { + position: relative; + top: -3em; + left: -3em; } + .view__header .divider { + background: #7A7A7A url("/images/stone_brick.png"); + position: absolute; + bottom: 0; + height: 3.2em; + width: 100%; } + +/* +Crafting Guide - templates/index.scss + +Copyright (c) 2014 by Redwood Labs +All rights reserved. +*/ +/* +Crafting Guide - recipe_books.scss + +Copyright (c) 2014 by Redwood Labs +All rights reserved. +*/ +.view__recipe_catalog { + position: relative; + width: 100%; + padding: 0 2em; } + .view__recipe_catalog button { + position: absolute; + top: 50%; + -moz-transform: translateY(-50%); + -o-transform: translateY(-50%); + -ms-transform: translateY(-50%); + -webkit-transform: translateY(-50%); + transform: translateY(-50%); + position: absolute; + right: 1em; } + .view__recipe_catalog input { + border: 0; + width: 90%; } + .view__recipe_catalog table { + background: white; + margin: 0 auto; + width: 98%; } + .view__recipe_catalog table td { + height: 3em; + padding: 0 1em; + position: relative; + vertical-align: middle; } + .view__recipe_catalog table td:nth-child(1) { + width: 30%; } + .view__recipe_catalog table td:nth-child(2) { + width: 70%; + border-left: 0.1em solid #D9D9D9; } + +/*# sourceMappingURL=main.css.map */ diff --git a/dist/css/main.css.map b/dist/css/main.css.map new file mode 100644 index 000000000..b09c1f4f4 --- /dev/null +++ b/dist/css/main.css.map @@ -0,0 +1,7 @@ +{ +"version": 3, +"mappings": "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", +"sources": ["../../src/css/reset.scss","../../src/css/mixins.scss","../../src/css/main.scss","../../src/css/templates/recipe_catalog.scss"], +"names": [], +"file": "main.css" +} diff --git a/dist/css/mocha.css b/dist/css/mocha.css new file mode 100644 index 000000000..42b9798fa --- /dev/null +++ b/dist/css/mocha.css @@ -0,0 +1,270 @@ +@charset "utf-8"; + +body { + margin:0; +} + +#mocha { + font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; + margin: 60px 50px; +} + +#mocha ul, +#mocha li { + margin: 0; + padding: 0; +} + +#mocha ul { + list-style: none; +} + +#mocha h1, +#mocha h2 { + margin: 0; +} + +#mocha h1 { + margin-top: 15px; + font-size: 1em; + font-weight: 200; +} + +#mocha h1 a { + text-decoration: none; + color: inherit; +} + +#mocha h1 a:hover { + text-decoration: underline; +} + +#mocha .suite .suite h1 { + margin-top: 0; + font-size: .8em; +} + +#mocha .hidden { + display: none; +} + +#mocha h2 { + font-size: 12px; + font-weight: normal; + cursor: pointer; +} + +#mocha .suite { + margin-left: 15px; +} + +#mocha .test { + margin-left: 15px; + overflow: hidden; +} + +#mocha .test.pending:hover h2::after { + content: '(pending)'; + font-family: arial, sans-serif; +} + +#mocha .test.pass.medium .duration { + background: #c09853; +} + +#mocha .test.pass.slow .duration { + background: #b94a48; +} + +#mocha .test.pass::before { + content: '✓'; + font-size: 12px; + display: block; + float: left; + margin-right: 5px; + color: #00d6b2; +} + +#mocha .test.pass .duration { + font-size: 9px; + margin-left: 5px; + padding: 2px 5px; + color: #fff; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); + -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); + box-shadow: inset 0 1px 1px rgba(0,0,0,.2); + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + -ms-border-radius: 5px; + -o-border-radius: 5px; + border-radius: 5px; +} + +#mocha .test.pass.fast .duration { + display: none; +} + +#mocha .test.pending { + color: #0b97c4; +} + +#mocha .test.pending::before { + content: '◦'; + color: #0b97c4; +} + +#mocha .test.fail { + color: #c00; +} + +#mocha .test.fail pre { + color: black; +} + +#mocha .test.fail::before { + content: '✖'; + font-size: 12px; + display: block; + float: left; + margin-right: 5px; + color: #c00; +} + +#mocha .test pre.error { + color: #c00; + max-height: 300px; + overflow: auto; +} + +/** + * (1): approximate for browsers not supporting calc + * (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border) + * ^^ seriously + */ +#mocha .test pre { + display: block; + float: left; + clear: left; + font: 12px/1.5 monaco, monospace; + margin: 5px; + padding: 15px; + border: 1px solid #eee; + max-width: 85%; /*(1)*/ + max-width: calc(100% - 42px); /*(2)*/ + word-wrap: break-word; + border-bottom-color: #ddd; + -webkit-border-radius: 3px; + -webkit-box-shadow: 0 1px 3px #eee; + -moz-border-radius: 3px; + -moz-box-shadow: 0 1px 3px #eee; + border-radius: 3px; +} + +#mocha .test h2 { + position: relative; +} + +#mocha .test a.replay { + position: absolute; + top: 3px; + right: 0; + text-decoration: none; + vertical-align: middle; + display: block; + width: 15px; + height: 15px; + line-height: 15px; + text-align: center; + background: #eee; + font-size: 15px; + -moz-border-radius: 15px; + border-radius: 15px; + -webkit-transition: opacity 200ms; + -moz-transition: opacity 200ms; + transition: opacity 200ms; + opacity: 0.3; + color: #888; +} + +#mocha .test:hover a.replay { + opacity: 1; +} + +#mocha-report.pass .test.fail { + display: none; +} + +#mocha-report.fail .test.pass { + display: none; +} + +#mocha-report.pending .test.pass, +#mocha-report.pending .test.fail { + display: none; +} +#mocha-report.pending .test.pass.pending { + display: block; +} + +#mocha-error { + color: #c00; + font-size: 1.5em; + font-weight: 100; + letter-spacing: 1px; +} + +#mocha-stats { + position: fixed; + top: 15px; + right: 10px; + font-size: 12px; + margin: 0; + color: #888; + z-index: 1; +} + +#mocha-stats .progress { + float: right; + padding-top: 0; +} + +#mocha-stats em { + color: black; +} + +#mocha-stats a { + text-decoration: none; + color: inherit; +} + +#mocha-stats a:hover { + border-bottom: 1px solid #eee; +} + +#mocha-stats li { + display: inline-block; + margin: 0 5px; + list-style: none; + padding-top: 11px; +} + +#mocha-stats canvas { + width: 40px; + height: 40px; +} + +#mocha code .comment { color: #ddd; } +#mocha code .init { color: #2f6fad; } +#mocha code .string { color: #5890ad; } +#mocha code .keyword { color: #8a6343; } +#mocha code .number { color: #2f6fad; } + +@media screen and (max-device-width: 480px) { + #mocha { + margin: 60px 0px; + } + + #mocha #stats { + position: absolute; + } +} diff --git a/html/data/applied_energetics.json b/dist/data/applied_energetics.json similarity index 100% rename from html/data/applied_energetics.json rename to dist/data/applied_energetics.json diff --git a/html/data/buildcraft.json b/dist/data/buildcraft.json similarity index 100% rename from html/data/buildcraft.json rename to dist/data/buildcraft.json diff --git a/html/data/gravisuite.json b/dist/data/gravisuite.json similarity index 100% rename from html/data/gravisuite.json rename to dist/data/gravisuite.json diff --git a/html/data/industrial_craft.json b/dist/data/industrial_craft.json similarity index 100% rename from html/data/industrial_craft.json rename to dist/data/industrial_craft.json diff --git a/html/data/more_blocks.json b/dist/data/more_blocks.json similarity index 100% rename from html/data/more_blocks.json rename to dist/data/more_blocks.json diff --git a/html/data/thermal_expansion.json b/dist/data/thermal_expansion.json similarity index 100% rename from html/data/thermal_expansion.json rename to dist/data/thermal_expansion.json diff --git a/html/data/vanilla.json b/dist/data/vanilla.json similarity index 100% rename from html/data/vanilla.json rename to dist/data/vanilla.json diff --git a/dist/fonts/press_start.ttf b/dist/fonts/press_start.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1efa15873077927f8a92ef926b318d520b806bc8 GIT binary patch literal 24708 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 literal 0 HcmV?d00001 diff --git a/dist/images/bedrock.png b/dist/images/bedrock.png new file mode 100644 index 0000000000000000000000000000000000000000..79ac81cb978eb87dd5a90952ea98539326bc6889 GIT binary patch literal 1398 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?3oVGw3ym^DX&fq^M6 zGbExU!q>+tIX_n~F(p4KRj(qq0H~UQ!KT6r$jnVGNmQuF&B-gas<2f8tFQvHLBje< z3ScEA*|tg%z5xo(`9-M;rh0~YMoM;E3JMA~MJZ`kK`w4k?LeNbQbtKhft9{~d3m{B zxv^e;QM$gNrKP35fswwEkuFe$ZgFK^Nn(X=Ua>O75STeGsl~}fnFS@8`FRQ;a}$&D zOG|8(lt3220o0wj1#pYQf&C3K6-}IwlS?ww5P^f@W{?b~qd}rp z&iT0oMXALgciNfS=wpZ>g2o0c7a5dVoS#z)3PL+`Bd7*sL39lf*fbyu;td8!-~i*_ zjtdxou(V{y^+xMKGce_?^K@|xiQrs2&2iEr10L7LS+ePmwBA?>R_S&2L8ipq} zCSQ()i>b2)wiX*kztAa=f3W=OjEL4R>DEG9W(ewKYw)cTJ)puIk*~=#r?uxur}2># z-tHUipHDU|I2V5FS8qp(%jOmTbePh%2>x#Q5pKJHqm$>lz_X-JZkr@5OV6Hr+4zm+ z_Ek@3yb638%TjPv*>TG~-gDnMHkw`D^x??831v^$ zvKL%o(z>x^=2<6Wp1O*Ir|wrb?2f#9KHo=GEwL~^O7ESj(XUwR|0%`s7X7h&l~0Al zUr%4a$+k)~e67Xbbz6TuTrYLxAIpZj`^z7j&hcB`@xJW)@4YuY^2)v_vCp%~@_#ym z*YDiCRU+aniFyZGqF5?JBlzB~nQ+h8al@~7A6XA>5Z9P-{D=9pJ*%$QcNhigC9IA( zcQWS8(-n`_EZ@&O@y7nh=MnBI)^E$o?#ND1`*!PL@T79l-5D=A(hGk-7WTiC7yQBI z@A`!dEh1OVH;E-OCb-!Z-)+dwv2OKv)hoDf{jBbo;%%QU@JrsVZs?Mbd-_7;&QXnT zr~XxTA62$%sb_e9a}~p%#Y#qs5}q@k2NoX7vATZi<^B`~4VQ(1UnfOuc&!!o_`#D{ z5eH|@DYLzklGpTJmklr6D5{>W?{Iv(neb-qt}Qzx!|!o$uGMC~WBn`sS)j-Nqo;p< zcwRbh^5uULg*iX>y-& l^nB80C$~dSc2+;GXI%VAL)%C(+89(adb;|#taD0e0sxt`F!ule literal 0 HcmV?d00001 diff --git a/dist/images/bookshelf.png b/dist/images/bookshelf.png new file mode 100644 index 0000000000000000000000000000000000000000..896c30e19014a861572f279173219b586d1a79f9 GIT binary patch literal 610 zcmV-o0-gPdP)) zZvEd*@5u`<*Ie?N2IKHeQ*w9jlY1|B7wJ9Mz)4>ZJJzqfSD#6>8*6`TKz3$I2=Co=)-vF@nSjIFI8;w2ZN57Gs*M1^w{QaB0#X2V@j)d3FclcMmrlcH zDh2P!Bs>}h6f!BH#oZRrYCvZF!Vy5)s-kvIHva=ao&gFV1M31%a2-%v2D;rY zbUGbqx7%QvCK#0#0XT4Khw&13`w+jXintcQ!Dc=b0JOu;l|2I-K&4WFa=8qp zQVEL1qRmg;1`0r5P^|g0HhTti0q{+nvY-Rt`V|BXK(_$b#2OTM2Bg0ZfUgX2m5}=D z0EjanOK}(gVhe)Kfc&qW0sI!FuqNnA^&2DxwU4O1*-hNM;AVqzn+WZUs*l$gygkL><$fH@>nPjK9S0Jph5rmdW`GOK zbvrKrZk}K>&@4pZCO-z}xnCV+M`3S%#1jC&cc*59erQhtWPPy!@G}Vuz^VfnNEZMD zVxS-Zta)IN3`hW3Ze=<4y#<4w0Sf(L@Y^691fT6Y^2!OtM wK-Fb!MF@Mi{FV3WGj#^w=7QDbS#~b?2A&CuK34i}>Hq)$07*qoM6N<$f?!1f4gdfE literal 0 HcmV?d00001 diff --git a/dist/images/dirt.png b/dist/images/dirt.png new file mode 100644 index 0000000000000000000000000000000000000000..28f300b8a51295e27d31e765edb8f41961fc1d40 GIT binary patch literal 1138 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 Nv9z@){_W1g{{Y*m{?Gsb literal 0 HcmV?d00001 diff --git a/dist/images/wordmark.png b/dist/images/wordmark.png new file mode 100644 index 0000000000000000000000000000000000000000..e538238ed2b023813ab3c665abfbb733c1a3e654 GIT binary patch literal 36148 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 b_PCh@%^P2fN529W-f~^DxN*74+&%GM%~qQ} literal 0 HcmV?d00001 diff --git a/dist/images/workbench_front.png b/dist/images/workbench_front.png new file mode 100644 index 0000000000000000000000000000000000000000..ec3ba9bf82299c99117c8cf5a4762635b3213af8 GIT binary patch literal 801 zcmV++1K#|JP)Y`~h7`H(m7~Bs+gd z{>_vVIKz2o?wc7GC-aeaKi)m}-Fv6=cw@Er{`p{ui?df*3|~GfX20H-I3I2$(EqTO zI_m)29sIz+?Vk_DzrT}WcKx-)k8k7h{_^7}aU$mc)<7R*pp#I&K;i%%U>r~(hejfD z0RO>JHI&l}U7-U_z*-n`2N?GM(UUk(xAVK7#|b@*gc>J}3Q~A8J*-3}%z=n|;P;o; ziDHdJ6n2+&`BoHA0e7#Uf+w46OX%)l3>(0@-F`QL+DRhtcK>NH{WMAdCGQTNmG_R5 z@$=FF-19wU+&BSSl&_6|@0^@+r;r(Jub0Wkh>>sKwLgbBpon-^YQQ@kz`e`C76Vo||-K96%iIiwpvR2^>=OwEQ7?!n@MgkeNO|1^oPa@h zAdCRdvDN`P;PrvX)d5|Dn&1v_ZKV$QG4u#H1#HjS2O_FkdO42~d@Q02W~X%tjXatxW7fbymAql#yBAR0mlMuB?5Q{b%< zK%(I45uk#8uUj6&+$_P$s1$^~AlJ`n%z1_k9cY>dKv^vXb@M=7A$s^=r7{mhWgDfr zu@3kw5S?qU19X7$(cHj#fGZr}?9n(6 zSx*!}6h?V6F(?W+!y+oo0HZKy09gzu8NdY;gDerj7^8xWAVI}nVKCx@@kIpD7-L)@ z>Vto-o$rocal5)}226Z7Nq2R1-P2XKmM*9`w9nHN748x2@`}0PUc6wE*C{AOh3<4LJqyGJ8M^aC|9%YYEPGatL6ZFiCi~_qch0N^9wEBY-d0 z$<$jHF~RYib4=!0V~)1&5o>#(a;!1uEAN=<|V$#z-g#ABRvg~G`bhCw1y=iR?CfBrv<$nQ{clw%6D9Y zfH{)c+c5>u00guI1?;ib0zjW1kOL6VyCGs40sBCr_W}$B;5|<~uD!tCE0E0gcAShy zC8k-5c`Akk<~%C%^lBf~fqrHaR#yukI8Vg^0Z@0e*hm0$9dI2s-_CXk8*@DZ%Ws$oeyfM;qryOD iECKIb*uUwn-}yg6FE#D)LXC_70000 + + + Crafting Guide + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dist/js/backbone.js b/dist/js/backbone.js new file mode 100644 index 000000000..24a550a0a --- /dev/null +++ b/dist/js/backbone.js @@ -0,0 +1,1608 @@ +// Backbone.js 1.1.2 + +// (c) 2010-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors +// Backbone may be freely distributed under the MIT license. +// For all details and documentation: +// http://backbonejs.org + +(function(root, factory) { + + // Set up Backbone appropriately for the environment. Start with AMD. + if (typeof define === 'function' && define.amd) { + define(['underscore', 'jquery', 'exports'], function(_, $, exports) { + // Export global even in AMD case in case this script is loaded with + // others that may still expect a global Backbone. + root.Backbone = factory(root, exports, _, $); + }); + + // Next for Node.js or CommonJS. jQuery may not be needed as a module. + } else if (typeof exports !== 'undefined') { + var _ = require('underscore'); + factory(root, exports, _); + + // Finally, as a browser global. + } else { + root.Backbone = factory(root, {}, root._, (root.jQuery || root.Zepto || root.ender || root.$)); + } + +}(this, function(root, Backbone, _, $) { + + // Initial Setup + // ------------- + + // Save the previous value of the `Backbone` variable, so that it can be + // restored later on, if `noConflict` is used. + var previousBackbone = root.Backbone; + + // Create local references to array methods we'll want to use later. + var array = []; + var push = array.push; + var slice = array.slice; + var splice = array.splice; + + // Current version of the library. Keep in sync with `package.json`. + Backbone.VERSION = '1.1.2'; + + // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns + // the `$` variable. + Backbone.$ = $; + + // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable + // to its previous owner. Returns a reference to this Backbone object. + Backbone.noConflict = function() { + root.Backbone = previousBackbone; + return this; + }; + + // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option + // will fake `"PATCH"`, `"PUT"` and `"DELETE"` requests via the `_method` parameter and + // set a `X-Http-Method-Override` header. + Backbone.emulateHTTP = false; + + // Turn on `emulateJSON` to support legacy servers that can't deal with direct + // `application/json` requests ... will encode the body as + // `application/x-www-form-urlencoded` instead and will send the model in a + // form param named `model`. + Backbone.emulateJSON = false; + + // Backbone.Events + // --------------- + + // A module that can be mixed in to *any object* in order to provide it with + // custom events. You may bind with `on` or remove with `off` callback + // functions to an event; `trigger`-ing an event fires all callbacks in + // succession. + // + // var object = {}; + // _.extend(object, Backbone.Events); + // object.on('expand', function(){ alert('expanded'); }); + // object.trigger('expand'); + // + var Events = Backbone.Events = { + + // Bind an event to a `callback` function. Passing `"all"` will bind + // the callback to all events fired. + on: function(name, callback, context) { + if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this; + this._events || (this._events = {}); + var events = this._events[name] || (this._events[name] = []); + events.push({callback: callback, context: context, ctx: context || this}); + return this; + }, + + // Bind an event to only be triggered a single time. After the first time + // the callback is invoked, it will be removed. + once: function(name, callback, context) { + if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this; + var self = this; + var once = _.once(function() { + self.off(name, once); + callback.apply(this, arguments); + }); + once._callback = callback; + return this.on(name, once, context); + }, + + // Remove one or many callbacks. If `context` is null, removes all + // callbacks with that function. If `callback` is null, removes all + // callbacks for the event. If `name` is null, removes all bound + // callbacks for all events. + off: function(name, callback, context) { + var retain, ev, events, names, i, l, j, k; + if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this; + if (!name && !callback && !context) { + this._events = void 0; + return this; + } + names = name ? [name] : _.keys(this._events); + for (i = 0, l = names.length; i < l; i++) { + name = names[i]; + if (events = this._events[name]) { + this._events[name] = retain = []; + if (callback || context) { + for (j = 0, k = events.length; j < k; j++) { + ev = events[j]; + if ((callback && callback !== ev.callback && callback !== ev.callback._callback) || + (context && context !== ev.context)) { + retain.push(ev); + } + } + } + if (!retain.length) delete this._events[name]; + } + } + + return this; + }, + + // Trigger one or many events, firing all bound callbacks. Callbacks are + // passed the same arguments as `trigger` is, apart from the event name + // (unless you're listening on `"all"`, which will cause your callback to + // receive the true name of the event as the first argument). + trigger: function(name) { + if (!this._events) return this; + var args = slice.call(arguments, 1); + if (!eventsApi(this, 'trigger', name, args)) return this; + var events = this._events[name]; + var allEvents = this._events.all; + if (events) triggerEvents(events, args); + if (allEvents) triggerEvents(allEvents, arguments); + return this; + }, + + // Tell this object to stop listening to either specific events ... or + // to every object it's currently listening to. + stopListening: function(obj, name, callback) { + var listeningTo = this._listeningTo; + if (!listeningTo) return this; + var remove = !name && !callback; + if (!callback && typeof name === 'object') callback = this; + if (obj) (listeningTo = {})[obj._listenId] = obj; + for (var id in listeningTo) { + obj = listeningTo[id]; + obj.off(name, callback, this); + if (remove || _.isEmpty(obj._events)) delete this._listeningTo[id]; + } + return this; + } + + }; + + // Regular expression used to split event strings. + var eventSplitter = /\s+/; + + // Implement fancy features of the Events API such as multiple event + // names `"change blur"` and jQuery-style event maps `{change: action}` + // in terms of the existing API. + var eventsApi = function(obj, action, name, rest) { + if (!name) return true; + + // Handle event maps. + if (typeof name === 'object') { + for (var key in name) { + obj[action].apply(obj, [key, name[key]].concat(rest)); + } + return false; + } + + // Handle space separated event names. + if (eventSplitter.test(name)) { + var names = name.split(eventSplitter); + for (var i = 0, l = names.length; i < l; i++) { + obj[action].apply(obj, [names[i]].concat(rest)); + } + return false; + } + + return true; + }; + + // A difficult-to-believe, but optimized internal dispatch function for + // triggering events. Tries to keep the usual cases speedy (most internal + // Backbone events have 3 arguments). + var triggerEvents = function(events, args) { + var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2]; + switch (args.length) { + case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return; + case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return; + case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return; + case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return; + default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return; + } + }; + + var listenMethods = {listenTo: 'on', listenToOnce: 'once'}; + + // Inversion-of-control versions of `on` and `once`. Tell *this* object to + // listen to an event in another object ... keeping track of what it's + // listening to. + _.each(listenMethods, function(implementation, method) { + Events[method] = function(obj, name, callback) { + var listeningTo = this._listeningTo || (this._listeningTo = {}); + var id = obj._listenId || (obj._listenId = _.uniqueId('l')); + listeningTo[id] = obj; + if (!callback && typeof name === 'object') callback = this; + obj[implementation](name, callback, this); + return this; + }; + }); + + // Aliases for backwards compatibility. + Events.bind = Events.on; + Events.unbind = Events.off; + + // Allow the `Backbone` object to serve as a global event bus, for folks who + // want global "pubsub" in a convenient place. + _.extend(Backbone, Events); + + // Backbone.Model + // -------------- + + // Backbone **Models** are the basic data object in the framework -- + // frequently representing a row in a table in a database on your server. + // A discrete chunk of data and a bunch of useful, related methods for + // performing computations and transformations on that data. + + // Create a new model with the specified attributes. A client id (`cid`) + // is automatically generated and assigned for you. + var Model = Backbone.Model = function(attributes, options) { + var attrs = attributes || {}; + options || (options = {}); + this.cid = _.uniqueId('c'); + this.attributes = {}; + if (options.collection) this.collection = options.collection; + if (options.parse) attrs = this.parse(attrs, options) || {}; + attrs = _.defaults({}, attrs, _.result(this, 'defaults')); + this.set(attrs, options); + this.changed = {}; + this.initialize.apply(this, arguments); + }; + + // Attach all inheritable methods to the Model prototype. + _.extend(Model.prototype, Events, { + + // A hash of attributes whose current and previous value differ. + changed: null, + + // The value returned during the last failed validation. + validationError: null, + + // The default name for the JSON `id` attribute is `"id"`. MongoDB and + // CouchDB users may want to set this to `"_id"`. + idAttribute: 'id', + + // Initialize is an empty function by default. Override it with your own + // initialization logic. + initialize: function(){}, + + // Return a copy of the model's `attributes` object. + toJSON: function(options) { + return _.clone(this.attributes); + }, + + // Proxy `Backbone.sync` by default -- but override this if you need + // custom syncing semantics for *this* particular model. + sync: function() { + return Backbone.sync.apply(this, arguments); + }, + + // Get the value of an attribute. + get: function(attr) { + return this.attributes[attr]; + }, + + // Get the HTML-escaped value of an attribute. + escape: function(attr) { + return _.escape(this.get(attr)); + }, + + // Returns `true` if the attribute contains a value that is not null + // or undefined. + has: function(attr) { + return this.get(attr) != null; + }, + + // Set a hash of model attributes on the object, firing `"change"`. This is + // the core primitive operation of a model, updating the data and notifying + // anyone who needs to know about the change in state. The heart of the beast. + set: function(key, val, options) { + var attr, attrs, unset, changes, silent, changing, prev, current; + if (key == null) return this; + + // Handle both `"key", value` and `{key: value}` -style arguments. + if (typeof key === 'object') { + attrs = key; + options = val; + } else { + (attrs = {})[key] = val; + } + + options || (options = {}); + + // Run validation. + if (!this._validate(attrs, options)) return false; + + // Extract attributes and options. + unset = options.unset; + silent = options.silent; + changes = []; + changing = this._changing; + this._changing = true; + + if (!changing) { + this._previousAttributes = _.clone(this.attributes); + this.changed = {}; + } + current = this.attributes, prev = this._previousAttributes; + + // Check for changes of `id`. + if (this.idAttribute in attrs) this.id = attrs[this.idAttribute]; + + // For each `set` attribute, update or delete the current value. + for (attr in attrs) { + val = attrs[attr]; + if (!_.isEqual(current[attr], val)) changes.push(attr); + if (!_.isEqual(prev[attr], val)) { + this.changed[attr] = val; + } else { + delete this.changed[attr]; + } + unset ? delete current[attr] : current[attr] = val; + } + + // Trigger all relevant attribute changes. + if (!silent) { + if (changes.length) this._pending = options; + for (var i = 0, l = changes.length; i < l; i++) { + this.trigger('change:' + changes[i], this, current[changes[i]], options); + } + } + + // You might be wondering why there's a `while` loop here. Changes can + // be recursively nested within `"change"` events. + if (changing) return this; + if (!silent) { + while (this._pending) { + options = this._pending; + this._pending = false; + this.trigger('change', this, options); + } + } + this._pending = false; + this._changing = false; + return this; + }, + + // Remove an attribute from the model, firing `"change"`. `unset` is a noop + // if the attribute doesn't exist. + unset: function(attr, options) { + return this.set(attr, void 0, _.extend({}, options, {unset: true})); + }, + + // Clear all attributes on the model, firing `"change"`. + clear: function(options) { + var attrs = {}; + for (var key in this.attributes) attrs[key] = void 0; + return this.set(attrs, _.extend({}, options, {unset: true})); + }, + + // Determine if the model has changed since the last `"change"` event. + // If you specify an attribute name, determine if that attribute has changed. + hasChanged: function(attr) { + if (attr == null) return !_.isEmpty(this.changed); + return _.has(this.changed, attr); + }, + + // Return an object containing all the attributes that have changed, or + // false if there are no changed attributes. Useful for determining what + // parts of a view need to be updated and/or what attributes need to be + // persisted to the server. Unset attributes will be set to undefined. + // You can also pass an attributes object to diff against the model, + // determining if there *would be* a change. + changedAttributes: function(diff) { + if (!diff) return this.hasChanged() ? _.clone(this.changed) : false; + var val, changed = false; + var old = this._changing ? this._previousAttributes : this.attributes; + for (var attr in diff) { + if (_.isEqual(old[attr], (val = diff[attr]))) continue; + (changed || (changed = {}))[attr] = val; + } + return changed; + }, + + // Get the previous value of an attribute, recorded at the time the last + // `"change"` event was fired. + previous: function(attr) { + if (attr == null || !this._previousAttributes) return null; + return this._previousAttributes[attr]; + }, + + // Get all of the attributes of the model at the time of the previous + // `"change"` event. + previousAttributes: function() { + return _.clone(this._previousAttributes); + }, + + // Fetch the model from the server. If the server's representation of the + // model differs from its current attributes, they will be overridden, + // triggering a `"change"` event. + fetch: function(options) { + options = options ? _.clone(options) : {}; + if (options.parse === void 0) options.parse = true; + var model = this; + var success = options.success; + options.success = function(resp) { + if (!model.set(model.parse(resp, options), options)) return false; + if (success) success(model, resp, options); + model.trigger('sync', model, resp, options); + }; + wrapError(this, options); + return this.sync('read', this, options); + }, + + // Set a hash of model attributes, and sync the model to the server. + // If the server returns an attributes hash that differs, the model's + // state will be `set` again. + save: function(key, val, options) { + var attrs, method, xhr, attributes = this.attributes; + + // Handle both `"key", value` and `{key: value}` -style arguments. + if (key == null || typeof key === 'object') { + attrs = key; + options = val; + } else { + (attrs = {})[key] = val; + } + + options = _.extend({validate: true}, options); + + // If we're not waiting and attributes exist, save acts as + // `set(attr).save(null, opts)` with validation. Otherwise, check if + // the model will be valid when the attributes, if any, are set. + if (attrs && !options.wait) { + if (!this.set(attrs, options)) return false; + } else { + if (!this._validate(attrs, options)) return false; + } + + // Set temporary attributes if `{wait: true}`. + if (attrs && options.wait) { + this.attributes = _.extend({}, attributes, attrs); + } + + // After a successful server-side save, the client is (optionally) + // updated with the server-side state. + if (options.parse === void 0) options.parse = true; + var model = this; + var success = options.success; + options.success = function(resp) { + // Ensure attributes are restored during synchronous saves. + model.attributes = attributes; + var serverAttrs = model.parse(resp, options); + if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs); + if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) { + return false; + } + if (success) success(model, resp, options); + model.trigger('sync', model, resp, options); + }; + wrapError(this, options); + + method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update'); + if (method === 'patch') options.attrs = attrs; + xhr = this.sync(method, this, options); + + // Restore attributes. + if (attrs && options.wait) this.attributes = attributes; + + return xhr; + }, + + // Destroy this model on the server if it was already persisted. + // Optimistically removes the model from its collection, if it has one. + // If `wait: true` is passed, waits for the server to respond before removal. + destroy: function(options) { + options = options ? _.clone(options) : {}; + var model = this; + var success = options.success; + + var destroy = function() { + model.trigger('destroy', model, model.collection, options); + }; + + options.success = function(resp) { + if (options.wait || model.isNew()) destroy(); + if (success) success(model, resp, options); + if (!model.isNew()) model.trigger('sync', model, resp, options); + }; + + if (this.isNew()) { + options.success(); + return false; + } + wrapError(this, options); + + var xhr = this.sync('delete', this, options); + if (!options.wait) destroy(); + return xhr; + }, + + // Default URL for the model's representation on the server -- if you're + // using Backbone's restful methods, override this to change the endpoint + // that will be called. + url: function() { + var base = + _.result(this, 'urlRoot') || + _.result(this.collection, 'url') || + urlError(); + if (this.isNew()) return base; + return base.replace(/([^\/])$/, '$1/') + encodeURIComponent(this.id); + }, + + // **parse** converts a response into the hash of attributes to be `set` on + // the model. The default implementation is just to pass the response along. + parse: function(resp, options) { + return resp; + }, + + // Create a new model with identical attributes to this one. + clone: function() { + return new this.constructor(this.attributes); + }, + + // A model is new if it has never been saved to the server, and lacks an id. + isNew: function() { + return !this.has(this.idAttribute); + }, + + // Check if the model is currently in a valid state. + isValid: function(options) { + return this._validate({}, _.extend(options || {}, { validate: true })); + }, + + // Run validation against the next complete set of model attributes, + // returning `true` if all is well. Otherwise, fire an `"invalid"` event. + _validate: function(attrs, options) { + if (!options.validate || !this.validate) return true; + attrs = _.extend({}, this.attributes, attrs); + var error = this.validationError = this.validate(attrs, options) || null; + if (!error) return true; + this.trigger('invalid', this, error, _.extend(options, {validationError: error})); + return false; + } + + }); + + // Underscore methods that we want to implement on the Model. + var modelMethods = ['keys', 'values', 'pairs', 'invert', 'pick', 'omit']; + + // Mix in each Underscore method as a proxy to `Model#attributes`. + _.each(modelMethods, function(method) { + Model.prototype[method] = function() { + var args = slice.call(arguments); + args.unshift(this.attributes); + return _[method].apply(_, args); + }; + }); + + // Backbone.Collection + // ------------------- + + // If models tend to represent a single row of data, a Backbone Collection is + // more analagous to a table full of data ... or a small slice or page of that + // table, or a collection of rows that belong together for a particular reason + // -- all of the messages in this particular folder, all of the documents + // belonging to this particular author, and so on. Collections maintain + // indexes of their models, both in order, and for lookup by `id`. + + // Create a new **Collection**, perhaps to contain a specific type of `model`. + // If a `comparator` is specified, the Collection will maintain + // its models in sort order, as they're added and removed. + var Collection = Backbone.Collection = function(models, options) { + options || (options = {}); + if (options.model) this.model = options.model; + if (options.comparator !== void 0) this.comparator = options.comparator; + this._reset(); + this.initialize.apply(this, arguments); + if (models) this.reset(models, _.extend({silent: true}, options)); + }; + + // Default options for `Collection#set`. + var setOptions = {add: true, remove: true, merge: true}; + var addOptions = {add: true, remove: false}; + + // Define the Collection's inheritable methods. + _.extend(Collection.prototype, Events, { + + // The default model for a collection is just a **Backbone.Model**. + // This should be overridden in most cases. + model: Model, + + // Initialize is an empty function by default. Override it with your own + // initialization logic. + initialize: function(){}, + + // The JSON representation of a Collection is an array of the + // models' attributes. + toJSON: function(options) { + return this.map(function(model){ return model.toJSON(options); }); + }, + + // Proxy `Backbone.sync` by default. + sync: function() { + return Backbone.sync.apply(this, arguments); + }, + + // Add a model, or list of models to the set. + add: function(models, options) { + return this.set(models, _.extend({merge: false}, options, addOptions)); + }, + + // Remove a model, or a list of models from the set. + remove: function(models, options) { + var singular = !_.isArray(models); + models = singular ? [models] : _.clone(models); + options || (options = {}); + var i, l, index, model; + for (i = 0, l = models.length; i < l; i++) { + model = models[i] = this.get(models[i]); + if (!model) continue; + delete this._byId[model.id]; + delete this._byId[model.cid]; + index = this.indexOf(model); + this.models.splice(index, 1); + this.length--; + if (!options.silent) { + options.index = index; + model.trigger('remove', model, this, options); + } + this._removeReference(model, options); + } + return singular ? models[0] : models; + }, + + // Update a collection by `set`-ing a new list of models, adding new ones, + // removing models that are no longer present, and merging models that + // already exist in the collection, as necessary. Similar to **Model#set**, + // the core operation for updating the data contained by the collection. + set: function(models, options) { + options = _.defaults({}, options, setOptions); + if (options.parse) models = this.parse(models, options); + var singular = !_.isArray(models); + models = singular ? (models ? [models] : []) : _.clone(models); + var i, l, id, model, attrs, existing, sort; + var at = options.at; + var targetModel = this.model; + var sortable = this.comparator && (at == null) && options.sort !== false; + var sortAttr = _.isString(this.comparator) ? this.comparator : null; + var toAdd = [], toRemove = [], modelMap = {}; + var add = options.add, merge = options.merge, remove = options.remove; + var order = !sortable && add && remove ? [] : false; + + // Turn bare objects into model references, and prevent invalid models + // from being added. + for (i = 0, l = models.length; i < l; i++) { + attrs = models[i] || {}; + if (attrs instanceof Model) { + id = model = attrs; + } else { + id = attrs[targetModel.prototype.idAttribute || 'id']; + } + + // If a duplicate is found, prevent it from being added and + // optionally merge it into the existing model. + if (existing = this.get(id)) { + if (remove) modelMap[existing.cid] = true; + if (merge) { + attrs = attrs === model ? model.attributes : attrs; + if (options.parse) attrs = existing.parse(attrs, options); + existing.set(attrs, options); + if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true; + } + models[i] = existing; + + // If this is a new, valid model, push it to the `toAdd` list. + } else if (add) { + model = models[i] = this._prepareModel(attrs, options); + if (!model) continue; + toAdd.push(model); + this._addReference(model, options); + } + + // Do not add multiple models with the same `id`. + model = existing || model; + if (order && (model.isNew() || !modelMap[model.id])) order.push(model); + modelMap[model.id] = true; + } + + // Remove nonexistent models if appropriate. + if (remove) { + for (i = 0, l = this.length; i < l; ++i) { + if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model); + } + if (toRemove.length) this.remove(toRemove, options); + } + + // See if sorting is needed, update `length` and splice in new models. + if (toAdd.length || (order && order.length)) { + if (sortable) sort = true; + this.length += toAdd.length; + if (at != null) { + for (i = 0, l = toAdd.length; i < l; i++) { + this.models.splice(at + i, 0, toAdd[i]); + } + } else { + if (order) this.models.length = 0; + var orderedModels = order || toAdd; + for (i = 0, l = orderedModels.length; i < l; i++) { + this.models.push(orderedModels[i]); + } + } + } + + // Silently sort the collection if appropriate. + if (sort) this.sort({silent: true}); + + // Unless silenced, it's time to fire all appropriate add/sort events. + if (!options.silent) { + for (i = 0, l = toAdd.length; i < l; i++) { + (model = toAdd[i]).trigger('add', model, this, options); + } + if (sort || (order && order.length)) this.trigger('sort', this, options); + } + + // Return the added (or merged) model (or models). + return singular ? models[0] : models; + }, + + // When you have more items than you want to add or remove individually, + // you can reset the entire set with a new list of models, without firing + // any granular `add` or `remove` events. Fires `reset` when finished. + // Useful for bulk operations and optimizations. + reset: function(models, options) { + options || (options = {}); + for (var i = 0, l = this.models.length; i < l; i++) { + this._removeReference(this.models[i], options); + } + options.previousModels = this.models; + this._reset(); + models = this.add(models, _.extend({silent: true}, options)); + if (!options.silent) this.trigger('reset', this, options); + return models; + }, + + // Add a model to the end of the collection. + push: function(model, options) { + return this.add(model, _.extend({at: this.length}, options)); + }, + + // Remove a model from the end of the collection. + pop: function(options) { + var model = this.at(this.length - 1); + this.remove(model, options); + return model; + }, + + // Add a model to the beginning of the collection. + unshift: function(model, options) { + return this.add(model, _.extend({at: 0}, options)); + }, + + // Remove a model from the beginning of the collection. + shift: function(options) { + var model = this.at(0); + this.remove(model, options); + return model; + }, + + // Slice out a sub-array of models from the collection. + slice: function() { + return slice.apply(this.models, arguments); + }, + + // Get a model from the set by id. + get: function(obj) { + if (obj == null) return void 0; + return this._byId[obj] || this._byId[obj.id] || this._byId[obj.cid]; + }, + + // Get the model at the given index. + at: function(index) { + return this.models[index]; + }, + + // Return models with matching attributes. Useful for simple cases of + // `filter`. + where: function(attrs, first) { + if (_.isEmpty(attrs)) return first ? void 0 : []; + return this[first ? 'find' : 'filter'](function(model) { + for (var key in attrs) { + if (attrs[key] !== model.get(key)) return false; + } + return true; + }); + }, + + // Return the first model with matching attributes. Useful for simple cases + // of `find`. + findWhere: function(attrs) { + return this.where(attrs, true); + }, + + // Force the collection to re-sort itself. You don't need to call this under + // normal circumstances, as the set will maintain sort order as each item + // is added. + sort: function(options) { + if (!this.comparator) throw new Error('Cannot sort a set without a comparator'); + options || (options = {}); + + // Run sort based on type of `comparator`. + if (_.isString(this.comparator) || this.comparator.length === 1) { + this.models = this.sortBy(this.comparator, this); + } else { + this.models.sort(_.bind(this.comparator, this)); + } + + if (!options.silent) this.trigger('sort', this, options); + return this; + }, + + // Pluck an attribute from each model in the collection. + pluck: function(attr) { + return _.invoke(this.models, 'get', attr); + }, + + // Fetch the default set of models for this collection, resetting the + // collection when they arrive. If `reset: true` is passed, the response + // data will be passed through the `reset` method instead of `set`. + fetch: function(options) { + options = options ? _.clone(options) : {}; + if (options.parse === void 0) options.parse = true; + var success = options.success; + var collection = this; + options.success = function(resp) { + var method = options.reset ? 'reset' : 'set'; + collection[method](resp, options); + if (success) success(collection, resp, options); + collection.trigger('sync', collection, resp, options); + }; + wrapError(this, options); + return this.sync('read', this, options); + }, + + // Create a new instance of a model in this collection. Add the model to the + // collection immediately, unless `wait: true` is passed, in which case we + // wait for the server to agree. + create: function(model, options) { + options = options ? _.clone(options) : {}; + if (!(model = this._prepareModel(model, options))) return false; + if (!options.wait) this.add(model, options); + var collection = this; + var success = options.success; + options.success = function(model, resp) { + if (options.wait) collection.add(model, options); + if (success) success(model, resp, options); + }; + model.save(null, options); + return model; + }, + + // **parse** converts a response into a list of models to be added to the + // collection. The default implementation is just to pass it through. + parse: function(resp, options) { + return resp; + }, + + // Create a new collection with an identical list of models as this one. + clone: function() { + return new this.constructor(this.models); + }, + + // Private method to reset all internal state. Called when the collection + // is first initialized or reset. + _reset: function() { + this.length = 0; + this.models = []; + this._byId = {}; + }, + + // Prepare a hash of attributes (or other model) to be added to this + // collection. + _prepareModel: function(attrs, options) { + if (attrs instanceof Model) return attrs; + options = options ? _.clone(options) : {}; + options.collection = this; + var model = new this.model(attrs, options); + if (!model.validationError) return model; + this.trigger('invalid', this, model.validationError, options); + return false; + }, + + // Internal method to create a model's ties to a collection. + _addReference: function(model, options) { + this._byId[model.cid] = model; + if (model.id != null) this._byId[model.id] = model; + if (!model.collection) model.collection = this; + model.on('all', this._onModelEvent, this); + }, + + // Internal method to sever a model's ties to a collection. + _removeReference: function(model, options) { + if (this === model.collection) delete model.collection; + model.off('all', this._onModelEvent, this); + }, + + // Internal method called every time a model in the set fires an event. + // Sets need to update their indexes when models change ids. All other + // events simply proxy through. "add" and "remove" events that originate + // in other collections are ignored. + _onModelEvent: function(event, model, collection, options) { + if ((event === 'add' || event === 'remove') && collection !== this) return; + if (event === 'destroy') this.remove(model, options); + if (model && event === 'change:' + model.idAttribute) { + delete this._byId[model.previous(model.idAttribute)]; + if (model.id != null) this._byId[model.id] = model; + } + this.trigger.apply(this, arguments); + } + + }); + + // Underscore methods that we want to implement on the Collection. + // 90% of the core usefulness of Backbone Collections is actually implemented + // right here: + var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl', + 'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select', + 'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke', + 'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest', + 'tail', 'drop', 'last', 'without', 'difference', 'indexOf', 'shuffle', + 'lastIndexOf', 'isEmpty', 'chain', 'sample']; + + // Mix in each Underscore method as a proxy to `Collection#models`. + _.each(methods, function(method) { + Collection.prototype[method] = function() { + var args = slice.call(arguments); + args.unshift(this.models); + return _[method].apply(_, args); + }; + }); + + // Underscore methods that take a property name as an argument. + var attributeMethods = ['groupBy', 'countBy', 'sortBy', 'indexBy']; + + // Use attributes instead of properties. + _.each(attributeMethods, function(method) { + Collection.prototype[method] = function(value, context) { + var iterator = _.isFunction(value) ? value : function(model) { + return model.get(value); + }; + return _[method](this.models, iterator, context); + }; + }); + + // Backbone.View + // ------------- + + // Backbone Views are almost more convention than they are actual code. A View + // is simply a JavaScript object that represents a logical chunk of UI in the + // DOM. This might be a single item, an entire list, a sidebar or panel, or + // even the surrounding frame which wraps your whole app. Defining a chunk of + // UI as a **View** allows you to define your DOM events declaratively, without + // having to worry about render order ... and makes it easy for the view to + // react to specific changes in the state of your models. + + // Creating a Backbone.View creates its initial element outside of the DOM, + // if an existing element is not provided... + var View = Backbone.View = function(options) { + this.cid = _.uniqueId('view'); + options || (options = {}); + _.extend(this, _.pick(options, viewOptions)); + this._ensureElement(); + this.initialize.apply(this, arguments); + this.delegateEvents(); + }; + + // Cached regex to split keys for `delegate`. + var delegateEventSplitter = /^(\S+)\s*(.*)$/; + + // List of view options to be merged as properties. + var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events']; + + // Set up all inheritable **Backbone.View** properties and methods. + _.extend(View.prototype, Events, { + + // The default `tagName` of a View's element is `"div"`. + tagName: 'div', + + // jQuery delegate for element lookup, scoped to DOM elements within the + // current view. This should be preferred to global lookups where possible. + $: function(selector) { + return this.$el.find(selector); + }, + + // Initialize is an empty function by default. Override it with your own + // initialization logic. + initialize: function(){}, + + // **render** is the core function that your view should override, in order + // to populate its element (`this.el`), with the appropriate HTML. The + // convention is for **render** to always return `this`. + render: function() { + return this; + }, + + // Remove this view by taking the element out of the DOM, and removing any + // applicable Backbone.Events listeners. + remove: function() { + this.$el.remove(); + this.stopListening(); + return this; + }, + + // Change the view's element (`this.el` property), including event + // re-delegation. + setElement: function(element, delegate) { + if (this.$el) this.undelegateEvents(); + this.$el = element instanceof Backbone.$ ? element : Backbone.$(element); + this.el = this.$el[0]; + if (delegate !== false) this.delegateEvents(); + return this; + }, + + // Set callbacks, where `this.events` is a hash of + // + // *{"event selector": "callback"}* + // + // { + // 'mousedown .title': 'edit', + // 'click .button': 'save', + // 'click .open': function(e) { ... } + // } + // + // pairs. Callbacks will be bound to the view, with `this` set properly. + // Uses event delegation for efficiency. + // Omitting the selector binds the event to `this.el`. + // This only works for delegate-able events: not `focus`, `blur`, and + // not `change`, `submit`, and `reset` in Internet Explorer. + delegateEvents: function(events) { + if (!(events || (events = _.result(this, 'events')))) return this; + this.undelegateEvents(); + for (var key in events) { + var method = events[key]; + if (!_.isFunction(method)) method = this[events[key]]; + if (!method) continue; + + var match = key.match(delegateEventSplitter); + var eventName = match[1], selector = match[2]; + method = _.bind(method, this); + eventName += '.delegateEvents' + this.cid; + if (selector === '') { + this.$el.on(eventName, method); + } else { + this.$el.on(eventName, selector, method); + } + } + return this; + }, + + // Clears all callbacks previously bound to the view with `delegateEvents`. + // You usually don't need to use this, but may wish to if you have multiple + // Backbone views attached to the same DOM element. + undelegateEvents: function() { + this.$el.off('.delegateEvents' + this.cid); + return this; + }, + + // Ensure that the View has a DOM element to render into. + // If `this.el` is a string, pass it through `$()`, take the first + // matching element, and re-assign it to `el`. Otherwise, create + // an element from the `id`, `className` and `tagName` properties. + _ensureElement: function() { + if (!this.el) { + var attrs = _.extend({}, _.result(this, 'attributes')); + if (this.id) attrs.id = _.result(this, 'id'); + if (this.className) attrs['class'] = _.result(this, 'className'); + var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs); + this.setElement($el, false); + } else { + this.setElement(_.result(this, 'el'), false); + } + } + + }); + + // Backbone.sync + // ------------- + + // Override this function to change the manner in which Backbone persists + // models to the server. You will be passed the type of request, and the + // model in question. By default, makes a RESTful Ajax request + // to the model's `url()`. Some possible customizations could be: + // + // * Use `setTimeout` to batch rapid-fire updates into a single request. + // * Send up the models as XML instead of JSON. + // * Persist models via WebSockets instead of Ajax. + // + // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests + // as `POST`, with a `_method` parameter containing the true HTTP method, + // as well as all requests with the body as `application/x-www-form-urlencoded` + // instead of `application/json` with the model in a param named `model`. + // Useful when interfacing with server-side languages like **PHP** that make + // it difficult to read the body of `PUT` requests. + Backbone.sync = function(method, model, options) { + var type = methodMap[method]; + + // Default options, unless specified. + _.defaults(options || (options = {}), { + emulateHTTP: Backbone.emulateHTTP, + emulateJSON: Backbone.emulateJSON + }); + + // Default JSON-request options. + var params = {type: type, dataType: 'json'}; + + // Ensure that we have a URL. + if (!options.url) { + params.url = _.result(model, 'url') || urlError(); + } + + // Ensure that we have the appropriate request data. + if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) { + params.contentType = 'application/json'; + params.data = JSON.stringify(options.attrs || model.toJSON(options)); + } + + // For older servers, emulate JSON by encoding the request into an HTML-form. + if (options.emulateJSON) { + params.contentType = 'application/x-www-form-urlencoded'; + params.data = params.data ? {model: params.data} : {}; + } + + // For older servers, emulate HTTP by mimicking the HTTP method with `_method` + // And an `X-HTTP-Method-Override` header. + if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) { + params.type = 'POST'; + if (options.emulateJSON) params.data._method = type; + var beforeSend = options.beforeSend; + options.beforeSend = function(xhr) { + xhr.setRequestHeader('X-HTTP-Method-Override', type); + if (beforeSend) return beforeSend.apply(this, arguments); + }; + } + + // Don't process data on a non-GET request. + if (params.type !== 'GET' && !options.emulateJSON) { + params.processData = false; + } + + // If we're sending a `PATCH` request, and we're in an old Internet Explorer + // that still has ActiveX enabled by default, override jQuery to use that + // for XHR instead. Remove this line when jQuery supports `PATCH` on IE8. + if (params.type === 'PATCH' && noXhrPatch) { + params.xhr = function() { + return new ActiveXObject("Microsoft.XMLHTTP"); + }; + } + + // Make the request, allowing the user to override any Ajax options. + var xhr = options.xhr = Backbone.ajax(_.extend(params, options)); + model.trigger('request', model, xhr, options); + return xhr; + }; + + var noXhrPatch = + typeof window !== 'undefined' && !!window.ActiveXObject && + !(window.XMLHttpRequest && (new XMLHttpRequest).dispatchEvent); + + // Map from CRUD to HTTP for our default `Backbone.sync` implementation. + var methodMap = { + 'create': 'POST', + 'update': 'PUT', + 'patch': 'PATCH', + 'delete': 'DELETE', + 'read': 'GET' + }; + + // Set the default implementation of `Backbone.ajax` to proxy through to `$`. + // Override this if you'd like to use a different library. + Backbone.ajax = function() { + return Backbone.$.ajax.apply(Backbone.$, arguments); + }; + + // Backbone.Router + // --------------- + + // Routers map faux-URLs to actions, and fire events when routes are + // matched. Creating a new one sets its `routes` hash, if not set statically. + var Router = Backbone.Router = function(options) { + options || (options = {}); + if (options.routes) this.routes = options.routes; + this._bindRoutes(); + this.initialize.apply(this, arguments); + }; + + // Cached regular expressions for matching named param parts and splatted + // parts of route strings. + var optionalParam = /\((.*?)\)/g; + var namedParam = /(\(\?)?:\w+/g; + var splatParam = /\*\w+/g; + var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g; + + // Set up all inheritable **Backbone.Router** properties and methods. + _.extend(Router.prototype, Events, { + + // Initialize is an empty function by default. Override it with your own + // initialization logic. + initialize: function(){}, + + // Manually bind a single named route to a callback. For example: + // + // this.route('search/:query/p:num', 'search', function(query, num) { + // ... + // }); + // + route: function(route, name, callback) { + if (!_.isRegExp(route)) route = this._routeToRegExp(route); + if (_.isFunction(name)) { + callback = name; + name = ''; + } + if (!callback) callback = this[name]; + var router = this; + Backbone.history.route(route, function(fragment) { + var args = router._extractParameters(route, fragment); + router.execute(callback, args); + router.trigger.apply(router, ['route:' + name].concat(args)); + router.trigger('route', name, args); + Backbone.history.trigger('route', router, name, args); + }); + return this; + }, + + // Execute a route handler with the provided parameters. This is an + // excellent place to do pre-route setup or post-route cleanup. + execute: function(callback, args) { + if (callback) callback.apply(this, args); + }, + + // Simple proxy to `Backbone.history` to save a fragment into the history. + navigate: function(fragment, options) { + Backbone.history.navigate(fragment, options); + return this; + }, + + // Bind all defined routes to `Backbone.history`. We have to reverse the + // order of the routes here to support behavior where the most general + // routes can be defined at the bottom of the route map. + _bindRoutes: function() { + if (!this.routes) return; + this.routes = _.result(this, 'routes'); + var route, routes = _.keys(this.routes); + while ((route = routes.pop()) != null) { + this.route(route, this.routes[route]); + } + }, + + // Convert a route string into a regular expression, suitable for matching + // against the current location hash. + _routeToRegExp: function(route) { + route = route.replace(escapeRegExp, '\\$&') + .replace(optionalParam, '(?:$1)?') + .replace(namedParam, function(match, optional) { + return optional ? match : '([^/?]+)'; + }) + .replace(splatParam, '([^?]*?)'); + return new RegExp('^' + route + '(?:\\?([\\s\\S]*))?$'); + }, + + // Given a route, and a URL fragment that it matches, return the array of + // extracted decoded parameters. Empty or unmatched parameters will be + // treated as `null` to normalize cross-browser behavior. + _extractParameters: function(route, fragment) { + var params = route.exec(fragment).slice(1); + return _.map(params, function(param, i) { + // Don't decode the search params. + if (i === params.length - 1) return param || null; + return param ? decodeURIComponent(param) : null; + }); + } + + }); + + // Backbone.History + // ---------------- + + // Handles cross-browser history management, based on either + // [pushState](http://diveintohtml5.info/history.html) and real URLs, or + // [onhashchange](https://developer.mozilla.org/en-US/docs/DOM/window.onhashchange) + // and URL fragments. If the browser supports neither (old IE, natch), + // falls back to polling. + var History = Backbone.History = function() { + this.handlers = []; + _.bindAll(this, 'checkUrl'); + + // Ensure that `History` can be used outside of the browser. + if (typeof window !== 'undefined') { + this.location = window.location; + this.history = window.history; + } + }; + + // Cached regex for stripping a leading hash/slash and trailing space. + var routeStripper = /^[#\/]|\s+$/g; + + // Cached regex for stripping leading and trailing slashes. + var rootStripper = /^\/+|\/+$/g; + + // Cached regex for detecting MSIE. + var isExplorer = /msie [\w.]+/; + + // Cached regex for removing a trailing slash. + var trailingSlash = /\/$/; + + // Cached regex for stripping urls of hash. + var pathStripper = /#.*$/; + + // Has the history handling already been started? + History.started = false; + + // Set up all inheritable **Backbone.History** properties and methods. + _.extend(History.prototype, Events, { + + // The default interval to poll for hash changes, if necessary, is + // twenty times a second. + interval: 50, + + // Are we at the app root? + atRoot: function() { + return this.location.pathname.replace(/[^\/]$/, '$&/') === this.root; + }, + + // Gets the true hash value. Cannot use location.hash directly due to bug + // in Firefox where location.hash will always be decoded. + getHash: function(window) { + var match = (window || this).location.href.match(/#(.*)$/); + return match ? match[1] : ''; + }, + + // Get the cross-browser normalized URL fragment, either from the URL, + // the hash, or the override. + getFragment: function(fragment, forcePushState) { + if (fragment == null) { + if (this._hasPushState || !this._wantsHashChange || forcePushState) { + fragment = decodeURI(this.location.pathname + this.location.search); + var root = this.root.replace(trailingSlash, ''); + if (!fragment.indexOf(root)) fragment = fragment.slice(root.length); + } else { + fragment = this.getHash(); + } + } + return fragment.replace(routeStripper, ''); + }, + + // Start the hash change handling, returning `true` if the current URL matches + // an existing route, and `false` otherwise. + start: function(options) { + if (History.started) throw new Error("Backbone.history has already been started"); + History.started = true; + + // Figure out the initial configuration. Do we need an iframe? + // Is pushState desired ... is it available? + this.options = _.extend({root: '/'}, this.options, options); + this.root = this.options.root; + this._wantsHashChange = this.options.hashChange !== false; + this._wantsPushState = !!this.options.pushState; + this._hasPushState = !!(this.options.pushState && this.history && this.history.pushState); + var fragment = this.getFragment(); + var docMode = document.documentMode; + var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7)); + + // Normalize root to always include a leading and trailing slash. + this.root = ('/' + this.root + '/').replace(rootStripper, '/'); + + if (oldIE && this._wantsHashChange) { + var frame = Backbone.$(' + + +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/httpd.conf b/httpd.conf deleted file mode 100644 index aee56f5cc..000000000 --- a/httpd.conf +++ /dev/null @@ -1,16 +0,0 @@ - - ServerName www.crafting-guide.com - ErrorLog logs/crafting-guide.com-error_log - CustomLog logs/crafting-guide.com-access_log common - - DocumentRoot /home/crafting-guide/repo/html - - AllowOverride None - - - - Options Indexes - Order allow,deny - Allow from all - - diff --git a/package.json b/package.json new file mode 100644 index 000000000..975ac358c --- /dev/null +++ b/package.json @@ -0,0 +1,40 @@ +{ + "name": "crafting-guide", + "version": "1.0.0", + "description": "crafting-guide ==============", + "main": "site/scripts/main.js", + "scripts": { + "test": "test" + }, + "repository": { + "type": "git", + "url": "https://github.com/andrewminer/crafting-guide.git" + }, + "author": "Andrew Miner", + "license": "ISC", + "bugs": { + "url": "https://github.com/andrewminer/crafting-guide/issues" + }, + "homepage": "https://github.com/andrewminer/crafting-guide", + "devDependencies": { + "coffeeify": "^1.0.0", + "grunt": "^0.4.5", + "grunt-browserify": "^3.2.1", + "grunt-contrib-clean": "^0.6.0", + "grunt-contrib-copy": "^0.7.0", + "grunt-contrib-jade": "^0.13.0", + "grunt-contrib-sass": "^0.8.1", + "grunt-contrib-watch": "^0.6.1" + }, + "dependencies": { + "backbone": "^1.1.2", + "chai": "^1.10.0", + "d3": "^3.5.2", + "jade": "^1.8.2", + "jquery": "^2.1.3", + "mocha": "^2.0.1", + "sinon": "^1.12.2", + "sinon-chai": "^2.6.0", + "when": "^3.6.4" + } +} diff --git a/scripts/server b/scripts/server index fd9cd2f94..def829f47 100755 --- a/scripts/server +++ b/scripts/server @@ -1,6 +1,6 @@ #!/bin/bash -pushd html &>/dev/null +pushd dist &>/dev/null python -m SimpleHTTPServer popd &>/dev/null diff --git a/src/css/main.scss b/src/css/main.scss new file mode 100644 index 000000000..ba3bb22d0 --- /dev/null +++ b/src/css/main.scss @@ -0,0 +1,152 @@ +/* +Crafting Guide - main.scss + +Copyright (c) 2014 by Redwood Labs +All rights reserved. +*/ + +@import 'mixins'; +@import 'reset'; + +// Constants /////////////////////////////////////////////////////////////////////////////////////////////////////////// + +$color-background: #AAC9FF; +$color-bedrock: #0A0A0A; +$color-content: rgba(230, 230, 230, 0.90); +$color-brick-dark: #7A7A7A; +$color-brick-light: #D9D9D9; +$color-footer: #3D1D09; +$color-footer-text: white; +$color-dirt: #906647; + +// Fonts /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@font-face { + font-family: 'PressStart'; + font-style: normal; + font-weight: 400; + src: url('/fonts/press_start.ttf') format('truetype'); +} + +// Common ////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +body { + background: $color-background url('/images/ice.png'); + font-size: 10px; +} + +h1 { + margin-bottom: 1em; + + * { display: inline; } + + img { + position: relative; height: 10em; width: 10em; + margin-right: 1em; + vertical-align: bottom; + } + + p { + font-family: PressStart; + font-size: 3em; + position: relative; top: -0.5em; + } +} + +h2 { + margin-bottom: 1em; + + * { display: inline; } + + img { + position: relative; height: 7.5em; width: 7.5em; + margin-right: 1em; + vertical-align: bottom; + } + + p { + font-family: PressStart; + font-size: 2em; + position: relative; top: -0.25em; + } +} + +.centered { + text-align: center; +} + +.content { + background: $color-content; + box-shadow: 10px 10px 20px #666; + margin: 2em auto; + max-width: 96em; + position: relative; + width: 100%; +} + +// Views /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +.view__footer { + background: $color-footer; + color: $color-footer-text; + margin-top: 2em; + + a { + color: $color-footer-text; + } + + .divider { + position: relative; height: 3.2em; width: 100%; + clear: both; + } + + .divider.top { + background: $color-dirt url('/images/grass_side.png'); + } + + .left, .center, .right { + position: relative; width: 33%; + float: left; + padding: 2em; + + p { + font-family: sans-serif; + font-size: 1.25em; + padding-bottom: 1.0em; + + &:last-child { + padding-bottom: 0; + } + } + + h2 { + padding-bottom: 1.0em; + + p { + font-family: PressStart; + font-size: 1.5em; + } + } + } + + .divider.bottom { + background: $color-bedrock url('/images/bedrock.png'); + } +} + +.view__header { + background: $color-brick-light url('/images/stone_brick_light.png'); + position: relative; height: 10em; + margin: 5em 0 2em 0; + + h1 { position: relative; top: -3em; left: -3em; } + + .divider { + background: $color-brick-dark url('/images/stone_brick.png'); + position: absolute; bottom: 0; height: 3.2em; width: 100%; + } +} + +// Child Stylesheets /////////////////////////////////////////////////////////////////////////////////////////////////// + +@import 'templates/index'; diff --git a/src/css/mixins.scss b/src/css/mixins.scss new file mode 100644 index 000000000..f17ac5f34 --- /dev/null +++ b/src/css/mixins.scss @@ -0,0 +1,26 @@ +/* +Crafting Guide - mixins.scss + +Copyright (c) 2014 by Redwood Labs +All rights reserved. +*/ + +@mixin box-sizing($value) { + -moz-box-sizing: $value; + -webkit-box-sizing: $value; + box-sizing: $value; +} + +@mixin center-vertical { + position: absolute; + top: 50%; + @include transform(translateY(-50%)); +} + +@mixin transform($transforms) { + -moz-transform: $transforms; + -o-transform: $transforms; + -ms-transform: $transforms; + -webkit-transform: $transforms; + transform: $transforms; +} \ No newline at end of file diff --git a/src/css/reset.scss b/src/css/reset.scss new file mode 100644 index 000000000..e55d2ce26 --- /dev/null +++ b/src/css/reset.scss @@ -0,0 +1,75 @@ +a,abbr,acronym,address,applet,article,aside,audio,b,big,blockquote,body,canvas,caption,center,cite,code,dd,del,details,dfn,dialog,div,dl,dt,em,embed,fieldset,figcaption,figure,font,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,hr,html,i,iframe,img,ins,kbd,label,legend,li,mark,menu,meter,nav,object,ol,output,p,pre,progress,q,rp,rt,ruby,s,samp,section,small,span,strike,strong,sub,summary,sup,table,tbody,td,tfoot,th,thead,time,tr,tt,u,ul,var,video,xmp { + border: 0; + margin: 0; + padding: 0; + font-size: 100%; + @include box-sizing(border-box); +} + +html,body { + height: 100%; +} + +article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section { + display: block; +} + +b,strong { + font-weight: bold; +} + +img { + color: transparent; + vertical-align: middle; + -ms-interpolation-mode: bicubic; +} + +ol,ul { + list-style: none; +} + +li { + display: list-item; +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +th,td,caption { + font-weight: normal; + vertical-align: top; + text-align: left; +} + +q { + quotes: none; +} + +q:before,q:after { + content: ''; + content: none; +} + +sub,sup,small { + font-size: 75%; +} + +sub,sup { + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +svg { + overflow: hidden; +} \ No newline at end of file diff --git a/src/css/templates/index.scss b/src/css/templates/index.scss new file mode 100644 index 000000000..748791869 --- /dev/null +++ b/src/css/templates/index.scss @@ -0,0 +1,8 @@ +/* +Crafting Guide - templates/index.scss + +Copyright (c) 2014 by Redwood Labs +All rights reserved. +*/ + +@import 'recipe_catalog'; diff --git a/src/css/templates/recipe_catalog.scss b/src/css/templates/recipe_catalog.scss new file mode 100644 index 000000000..b28df4748 --- /dev/null +++ b/src/css/templates/recipe_catalog.scss @@ -0,0 +1,28 @@ +/* +Crafting Guide - recipe_books.scss + +Copyright (c) 2014 by Redwood Labs +All rights reserved. +*/ + +.view__recipe_catalog { + position: relative; width: 100%; + padding: 0 2em; + + button { + @include center-vertical; + position: absolute; right: 1em; + } + + input { border: 0; width: 90%; } + + table { + background: white; + margin: 0 auto; + width: 98%; + + td { height: 3em; padding: 0 1em; position: relative; vertical-align: middle; } + td:nth-child(1) { width: 30%; } + td:nth-child(2) { width: 70%; border-left: 0.1em solid $color-brick-light; } + } +} diff --git a/src/data/applied_energetics.json b/src/data/applied_energetics.json new file mode 100644 index 000000000..e152021e4 --- /dev/null +++ b/src/data/applied_energetics.json @@ -0,0 +1,333 @@ +{ + "name": "Applied Energetics", + "description": "Applied Energetics rv12-b, by AlgorithmX2", + "recipes": [ + + { + "output": [[1, "Grind Stone"]], + "input": [[3, "Certus Quartz Dust"], [3, "Stone"], [2, "Cobblestone"],[1, "Wooden Gear"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Quartz Cutting Knife"]], + "input": [[1, "Iron"], [2, "Stick"], [2, "Certus Quartz"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Basic Processor Assembly"]], + "input": [[1, "Gold Ingot"], [2, "Redstone"], [1, "Silicon"]], + "tools": ["Crafting Table","Quartz Cutting Knife"] + }, { + "output": [[1, "Advanced Processor Assembly"]], + "input": [[1, "Diamond"], [2, "Redstone"], [1, "Silicon"]], + "tools": ["Crafting Table","Quartz Cutting Knife"] + }, { + "output": [[1, "Silicon"]], + "input": [[1, "Certus Quartz Dust"]], + "tools": ["Furnace"] + }, { + "output": [[1, "ME Basic Processor"]], + "input": [[1, "Basic Processor Assembly"]], + "tools": ["Furnace"] + }, { + "output": [[1, "ME Basic Processor"]], + "input": [[1, "Redstone Golden Chipset"], [1,"Silicon"], [1,"Fluix Dust"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[1, "ME Advanced Processor"]], + "input": [[1, "Advanced Processor Assembly"]], + "tools": ["Furnace"] + }, { + "output": [[1, "ME Advanced Processor"]], + "input": [[1, "Redstone Diamond Chipset"], [1,"Silicon"], [1,"Fluix Dust"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[1, "Vibration Catalyst"]], + "input": [[1, "Iron Ingot"], [1, "ME Conversion Matrix"], [1, "Lava Bucket"],[1,"Energy Cell"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Entropy Accelerator"]], + "input": [[1, "Iron Ingot"], [1, "ME Conversion Matrix"], [1, "Ice"],[1,"Energy Cell"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Tiny TNT"]], + "input": [[2, "Gunpowder"], [2, "Certus Quartz Dust"]], + "tools": [] + }, { + "output": [[8, "ME Cable - Blue"]], + "input": [[1, "Lapis Lazuli"],[8,"ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "ME Cable - Black"]], + "input": [[1, "Ink Sac"],[8,"ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "ME Cable - White"]], + "input": [[1, "Bone Meal"],[8,"ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "ME Cable - Brown"]], + "input": [[1, "Cocoa Beans"],[8,"ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "ME Cable - Red"]], + "input": [[1, "Rose Red"],[8,"ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "ME Cable - Yellow"]], + "input": [[1, "Dandelion Yellow"],[8,"ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "ME Cable - Green"]], + "input": [[1, "Cactus Green"],[8,"ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "ME Cable - Green"]], + "input": [[1, "Cactus Green"],[8,"ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Pattern Provider"]], + "input": [[4, "Iron Ingot"],[1,"Crafting Table"],[2,"Conversion Matrix"],[1,"ME Advanced Processor"],[1,"Storage Cell"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Controller"]], + "input": [[4, "Iron Ingot"], [4, "Fluix Crystal"],[1, "ME Advanced Processor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Drive"]], + "input": [[4, "Iron Ingot"], [2, "Glass"],[2,"ME Basic Processor"],[1,"Chest"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Pattern Encoder"]], + "input": [[7, "Iron Ingot"],[1,"Crafting Table"],[1,"Conversion Matrix"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Wireless Access Point"]], + "input": [[4, "Iron Ingot"],[3,"Glass"],[1,"Wireless Receiver"],[1,"ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Access Terminal"]], + "input": [[4, "Iron Ingot"], [3, "Glass"],[1,"Conversion Matrix"],[1,"ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Chest"]], + "input": [[5, "Iron Ingot"], [1, "Chest"], [1, "Conversion Matrix"], [2, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Interface"]], + "input": [[4, "Iron Ingot"], [3, "Glass"],[1,"Conversion Matrix"],[1,"ME Cable"]], + "tools": ["Craftin Table"] + }, { + "output": [[1, "ME Partition Editor"]], + "input": [[5, "Iron Ingot"],[2,"Glass"],[1,"Conversion Matrix"],[1,"Crafting Table"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Precision Export Bus"]], + "input": [[1, "ME Basic Export Bus"],[1,"ME Basic Processor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Precision Import Bus"]], + "input": [[1, "ME Basic Import Bus"],[1,"ME Basic Processor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Crafting Terminal"]], + "input": [[4, "Iron Ingot"],[2,"Glass"],[1,"Crafting Table"],[1,"Storage Cell"],[1,"ME Access Terminal"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Level Emitter"]], + "input": [[2, "Iron Ingot"], [1, "ME Basic Processor"], [1, "ME Cable"], [1, "Redstone Torch"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Crafting CPU"]], + "input": [[4, "Iron Ingot"],[2, "Certus Quartz"],[2, "Glowstone Dust"],[1, "ME Advanced Processor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Heat Vent"]], + "input": [[4, "Iron Ingot"],[4, "Iron Bars"],[1, "ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Assembler Containment Wall"]], + "input": [[4, "Iron Ingot"],[4, "Gold Ingot"],[1, "Certus Quartz"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Dark Cable"]], + "input": [[2, "Redstone"],[2, "ME Cable"],[1, "Lever"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Storage Bus"]], + "input": [[1, "ME Cable"],[1, "ME Interface"],[3, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME IO Port"]], + "input": [[3, "Glass"],[2, "ME Drive"],[1, "ME Cable"],[2, "Iron Ingot"],[1, "ME Basic Processor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Crafting Monitor"]], + "input": [[4, "Iron Ingot"],[3, "Glass"],[1, "ME Cable"],[1, "ME Basic Processor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Storage Monitor"]], + "input": [[4, "Iron Ingot"],[3, "Glass"],[1, "ME Cable"],[1, "ME Level Emitter"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Covered Cable"]], + "input": [[1, "ME Cable"],[1, "Wool"]], + "tools": ["Crafting Table"] + }, { + "output": [[3, "ME Cable"]], + "input": [[6, "Glass"],[3, "Fluix Dust"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Fuzzy Storage Bus"]], + "input": [[4, "Wool"],[1, "ME Storage Bus"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Fuzzy Export Bus"]], + "input": [[1, "ME Basic Export Bus"],[1, "ME Advanced Processor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Fuzzy Import Bus"]], + "input": [[1, "ME Basic Import Bus"],[1, "ME Advanced Processor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Basic Export Bus"]], + "input": [[1, "ME Cable"],[2, "Iron Ingot"],[1, "ME Interface"],[1, "Piston"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Basic Import Bus"]], + "input": [[1, "ME Cable"],[2, "Iron Ingot"],[1, "ME Interface"],[1, "Sticky Piston"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Transition Plane"]], + "input": [[3, "Fluix Dust"],[4, "Iron Ingot"],[1, "Conversion Matrix"],[1, "ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Energy Cell"]], + "input": [[4, "Iron Ingot"],[4, "Fluix Crystal"],[1, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Power Relay"]], + "input": [[4, "Iron Ingot"],[4, "ME Cable"],[1, "Energy Cell"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Condenser"]], + "input": [[4, "Iron Ingot"],[4, "Glass"],[1, "Fluix Dust"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Quantum Field Ring"]], + "input": [[4, "Iron Ingot"],[2, "ME Basic Processor"],[1, "ME Advanced Processor"],[1, "Energy Cell"],[1, "ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Quantum Link Chamber"]], + "input": [[4, "Quartz Glass"],[4, "Fluix Pearl"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Certus Quartz Block"]], + "input": [[4, "Certus Quartz"]], + "tools": ["Crafting Table"] + }, { + "output": [[4, "Quartz Glass"]], + "input": [[5, "Certus Quartz Dust"],[4, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Vibrant Quartz Glass"]], + "input": [[1, "Quartz Glass"],[2, "Glowstone Dust"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME 1k Storage"]], + "input": [[2, "Glass"],[3, "Redstone"],[1, "Storage Cell"],[3, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME 4k Storage"]], + "input": [[2, "Glass"],[3, "Redstone"],[1, "Storage Segment"],[3, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME 16k Storage"]], + "input": [[2, "Glass"],[3, "Redstone"],[1, "Storage Block"],[3, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME 64k Storage"]], + "input": [[2, "Glass"],[3, "Redstone"],[1, "Storage Cluster"],[3, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Conversion Matrix"]], + "input": [[4, "Iron Ingot"],[1, "Nether Quartz"],[2, "Fluix Dust"],[1, "ME Basic Processor"],[1, "Certus Quartz"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Storage Cell"]], + "input": [[4, "Redstone"],[4, "Certus Quartz"],[1, "ME Basic Processor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Storage Segment"]], + "input": [[4, "Redstone"],[3, "Storage Cell"],[1, "Glass"],[1,"ME Basic Processor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Storage Block"]], + "input": [[4, "Glowstone"],[3, "Storage Segment"],[1, "Glass"],[1,"ME Advanced Processor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Storage Cluster"]], + "input": [[4, "Glowstone"],[3, "Storage Block"],[1, "Glass"],[1,"ME Advanced Processor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Wireless Receiver"]], + "input": [[1, "Fluix Pearl"],[3, "Iron Ingot"],[1, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Wireless Booster"]], + "input": [[2, "Iron Ingot"],[1, "Redstone"],[1, "Certus Quartz"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Wooden Crank"]], + "input": [[5, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Flour"]], + "input": [[1, "Wheat"]], + "tools": ["Pulverizer"] + }, { + "output": [[2, "Fluix Dust"]], + "input": [[1, "Redstone"],[1, "Certus Quartz Dust"],[1, "Nether Quartz Dust"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Blank Pattern"]], + "input": [[2, "Glass"],[3, "Glowstone"],[1, "Certus Quartz"],[3, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Nether Quartz Dust"]], + "input": [[1, "Nether Quartz"]], + "tools": ["Pulverizer"] + }, { + "output": [[1, "Fluix Crystal"]], + "input": [[1, "Certus Quartz"],[1, "Nether Quartz"],[1, "Redstone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Fluix Pearl"]], + "input": [[4, "Fluix Dust"],[4, "Fluix Crystal"],[1, "Ender Pearl"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Matter Ball"]], + "input": [[256, "Cobblestone"]], + "tools": ["ME Condenser"] + }, { + "output": [[1, "Singularity"]], + "input": [[25600, "Cobblestone"]], + "tools": ["ME Condenser"] + }, { + "output": [[1, "Ender Pearl Dust"]], + "input": [[1, "Ender Pearl"]], + "tools": ["Pulverizer"] + }, { + "output": [[1, "Quartz Wrench"]], + "input": [[5, "Certus Quartz"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Wireless Access Terminal"]], + "input": [[1, "Wireless Receiver"],[1, "ME Access Terminal"],[1, "Energy Cell"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Matter Cannon"]], + "input": [[3, "Iron Ingot"],[1, "Conversion Matrix"],[1, "Storage Segment"],[1, "Energy Cell"]], + "tools": ["Crafting Table"] + } + ] +} + diff --git a/src/data/buildcraft.json b/src/data/buildcraft.json new file mode 100644 index 000000000..0c68485cc --- /dev/null +++ b/src/data/buildcraft.json @@ -0,0 +1,256 @@ +{ + "name": "BuildCraft", + "description": "Crafting recipes from BuildCraft 3, by SpaceToad", + "recipes": [ + { + "output": [[1, "Advanced Crafting Table"]], + "input": [[6, "Obsidian"], [1, "Crafting Table"], [1, "Chest"], [1, "Redstone Chipset"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Assembly Table"]], + "input": [[6, "Obsidian"], [1, "Diamond"], [1, "Diamond Gear"], [1, "Redstone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Automatic Crafting Table"]], + "input": [[4, "Wooden Gear"], [1, "Crafting Table"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Basic Gate"]], + "input": [[1, "Redstone Chipset"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[8, "Blue Pipe Wire"]], + "input": [[1, "Iron Ingot"], [1, "Redstone"], [1, "Lapis Lazuli"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[1, "Chute"]], + "input": [[5, "Iron Ingot"], [1, "Cobblestone Gear"], [1, "Chest"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Cobblestone Conductive Pipe"]], + "input": [[1, "Cobblestone Pipe"], [1, "Redstone"]], + "tools": [] + }, { + "output": [[1, "Cobblestone Gear"]], + "input": [[1, "Wooden Gear"], [4, "Cobblestone"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "Cobblestone Pipe"]], + "input": [[2, "Cobblestone"], [1, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Cobblestone Waterproof Pipe"]], + "input": [[1, "Cobblestone Pipe"], [1, "Pipe Waterproof"]], + "tools": [] + }, { + "output": [[1, "Combustion Engine"]], + "input": [[3, "Iron Ingot"], [2, "Iron Gear"], [1, "Glass"], [1, "Piston"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Diamond AND Gate"]], + "input": [[1, "Diamond Chipset"], [1, "Red Pipe Wire"], [1, "Blue Pipe Wire"], [1, "Yellow Pipe Wire"], [1, "Green Pipe Wire"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[1, "Diamond Chipset"]], + "input": [[1, "Redstone"], [1, "Diamond"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[8, "Diamond Pipe"]], + "input": [[2, "Diamond"], [1, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Diamond Conductive Pipe"]], + "input": [[1, "Diamond Pipe"], [1, "Redstone"]], + "tools": [] + }, { + "output": [[1, "Diamond Gear"]], + "input": [[1, "Gold Gear"], [4, "Diamond"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Diamond OR Gate"]], + "input": [[1, "Diamond Chipset"], [1, "Red Pipe Wire"], [1, "Blue Pipe Wire"], [1, "Yellow Pipe Wire"], [1, "Green Pipe Wire"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[8, "Emerald Pipe"]], + "input": [[2, "Emerald"], [1, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Emerald Waterproof Pipe"]], + "input": [[1, "Emerald Pipe"], [1, "Pipe Waterproof"]], + "tools": [] + }, { + "output": [[1, "Facade"]], + "input": [[3, "Structure Pipe"], [1, "source block"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[1, "Filler"]], + "input": [[2, "Dandelion Yellow"], [2, "Ink Sac"], [1, "Landmark"], [1, "Chest"], [1, "Crafting Table"], [2, "Gold Gear"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Gold AND Gate"]], + "input": [[1, "Gold Chipset"], [1, "Red Pipe Wire"], [1, "Blue Pipe Wire"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[1, "Gold Chipset"]], + "input": [[1, "Redstone"], [1, "Gold Ingot"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[1, "Gold Conductive Pipe"]], + "input": [[1, "Gold Pipe"], [1, "Redstone"]], + "tools": [] + }, { + "output": [[1, "Gold Gear"]], + "input": [[1, "Iron Gear"], [4, "Gold Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Gold OR Gate"]], + "input": [[1, "Gold Chipset"], [1, "Red Pipe Wire"], [1, "Blue Pipe Wire"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[8, "Gold Pipe"]], + "input": [[2, "Gold Ingot"], [1, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Gold Waterproof Pipe"]], + "input": [[1, "Gold Pipe"], [1, "Pipe Waterproof"]], + "tools": [] + }, { + "output": [[8, "Green Pipe Wire"]], + "input": [[1, "Iron Ingot"], [1, "Redstone"], [1, "Cactus Green"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[1, "Iron AND Gate"]], + "input": [[1, "Iron Chipset"], [1, "Red Pipe Wire"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[1, "Iron Chipset"]], + "input": [[1, "Redstone"], [1, "Iron Ingot"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[1, "Iron Gear"]], + "input": [[1, "Cobblestone Gear"], [4, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Iron OR Gate"]], + "input": [[1, "Iron Chipset"], [1, "Red Pipe Wire"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[8, "Iron Pipe"]], + "input": [[2, "Iron Ingot"], [1, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Iron Waterproof Pipe"]], + "input": [[1, "Iron Pipe"], [1, "Pipe Waterproof"]], + "tools": [] + }, { + "output": [[1, "Landmark"]], + "input": [[1, "Redstone Torch"], [1, "Lapis Lazuli"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Laser"]], + "input": [[5, "Redstone"], [2, "Diamond"], [2, "Obsidian"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Mining Well"]], + "input": [[6, "Iron Ingot"], [1, "Iron Gear"], [1, "Iron Pickaxe"], [1, "Redstone"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "Obsidian Pipe"]], + "input": [[2, "Obsidian"], [1, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Pipe Waterproof"]], + "input": [[1, "Cactus Green"]], + "tools": [] + }, { + "output": [[1, "Pump"]], + "input": [[1, "Mining Well"], [1, "Tank"]], + "tools": [] + }, { + "output": [[1, "Quarry"]], + "input": [[3, "Iron Gear"], [2, "Gold Gear"], [2, "Diamond Gear"], [1, "Diamond Pickaxe"], [1, "Redstone"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "Red Pipe Wire"]], + "input": [[1, "Iron Ingot"], [1, "Redstone"], [1, "Rose Red"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[1, "Redstone Chipset"]], + "input": [[1, "Redstone"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[1, "Redstone Engine"]], + "input": [[3, "Oak Plank"], [2, "Wooden Gear"], [1, "Glass"], [1, "Piston"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Refinery"]], + "input": [[3, "Tank"], [2, "Redstone Torch"], [1, "Diamond Gear"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "Sandstone Pipe"]], + "input": [[2, "Sandstone"], [1, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Sandstone Waterproof Pipe"]], + "input": [[1, "Sandstone Pipe"], [1, "Pipe Waterproof"]], + "tools": [] + }, { + "output": [[1, "Stirling Engine"]], + "input": [[3, "Cobblestone"], [2, "Cobblestone Gear"], [1, "Glass"], [1, "Piston"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Stone Conductive Pipe"]], + "input": [[1, "Stone Pipe"], [1, "Redstone"]], + "tools": [] + }, { + "output": [[8, "Stone Pipe"]], + "input": [[2, "Stone"], [1, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Stone Waterproof Pipe"]], + "input": [[1, "Stone Pipe"], [1, "Pipe Waterproof"]], + "tools": [] + }, { + "output": [[8, "Stripe Pipe"]], + "input": [[1, "Ink Sac"], [1, "Glass"], [1, "Dandelion Yellow"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Structure Pipe"]], + "input": [[1, "Cobblestone Pipe"], [1, "Gravel"]], + "tools": [] + }, { + "output": [[1, "Tank"]], + "input": [[8, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Wooden Conductive Pipe"]], + "input": [[1, "Wooden Pipe"], [1, "Redstone"]], + "tools": [] + }, { + "output": [[1, "Wooden Gear"]], + "input": [[4, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "Wooden Pipe"]], + "input": [[2, "Oak Plank"], [1, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Wooden Waterproof Pipe"]], + "input": [[1, "Wooden Pipe"], [1, "Pipe Waterproof"]], + "tools": [] + }, { + "output": [[1, "Wrench (buildcraft)"]], + "input": [[3, "Iron Ingot"], [1, "Cobblestone Gear"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "Void Pipe"]], + "input": [[1, "Ink Sac"], [1, "Glass"], [1, "Redstone"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "Yellow Pipe Wire"]], + "input": [[1, "Iron Ingot"], [1, "Redstone"], [1, "Dandelion Yellow"]], + "tools": ["Assembly Table", "Laser"] + } + ] +} + diff --git a/src/data/gravisuite.json b/src/data/gravisuite.json new file mode 100644 index 000000000..dfedf77e0 --- /dev/null +++ b/src/data/gravisuite.json @@ -0,0 +1,67 @@ +{ + "name": "GraviSuite", + "description": "Crafting recipes from GraviSuite, by flotschi301", + "recipes": [ + { + "output": [[1, "GraviChestPlate"]], + "input": [[1, "Quantum Bodyarmor"], [1, "HV Transformer"], [1, "Ultimate Lappack"], [2, "Gravitation Engine"], [4, "Superconductor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Ultimate Lappack"]], + "input": [[6, "Lapotron Crystal"], [1, "Iridium Plate"], [1, "LapPack"], [1, "Superconductor"]], + "tools": ["Crafting Table"] + }, { + "output": [[3, "Superconductor"]], + "input": [[6, "Superconductor Cover"], [2, "Glass Fiber Cable"], [1, "Gold Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[3, "Superconductor Cover"]], + "input": [[4, "Advanced Alloy"], [3, "Carbon Plate"], [2, "Iridium Plate"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Gravitation Engine"]], + "input": [[4, "Tesla Coil"], [2, "Superconductor"], [2, "Cooling Core"], [1, "HV Transformer"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Cooling Core"]], + "input": [[4, "60K Cooling Cell"], [2, "Advanced Heat Exchanger"], [2, "Heat-Capacity Reactor Plating"], [1, "Iridium Plate"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Advanced Chainsaw"]], + "input": [[1, "Diamond"], [3, "Overclocker Upgrade"], [1, "Chainsaw"], [2, "Advanced Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Advanced Diamond Drill"]], + "input": [[1, "Diamond Drill"], [3, "Overclocker Upgrade"], [2, "Advanced Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Advanced Electric Jetpack"]], + "input": [[2, "Carbon Plate"], [2, "Engine Booster"], [2, "Glass Fiber Cable"], [1, "Electric Jetpack"], [1, "Advanced Lappack"], [1, "Advanced Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Advanced Lappack"]], + "input": [[1, "LapPack"], [1, "Advanced Circuit"], [1, "Lapotron Crystal"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "GraviTool"]], + "input": [[2, "Carbon Plate"], [2, "Advanced Alloy"], [1, "Advanced Circuit"], [1, "Electric Wrench"], [1, "Electric Treetap"], [1, "Electric Hoe"], [1, "Energy Crystal"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Magnetron"]], + "input": [[4, "Refined Iron"], [4, "Copper Ingot"], [1, "Superconductor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Varja Core"]], + "input": [[1, "Magnetron"], [1, "Tesla Coil"], [1, "HV Transformer"], [2, "Iridium Plate"], [2, "Superconductor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Vajra"]], + "input": [[2, "Refined Iron"], [1, "Energy Crystal"], [1, "Varja Core"], [1, "Carbon Plate"], [2, "Advanced Alloy"], [1, "Lapotron Crystal"], [1, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Engine Booster"]], + "input": [[2, "Glowstone"], [2, "Advanced Circuit"], [3, "Advanced Alloy"], [1, "Overclocker Upgrade"], [1, "Advanced Heat Vent"]], + "tools": ["Crafting Table"] + } + ] +} diff --git a/src/data/industrial_craft.json b/src/data/industrial_craft.json new file mode 100644 index 000000000..00f9bddd1 --- /dev/null +++ b/src/data/industrial_craft.json @@ -0,0 +1,904 @@ +{ + "name": "Industrial Craft", + "description": "Crafting recipes from IndustrialCraft 2, by Alblaka", + "recipes": [ + { + "output": [[1, "Static Boots"]], + "input": [[4, "Iron Ingot"], [3, "Insulated Copper Cable"], [1, "Wool"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "CFPack"]], + "input": [[4, "Fuel Can"], [2, "CF Sprayer"], [1, "Electronic Circuit"], [1, "Tin Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[4, "Tin Can"]], + "input": [[5, "Tin Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Scrap Box"]], + "input": [[9, "Scrap"]], + "tools": ["Crafting Table"] + }, { + "output": [[16, "Coin"]], + "input": [[4, "Refined Iron"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Treetap"]], + "input": [[5, "Oak Plank"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Toolbox"]], + "input": [[5, "Iron Ingot"], [1, "Chest"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Painter"]], + "input": [[3, "Wool"], [2, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "EU Reader"]], + "input": [[4, "Insulated Copper Cable"], [1, "Electronic Circuit"], [1, "Glowstone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Cutter"]], + "input": [[5, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "CF Sprayer"]], + "input": [[4, "Cobblestone"], [1, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "FreqTrans"]], + "input": [[1, "Insulated Copper Cable"], [1, "Electronic Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Dynamite-O-Mote"]], + "input": [[2, "Tin Ingot"], [1, "Insulated Copper Cable"], [1, "Lapis Lazuli"], [1, "FreqTrans"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Nano Saber"]], + "input": [[2, "Advanced Alloy"], [2, "Carbon Plate"], [2, "Glowstone"], [1, "Energy Cell"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Mining Laser"]], + "input": [[4, "Advanced Alloy"], [2, "Energy Crystal"], [1, "Redstone"], [1, "Advanced Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Electric Wrench"]], + "input": [[1, "Wrench"], [1, "Electric Circuit"], [1, "RE Battery"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Electric Treetap"]], + "input": [[1, "Treetap"], [1, "Electric Circuit"], [1, "RE Battery"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Diamond Drill"]], + "input": [[3, "Diamond"], [1, "Mining Drill"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Mining Drill"]], + "input": [[5, "Refined Iron"], [1, "Electronic Circuit"], [1, "RE Battery"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Chainsaw"]], + "input": [[5, "Refined Iron"], [1, "Electronic Circuit"], [1, "RE Battery"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Uranium Block"]], + "input": [[9, "Refined Uranium"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Refined Uranium"]], + "input": [[1, "Uranium"]], + "tools": ["Compressor"] + }, { + "output": [[1, "Tin Block"]], + "input": [[9, "Tin Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bronze Block"]], + "input": [[9, "Bronze Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Copper Block"]], + "input": [[9, "Copper Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Rail Track"]], + "input": [[6, "Bronze"], [1, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Biofuel Cell"]], + "input": [[1, "Bio Cell"]], + "tools": ["Extractor"] + }, { + "output": [[1, "Bio Cell"]], + "input": [[1, "Empty Cell"], [1, "Compressed Plantball"]], + "tools": [] + }, { + "output": [[8, "Sticky Dynamite"]], + "input": [[8, "Dynamite"], [1, "Resin"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "Dynamite"]], + "input": [[1, "String"], [1, "Industrial TNT"]], + "tools": ["Crafting Table"] + }, { + "output": [[4, "Industrial TNT"]], + "input": [[6, "Flint"], [3, "TNT"]], + "tools": ["Crafting Table"] + }, { + "output": [[16, "Scaffold"]], + "input": [[3, "Oak Plank"], [3, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[3, "Rubber Trampoline"]], + "input": [[6, "Rubber"]], + "tools": ["Crafting Table"] + }, { + "output": [[7, "Reinforced Glass"]], + "input": [[7, "Glass"], [2, "Advanced Alloy"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Reinforced Door"]], + "input": [[6, "Reinforced Stone"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "Reinforced Stone"]], + "input": [[8, "Stone"], [1, "Advanced Alloy"]], + "tools": ["Crafting Table"] + }, { + "output": [[16, "Iron Scaffold"]], + "input": [[3, "Reinfined Iron"], [3, "Iron Fence"]], + "tools": ["Crafting Table"] + }, { + "output": [[12, "Iron Fence"]], + "input": [[6, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Luminator"]], + "input": [[5, "Glass"], [2, "Reinforced Iron"], [1, "Insulated Copper Cable"], [1, "Tin Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Construction Foam"], [1, "Bucket"]], + "input": [[1, "Clay Dust"], [1, "Water Bucket"], [1, "Coal Dust"], [1, "Redstone"]], + "tools": [] + }, { + "output": [[1, "Diamond (crafted)"]], + "input": [[1, "Coal Chunk"]], + "tools": ["Compressor"] + }, { + "output": [[1, "Coal Chunk"]], + "input": [[8, "Compressed Coal Ball"], [1, "Obsidian"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Coal Chunk"]], + "input": [[8, "Compressed Coal Ball"], [1, "Brick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Coal Chunk"]], + "input": [[8, "Compressed Coal Ball"], [1, "Iron Block"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Compressed Coal Ball"]], + "input": [[1, "Coal Ball"]], + "tools": ["Compressor"] + }, { + "output": [[1, "Coal Ball"]], + "input": [[8, "Coal Dust"], [1, "1 Flint"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Thick Neutron Reflector"]], + "input": [[4, "Neutron Reflector"], [1, "Dense Copper Plate"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Neutron Reflector"]], + "input": [[4, "Tin Dust"], [4, "Coal Dust"], [1, "Dense Copper Plate"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Depleted Isotope Cell"]], + "input": [[1, "Near-Depleted Uranium Cell"], [1, "Coal Dust"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Near-Depleted Uranium Cell"]], + "input": [[8, "Empty Cell"], [1, "Uranium Fuel Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Quad Uranium Cell"]], + "input": [[3, "Dense Copper Plate"], [2, "Dual Uranium Cell"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Dual Uranium Cell"]], + "input": [[2, "Uranium Cell"], [1, "Dense Copper Plate"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Uranium Cell"]], + "input": [[1, "Empty Cell"], [1, "Uranium Fuel Ingot"]], + "tools": [] + }, { + "output": [[1, "Heat-Capacity Reactor Plating"]], + "input": [[2, "Dense Copper Plate"], [1, "Reactor Plating"]], + "tools": [] + }, { + "output": [[1, "Containment Reactor Plating"]], + "input": [[2, "Advanced Alloy"], [1, "Reactor Plating"]], + "tools": [] + }, { + "output": [[1, "Reactor Plating"]], + "input": [[1, "Dense Copper Plate"], [1, "Advanced Alloy"]], + "tools": [] + }, { + "output": [[1, "Lava Cell"], [1, "Bucket"]], + "input": [[1, "Empty Cell"], [1, "Lava Bucket"]], + "tools": [] + }, { + "output": [[1, "Heating Cell"]], + "input": [[1, "Electronic Circuit"], [1, "Lava Cell"], [1, "Dense Copper Plate"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Component Heat Exchanger"]], + "input": [[4, "Gold Ingot"], [1, "Heat Exchanger"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Core Heat Exchanger"]], + "input": [[2, "Dense Copper Plate"], [1, "Heat Exchanger"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Advanced Heat Exchanger"]], + "input": [[4, "Glass Fiber Cable"], [2, "Heat Exchanger"], [2, "Electronic Circuit"], [1, "Dense Copper Plate"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "LZH-Condensator"]], + "input": [[4, "Redstone"], [2, "RSH-Condensator"], [1, "Reactor Heat Vent"], [1, "Core Heat Exchanger"], [1, "Lapis Lazuli Block"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Heat Exchanger"]], + "input": [[3, "Tin Ingot"], [1, "Electronic Circuit"], [1, "Dense Copper Plate"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "RSH-Condensator"]], + "input": [[7, "Redstone"], [1, "Heat Vent"], [1, "Heat Exchanger"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Overclocked Heat Vent"]], + "input": [[2, "Gold Ingot"], [1, "Reactor Heat Vent"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Advanced Heat Vent"]], + "input": [[6, "Iron Bars"], [2, "Heat Vent"], [1, "Diamond"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Reactor Heat Vent"]], + "input": [[2, "Dense Copper Plate"], [1, "Heat Vent"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Heat Vent"]], + "input": [[4, "Refined Iron"], [4, "Iron Bars"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Trade-O-Mat"]], + "input": [[3, "Redstone"], [2, "Chest"], [1, "Machine Block"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Tesla Coil"]], + "input": [[5, "Redstone"], [2, "Refined Iron"], [1, "Electronic Circuit"], [1, "MV Transformer"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "TFBP - Mushroom"]], + "input": [[4, "Brown Mushroom"], [4, "Mycelium"], [1, "Empty TFBP"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "TFBP - Irrigation"]], + "input": [[4, "Water Bucket"], [1, "Empty TFBP"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "TFBP - Flatificator"]], + "input": [[4, "Dirt"], [1, "Empty TFBP"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "TFBP - Desertification"]], + "input": [[4, "Sand"], [1, "Empty TFBP"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "TFBP - Cultivation"]], + "input": [[4, "Seed"], [1, "Empty TFBP"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "TFBP - Compression"]], + "input": [[4, "Stone"], [4, "Cobblestone"], [1, "Empty TFBP"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "TFBP - Chilling"]], + "input": [[4, "Snow"], [1, "Empty TFBP"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Empty TFBP"]], + "input": [[2, "Redstone"], [1, "Advanced Circuit"], [1, "Electronic Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Terraformer"]], + "input": [[4, "Glowstone"], [3, "Dirt"], [1, "Advanced Machine Block"], [1, "TFBP"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Personal Safe"]], + "input": [[1, "Electronic Circuit"], [1, "Machine Block"], [1, "Chest"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Magnetizer"]], + "input": [[6, "Redstone"], [1, "Iron Fence"], [1, "Machine Block"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Electrolyzer"]], + "input": [[4, "Insulated Copper Cable"], [2, "RE Battery"], [1, "Machine Block"], [1, "Electronic Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Recycler"]], + "input": [[3, "Dirt"], [2, "Refined Iron"], [1, "Compressor"], [1, "Glowstone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Mass Fabricator"]], + "input": [[4, "Glowstone"], [2, "Advanced Circuit"], [2, "Advanced Machine Block"], [1, "Lapotron Crystal"]], + "tools": ["Crafting Table"] + }, { + "output": [[5, "Bone Meal"]], + "input": [[1, "Bone"]], + "tools": ["Macerator"] + }, { + "output": [[5, "Blaze Powder"]], + "input": [[1, "Blaze Rod"]], + "tools": ["Macerator"] + }, { + "output": [[3, "Coffee Powder"]], + "input": [[1, "Coffee Beans"]], + "tools": ["Macerator"] + }, { + "output": [[4, "String"]], + "input": [[1, "Wool"]], + "tools": ["Macerator"] + }, { + "output": [[1, "Induction Furnace"]], + "input": [[7, "Copper Ingot"], [1, "Electric Furnace"], [1, "Advanced Machine Block"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Biofuel Cell"]], + "input": [[1, "Bio Cell"]], + "tools": ["Extractor"] + }, { + "output": [[1, "Electric Furnace"]], + "input": [[2, "Redstone"], [1, "Electronic Circuit"], [1, "Iron Furnace"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Nether Brick"]], + "input": [[3, "Netherrack"]], + "tools": ["Compressor"] + }, { + "output": [[1, "CF Pellet"]], + "input": [[1, "Construction Foam"]], + "tools": ["Compressor"] + }, { + "output": [[1, "Ice"]], + "input": [[1, "Snowball"]], + "tools": ["Compressor"] + }, { + "output": [[1, "Snowball"]], + "input": [[1, "Water Cell"]], + "tools": ["Compressor"] + }, { + "output": [[1, "Compressed Plantball"]], + "input": [[1, "Plantball"]], + "tools": ["Compressor"] + }, { + "output": [[1, "Diamond (industrial)"]], + "input": [[1, "Coal Chunk"]], + "tools": ["Compressor"] + }, { + "output": [[1, "Canning Machine"]], + "input": [[7, "Tin Ingot"], [1, "Electronic Circuit"], [1, "Machine Block"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Wind Mill"]], + "input": [[4, "Iron"], [1, "Generator"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Water Mill"]], + "input": [[4, "Stick"], [4, "Oak Plank"], [1, "Generator"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Advanced Alloy"]], + "input": [[1, "Mixed Metal Ingot"]], + "tools": ["Compressor"] + }, { + "output": [[1, "Advanced Circuit"]], + "input": [[4, "Redstone"], [2, "Glowstone"], [2, "Lapis Lazuli"], [1, "Electronic Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "BatBox"]], + "input": [[3, "RE Battery"], [5, "Oak Plank"], [1, "Insulated Copper Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "BatPack"]], + "input": [[6, "RE Battery"], [1, "Electronic Circuit"], [1, "Tin Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bronze Axe"]], + "input": [[3, "Bronze Ingot"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bronze Shovel"]], + "input": [[1, "Bronze Ingot"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bronze Chestplate"]], + "input": [[8, "Bronze Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bronze Block"]], + "input": [[9, "Bronze Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bronze Boots"]], + "input": [[4, "Bronze Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Bronze Dust"]], + "input": [[3, "Copper Dust"], [1, "Tin Dust"]], + "tools": [] + }, { + "output": [[1, "Bronze Helm"]], + "input": [[5, "Bronze Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bronze Hoe"]], + "input": [[2, "Bronze Ingot"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bronze Ingot"]], + "input": [[1, "Bronze Dust"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Bronze Leggings"]], + "input": [[7, "Bronze Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bronze Pickaxe"]], + "input": [[3, "Bronze Ingot"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bronze Sword"]], + "input": [[2, "Bronze Ingot"], [1, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Carbon Plate"]], + "input": [[1, "Raw Carbon Mesh"]], + "tools": ["Compressor"] + }, { + "output": [[1, "Clay Dust"]], + "input": [[1, "Clay Block"]], + "tools": ["Macerator"] + }, { + "output": [[1, "Coal Dust"]], + "input": [[1, "Coal"]], + "tools": ["Macerator"] + }, { + "output": [[1, "Composite Armor Vest"]], + "input": [[1, "Advanced Alloy"], [1, "Iron Chestplate"], [1, "Leather Tunic"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Compressed Air Cell"]], + "input": [[1, "Empty Cell"]], + "tools": ["Compressor"] + }, { + "output": [[1, "Compressor"]], + "input": [[6, "Stone"], [1, "Machine Block"], [1, "Electronic Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[6, "Copper Cable"]], + "input": [[3, "Copper Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Copper Dust"]], + "input": [[1, "Copper Ore"]], + "tools": ["Macerator"] + }, { + "output": [[1, "Copper Ingot"]], + "input": [[1, "Copper Ore"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Crop-Matron"]], + "input": [[5, "Crops"], [2, "Electronic Circuit"], [1, "Machine Block"], [1, "Chest"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Cropnalyzer"]], + "input": [[4, "Redstone"], [2, "Insulated Copper Cable"], [1, "Electronic Circuit"], [1, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Crops"]], + "input": [[4, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Electric Hoe"]], + "input": [[2, "Refined Iron"], [1, "Electronic Circuit"], [1, "RE Battery"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Electric Jetpack"]], + "input": [[4, "Refined Iron"], [2, "Glowstone"], [1, "BatBox"], [1, "Advanced Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Electronic Circuit"]], + "input": [[6, "Insulated Copper Cable"], [2, "Redstone"], [1, "Refined Iron"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Empty Booze Barrel"]], + "input": [[2, "Oak Plank"], [1, "Rubber Wood Log"]], + "tools": ["Crafting Table"] + }, { + "output": [[16, "Empty Cell"]], + "input": [[4, "Tin"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Energy Crystal"]], + "input": [[8, "Redstone"], [1, "Diamond"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Extractor"]], + "input": [[4, "Tree Tap"], [1, "Machine Block"], [1, "Electronic Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Fertilizer"]], + "input": [[2, "Scrap"], [1, "Fertilizer"]], + "tools": [] + }, { + "output": [[2, "Fertilizer"]], + "input": [[1, "Scrap"], [1, "Bonemeal"]], + "tools": [] + }, { + "output": [[1, "Fuel Can"]], + "input": [[7, "Tin Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Fuel Can (filled)"]], + "input": [[6, "Coalfuel Cell"], [1, "Fuel Cell"]], + "tools": ["Canning Machine"] + }, { + "output": [[1, "Generator"]], + "input": [[1, "RE Battery"], [1, "Machine Block"], [1, "Furnace"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Generator"]], + "input": [[3, "Refined Iron"], [1, "RE Battery"], [1, "Iron Furnace"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Gold Dust"]], + "input": [[1, "Gold Ore"]], + "tools": ["Macerator"] + }, { + "output": [[2, "Grin Powder"]], + "input": [[1, "Spider Eye"]], + "tools": ["Macerator"] + }, { + "output": [[1, "Hazmat Suit"]], + "input": [[6, "Rubber"], [2, "Orange Dye"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Hazmat Suit Leggings"]], + "input": [[6, "Rubber"], [1, "Orange Dye"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Hydration Cell"]], + "input": [[1, "Water Cell"]], + "tools": ["Extractor"] + }, { + "output": [[1, "Insulated Copper Cable"]], + "input": [[1, "Copper Cable"], [1, "Rubber"]], + "tools": [] + }, { + "output": [[1, "Iridium Ore"]], + "input": [[7, "UU Matter"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Iridium Plate"]], + "input": [[4, "Iridium Ore"], [4, "Advanced Alloy"], [1, "Diamond"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Iron Dust"]], + "input": [[1, "Iron Ore"]], + "tools": ["Macerator"] + }, { + "output": [[1, "Iron Furnace"]], + "input": [[8, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Iron Furnace"]], + "input": [[5, "Iron Ingot"], [1, "Furnace"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Jetpack"]], + "input": [[4, "Refined Iron"], [2, "Redstone"], [1, "Electronic Circuit"], [1, "Fuel Can"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Lapotron Crystal"]], + "input": [[6, "Lapis Lazuli"], [2, "Electronic Circuit"], [1, "Energy Crystal"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "LapPack"]], + "input": [[6, "Lapis Lazuli Block"], [1, "Advanced Circuit"], [1, "BatPack"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Macerator"]], + "input": [[3, "Flint"], [2, "Cobblestone"], [1, "Machine Block"], [1, "Electronic Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Machine Block"]], + "input": [[8, "Refined Iron"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Mixed Metal Ingot"]], + "input": [[3, "Refined Iron"], [3, "Bronze Ingot"], [3, "Tin Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "NanoSuit Bodyarmor"]], + "input": [[7, "Carbon Plate"], [1, "Energy Crystal"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "NanoSuit Boots"]], + "input": [[4, "Carbon Plate"], [1, "Energy Crystal"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "NanoSuit Helmet"]], + "input": [[3, "Carbon Plate"], [1, "Glass"], [1, "Energy Crystal"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "NanoSuit Leggings"]], + "input": [[6, "Carbon Plate"], [1, "Energy Crystal"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Quantum Bodyarmor"]], + "input": [[4, "Iridium Plate"], [3, "Advanced Alloy"], [1, "Lapotron Crystal"], [1, "NanoSuit Bodyarmor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Quantum Boots"]], + "input": [[2, "Iridium Plate"], [2, "Rubber Boots"], [1, "Lapotron Crystal"], [1, "NanoSuit Boots"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Quantum Helmet"]], + "input": [[2, "Iridium Plate"], [2, "Advanced Circuit"], [1, "Reinforced Glass"], [1, "Lapotron Crystal"], [1, "NanoSuit Helmet"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Quantum Leggings"]], + "input": [[1, "Iridium Plate"], [2, "Machine Block"], [2, "Glowstone"], [1, "Lapotron Crystal"], [1, "NanoSuit Leggings"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Raw Carbon Fibers"]], + "input": [[4, "Coal Dust"]], + "tools": [] + }, { + "output": [[1, "Raw Carbon Mesh"]], + "input": [[2, "Raw Carbon Fibers"]], + "tools": [] + }, { + "output": [[1, "RE Battery"]], + "input": [[4, "Tin Ingot"], [2, "Redstone"], [1, "Insulated Copper Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Refined Iron"]], + "input": [[1, "Iron Ingot"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[7, "Reinforced Glass"]], + "input": [[7, "Glass"], [2, "Advanced Alloy"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Rubber"]], + "input": [[1, "Resin"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Rubber Boots"]], + "input": [[6, "Rubber"], [1, "Wool"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Scuba Helmet"]], + "input": [[4, "Rubber"], [1, "Orange Dye"], [1, "Glass"], [1, "Iron Bars"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Silver Dust"]], + "input": [[1, "Silver Ore"]], + "tools": ["Macerator"] + }, { + "output": [[1, "Silver Ingot"]], + "input": [[1, "Silver Ore"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Solar Helmet"]], + "input": [[5, "Iron Ore"], [3, "Insulated Copper Cable"], [1, "Solar Panel"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Solar Panel"]], + "input": [[3, "Coal Dust"], [3, "Glass"], [2, "Electronic Circuit"], [1, "Generator"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Stone Mug"]], + "input": [[7, "Stone"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Tin Dust"]], + "input": [[1, "Tin Ore"]], + "tools": ["Macerator"] + }, { + "output": [[1, "Tin Ingot"]], + "input": [[1, "Tin Ore"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Tree Tap"]], + "input": [[5, "Oak Plank"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Water Cell"], [1, "Bucket"]], + "input": [[1, "Empty Cell"], [1, "Water Bucket"]], + "tools": [] + }, { + "output": [[1, "Weed-EX"]], + "input": [[1, "Empty Cell"], [1, "Grin Powder"], [1, "Redstone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Wrench (industrial craft)"]], + "input": [[6, "Bronze Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Detector Cable"]], + "input": [[3, "Redstone"], [1, "Electronic Circuit"], [1, "HV 3x Insulated Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "HV 3x Insulated Cable"]], + "input": [[1, "HV 2x Insulated Cable"], [1, "Rubber"]], + "tools": [] + }, { + "output": [[1, "HV 2x Insulated Cable"]], + "input": [[1, "HV Insulated Cable"], [1, "Rubber"]], + "tools": [] + }, { + "output": [[1, "HV Insulated Cable"]], + "input": [[1, "HV Cable"], [1, "Rubber"]], + "tools": [] + }, { + "output": [[12, "HV Cable"]], + "input": [[3, "Refined Iron"]], + "tools": ["Crafting Table"] + }, { + "output": [[4, "Glass Fiber Cable"]], + "input": [[6, "Glass"], [2, "Redstone"], [1, "Diamond"]], + "tools": ["Crafting Table"] + }, { + "output": [[12, "Gold Cable"]], + "input": [[3, "Gold Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Insulated Gold Cable"]], + "input": [[1, "Gold Cable"], [1, "Rubber"]], + "tools": [] + }, { + "output": [[1, "2x Ins. Gold Cable"]], + "input": [[1, "Insulated Gold Cable"], [1, "Rubber"]], + "tools": [] + }, { + "output": [[1, "Splitter Cable"]], + "input": [[2, "HV 3x Insulated Cable"], [2, "Redstone"], [1, "Lever"]], + "tools": [] + }, { + "output": [[9, "Tin Cable"]], + "input": [[3, "Tin Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "MFE"]], + "input": [[4, "2x Ins. Gold Cable"], [2, "Energy Crystal"], [1, "Machine Block"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "MFSU"]], + "input": [[6, "Lapotron Crystal"], [1, "Advanced Machine Block"], [1, "MFE"], [1, "Advanced Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Advanced Machine Block"]], + "input": [[2, "Advanced Alloy"], [2, "Carbon Plate"], [1, "Machine Block"]], + "tools": ["Crafting Table"] + }, { + "output": [[5, "Single-Use Battery"]], + "input": [[1, "Insulated Copper Cable"], [1, "Redstone"], [1, "Coal Dust"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "Hydrated Coal Dust"], [1, "Bucket"]], + "input": [[8, "Coal Dust"], [1, "Water Bucket"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Compressed Hyd. Coalclump"]], + "input": [[1, "Hydrated Coal Dust"]], + "tools": ["Compressor"] + }, { + "output": [[1, "H. Coal Cell"]], + "input": [[1, "Compressed Hyd. Coalclump"], [1, "Empty Cell"]], + "tools": [] + }, { + "output": [[1, "Coalfuel Cell"]], + "input": [[1, "H. Coal Cell"]], + "tools": ["Extractor"] + }, { + "output": [[1, "HV Transformer"]], + "input": [[2, "HV 3x Insulated Cable"], [1, "MV Transformer"], [1, "Energy Crystal"], [1, "Electronic Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "MV Transformer"]], + "input": [[2, "2x Ins. Gold Cable"], [1, "Machine Block"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "LV Transformer"]], + "input": [[4, "Oak Plank"], [3, "Copper Ingot"], [2, "Insulated Copper Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Energy Storage Upgrade"]], + "input": [[5, "Oak Plank"], [2, "Insulated Copper Cable"], [1, "RE Battery"], [1, "Electronic Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Overclocker Upgrade"]], + "input": [[3, "10K Cooling Cell"], [2, "Insulated Copper Cable"], [1, "Electronic Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "10K Cooling Cell"], [1, "Bucket"]], + "input": [[4, "Tin Ingot"], [1, "Water Bucket"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "30K Cooling Cell"]], + "input": [[6, "Tin Ingot"], [3, "10K Cooling Cell"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "60K Cooling Cell"]], + "input": [[6, "Tin Ingot"], [2, "30K Cooling Cell"], [1, "Dense Copper Plate"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Dense Copper Plate"]], + "input": [[8, "Copper Ingot"]], + "tools": ["Compressor"] + }, { + "output": [[1, "Reactor Chamber"]], + "input": [[4, "Dense Copper Plate"], [1, "Machine Block"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Transformer Upgrade"]], + "input": [[5, "Glass"], [2, "2x Ins. Gold Cable"], [1, "Electronic Circuit"], [1, "MV Transformer"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Miner"]], + "input": [[2, "Electronic Circuit"], [2, "Mining Pipe"], [1, "Machine Block"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "Mining Pipe"]], + "input": [[6, "Refined Iron"], [1, "Treetap"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "OD Scanner"]], + "input": [[3, "Insulated Copper Cable"], [2, "Electronic Circuit"], [1, "RE Battery"], [1, "Glowstone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "OV Scanner"]], + "input": [[3, "Glowstone"], [2, "2x Ins. Gold Cable"], [1, "Advanced Circuit"], [1, "OD Scanner"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "OV Scanner"]], + "input": [[3, "Glowstone"], [2, "2x Ins. Gold Cable"], [1, "Advanced Circuit"], [1, "RE Battery (charged)"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "RE Battery (charged)"]], + "input": [[1, "RE Battery"], [10000, "EU"]], + "tools": ["Generator"] + }, { + "output": [[1, "Pump"]], + "input": [[4, "Empty Cell"], [2, "Mining Pipe"], [1, "Electronic Circuit"], [1, "Machine Block"], [1, "Treetap"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Geothermal Generator"]], + "input": [[4, "Glass"], [2, "Empty Cell"], [2, "Refined Iron"], [1, "Generator"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Nuclear Reactor"]], + "input": [[3, "Reactor Chamber"], [1, "Advanced Circuit"], [1, "Generator"]], + "tools": ["Crafting Table"] + } + ] +} + diff --git a/src/data/more_blocks.json b/src/data/more_blocks.json new file mode 100644 index 000000000..919adea09 --- /dev/null +++ b/src/data/more_blocks.json @@ -0,0 +1,123 @@ +{ + "name": "MoreBlocks", + "description": "Crafting recipes from More Blocks Mod, by MCE626", + "recipes": [ + { + "output": [[1, "Cement Block"]], + "input": [[1, "Gravel"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Healer"]], + "input": [[2, "Essence of Life"], [1, "Essence of Earth"], [1, "Essence of Fire"], [1, "Essence of Water"], [1, "Essence of Air"], [3, "Red Dye"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Crying Obsidian"]], + "input": [[1, "Obsidian"], [1, "Water Bucket"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Lava Cobblestone"]], + "input": [[1, "Cobblestone"], [1, "Lava Bucket"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Lava Obsidian"]], + "input": [[1, "Obsidian"], [1, "Lava Bucket"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Crystal Block"]], + "input": [[9, "Crystal Gem"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Einsteinium Bomb"]], + "input": [[8, "Iron Ingot"], [1, "Einsteinium Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Neptunium Bomb"]], + "input": [[8, "Iron Ingot"], [1, "Neptunium Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Uranium Bomb"]], + "input": [[8, "Iron Ingot"], [1, "Uranium Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Ultimate Nuker"]], + "input": [[3, "Iron Ingot"], [1, "Einsteinium Ingot"], [1, "Neptunium"], [1, "Uranium Ingot"], [1, "Explosive Charge"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Einsteinium Ingot"]], + "input": [[1, "Einsteinium Ore"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Neptunium Ingot"]], + "input": [[1, "Neptunium Ore"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Uranium Ingot"]], + "input": [[1, "Uranium Ore"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Crystal Piece"]], + "input": [[7, "Crystal Dust"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Crystal Piece"]], + "input": [[1, "Crystal Nugget"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Crystal Nugget"]], + "input": [[5, "Crystal Piece"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Crystal Piece"]], + "input": [[1, "Crystal Gem"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Crystal Gem"]], + "input": [[7, "Crystal Nugget"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Crystal Gem"]], + "input": [[1, "Crystal Block"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Stone Brick"]], + "input": [[1, "Stone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Crystal Ball"]], + "input": [[4, "Crystal Gem"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Hard Crystal Ball"]], + "input": [[1, "Crystal Ball"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Essence of Life"]], + "input": [[1, "Flower"], [1, "Hard Crystal Ball"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Essence of Fire"]], + "input": [[1, "Lava Bucket"], [1, "Hard Crystal Ball"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Essence of Water"]], + "input": [[1, "Water Bucket"], [1, "Hard Crystal Ball"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Essence of Earth"]], + "input": [[1, "Dirt"], [1, "Hard Crystal Ball"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Essence of Air"]], + "input": [[1, "Hard Crystal Ball"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Popcorn"]], + "input": [[1, "Corn Seeds"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Chisel"]], + "input": [[1, "Iron Ingot"], [1, "Stick"]], + "tools": ["Crafting Table"] + } + ] +} diff --git a/src/data/thermal_expansion.json b/src/data/thermal_expansion.json new file mode 100644 index 000000000..92b66d3a7 --- /dev/null +++ b/src/data/thermal_expansion.json @@ -0,0 +1,211 @@ +{ + "name": "Thermal Expansion", + "description": "Crafting Recipes from Thermal Expansion, by King Lemming and the CoFH team", + "recipes": [ + { + "output": [[1, "Aqueous Accumulator"]], + "input": [[1, "Bucket"], [2, "Glass"], [1, "Machine Frame"], [1, "Pneumatic Servo"], [2, "Tin Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Copper Gear"]], + "input": [[1, "Cobblestone Gear"], [4, "Copper Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Crescent Hammer"]], + "input": [[3, "Iron Ingot"], [1, "Silver Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Cyclic Assembler"]], + "input": [[1, "Chest"], [2, "Copper Ingot"], [1, "Machine Frame"], [1, "Redstone Reception Coil"], [2, "Tin Gear"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Electrum Blend"]], + "input": [[1, "Gold Dust"], [1, "Silver Dust"]], + "tools": [] + }, { + "output": [[1, "Electrum Ingot"]], + "input": [[1, "Electrum Blend"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Energetic Infuser"]], + "input": [[2, "Copper Ingot"], [1, "Machine Frame"], [1, "Redstone Reception Coil"], [2, "Redstone Transmission Coil"], [1, "Shiny Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[250, "Energized Glowstone"]], + "input": [[1, "Glowstone Dust"]], + "tools": ["Magma Crucible"] + }, { + "output": [[1, "Energy Cell Frame (Empty)"]], + "input": [[1, "Diamond"], [4, "Electrum Ingot"], [4, "Hardened Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Energy Cell Frame (Full)"]], + "input": [[1, "Energy Cell Frame (Empty)"], [1000, "Molten Redstone"]], + "tools": ["Liquid Transposer"] + }, { + "output": [[4, "Energy Conduit (Empty)"]], + "input": [[2, "Electrum Ingot"], [1, "Hardened Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Energy Tesseract"]], + "input": [[1, "Electrum Ingot"], [2, "Lead Ingot"], [1, "Redstone Conductance Coil"], [2, "Tin Ingot"], [1, "Unattuned Tesseract"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Glacial Precipitator"]], + "input": [[2, "Copper Ingot"], [1, "Machine Frame"], [1, "Piston"], [1, "Redstone Reception Coil"], [2, "Snow (Block)"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Glowstone Illuminator"]], + "input": [[1000, "Energized Glowstone"], [1, "Illuminator Frame"]], + "tools": ["Liquid Transposer"] + }, { + "output": [[1, "Hardened Glass"]], + "input": [[1, "Lead Ingot"], [2, "Pulverized Obsidian"]], + "tools": ["Induction Smelter"] + }, { + "output": [[1, "Igneous Extruder"]], + "input": [[2, "Glass"], [1, "Machine Frame"], [1, "Piston"], [1, "Pneumatic Servo"], [2, "Tin Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Illuminator Frame"]], + "input": [[2, "Hardened Glass"], [1, "Nether Quartz"], [1, "Redstone Dust"], [1, "Silver Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Induction Smelter"]], + "input": [[1, "Bucket"], [2, "Copper Ingot"], [2, "Invar Ingot"], [1, "Machine Frame"], [1, "Redstone Reception Coil"]], + "tools": ["Crafting Table"] + }, { + "output": [[3, "Invar Blend"]], + "input": [[2, "Iron Dust"], [1, "Pulverized Ferrous Dust"]], + "tools": [] + }, { + "output": [[1, "Invar Gear"]], + "input": [[4, "Invar Ingot"], [1, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Invar Ingot"]], + "input": [[1, "Invar Blend"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Item Tesseract"]], + "input": [[1, "Pneumatic Servo"], [2, "Silver Ingot"], [3, "Tin Ingot"], [1, "Unattuned Tesseract"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Lead Ingot"]], + "input": [[1, "Lead Ore"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Liquid Tesseract"]], + "input": [[1, "Copper Ingot"], [1, "Pneumatic Servo"], [2, "Silver Ingot"], [2, "Tin Ingot"], [1, "Unattuned Tesseract"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Liquid Transposer"]], + "input": [[1, "Bucket"], [2, "Copper Ingot"], [2, "Glass"], [1, "Machine Frame"], [1, "Redstone Reception Coil"]], + "tools": ["Crafting Table"] + }, { + "output": [[4, "Liquiduct"]], + "input": [[2, "Copper Ingot"], [1, "Hardened Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Machine Frame"]], + "input": [[4, "Iron Ingot"], [4, "Glass"], [1, "Gold Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Magma Crucible"]], + "input": [[1, "Bucket"], [2, "Copper Ingot"], [1, "Machine Frame"], [2, "Nether Brick (block)"], [1, "Redstone Reception Coil"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Magmatic Engine"]], + "input": [[2, "Invar Gear"], [3, "Invar Ingot"], [1, "Piston"], [1, "Redstone Transmission Coil"]], + "tools": ["Crafting Table"] + }, { + "output": [[250, "Molten Ender"]], + "input": [[1, "Ender Pearl"]], + "tools": ["Magma Crucible"] + }, { + "output": [[25, "Molten Redstone"]], + "input": [[1, "Redstone Dust"]], + "tools": ["Magma Crucible"] + }, { + "output": [[1, "Multimeter"]], + "input": [[2, "Copper Ingot"], [2, "Lead Ingot"], [1, "Redstone Conductance Coil"], [1, "Tin Gear"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Pneumatic Servo"]], + "input": [[2, "Glass"], [2, "Iron Ingot"], [1, "Redstone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Portable Tank"]], + "input": [[4, "Hardened Glass"], [1, "Tin Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Powered Furnace"]], + "input": [[2, "Bricks"], [2, "Copper Ingot"], [1, "Machine Frame"], [1, "Redstone"], [1, "Redstone Conductance Coil"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Pulverized Ferrous Dust"]], + "input": [[1, "Ferrous Ore"]], + "tools": ["Pulverizer"] + }, { + "output": [[1, "Pulverized Obsidian"]], + "input": [[1, "Obsidian"]], + "tools": ["Pulverizer"] + }, { + "output": [[1, "Pulverizer"]], + "input": [[2, "Copper Ingot"], [2, "Flint"], [1, "Machine Frame"], [1, "Piston"], [1, "Redstone Reception Coil"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Redstone Conductance Coil"]], + "input": [[2, "Redstone"], [1, "Electrum Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Redstone Energy Cell"]], + "input": [[3, "Electrum Ingot"], [1, "Energy Cell Frame (Full)"], [2, "Lead Ingot"], [1, "Redstone Conductance Coil"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Redstone Energy Conduit"]], + "input": [[1, "Energy Conduit (Empty)"], [50, "Molten Redstone"]], + "tools": ["Liquid Transposer"] + }, { + "output": [[1, "Redstone Reception Coil"]], + "input": [[2, "Redstone"], [1, "Gold Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Redstone Transmission Coil"]], + "input": [[2, "Redstone"], [1, "Silver Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Sawmill"]], + "input": [[2, "Copper Ingot"], [1, "Iron Axe"], [1, "Machine Frame"], [1, "Redstone Reception Coil"], [2, "Oak Plank"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Schematic"]], + "input": [[1, "Lapis Lazuli"], [3, "Paper"]], + "tools": [] + }, { + "output": [[1, "Shiny Dust"]], + "input": [[10, "Ferrous Ore"]], + "tools": ["Pulverizer"] + }, { + "output": [[1, "Shiny Ingot"]], + "input": [[1, "Shiny Dust"], [125, "milli-coal"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Steam Engine"]], + "input": [[2, "Copper Gear"], [3, "Copper Ingot"], [1, "Piston"], [1, "Redstone Transmission Coil"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Tesseract Frame"]], + "input": [[1, "Diamond"], [4, "Hardened Glass"], [4, "Tin Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Tin Gear"]], + "input": [[4, "Tin Ingot"], [1, "Cobblestone Gear"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Unattuned Tesseract"]], + "input": [[1000, "Molten Ender"], [1, "Tesseract Frame"]], + "tools": ["Liquid Transposer"] + } + ] +} diff --git a/src/data/vanilla.json b/src/data/vanilla.json new file mode 100644 index 000000000..02cc20856 --- /dev/null +++ b/src/data/vanilla.json @@ -0,0 +1,564 @@ +{ + "name": "Vanilla Recipes", + "description": "Crafting recipes from vanilla Minecraft (in progress)", + "recipes": [ + { + "output": [[4, "Arrow"]], + "input": [[1, "Flint"], [1, "Stick"], [1, "Feather"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Baked Potato"]], + "input": [[1, "Potato"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Beacon"]], + "input": [[5, "Glass"], [3, "Obsidian"], [1, "Nether Star"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bed"]], + "input": [[3, "Wool"], [3, "Oak Plank"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Blaze Powder"]], + "input": [[1, "Blaze Rod"]], + "tools": [] + }, { + "output": [[1, "Boat"]], + "input": [[5, "Oak Plank"]], + "tools": ["Crafting Table"] + }, { + "output": [[3, "Bone Meal"]], + "input": [[1, "Bone"]], + "tools": [] + }, { + "output": [[1, "Book"]], + "input": [[1, "Leather"], [3, "Paper"]], + "tools": [] + }, { + "output": [[1, "Book and Quill"]], + "input": [[1, "Book"], [1, "Ink Sac"], [1, "Feather"]], + "tools": [] + }, { + "output": [[1, "Bookshelf"]], + "input": [[6, "Oak Plank"], [3, "Book"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bow"]], + "input": [[3, "Stick"], [3, "String"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bowl"]], + "input": [[3, "Oak Plank"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bread"]], + "input": [[3, "Wheat"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Brewing Stand"]], + "input": [[1, "Blaze Rod"], [3, "Cobblestone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Brick"]], + "input": [[1, "Clay"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Bricks"]], + "input": [[4, "Brick"]], + "tools": [] + }, { + "output": [[1, "Bucket"]], + "input": [[3, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Cactus Green"]], + "input": [[1, "Cactus"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Cake"], [1, "Bucket"]], + "input": [[3, "Milk"], [2, "Sugar"], [3, "Wheat"], [1, "Egg"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Carrot on a Stick"]], + "input": [[1, "Fishing Rod"], [1, "Carrot"]], + "tools": [] + }, { + "output": [[1, "Cauldron"]], + "input": [[7, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Chain Boots"]], + "input": [[4, "Fire"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Chain Chestplate"]], + "input": [[8, "Fire"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Chain Helmet"]], + "input": [[5, "Fire"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Chain Leggings"]], + "input": [[7, "Fire"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Charcoal"]], + "input": [[1, "Oak Log"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Chest"]], + "input": [[8, "Oak Plank"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Clay Block"]], + "input": [[4, "Clay"]], + "tools": [] + }, { + "output": [[1, "Clock"]], + "input": [[4, "Gold Ingot"], [1, "Redstone"]], + "tools": [] + }, { + "output": [[1, "Compass"]], + "input": [[4, "Iron Ingot"], [1, "Redstone"]], + "tools": [] + }, { + "output": [[1, "Cooked Chicken"]], + "input": [[1, "Raw Chicken"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Cooked Fish"]], + "input": [[1, "Raw Fish"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Cooked Porkchop"]], + "input": [[1, "Raw Porkchop"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Cookie"]], + "input": [[1, "Cocoa Beans"], [2, "Wheat"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Crafting Table"]], + "input": [[4, "Oak Plank"]], + "tools": [] + }, { + "output": [[2, "Cyan Dye"]], + "input": [[1, "Cactus Green"], [1, "Lapis Lazuli"]], + "tools": [] + }, { + "output": [[2, "Dandelion Yellow"]], + "input": [[1, "Dandelion"]], + "tools": [] + }, { + "output": [[1, "Diamond Axe"]], + "input": [[3, "Diamond"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Diamond Boots"]], + "input": [[4, "Diamond"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Diamond Chestplate"]], + "input": [[8, "Diamond"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Diamond Helm"]], + "input": [[5, "Diamond"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Diamond Hoe"]], + "input": [[2, "Diamond"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Diamond Leggings"]], + "input": [[7, "Diamond"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Diamond Pickaxe"]], + "input": [[3, "Diamond"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Diamond Sword"]], + "input": [[2, "Diamond"], [1, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Eye of Ender"]], + "input": [[1, "Ender Pearl"], [1, "Blaze Powder"]], + "tools": [] + }, { + "output": [[1, "Fermented Spider Eye"]], + "input": [[1, "Spider Eye"], [1, "Brown Mushroom"], [1, "Sugar"]], + "tools": [] + }, { + "output": [[3, "Fire Charge"]], + "input": [[1, "Blaze Powder"], [1, "Coal"], [1, "Gunpowder"]], + "tools": [] + }, { + "output": [[1, "Fishing Rod"]], + "input": [[3, "Stick"], [2, "String"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Flint and Steel"]], + "input": [[1, "Iron Ingot"], [1, "Flint"]], + "tools": [] + }, { + "output": [[1, "Furnace"]], + "input": [[8, "Cobblestone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Glass"]], + "input": [[1, "Sand"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[3, "Glass Bottle"]], + "input": [[3, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[16, "Glass Panes"]], + "input": [[6, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Glistering Melon"]], + "input": [[1, "Melon"], [8, "Gold Nugget"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Gold Axe"]], + "input": [[3, "Gold Ingot"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Gold Boots"]], + "input": [[4, "Gold Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Gold Chestplate"]], + "input": [[8, "Gold Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Gold Helm"]], + "input": [[5, "Gold Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Gold Hoe"]], + "input": [[2, "Gold Ingot"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Gold Leggings"]], + "input": [[7, "Gold Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Gold Ingot"]], + "input": [[1, "Gold Ore"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[9, "Gold Nugget"]], + "input": [[1, "Gold Ingot"]], + "tools": [] + }, { + "output": [[1, "Gold Pickaxe"]], + "input": [[3, "Gold Ingot"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Gold Sword"]], + "input": [[2, "Gold Ingot"], [1, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Golden Apple"]], + "input": [[9, "Gold Ingot"], [1, "Apple"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Golden Carrot"]], + "input": [[8, "Gold Nugget"], [1, "Carrot"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Gray Dye"]], + "input": [[1, "Bone Meal"], [1, "Ink Sac"]], + "tools": [] + }, { + "output": [[1, "Hopper"]], + "input": [[5, "Iron Ingot"], [1, "Chest"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Iron Axe"]], + "input": [[3, "Iron Ingot"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[16, "Iron Bars"]], + "input": [[6, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Iron Boots"]], + "input": [[4, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Iron Chestplate"]], + "input": [[8, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Iron Door"]], + "input": [[6, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Iron Helm"]], + "input": [[5, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Iron Hoe"]], + "input": [[2, "Iron Ingot"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Iron Ingot"]], + "input": [[1, "Iron Ore"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Iron Leggings"]], + "input": [[7, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[9, "Iron Nugget"]], + "input": [[1, "Iron Ingot"]], + "tools": [] + }, { + "output": [[1, "Iron Pickaxe"]], + "input": [[3, "Iron Ingot"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Iron Sword"]], + "input": [[2, "Iron Ingot"], [1, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Lapis Lazuli Block"]], + "input": [[9, "Lapis Lazuli"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Lava Bucket"]], + "input": [[1, "Bucket"], [1, "Lava Source Block"]], + "tools": [] + }, { + "output": [[2, "Lead"]], + "input": [[4, "String"], [1, "Slimeball"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Leather Boots"]], + "input": [[4, "Leather"]], + "tools": [] + }, { + "output": [[1, "Leather Tunic"]], + "input": [[8, "Leather"]], + "tools": [] + }, { + "output": [[1, "Leather Helm"]], + "input": [[5, "Leather"]], + "tools": [] + }, { + "output": [[1, "Leather Leggings"]], + "input": [[7, "Leather"]], + "tools": [] + }, { + "output": [[2, "Light Blue Dye"]], + "input": [[1, "Bone Meal"], [1, "Lapis Lazuli"]], + "tools": [] + }, { + "output": [[3, "Light Gray Dye"]], + "input": [[2, "Bone Meal"], [1, "Ink Sac"]], + "tools": [] + }, { + "output": [[2, "Light Gray Dye"]], + "input": [[1, "Bone Meal"], [1, "Gray Dye"]], + "tools": [] + }, { + "output": [[2, "Lime Dye"]], + "input": [[1, "Bone Meal"], [1, "Cactus Green"]], + "tools": [] + }, { + "output": [[2, "Magenta Dye"]], + "input": [[1, "Pink Dye"], [1, "Purple Dye"]], + "tools": [] + }, { + "output": [[3, "Magenta Dye"]], + "input": [[1, "Rose Red"], [1, "Pink Dye"], [1, "Lapis Lazuli"]], + "tools": [] + }, { + "output": [[4, "Magenta Dye"]], + "input": [[2, "Rose Red"], [1, "Bone Meal"], [1, "Lapis Lazuli"]], + "tools": [] + }, { + "output": [[1, "Magma Cream"]], + "input": [[1, "Slimeball"], [1, "Blaze Powder"]], + "tools": [] + }, { + "output": [[1, "Melon Seeds"]], + "input": [[1, "Melon"]], + "tools": [] + }, { + "output": [[1, "Milk"]], + "input": [[1, "Bucket"]], + "tools": ["Cow"] + }, { + "output": [[1, "Minecart"]], + "input": [[5, "Iron"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Minecart with Chest"]], + "input": [[1, "Minecart"], [1, "Chest"]], + "tools": [] + }, { + "output": [[1, "Minecart with Furnace"]], + "input": [[1, "Minecart"], [1, "Furnace"]], + "tools": [] + }, { + "output": [[1, "Minecart with Hopper"]], + "input": [[1, "Minecart"], [1, "Hopper"]], + "tools": [] + }, { + "output": [[1, "Minecart with TNT"]], + "input": [[1, "Minecart"], [1, "TNT"]], + "tools": [] + }, { + "output": [[1, "Mushroom Stew"]], + "input": [[1, "Bowl"], [1, "Red Mushroom"], [1, "Brown Mushroom"]], + "tools": [] + }, { + "output": [[1, "Nether Brick (item)"]], + "input": [[1, "Netherrack"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Nether Brick (block)"]], + "input": [[4, "Nether Brick (item)"]], + "tools": [] + }, { + "output": [[4, "Oak Plank"]], + "input": [[1, "Oak Log"]], + "tools": [] + }, { + "output": [[2, "Orange Dye"]], + "input": [[1, "Dandelion Yellow"], [1, "Rose Red"]], + "tools": [] + }, { + "output": [[3, "Paper"]], + "input": [[3, "Sugar Cane"]], + "tools": [] + }, { + "output": [[2, "Pink Dye"]], + "input": [[1, "Bone Meal"], [1, "Rose Red"]], + "tools": [] + }, { + "output": [[1, "Piston"]], + "input": [[4, "Cobblestone"], [3, "Oak Plank"], [1, "Iron Ingot"], [1, "Redstone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Pumpkin Pie"]], + "input": [[1, "Sugar"], [1, "Pumpkin"], [1, "Egg"]], + "tools": [] + }, { + "output": [[4, "Pumpkin Seeds"]], + "input": [[1, "Pumpkin"]], + "tools": [] + }, { + "output": [[2, "Purple Dye"]], + "input": [[1, "Rose Red"], [1, "Lapis Lazuli"]], + "tools": [] + }, { + "output": [[1, "Redstone Comparator"]], + "input": [[3, "Redstone Torch"], [1, "Nether Quartz"], [3, "Stone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Redstone Repeater"]], + "input": [[2, "Redstone Torch"], [1, "Redstone"], [3, "Stone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Redstone Torch"]], + "input": [[1, "Redstone"], [1, "Stick"]], + "tools": [] + }, { + "output": [[2, "Rose Red"]], + "input": [[1, "Rose"]], + "tools": [] + }, { + "output": [[1, "Shears"]], + "input": [[2, "Iron Ingot"]], + "tools": [] + }, { + "output": [[1, "Sign"]], + "input": [[6, "Oak Plank"], [1, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Steak"]], + "input": [[1, "Raw Beef"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[4, "Stick"]], + "input": [[2, "Oak Plank"]], + "tools": [] + }, { + "output": [[1, "Sticky Piston"]], + "input": [[1, "Piston"], [1, "Slimeball"]], + "tools": [] + }, { + "output": [[1, "Sugar"]], + "input": [[1, "Sugar Cane"]], + "tools": [] + }, { + "output": [[1, "Stone"]], + "input": [[1, "Cobblestone"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Stone Axe"]], + "input": [[3, "Cobblestone"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Stone Button"]], + "input": [[1, "Stone"]], + "tools": [] + }, { + "output": [[1, "Stone Hoe"]], + "input": [[2, "Cobblestone"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Stone Pickaxe"]], + "input": [[3, "Cobblestone"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Stone Sword"]], + "input": [[2, "Cobblestone"], [1, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "TNT"]], + "input": [[5, "Gunpowder"], [4, "Sand"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Water Bucket"]], + "input": [[1, "Bucket"], [1, "Water Source Block"]], + "tools": [] + }, { + "output": [[1, "Wooden Axe"]], + "input": [[3, "Oak Plank"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Wooden Button"]], + "input": [[1, "Oak Plank"]], + "tools": [] + }, { + "output": [[1, "Wooden Door"]], + "input": [[6, "Oak Plank"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Wooden Hoe"]], + "input": [[2, "Oak Plank"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Wooden Pickaxe"]], + "input": [[3, "Oak Plank"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Wooden Sword"]], + "input": [[2, "Oak Plank"], [1, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Lever"]], + "input": [[1, "Stick"], [1, "Cobblestone"]], + "tools": [] + } + ] +} + diff --git a/src/fonts/press_start.ttf b/src/fonts/press_start.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1efa15873077927f8a92ef926b318d520b806bc8 GIT binary patch literal 24708 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 literal 0 HcmV?d00001 diff --git a/src/images/bedrock.png b/src/images/bedrock.png new file mode 100755 index 0000000000000000000000000000000000000000..79ac81cb978eb87dd5a90952ea98539326bc6889 GIT binary patch literal 1398 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?3oVGw3ym^DX&fq^M6 zGbExU!q>+tIX_n~F(p4KRj(qq0H~UQ!KT6r$jnVGNmQuF&B-gas<2f8tFQvHLBje< z3ScEA*|tg%z5xo(`9-M;rh0~YMoM;E3JMA~MJZ`kK`w4k?LeNbQbtKhft9{~d3m{B zxv^e;QM$gNrKP35fswwEkuFe$ZgFK^Nn(X=Ua>O75STeGsl~}fnFS@8`FRQ;a}$&D zOG|8(lt3220o0wj1#pYQf&C3K6-}IwlS?ww5P^f@W{?b~qd}rp z&iT0oMXALgciNfS=wpZ>g2o0c7a5dVoS#z)3PL+`Bd7*sL39lf*fbyu;td8!-~i*_ zjtdxou(V{y^+xMKGce_?^K@|xiQrs2&2iEr10L7LS+ePmwBA?>R_S&2L8ipq} zCSQ()i>b2)wiX*kztAa=f3W=OjEL4R>DEG9W(ewKYw)cTJ)puIk*~=#r?uxur}2># z-tHUipHDU|I2V5FS8qp(%jOmTbePh%2>x#Q5pKJHqm$>lz_X-JZkr@5OV6Hr+4zm+ z_Ek@3yb638%TjPv*>TG~-gDnMHkw`D^x??831v^$ zvKL%o(z>x^=2<6Wp1O*Ir|wrb?2f#9KHo=GEwL~^O7ESj(XUwR|0%`s7X7h&l~0Al zUr%4a$+k)~e67Xbbz6TuTrYLxAIpZj`^z7j&hcB`@xJW)@4YuY^2)v_vCp%~@_#ym z*YDiCRU+aniFyZGqF5?JBlzB~nQ+h8al@~7A6XA>5Z9P-{D=9pJ*%$QcNhigC9IA( zcQWS8(-n`_EZ@&O@y7nh=MnBI)^E$o?#ND1`*!PL@T79l-5D=A(hGk-7WTiC7yQBI z@A`!dEh1OVH;E-OCb-!Z-)+dwv2OKv)hoDf{jBbo;%%QU@JrsVZs?Mbd-_7;&QXnT zr~XxTA62$%sb_e9a}~p%#Y#qs5}q@k2NoX7vATZi<^B`~4VQ(1UnfOuc&!!o_`#D{ z5eH|@DYLzklGpTJmklr6D5{>W?{Iv(neb-qt}Qzx!|!o$uGMC~WBn`sS)j-Nqo;p< zcwRbh^5uULg*iX>y-& l^nB80C$~dSc2+;GXI%VAL)%C(+89(adb;|#taD0e0sxt`F!ule literal 0 HcmV?d00001 diff --git a/src/images/bookshelf.png b/src/images/bookshelf.png new file mode 100755 index 0000000000000000000000000000000000000000..896c30e19014a861572f279173219b586d1a79f9 GIT binary patch literal 610 zcmV-o0-gPdP)) zZvEd*@5u`<*Ie?N2IKHeQ*w9jlY1|B7wJ9Mz)4>ZJJzqfSD#6>8*6`TKz3$I2=Co=)-vF@nSjIFI8;w2ZN57Gs*M1^w{QaB0#X2V@j)d3FclcMmrlcH zDh2P!Bs>}h6f!BH#oZRrYCvZF!Vy5)s-kvIHva=ao&gFV1M31%a2-%v2D;rY zbUGbqx7%QvCK#0#0XT4Khw&13`w+jXintcQ!Dc=b0JOu;l|2I-K&4WFa=8qp zQVEL1qRmg;1`0r5P^|g0HhTti0q{+nvY-Rt`V|BXK(_$b#2OTM2Bg0ZfUgX2m5}=D z0EjanOK}(gVhe)Kfc&qW0sI!FuqNnA^&2DxwU4O1*-hNM;AVqzn+WZUs*l$gygkL><$fH@>nPjK9S0Jph5rmdW`GOK zbvrKrZk}K>&@4pZCO-z}xnCV+M`3S%#1jC&cc*59erQhtWPPy!@G}Vuz^VfnNEZMD zVxS-Zta)IN3`hW3Ze=<4y#<4w0Sf(L@Y^691fT6Y^2!OtM wK-Fb!MF@Mi{FV3WGj#^w=7QDbS#~b?2A&CuK34i}>Hq)$07*qoM6N<$f?!1f4gdfE literal 0 HcmV?d00001 diff --git a/src/images/dirt.png b/src/images/dirt.png new file mode 100755 index 0000000000000000000000000000000000000000..28f300b8a51295e27d31e765edb8f41961fc1d40 GIT binary patch literal 1138 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 Nv9z@){_W1g{{Y*m{?Gsb literal 0 HcmV?d00001 diff --git a/src/images/wordmark.png b/src/images/wordmark.png new file mode 100644 index 0000000000000000000000000000000000000000..e538238ed2b023813ab3c665abfbb733c1a3e654 GIT binary patch literal 36148 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 b_PCh@%^P2fN529W-f~^DxN*74+&%GM%~qQ} literal 0 HcmV?d00001 diff --git a/src/images/workbench_front.png b/src/images/workbench_front.png new file mode 100755 index 0000000000000000000000000000000000000000..ec3ba9bf82299c99117c8cf5a4762635b3213af8 GIT binary patch literal 801 zcmV++1K#|JP)Y`~h7`H(m7~Bs+gd z{>_vVIKz2o?wc7GC-aeaKi)m}-Fv6=cw@Er{`p{ui?df*3|~GfX20H-I3I2$(EqTO zI_m)29sIz+?Vk_DzrT}WcKx-)k8k7h{_^7}aU$mc)<7R*pp#I&K;i%%U>r~(hejfD z0RO>JHI&l}U7-U_z*-n`2N?GM(UUk(xAVK7#|b@*gc>J}3Q~A8J*-3}%z=n|;P;o; ziDHdJ6n2+&`BoHA0e7#Uf+w46OX%)l3>(0@-F`QL+DRhtcK>NH{WMAdCGQTNmG_R5 z@$=FF-19wU+&BSSl&_6|@0^@+r;r(Jub0Wkh>>sKwLgbBpon-^YQQ@kz`e`C76Vo||-K96%iIiwpvR2^>=OwEQ7?!n@MgkeNO|1^oPa@h zAdCRdvDN`P;PrvX)d5|Dn&1v_ZKV$QG4u#H1#HjS2O_FkdO42~d@Q02W~X%tjXatxW7fbymAql#yBAR0mlMuB?5Q{b%< zK%(I45uk#8uUj6&+$_P$s1$^~AlJ`n%z1_k9cY>dKv^vXb@M=7A$s^=r7{mhWgDfr zu@3kw5S?qU19X7$(cHj#fGZr}?9n(6 zSx*!}6h?V6F(?W+!y+oo0HZKy09gzu8NdY;gDerj7^8xWAVI}nVKCx@@kIpD7-L)@ z>Vto-o$rocal5)}226Z7Nq2R1-P2XKmM*9`w9nHN748x2@`}0PUc6wE*C{AOh3<4LJqyGJ8M^aC|9%YYEPGatL6ZFiCi~_qch0N^9wEBY-d0 z$<$jHF~RYib4=!0V~)1&5o>#(a;!1uEAN=<|V$#z-g#ABRvg~G`bhCw1y=iR?CfBrv<$nQ{clw%6D9Y zfH{)c+c5>u00guI1?;ib0zjW1kOL6VyCGs40sBCr_W}$B;5|<~uD!tCE0E0gcAShy zC8k-5c`Akk<~%C%^lBf~fqrHaR#yukI8Vg^0Z@0e*hm0$9dI2s-_CXk8*@DZ%Ws$oeyfM;qryOD iECKIb*uUwn-}yg6FE#D)LXC_70000create an issue on GitHub or + | email me.

+ .center + h2: p Donate + p Crafting Guide is free for all, but if you find it helpful, donations in any amount are gratefully accepted. + form(action="https://www.paypal.com/cgi-bin/webscr", class="centered", method="post", target="_top") + input(type="hidden", name="cmd", value="_s-xclick") + input(type="hidden", name="hosted_button_id", value="GCB2TYZJYLAE6") + input(type="image", src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif", border="0", + name="submit" alt="PayPal - The safer, easier way to pay online!") + img(src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif", width="1", height="1") + .right + h2: p Get Involved + p Crafting Guide is completely open-source, and you can help! Whether you want to write a recipe book (all + | simple JSON), or implement new features, just head over to GitHub to get started. + .centered + iframe(src="http://ghbtns.com/github-btn.html?user=andrewminer&repo=crafting-guide&type=fork&size=large", + allowtransparency="true", frameborder="0", scrolling="0", width="100", height="32") + .divider.bottom diff --git a/src/pages/includes/_google_analytics.jade b/src/pages/includes/_google_analytics.jade new file mode 100644 index 000000000..b9d6b2716 --- /dev/null +++ b/src/pages/includes/_google_analytics.jade @@ -0,0 +1,15 @@ +//- +//- Crafting Guide - _google_analytics.jade +//- +//- Copyright (c) 2014 by Redwood Labs +//- All rights reserved. +//- + +script. + (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ + (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), + m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) + })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); + + ga('create', 'UA-5871323-4', 'crafting-guide.com'); + ga('send', 'pageview'); diff --git a/src/pages/includes/_header.jade b/src/pages/includes/_header.jade new file mode 100644 index 000000000..6241dece0 --- /dev/null +++ b/src/pages/includes/_header.jade @@ -0,0 +1,12 @@ +//- +//- Crafting Guide - _header.jade +//- +//- Copyright (c) 2014 by Redwood Labs +//- All rights reserved. +//- + +.view__header + h1 + img(src="images/workbench_front.png") + p Crafting Guide + .divider.bottom diff --git a/src/pages/index.jade b/src/pages/index.jade new file mode 100644 index 000000000..db86abcee --- /dev/null +++ b/src/pages/index.jade @@ -0,0 +1,15 @@ +//- +//- Crafting Guide - index.jade +//- +//- Copyright (c) 2014 by Redwood Labs +//- All rights reserved. +//- + +extends ./layouts/basic + +block content + .page + +append scripts + script(src="/js/main.js") + include ./includes/_google_analytics.jade diff --git a/src/pages/layouts/basic.jade b/src/pages/layouts/basic.jade new file mode 100644 index 000000000..b46a4fc62 --- /dev/null +++ b/src/pages/layouts/basic.jade @@ -0,0 +1,33 @@ +//- +//- Crafting Guide - basic.jade +//- +//- Copyright (c) 2014 by Redwood Labs +//- All rights reserved. +//- + +block basic-vars + - var pageTitle = 'Crafting Guide' + +doctype html +html + head + title= pageTitle + meta(charset="UTF-8") + + block styles + link(rel="stylesheet", type="text/css", href="css/main.css") + + body + .content + include ../includes/_header.jade + + block content + + include ../includes/_footer.jade + + block scripts + script(src="/js/underscore.js") + script(src="/js/jquery.js") + script(src="/js/backbone.js") + script(src="/js/jade.js") + script(src="/js/when.js") diff --git a/src/pages/test.jade b/src/pages/test.jade new file mode 100644 index 000000000..e1b1343a6 --- /dev/null +++ b/src/pages/test.jade @@ -0,0 +1,20 @@ +//- +//- Crafting Guide - test.jade +//- +//- Copyright (c) 2014 by Redwood Labs +//- All rights reserved. +//- + +extend ./layouts/basic + +append styles + link(rel="stylesheet", type="text/css", href="css/mocha.css") + style #mocha-stats { position: absolute; top: 9em; } + +block content + #mocha + +append scripts + script(src="/js/mocha.js") + script(src="/js/chai.js") + script(src="/js/test.js") diff --git a/src/scripts/constants.coffee b/src/scripts/constants.coffee new file mode 100644 index 000000000..546023138 --- /dev/null +++ b/src/scripts/constants.coffee @@ -0,0 +1,24 @@ +### +# Crafting Guide - constants.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +exports.Duration = Duration = {} +Duration.snap = 100 +Duration.fast = Duration.snap * 2 +Duration.normal = Duration.fast * 2 +Duration.slow = Duration.normal * 2 + +exports.Opacity = Opacity = {} +Opacity.hidden = 1e-6 +Opacity.shown = 1 + +exports.Event = Event = {} +Event.book = {} +Event.book.load = {} +Event.book.load.started = 'book:load:started' # controller, url +Event.book.load.succeeded = 'book:load:succeeded' # controller, book +Event.book.load.failed = 'book:load:failed' # controller, error message +Event.book.load.finished = 'book:load:finished' # controller diff --git a/src/scripts/controllers/base_controller.coffee b/src/scripts/controllers/base_controller.coffee new file mode 100644 index 000000000..ee481fb6b --- /dev/null +++ b/src/scripts/controllers/base_controller.coffee @@ -0,0 +1,77 @@ +### +# Crafting Guide - base_controller.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +views = require '../views' + +######################################################################################################################## + +module.exports = class BaseController extends Backbone.View + + constructor: (options={})-> + @_rendered = false + @_parent = options.parent + @_children = [] + + @_loadTemplate options.templateName + super options + + # Public Methods ############################################################################### + + addChild: (Controller, atSelector, options={})-> + options.el = @$(atSelector)[0] + options.parent = this + + child = new Controller options + child.render() + @_children.push child + return child + + refresh: -> + logger.verbose "#{this} refreshing" + + # Event Methods ################################################################################ + + onWillRender: -> # do nothing + + onDidRender: -> + @refresh() + + # Backbone.View Overrides ###################################################################### + + render: (options={})-> + return this unless not @_rendered or options.force + + data = (@model?.toHash? and @model.toHash()) or @model or {} + + if not @_template? + logger.error "Default render called for #{@constructor.name} without a template" + return this + + logger.verbose "#{this} rendering with data: #{data}" + @onWillRender() + $oldEl = @$el + $newEl = Backbone.$(@_template(data)) + if $oldEl + $oldEl.replaceWith $newEl + $newEl.addClass $oldEl.attr 'class' + + @setElement $newEl + @_rendered = true + @onDidRender() + + return this + + # Object Overrides ############################################################################# + + toString: -> + return "#{@constructor.name}(#{@cid})" + + # Private Methods ############################################################################## + + _loadTemplate: (templateName)-> + if templateName? + @_template = views[templateName] diff --git a/src/scripts/controllers/landing_page_controller.coffee b/src/scripts/controllers/landing_page_controller.coffee new file mode 100644 index 000000000..c9052fa07 --- /dev/null +++ b/src/scripts/controllers/landing_page_controller.coffee @@ -0,0 +1,25 @@ +### +# Crafting Guide - crafting_guide_controller.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +BaseController = require './base_controller' +LandingPage = require '../models/landing_page' +RecipeCatalogController = require './recipe_catalog_controller' + +######################################################################################################################## + +module.exports = class LandingPageController extends BaseController + + constructor: (options={})-> + options.model ?= new LandingPage + options.templateName = 'landing_page' + super options + + # BaseController Overrides ##################################################################### + + onDidRender: -> + @recipeBooksController = @addChild RecipeCatalogController, '.view__recipe_catalog' + super diff --git a/src/scripts/controllers/recipe_catalog_controller.coffee b/src/scripts/controllers/recipe_catalog_controller.coffee new file mode 100644 index 000000000..e20b8089d --- /dev/null +++ b/src/scripts/controllers/recipe_catalog_controller.coffee @@ -0,0 +1,16 @@ +### +# Crafting Guide - recipe_catalog_controller.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +BaseController = require './base_controller' + +######################################################################################################################## + +module.exports = class RecipeCatalogController extends BaseController + + constructor: (options={})-> + options.templateName = 'recipe_catalog' + super options diff --git a/src/scripts/crafting_guide_router.coffee b/src/scripts/crafting_guide_router.coffee new file mode 100644 index 000000000..ce971d19e --- /dev/null +++ b/src/scripts/crafting_guide_router.coffee @@ -0,0 +1,57 @@ +### +# Crafting Guide - router.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +{Duration} = require './constants' +LandingPageController = require './controllers/landing_page_controller' +{Opacity} = require './constants' + +######################################################################################################################## + +module.exports = class CraftingGuideRouter extends Backbone.Router + + constructor: (options={})-> + @_page = null + @_pageControllers = {} + super options + + # Backbone.Router Overrides #################################################################### + + routes: + '': 'landing' + + # Route Methods ################################################################################ + + landing: -> + @_pageControllers.landing ?= new LandingPageController + @_setPage 'landing' + + # Private Methods ############################################################################## + + _setPage: (controllerName)-> + controller = @_pageControllers[controllerName] + if not controller? then throw new Error "cannot find controller named: #{controllerName}" + return if @_page is controller + + logger.info "changing to #{controllerName} page" + showDuration = Duration.normal + show = => + @_page = controller + + controller.render() + # controller.$el.css 'opacity', Opacity.hidden + + $pageContent = $('.page') + $pageContent.empty() + $pageContent.append controller.$el + + controller.$el.fadeIn showDuration + + if @_mainController? + showDuration = Duration.fast + @_page.$el.fadeOut Duration.fast, show + else + show() diff --git a/src/scripts/logger.coffee b/src/scripts/logger.coffee new file mode 100644 index 000000000..823eb2a19 --- /dev/null +++ b/src/scripts/logger.coffee @@ -0,0 +1,87 @@ +### +# Crafting Guide - logger.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +######################################################################################################################## + +module.exports = class Logger + + @TRACE = {name:'TRACE ', value:0} + @DEBUG = {name:'DEBUG ', value:1} + @VERBOSE = {name:'VERBOSE', value:2} + @INFO = {name:'INFO ', value:3} + @WARNING = {name:'WARNING', value:4} + @ERROR = {name:'ERROR ', value:5} + @FATAL = {name:'FATAL ', value:6} + + ALL_LEVELS = [@TRACE, @DEBUG, @VERBOSE, @INFO, @WARNING, @ERROR, @FATAL] + + constructor: (options={})-> + options.level ?= Logger.FATAL + @formatText = if options.format? then options.format else "<%= timestamp %> | <%= level %> | <%= message %>" + @level = @_parseLevel options + + @_format = _.template @formatText + + log: (level, message)-> + return unless level.value >= @level.value + message = message() if _.isFunction message + + entry = {timestamp:new Date(), level:level, message:message} + entry.level ?= @level + + lines = @_formatEntry entry + if entry.level.value < Logger.WARNING.value + console.log(line) for line in lines + else + console.error(line) for line in lines + + # Log Methods ################################################################################## + + trace: (message)-> @log Logger.TRACE, message + + debug: (message)-> @log Logger.DEBUG, message + + verbose: (message)-> @log Logger.VERBOSE, message + + info: (message)-> @log Logger.INFO, message + + warning: (message)-> @log Logger.WARNING, message + + error: (message)-> + message = "#{message.stack}" if message.stack? + @log Logger.ERROR, message + + fatal: (message)-> @log Logger.FATAL, message + + # Private Methods ############################################################################## + + _formatEntry: (entry, lines=[])-> + message = entry.message.replace /\\n/g, '\n' + for line in message.split '\n' + result = [] + result.push @_format + timestamp: "#{entry.timestamp}" + level: entry.level.name + message: line + lines.push result.join '' + return lines + + _parseLevel: (options)-> + return Logger.FATAL unless _(options).has 'level' + level = options.level + + if not level? + candidates = [] + else if _.isString level + candidates = (l for l in ALL_LEVELS when l.name.trim().toLowerCase() is level.trim().toLowerCase()) + else if _.isNumber level + candidates = (l for l in ALL_LEVELS when l.value is level) + else if level? + candidates = (l for l in ALL_LEVELS when l is level) + + throw new Error "invalid level: #{level}" unless candidates.length > 0 + return candidates[0] diff --git a/src/scripts/main.coffee b/src/scripts/main.coffee new file mode 100644 index 000000000..0a12c5a34 --- /dev/null +++ b/src/scripts/main.coffee @@ -0,0 +1,20 @@ +### +# Crafting Guide - main.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +views = require './views' +Logger = require './logger' +CraftingGuideRouter = require './crafting_guide_router' + +if typeof(global) is 'undefined' + window.global = window + +global.views = views +global.logger = new Logger level:Logger.TRACE +global.router = new CraftingGuideRouter + +logger.info "CraftingGuide is ready" +Backbone.history.start pushState:true diff --git a/src/scripts/models/base_model.coffee b/src/scripts/models/base_model.coffee new file mode 100644 index 000000000..73158ad6d --- /dev/null +++ b/src/scripts/models/base_model.coffee @@ -0,0 +1,28 @@ +### +# crafting_guide - base_model.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +######################################################################################################################## + +module.exports = class BaseModel extends Backbone.Model + + constructor: (attributes={}, options={})-> + super attributes, options + + makeGetter = (name)-> return -> @get name + makeSetter = (name)-> return (value)-> @set name, value + for name in _.keys attributes + continue if name is 'id' + Object.defineProperty this, name, get:makeGetter(name), set:makeSetter(name) + + # Backbone.Model Overrides ##################################################################### + + sync: -> # do nothing + + # Object Overrides ############################################################################# + + toString: -> + return "#{@constructor.name} (#{@cid})" diff --git a/src/scripts/models/item.coffee b/src/scripts/models/item.coffee new file mode 100644 index 000000000..463580620 --- /dev/null +++ b/src/scripts/models/item.coffee @@ -0,0 +1,19 @@ +### +# Crafting Guide - item.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +BaseModel = require './base_model' + +######################################################################################################################## + +module.exports = class Item extends BaseModel + + constructor: (attributes={}, options={})-> + attributes.name ?= '' + attributes.quantity ?= 1 + super attributes, options + + # Public Methods ############################################################################### \ No newline at end of file diff --git a/src/scripts/models/landing_page.coffee b/src/scripts/models/landing_page.coffee new file mode 100644 index 000000000..e252b8982 --- /dev/null +++ b/src/scripts/models/landing_page.coffee @@ -0,0 +1,17 @@ +### +# Crafting Guide - landing_page.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +BaseModel = require './base_model' +RecipeCatalog = require './recipe_catalog' + +######################################################################################################################## + +module.exports = class LandingPage extends BaseModel + + constructor: (attributes={}, options={})-> + attributes.catalog ?= new RecipeCatalog + super attributes, options diff --git a/src/scripts/models/parser_versions/v1.coffee b/src/scripts/models/parser_versions/v1.coffee new file mode 100644 index 000000000..9451f8b7b --- /dev/null +++ b/src/scripts/models/parser_versions/v1.coffee @@ -0,0 +1,81 @@ +### +# Crafting Guide - v1.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +Item = require '../item' +Recipe = require '../recipe' +RecipeBook = require '../recipe_book' + + +######################################################################################################################## + +module.exports = class V1 + + constructor: -> + @_errorLocation = 'the header information' + + parse: (data)-> + return @_parseRecipeBook data + + # Private Methods ############################################################################## + + _parseRecipeBook: (data)-> + if not data? then throw new Error 'recipe book data is missing' + if not data.version? then throw new Error 'version is required' + if not data.mod_name? then throw new Error 'mod_name is required' + if not data.mod_version? then throw new Error 'mod_version is required' + if not _.isArray(data.recipes) then throw new Error 'recipes must be an array' + + book = new RecipeBook version:data.version, modName:data.mod_name, modVersion:data.mod_version + book.description = data.description or '' + + for index in [0...data.recipes.length] + @_errorLocation = "recipe #{index + 1}" + recipeData = data.recipes[index] + book.recipes.push @_parseRecipe recipeData + + return book + + _parseRecipe: (data, options={})-> + if not data? then throw new Error "recipe data is missing for #{@_errorLocation}" + if not data.output? then throw new Error "#{@_errorLocation} is missing output" + if not data.input? then throw new Error "#{@_errorLocation} is missing input" + + output = @_parseItemList data.output, field:'output', canBeEmpty:false + @_errorLocation = "recipe for output[0].name" + + data.tools ?= [] + input = @_parseItemList data.input, field:'input', canBeEmpty:false + tools = @_parseItemList data.tools, field:'tools', canBeEmpty:true + + return new Recipe input:input, output:output, tools:tools + + _parseItemList: (data, options={})-> + if not data? then throw new Error "#{@_errorLocation} must have an #{options.field} field" + + if not _.isArray(data) then data = [data] + if data.length is 0 and not options.canBeEmpty + throw new Error "#{options.field} for #{@_errorLocation} cannot be empty" + + result = [] + for index in [0...data.length] + itemData = data[index] + result.push @_parseItem itemData, field:options.field, index:index + + return result + + _parseItem: (data, options={})-> + errorBase = "#{options.field} element #{options.index} for #{@_errorLocation}" + if not data? then throw new Error "#{errorBase} is missing" + + if _.isString(data) then data = [1, data] + if not _.isArray(data) then throw new Error "#{errorBase} must be an array" + + if data.length is 1 then data.unshift 1 + if data.length isnt 2 then throw new Error "#{errorBase} must have at least one element" + if not _.isNumber(data[0]) then throw new Error "#{errorBase} must start with a number" + + return new Item quantity:data[0], name:data[1] diff --git a/src/scripts/models/recipe.coffee b/src/scripts/models/recipe.coffee new file mode 100644 index 000000000..672d6aa51 --- /dev/null +++ b/src/scripts/models/recipe.coffee @@ -0,0 +1,17 @@ +### +# Crafting Guide - recipe.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +BaseModel = require './base_model' + +######################################################################################################################## + +module.exports = class Recipe extends BaseModel + + constructor: (attributes={}, options={})-> + super attributes, options + + Object.defineProperty this, 'name', get:-> @output[0].name diff --git a/src/scripts/models/recipe_book.coffee b/src/scripts/models/recipe_book.coffee new file mode 100644 index 000000000..02c0d7013 --- /dev/null +++ b/src/scripts/models/recipe_book.coffee @@ -0,0 +1,38 @@ +### +# Crafting Guide - recipe_book.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +BaseModel = require './base_model' + +######################################################################################################################## + +module.exports = class RecipeBook extends BaseModel + + constructor: (attributes={}, options={})-> + if _.isEmpty(attributes.modName) then throw new Error 'modName cannot be empty' + if _.isEmpty(attributes.modVersion) then throw new Error 'modVersion cannot be empty' + + attributes.description ?= '' + attributes.recipes ?= [] + super attributes, options + + # Public Methods ############################################################################### + + getRecipes: (name)-> + result = [] + for recipe in @recipes + if recipe.name is name + result.push recipe + + return result + + # Object Overrides ############################################################################# + + toString: -> + return "RecipeBook (#{@cid}) { + modName:#{@modName}, + modVersion:#{@modVersion}, + recipes:#{@recipes.length} items}" diff --git a/src/scripts/models/recipe_book_parser.coffee b/src/scripts/models/recipe_book_parser.coffee new file mode 100644 index 000000000..6376190ee --- /dev/null +++ b/src/scripts/models/recipe_book_parser.coffee @@ -0,0 +1,26 @@ +### +# Crafting Guide - recipe_book_parser.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +V1 = require './parser_versions/v1' + +######################################################################################################################## + +module.exports = class RecipeBookParser + + constructor: -> + @_parsers = + '1': new V1 + + parse: (data)-> + if not data? then throw new Error 'recipe book data is missing' + if not data.version? then throw new Error 'version is required' + + parser = @_parsers["#{data.version}"] + if not parser? + throw new Error "cannot parse version #{data.version} recipe books" + + return parser.parse data diff --git a/src/scripts/models/recipe_catalog.coffee b/src/scripts/models/recipe_catalog.coffee new file mode 100644 index 000000000..ad5a30f53 --- /dev/null +++ b/src/scripts/models/recipe_catalog.coffee @@ -0,0 +1,54 @@ +### +# Crafting Guide - recipe_catalog.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +BaseModel = require './base_model' +{Event} = require '../constants' +RecipeBookParser = require './recipe_book_parser' + +######################################################################################################################## + +module.exports = class RecipeCatalog extends BaseModel + + constructor: (attributes={}, options={})-> + attributes.books ?= [] + super attributes, options + + @_parser = new RecipeBookParser + + # Public Methods ############################################################################### + + loadBook: (url)-> + @trigger Event.book.load.started, this, url + $.ajax + url: url + dataType: 'json' + success: (data, status, xhr)=> @onBookLoaded(data, status, xhr) + error: (xhr, status, error)=> @onBookLoadFailed(error, status, xhr) + + # Event Methods ################################################################################ + + onBookLoaded: (data, status, xhr)-> + try + @books.push @_parser.parse data + _(@books).sortBy 'name' + + logger.info "loaded recipe book: #{book}" + @trigger Event.book.load.succeeded, this, book + @trigger Event.book.load.finished, this + catch e + @onBookLoadFailed error, status, xhr + + + onBookLoadFailed: (error, status, xhr)-> + logger.error "failed to load recipe book: #{error}" + @trigger Event.book.load.failed, this, error.message + @trigger Event.book.load.finished, this + + # Object Overrides ############################################################################# + + toString: -> + return "RecipeCatalog (#{@cid}) {books:#{@books.length} items}" diff --git a/src/scripts/views.js b/src/scripts/views.js new file mode 100644 index 000000000..d4d321650 --- /dev/null +++ b/src/scripts/views.js @@ -0,0 +1,32 @@ +var jade = jade || require('jade').runtime; + +this["JST"] = this["JST"] || {}; + +this["JST"]["landing_page"] = function template(locals) { +var buf = []; +var jade_mixins = {}; +var jade_interp; + +var jade_indent = []; +buf.push("\n
\n
\n
\n
");;return buf.join(""); +}; + +this["JST"]["recipe_catalog"] = function template(locals) { +var buf = []; +var jade_mixins = {}; +var jade_interp; + +var jade_indent = []; +buf.push("\n
\n

\n

Recipe Catalog

\n

\n \n \n \n \n \n
 \n \n \n
\n
\n

\n
\n
");;return buf.join(""); +}; + +this["JST"]["test"] = function template(locals) { +var buf = []; +var jade_mixins = {}; +var jade_interp; + +var jade_indent = []; +buf.push("\n

Hello world!

");;return buf.join(""); +}; + +if (typeof exports === 'object' && exports) {module.exports = this["JST"];} \ No newline at end of file diff --git a/src/templates/landing_page.jade b/src/templates/landing_page.jade new file mode 100644 index 000000000..d7c3f1bad --- /dev/null +++ b/src/templates/landing_page.jade @@ -0,0 +1,10 @@ +//- +//- Crafting Guide - landing_page.jade +//- +//- Copyright (c) 2014 by Redwood Labs +//- All rights reserved. +//- + +.view__landing_page + .view__recipe_catalog + .view__crafter diff --git a/src/templates/recipe_catalog.jade b/src/templates/recipe_catalog.jade new file mode 100644 index 000000000..b7190380b --- /dev/null +++ b/src/templates/recipe_catalog.jade @@ -0,0 +1,19 @@ +//- +//- Crafting Guide - recipe_catalog.jade +//- +//- Copyright (c) 2014 by Redwood Labs +//- All rights reserved. +//- + +.view__recipe_catalog + h2 + img(src="/images/bookshelf.png") + p Recipe Catalog + + table.books + tr + td   + td + input.recipe_book_url(placeholder="enter a URL to load another recipe book...") + button.recipe_book_load_button Load + .load_error: p diff --git a/src/templates/test.jade b/src/templates/test.jade new file mode 100644 index 000000000..ac2fdc2ca --- /dev/null +++ b/src/templates/test.jade @@ -0,0 +1,8 @@ +//- +//- Crafting Guide - test.jade +//- +//- Copyright (c) 2014 by Redwood Labs +//- All rights reserved. +//- + +p Hello world! diff --git a/test/parser_versions/v1.test.coffee b/test/parser_versions/v1.test.coffee new file mode 100644 index 000000000..3234c25b2 --- /dev/null +++ b/test/parser_versions/v1.test.coffee @@ -0,0 +1,124 @@ +### +# Crafting Guide - v1.test.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +V1 = require '../../src/scripts/models/parser_versions/v1' + +######################################################################################################################## + +parser = null + +######################################################################################################################## + +describe 'RecipeBookParser.V1', -> + + before -> parser = new V1 + + describe '_parseRecipeBook', -> + + it 'requires a mod_name', -> + data = version:1, mod_version:'1.0', recipes:[] + expect(-> parser._parseRecipeBook data).to.throw Error, 'mod_name is required' + + it 'requires a mod_version', -> + data = version:1, mod_name:'Empty', recipes:[] + expect(-> parser._parseRecipeBook data).to.throw Error, 'mod_version is required' + + it 'can parse an empty recipe book', -> + data = + version: 1 + mod_name: 'Empty' + mod_version: '1.0' + recipes: [] + book = parser._parseRecipeBook data + book.modName.should.equal 'Empty' + book.modVersion.should.equal '1.0' + + it 'can parse a non-empty recipe book', -> + data = + version: 1 + mod_name: 'Minecraft' + mod_version: '1.7.10' + recipes: [ + { input:'sugar cane', output:'sugar' } + { input:[[3, 'wool'], [3, 'planks']], tools:'crafting table', output:'bed' } + ] + book = parser._parseRecipeBook data + book.modName.should.equal 'Minecraft' + book.modVersion.should.equal '1.7.10' + (r.name for r in book.recipes).sort().should.eql ['bed', 'sugar'] + + describe '_parseRecipe', -> + + it 'requires output to be defined', -> + parser._errorLocation = 'boat' + expect(-> parser._parseRecipe input:'wool').to.throw Error, 'boat is missing output' + + it 'requires input to be defined', -> + parser._errorLocation = 'boat' + expect(-> parser._parseRecipe output:'wool').to.throw Error, 'boat is missing input' + + it 'can parse a regular recipe', -> + data = + output: 'bed' + input: [[3, 'planks'], [3, 'wool']] + tools: 'crafting table' + recipe = parser._parseRecipe data + (i.name for i in recipe.output).should.eql ['bed'] + (i.name for i in recipe.input).sort().should.eql ['planks', 'wool'] + (i.name for i in recipe.tools).should.eql ['crafting table'] + + it 'can parse a recipe without tools', -> + recipe = parser._parseRecipe output:'sugar', input:'sugar cane' + (i.name for i in recipe.output).should.eql ['sugar'] + (i.name for i in recipe.input).sort().should.eql ['sugar cane'] + (i.name for i in recipe.tools).should.eql [] + + describe '_parseItemList', -> + + it 'can promote a single item to a list', -> + list = parser._parseItemList 'boat' + (i.name for i in list).should.eql ['boat'] + + it 'can require a list to be non-empty', -> + parser._errorLocation = 'boat' + options = field:'output', canBeEmpty:false + expect(-> parser._parseItemList [], options).to.throw Error, 'output for boat cannot be empty' + + it 'can allow an empty list', -> + list = parser._parseItemList [], canBeEmpty:true + list.length.should.equal 0 + + it 'can parse a non-empty list', -> + list = parser._parseItemList [[3, 'plank'], [3, 'wool']] + (i.name for i in list).sort().should.eql ['plank', 'wool'] + + describe '_parseItem', -> + + it 'requires the array to have at least one element', -> + parser._errorLocation = 'boat' + options = index:1, field:'output' + expect(-> parser._parseItem([], options)).to.throw Error, + "output element 1 for boat must have at least one element" + + it 'can fill in a missing number', -> + item = parser._parseItem 'boat' + item.name.should.equal 'boat' + item.quantity.should.equal 1 + + item2 = parser._parseItem ['boat'] + item2.name.should.equal 'boat' + item2.quantity.should.equal 1 + + it 'requires the data to start with a number', -> + parser._errorLocation = 'boat' + options = index:1, field:'output' + expect(-> parser._parseItem(['2', 'book'], options)).to.throw Error, + "output element 1 for boat must start with a number" + + it 'can parse a basic item', -> + item = parser._parseItem [2, 'book'] + item.constructor.name.should.equal 'Item' diff --git a/test/test.coffee b/test/test.coffee new file mode 100644 index 000000000..2d3b01ed3 --- /dev/null +++ b/test/test.coffee @@ -0,0 +1,27 @@ +### +# Crafting Guide - test.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +# Test Set-up ########################################################################################################## + +chai.use require 'sinon-chai' +chai.config.includeStack = true + +if typeof(global) is 'undefined' + window.global = window + +global.assert = chai.assert +global.expect = chai.expect +global.should = chai.should() + +# Test Registry ######################################################################################################## + +mocha.setup 'bdd' + +require './parser_versions/v1.test' + +mocha.checkLeaks() +mocha.run()
+
+

+

Crafting Guide

+

+
+
+
+
+