From ddfe0d885012bb4f8d8f22c11955e8e24c2d50d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Gonz=C3=A1lez?= Date: Thu, 11 Jun 2015 21:11:42 -0300 Subject: [PATCH 01/21] Blocks are always assigned in the same order (the block index is kept constant while rotating) --- demo.html | 77 +++++++++++++++++++++++++++++++ src/blockrain.jquery.src.js | 82 +++++++++++++++++----------------- src/blockrain.jquery.themes.js | 13 ++++++ 3 files changed, 131 insertions(+), 41 deletions(-) create mode 100644 demo.html diff --git a/demo.html b/demo.html new file mode 100644 index 0000000..9557aa5 --- /dev/null +++ b/demo.html @@ -0,0 +1,77 @@ + + + + + + Blockrain.js - A Tetris game in HTML5 + Javascript (with autoplay!) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

Try it yourself!

+
+
+
+
+
+
+ +
+ + + + + + + + + + diff --git a/src/blockrain.jquery.src.js b/src/blockrain.jquery.src.js index debeae8..b88cb78 100644 --- a/src/blockrain.jquery.src.js +++ b/src/blockrain.jquery.src.js @@ -452,9 +452,9 @@ if (drop) { this.y++; } var blocks = this.getBlocks(_orientation), - x = _x === undefined ? this.x : _x, - y = _y === undefined ? this.y : _y, - i = 0; + x = _x === undefined ? this.x : _x, + y = _y === undefined ? this.y : _y, + i = 0; for (; i maxx) { maxx = blocks[i]; } @@ -485,14 +485,14 @@ this._shapeFactory = { line: function() { - /* - * X X - * O XOXX O XOXX - * X X - * X X + /* . . + * X + * O XOXX + * X + * X */ - var ver = [0, -1, 0, -2, 0, -3, 0, -4], - hor = [-1, -2, 0, -2, 1, -2, 2, -2]; + var ver = [ 0, -1, 0, -2, 0, -3, 0, -4], + hor = [-1, -2, 0, -2, 1, -2, 2, -2]; return new Shape(game, [ver, hor, ver, hor], true, 'line'); }, square: function() { @@ -505,61 +505,61 @@ }, arrow: function() { /* - * X X X + * . .X .X .X * XOX OX XOX XO - * X X X + * X X X */ return new Shape(game, [ - [0, -1, 1, -1, 2, -1, 1, -2], - [1, -2, 1, -1, 1, 0, 2, -1], - [0, -1, 1, -1, 2, -1, 1, 0], - [0, -1, 1, -1, 1, -2, 1, 0] + [0, -1, 1, -1, 2, -1, 1, -2], + [1, -2, 1, -1, 1, 0, 2, -1], + [2, -1, 1, -1, 1, 0, 0, -1], + [1, 0, 1, -1, 1, -2, 0, -1] ], false, 'arrow'); }, rightHook: function() { /* - * XX X X - * XOX O XOX O - * X X XX + * X .X . .XX + * XOX O XOX O + * XX X X */ return new Shape(game, [ - [0, 0, 0, -1, 1, -1, 2, -1], - [0, -2, 1, 0, 1, -1, 1, -2], - [0, -1, 1, -1, 2, -1, 2, -2], - [0, -2, 0, -1, 0, 0, 1, 0] + [0, 0, 0, -1, 1, -1, 2, -1], + [0, -2, 1, -2, 1, -1, 1, 0], + [2, -2, 2, -1, 1, -1, 0, -1], + [2, 0, 1, 0, 1, -1, 1, -2] ], false, 'rightHook'); }, leftHook: function() { /* - * X X XX - * XOX O XOX O - * X XX X + * . .XX X .X + * XOX O XOX O + * X X XX */ return new Shape(game, [ - [2, 0, 0, -1, 1, -1, 2, -1], - [0, 0, 1, 0, 1, -1, 1, -2], - [0, -2, 0, -1, 1, -1, 2, -1], - [0, 0, 0, -1, 0, -2, 1, -2] + [2, -2, 2, -1, 1, -1, 0, -1], + [0, 2, 0, 1, 1, -1, 1, -2], + [0, 0, 0, -1, 1, -1, 2, -1], + [0, -2, 1, -2, 1, -1, 1, 0] ], false, 'leftHook'); }, leftZag: function() { /* - * X - * XO OX - * XX X + * X .XX + * XO XO + * X */ - var ver = [0, 0, 0, -1, 1, -1, 1, -2], - hor = [0, -1, 1, -1, 1, 0, 2, 0]; + var ver = [0, 0, 0, -1, 1, -1, 1, -2], + hor = [0, -1, 1, -1, 1, 0, 2, 0]; return new Shape(game, [hor, ver, hor, ver], true, 'leftZag'); }, rightZag: function() { /* - * X - * OX OX - * XX X + * .X XX + * XO OX + * X */ - var ver = [0, -2, 0, -1, 1, -1, 1, 0], - hor = [0, 0, 1, 0, 1, -1, 2, -1]; + var ver = [1, 0, 1, -1, 0, -1, 0, -2], + hor = [0, 0, 1, 0, 1, -1, 2, -1]; return new Shape(game, [hor, ver, hor, ver], true, 'rightZag'); } }; diff --git a/src/blockrain.jquery.themes.js b/src/blockrain.jquery.themes.js index 4699d0e..5aebb04 100644 --- a/src/blockrain.jquery.themes.js +++ b/src/blockrain.jquery.themes.js @@ -2,6 +2,19 @@ * Themes. You can add more custom themes to this object. */ window.BlockrainThemes = { + 'individual': { + background: '#040304', + backgroundGrid: 'data:image/png;base64,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', + blocks: { + line: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAABACAIAAAB6Pz7pAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkRGRTkyMEZFMTA5MjExRTVBQkY1RDMyM0REODFEMDI5IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkRGRTkyMEZGMTA5MjExRTVBQkY1RDMyM0REODFEMDI5Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6REZFOTIwRkMxMDkyMTFFNUFCRjVEMzIzREQ4MUQwMjkiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6REZFOTIwRkQxMDkyMTFFNUFCRjVEMzIzREQ4MUQwMjkiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6Kbda4AAAGSklEQVR42uyd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', + square: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAABACAIAAAB6Pz7pAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkRGRTkyMEZFMTA5MjExRTVBQkY1RDMyM0REODFEMDI5IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkRGRTkyMEZGMTA5MjExRTVBQkY1RDMyM0REODFEMDI5Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6REZFOTIwRkMxMDkyMTFFNUFCRjVEMzIzREQ4MUQwMjkiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6REZFOTIwRkQxMDkyMTFFNUFCRjVEMzIzREQ4MUQwMjkiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6Kbda4AAAGSklEQVR42uyd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', + arrow: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAABACAIAAAB6Pz7pAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkRGRTkyMEZFMTA5MjExRTVBQkY1RDMyM0REODFEMDI5IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkRGRTkyMEZGMTA5MjExRTVBQkY1RDMyM0REODFEMDI5Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6REZFOTIwRkMxMDkyMTFFNUFCRjVEMzIzREQ4MUQwMjkiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6REZFOTIwRkQxMDkyMTFFNUFCRjVEMzIzREQ4MUQwMjkiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6Kbda4AAAGSklEQVR42uyd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', + rightHook:'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAABACAIAAAB6Pz7pAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkRGRTkyMEZFMTA5MjExRTVBQkY1RDMyM0REODFEMDI5IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkRGRTkyMEZGMTA5MjExRTVBQkY1RDMyM0REODFEMDI5Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6REZFOTIwRkMxMDkyMTFFNUFCRjVEMzIzREQ4MUQwMjkiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6REZFOTIwRkQxMDkyMTFFNUFCRjVEMzIzREQ4MUQwMjkiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6Kbda4AAAGSklEQVR42uyd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', + leftHook: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAABACAIAAAB6Pz7pAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkRGRTkyMEZFMTA5MjExRTVBQkY1RDMyM0REODFEMDI5IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkRGRTkyMEZGMTA5MjExRTVBQkY1RDMyM0REODFEMDI5Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6REZFOTIwRkMxMDkyMTFFNUFCRjVEMzIzREQ4MUQwMjkiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6REZFOTIwRkQxMDkyMTFFNUFCRjVEMzIzREQ4MUQwMjkiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6Kbda4AAAGSklEQVR42uyd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', + rightZag: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAABACAIAAAB6Pz7pAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkRGRTkyMEZFMTA5MjExRTVBQkY1RDMyM0REODFEMDI5IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkRGRTkyMEZGMTA5MjExRTVBQkY1RDMyM0REODFEMDI5Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6REZFOTIwRkMxMDkyMTFFNUFCRjVEMzIzREQ4MUQwMjkiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6REZFOTIwRkQxMDkyMTFFNUFCRjVEMzIzREQ4MUQwMjkiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6Kbda4AAAGSklEQVR42uyd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', + leftZag: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAABACAIAAAB6Pz7pAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkRGRTkyMEZFMTA5MjExRTVBQkY1RDMyM0REODFEMDI5IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkRGRTkyMEZGMTA5MjExRTVBQkY1RDMyM0REODFEMDI5Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6REZFOTIwRkMxMDkyMTFFNUFCRjVEMzIzREQ4MUQwMjkiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6REZFOTIwRkQxMDkyMTFFNUFCRjVEMzIzREQ4MUQwMjkiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6Kbda4AAAGSklEQVR42uydP2gTURzHn+Lk3oK4WKmgVCm6VEToUItmEJeASyWDQ/2DDkVRh04OCSgdFKOOJR0sOnQSoQlSKdZOIiRQUGgHQWgQBxvX+D0v3r27XEwu3t17L/l+yHBpa/zd3e/73vf3/lx21et1QUi/spuXgFAAhFAAhFAAhFAAhFAAhFAAhFAAhFAAhPQie3gJgtnaErWa+3ZoSOzda1L8lYrn7eCgGBjgXU1WALgHjx83jkdHxdWrul+MX7/E2pooFkUuF/Db8XFx8aJIp/XNJFzwd+/E4qJYWQn47fCwuHxZnD8vRkaMTNVq1ZKxQ6EgpqYi+Nh6TBSLdXy485qerutMrVYvFOrDw56YW73yee3ix9UeH+8oePtebG/XjQNhy2eB+xUF8Qggmw246NpSLofIHvuVTlua0YHNTSuYUMHjBanjHxrE0pL/FCISwJ7oXcTMjHj+3JiOdWFBXLoU4BYmJsTp0423X7+KN288vuLVK+tvslnFwa+vi5MnA34On4bwHKvTHP+XL2JyUrx/b0ZhAPNz61ZcH55Qa6RnDwAn4LM9iPPDh5Y2w/fH+Iny5l+OB/0YWspW9gYdne/uaO5Lm82PfP21s0C4vnJ8OJa7LW2vNdLdCbhV6ssJJ58jEk45yAPnandS6vg0oL8RkrPIPlkdBeAreW2LCUkY0digqEV4HXp6nxnFOeqggc4LEvQPmhf0rbpo3CM5oyISQBQTYbmcOHPGM1y4vCwOHDCmDMhkxLNnnQ7zX7hg2WuHjx/Vxz81FWKOAqb/7l337adPWt+auTmrXLG5cUPLmWDUYffuecqv168b2b+zY4YAws5w4RxbzTcZgTwPUCrpGydSy5mQmZ6OafrivwUwNua2KDiYn3fz6fPn3pw8lO/Ejx9mn4vTvmo4KenMc6HLvX9f45ng2VlrAvXcOU/fSoxAtnNagYx3xPnwYXzDtVEIAE3+y5dcamIMP3+6xxMTBpgf1F2xEdFq0L7K/tVV99iZLDOIxUX3eHTUJPMTw5ADl0OHZ2PDPT50yLDgUfXKU8KplHYRPnqUjPmhALpia8uTQMeOGRb8lSvuW7gL3UarKxV3UDFm80MBdMWLF+4xin6DNgkgtyYn3cY1zqGV7s3P9eueyxs/FEAYqlXPpEck69ETyCrUlGj4jx71ZP/ysnaV2/y827sWCsn0TtwRFoa5OY9/0G1nCRyObyvP9+/WwlUf2ay4eVO7vgsd1LVrjeN0OrHGhQLoGHlsTsQ1M/9f1Gr/Woiu8442n/l58CCx/5kC6LhxldukfN68jYVwF4cPWweplHa1rwrzQwGEaZ9u33YNNBrRTMbIE3H6B/g3lJiayACNiwrzQwF0zMyM66RRPqKD1nPwZ2hIlMv+H+7sWIuyVlc97gjHeBWLWswEo3FRYX4axL5Xw6zNR233N7fdNKP5xn/fTj3lpyOH1HZzQgwbYjgM+k8WFjzjnmgyx8ZMPRf0WnAXm5ueBXB37lgGT6H5cTZko0ZXYSwpgNaUSp798tmspkvHQgHfv7TkqYzX1rQwP0+eKDGWFEDr7Je3uSH7e2ax98iIVQTL3Zqq3tWprNSNqrEIDqJS6dnst0ml3JoYWZj8812qVf/TaKCHtsjrcOVjm+6Gj1gEt3n0gz7PwIr2WWByKaw8gEheLIKjKcvkFWPptGeTJ+k5KABmf1/DGuAvzdO9PZz98tYqJduCBwetJQ9hkafzUMdHsR2PAvib/ZmMOyjR822/XEEqGdsdGOiyZnUEgOyPYtEELVBT9qNFzOd7Ofvh9ORlERruimQNkCi+pT4a7hRpRbXapdOTOXWKAuhjcjm3ObSz36CHOsJJI/7On04Hwch9nfgzA9Xfz7Pp7xrg6VPPUp/9+4O/HKktCpcWI3687M0uJ06IgweDE3p9Xbx96zlZYfK6bgogGnyPhl1ZCf52rbYo3x3mi1xe6bCxEXxSHOSlAHqWtt/Qgy5rdpbZzxrAcLa3LRMfaiAfnUO5bC3+Yfb/YZf1JRkxgeLMmXDZt0/HtcSlkvj2LYLPOXtWcSlpX2p7dL+5+bcfgHXkiDXgY3TJK2fU8eORLCCNUwCE0AIRQgEQQgEQQgEQQgEQQgEQQgEQQgEQQgEQQgEQQgEQQgEQkgi/BRgAZKy86ZGCockAAAAASUVORK5CYII=' + } + }, 'candy': { background: '#040304', backgroundGrid: 'data:image/png;base64,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', From dd2e9b40ea9ef2a3bac71073299e530194a07829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Gonz=C3=A1lez?= Date: Thu, 11 Jun 2015 21:30:27 -0300 Subject: [PATCH 02/21] The block rotation system kind of works. --- demo.html | 2 +- src/blockrain.jquery.src.js | 31 ++++++++++++++++++++++--------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/demo.html b/demo.html index 9557aa5..24a892d 100644 --- a/demo.html +++ b/demo.html @@ -59,7 +59,7 @@

Try it yourself!

var $demo = $('#tetris-demo').blockrain({ speed: 20, - theme: 'vim', + theme: 'individual', onStart: function() { }, diff --git a/src/blockrain.jquery.src.js b/src/blockrain.jquery.src.js index b88cb78..39e54ce 100644 --- a/src/blockrain.jquery.src.js +++ b/src/blockrain.jquery.src.js @@ -265,9 +265,9 @@ var cx = x * this._block_size; var cy = y * this._block_size; - this._ctx.drawImage( this._theme.backgroundGrid, - 0, 0, this._theme.backgroundGrid.width, this._theme.backgroundGrid.height, - cx, cy, this._block_size, this._block_size); + this._ctx.drawImage( this._theme.backgroundGrid, + 0, 0, this._theme.backgroundGrid.width, this._theme.backgroundGrid.height, + cx, cy, this._block_size, this._block_size); } } @@ -302,7 +302,7 @@ * The blockType is used to draw any block. * The falling attribute is needed to apply different styles for falling and placed blocks. */ - _drawBlock: function(x, y, blockType, falling) { + _drawBlock: function(x, y, blockType, blockIndex, blockRotation, falling) { // convert x and y to pixel x = x * this._block_size; @@ -313,7 +313,7 @@ var borderDistance = Math.round(this._block_size*0.23); var squareDistance = Math.round(this._block_size*0.30); - var color = this._getBlockColor(blockType, falling); + var color = this._getBlockColor(blockType, blockIndex, falling); // Draw the main square this._ctx.globalAlpha = 1.0; @@ -325,7 +325,17 @@ // Not loaded if( color.width === 0 || color.height === 0 ){ return; } - this._ctx.drawImage(color, 0, 0, color.width, color.height, x, y, this._block_size, this._block_size); + //this._ctx.drawImage(color, 0, 0, color.width, color.height, x, y, this._block_size, this._block_size); + // Uses a long tile (4 subtiles) + var tilesize = color.height; + this._ctx.save(); + + this._ctx.translate(x, y); + this._ctx.rotate(Math.PI/2 * blockRotation); + this._ctx.drawImage(color, blockIndex*tilesize, 0, tilesize, tilesize, + 0, 0, this._block_size, this._block_size); + + this._ctx.restore(); } else if( typeof color === 'string' ) @@ -373,7 +383,7 @@ }, - _getBlockColor: function(blockName, falling) { + _getBlockColor: function(blockName, blockIndex, falling) { /** * The theme allows us to do many things: * - Use a specific color for the falling block (primary), regardless of the proper color. @@ -423,6 +433,7 @@ }); return this; }, + blockType: blockType, blocksLen: orientations[0].length, orientations: orientations, @@ -454,10 +465,12 @@ var blocks = this.getBlocks(_orientation), x = _x === undefined ? this.x : _x, y = _y === undefined ? this.y : _y, - i = 0; + i = 0, + index = 0; for (; i Date: Fri, 12 Jun 2015 00:19:08 -0300 Subject: [PATCH 03/21] INTRODUCING: The world's first Tetris in which you can rotate the square. --- demo.html | 2 +- src/blockrain.jquery.src.js | 100 ++++++++++++++++++++++++------------ 2 files changed, 67 insertions(+), 35 deletions(-) diff --git a/demo.html b/demo.html index 24a892d..bafe2ad 100644 --- a/demo.html +++ b/demo.html @@ -58,7 +58,7 @@

Try it yourself!

diff --git a/src/blockrain.css b/src/blockrain.css index 99bf1ec..ad5714a 100644 --- a/src/blockrain.css +++ b/src/blockrain.css @@ -7,6 +7,70 @@ line-height: 140%; } +/* Touch Controls */ +.blockrain-touch { + position: absolute; + width: 50px; + height: 50px; + display: block; + border-radius: 100%; + border: 1px solid white; + background: rgba(255,255,255,0.2); + z-index: 10; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + line-height: 50px; + text-align: center; +} +.blockrain-touch:active { + background: rgba(255,255,255,0.3); +} + +.blockrain-touch-left { + left: 10px; + bottom: 10px; +} +.blockrain-touch-left::after { + content: "<"; +} +.blockrain-touch-right { + right: 10px; + bottom: 10px; +} +.blockrain-touch-right::after { + content: ">"; +} + +.blockrain-touch-rotate-left { + left: 10px; + bottom: 80px; +} +.blockrain-touch-rotate-left::after { + content: ""; +} + +.blockrain-touch-drop { + left: 50%; + margin-left: -25px; + bottom: 10px; +} +.blockrain-touch-drop::after { + content: "."; +} + /* Buttons */ .blockrain-btn { position: relative; diff --git a/src/blockrain.jquery.src.js b/src/blockrain.jquery.src.js index a226e13..a2b463f 100644 --- a/src/blockrain.jquery.src.js +++ b/src/blockrain.jquery.src.js @@ -83,6 +83,7 @@ this._doStart(); } this._setupControls( ! enable ); + this._setupTouchControls( ! enable ); }, controls: function(enable) { @@ -90,6 +91,11 @@ this._setupControls(enable); }, + touchControls: function(enable) { + if( typeof enable !== 'boolean' ){ enable = true; } + this._setupTouchControls(enable); + }, + score: function(newScore) { if( typeof newScore !== 'undefined' && parseInt(newScore) >= 0 ) { this._filled.score = parseInt(newScore); @@ -216,7 +222,6 @@ var renderLoop = function(){ requestAnimationFrame(renderLoop); game._board.render(); - console.log("render"); }; renderLoop(); @@ -503,6 +508,11 @@ this.x--; } }, + drop: function() { + if (!game._checkCollisions(this.x, this.y + 1, this.getBlocks())) { + this.y++; + } + }, getBlocks: function(orientation) { // optional param return this.orientations[orientation !== undefined ? orientation : this.orientation]; }, @@ -1063,6 +1073,20 @@ }); game._$gameholder.append(game._$gameover); + this._createControls(); + }, + + + _createControls: function() { + + var game = this; + + game._$touchLeft = $('').appendTo(game._$gameholder); + game._$touchRight = $('').appendTo(game._$gameholder); + game._$touchRotateRight = $('').appendTo(game._$gameholder); + game._$touchRotateLeft = $('').appendTo(game._$gameholder); + game._$touchDrop = $('').appendTo(game._$gameholder); + }, @@ -1224,10 +1248,10 @@ caught = true; if (game.options.asdwKeys) { switch(evt.keyCode) { - case 65: /*a*/ game._board.cur.moveLeft(); break; - case 87: /*w*/ game._board.cur.rotate(true); break; - case 68: /*d*/ game._board.cur.moveRight(); break; - case 83: /*s*/ game._board.dropCount = game._board.dropDelay; break; + case 65: /*a*/ game._board.cur.moveLeft(); break; + case 87: /*w*/ game._board.cur.rotate(true); break; + case 68: /*d*/ game._board.cur.moveRight(); break; + case 83: /*s*/ game._board.dropCount = game._board.dropDelay; break; } } switch(evt.keyCode) { @@ -1277,11 +1301,65 @@ // Unbind everything by default // Use event namespacing so we don't ruin other keypress events - $(document).unbind('keypress.blockrain').unbind('keydown.blockrain').unbind('keyup.blockrain'); + $(document) .unbind('keypress.blockrain') + .unbind('keydown.blockrain') + .unbind('keyup.blockrain'); + + if( ! game.options.autoplay ) { + if( enable ) { + $(document) .bind('keypress.blockrain', keypress) + .bind('keydown.blockrain', keydown) + .bind('keyup.blockrain', keyup); + } + } + }, + + + _setupTouchControls: function(enable) { + + var game = this; + + var moveLeft = function(event){ + event.preventDefault(); + game._board.cur.moveLeft(); + }; + var moveRight = function(event){ + event.preventDefault(); + game._board.cur.moveRight(); + }; + var drop = function(event){ + event.preventDefault(); + game._board.dropCount = game._board.dropDelay; + }; + var rotateLeft = function(event){ + event.preventDefault(); + game._board.cur.rotate(false); + }; + var rotateRight = function(event){ + event.preventDefault(); + game._board.cur.rotate(true); + }; + + // Unbind everything by default + game._$touchLeft.unbind('mousedown'); + game._$touchRight.unbind('mousedown'); + game._$touchRotateLeft.unbind('mousedown'); + game._$touchRotateRight.unbind('mousedown'); + game._$touchDrop.unbind('mousedown'); if( ! game.options.autoplay ) { if( enable ) { - $(document).bind('keypress.blockrain', keypress).bind('keydown.blockrain', keydown).bind('keyup.blockrain', keyup); + game._$touchLeft.show().bind('mousedown', moveLeft); + game._$touchRight.show().bind('mousedown', moveRight); + game._$touchRotateLeft.show().bind('mousedown', rotateLeft); + game._$touchRotateRight.show().bind('mousedown', rotateRight); + game._$touchDrop.show().bind('mousedown', drop); + } else { + game._$touchLeft.hide(); + game._$touchRight.hide(); + game._$touchRotateLeft.hide(); + game._$touchRotateRight.hide(); + game._$touchDrop.hide(); } } } From e1ef9778dee500ea53de5ce316bb7fcd45d7ea84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Gonz=C3=A1lez?= Date: Sun, 14 Jun 2015 21:28:43 -0300 Subject: [PATCH 10/21] Touch controls work better. --- src/blockrain.css | 10 +++++----- src/blockrain.jquery.src.js | 22 ++++++++++++---------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/blockrain.css b/src/blockrain.css index ad5714a..6563c52 100644 --- a/src/blockrain.css +++ b/src/blockrain.css @@ -32,14 +32,14 @@ } .blockrain-touch-left { - left: 10px; + left: -60px; bottom: 10px; } .blockrain-touch-left::after { content: "<"; } .blockrain-touch-right { - right: 10px; + right: -60px; bottom: 10px; } .blockrain-touch-right::after { @@ -47,7 +47,7 @@ } .blockrain-touch-rotate-left { - left: 10px; + left: -60px; bottom: 80px; } .blockrain-touch-rotate-left::after { @@ -55,7 +55,7 @@ } .blockrain-touch-rotate-right { - right: 10px; + right: -60px; bottom: 80px; } .blockrain-touch-rotate-right::after { @@ -65,7 +65,7 @@ .blockrain-touch-drop { left: 50%; margin-left: -25px; - bottom: 10px; + bottom: -60px; } .blockrain-touch-drop::after { content: "."; diff --git a/src/blockrain.jquery.src.js b/src/blockrain.jquery.src.js index a2b463f..fa083b6 100644 --- a/src/blockrain.jquery.src.js +++ b/src/blockrain.jquery.src.js @@ -227,8 +227,10 @@ if( this.options.autoplay ) { this.autoplay(true); + this._setupTouchControls(false); } else { this._setupControls(true); + this._setupTouchControls(false); } }, @@ -1341,19 +1343,19 @@ }; // Unbind everything by default - game._$touchLeft.unbind('mousedown'); - game._$touchRight.unbind('mousedown'); - game._$touchRotateLeft.unbind('mousedown'); - game._$touchRotateRight.unbind('mousedown'); - game._$touchDrop.unbind('mousedown'); + game._$touchLeft.unbind('touchstart'); + game._$touchRight.unbind('touchstart'); + game._$touchRotateLeft.unbind('touchstart'); + game._$touchRotateRight.unbind('touchstart'); + game._$touchDrop.unbind('touchstart'); if( ! game.options.autoplay ) { if( enable ) { - game._$touchLeft.show().bind('mousedown', moveLeft); - game._$touchRight.show().bind('mousedown', moveRight); - game._$touchRotateLeft.show().bind('mousedown', rotateLeft); - game._$touchRotateRight.show().bind('mousedown', rotateRight); - game._$touchDrop.show().bind('mousedown', drop); + game._$touchLeft.show().bind('touchstart', moveLeft); + game._$touchRight.show().bind('touchstart', moveRight); + game._$touchRotateLeft.show().bind('touchstart', rotateLeft); + game._$touchRotateRight.show().bind('touchstart', rotateRight); + game._$touchDrop.show().bind('touchstart', drop); } else { game._$touchLeft.hide(); game._$touchRight.hide(); From 339631577baccea5324f5b7ead1a2912f4e87fd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Gonz=C3=A1lez?= Date: Mon, 15 Jun 2015 18:56:29 -0300 Subject: [PATCH 11/21] Assets can be loaded via URL. --- assets/blocks/individual/arrow.png | Bin 0 -> 1427 bytes assets/blocks/individual/leftHook.png | Bin 0 -> 1011 bytes assets/blocks/individual/leftZag.png | Bin 0 -> 1327 bytes assets/blocks/individual/line.png | Bin 0 -> 2114 bytes assets/blocks/individual/rightHook.png | Bin 0 -> 1583 bytes assets/blocks/individual/rightZag.png | Bin 0 -> 902 bytes assets/blocks/individual/square.png | Bin 0 -> 2058 bytes demo.html | 2 +- src/blockrain.jquery.src.js | 128 ++++++++++++++++--------- src/blockrain.jquery.themes.js | 14 +-- 10 files changed, 90 insertions(+), 54 deletions(-) create mode 100644 assets/blocks/individual/arrow.png create mode 100644 assets/blocks/individual/leftHook.png create mode 100644 assets/blocks/individual/leftZag.png create mode 100644 assets/blocks/individual/line.png create mode 100644 assets/blocks/individual/rightHook.png create mode 100644 assets/blocks/individual/rightZag.png create mode 100644 assets/blocks/individual/square.png diff --git a/assets/blocks/individual/arrow.png b/assets/blocks/individual/arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..6afaad12d1a474ff987dee413ab8a64825ba3b04 GIT binary patch literal 1427 zcmZ`(c~H^`6#l`2A&$wGqU3JU9<<+=)LCLZg0q?z}D37Th~q!e^c86EwF++`wU34Ic@>O^}3q7mDZwJp{*cnjS<`}b% z`_gLY{=jyGc0Ci(bvZmAj{K#hNBX96q8yh?=F$6g9V$+J=SiBgNtsA(SfC2vi6wrfeb=jQ!j!B4h*{h#@dcv+UnsVf3 zld^pb8%|9V`PwTZyHj_bltkz8Csu&LLAy*##wxE|{@$Tral#}!bKvMP`X+k=u8Z=M z+glo^WJg20`L9rj9`?Y8T)F&s-rja4U!nogJ7j%KC}YV2(VL3(eHEypuxEgrFMV5;034nYGjbEk&aLuwE`bW2YBT-ws)NRi4P*&K9D zd@I`l-TCH%0z3Fq8M}@3t-5)5Gbi@+Vs13q7PI@4omgSog9G63dZY7x}`96vrH{C4e3F*kL z&Vkx}6z&$0i@@_-tj2%wF&( z=9O?Wcs_tS3LX?Ky;{18YXIdLt~peK+Qzk8r0xpk1m4guK`JT@Kt>3JLR7KHcWJ$8 zr~SfatjVINDxz)jxDM-<&)+#G7LW}o?|jJDPG#vIs;`Skpl;9RDn&(o40`t_!CpI~ zs;o~WMcF|nes^~udKjW5bFs;36e`x~P-Ekd-*np+W~AY9$NX-c6$&1l326)=y|%Wn z&f*Is$@PU)_Vhd2SVYPNWgpW_YHIt4o?BJcS|B3uN8z9^Ip|+6`2|b$7I7eYfMn?d UT%QKjSFtSMiuZ7Aa0t))6M+MRx&QzG literal 0 HcmV?d00001 diff --git a/assets/blocks/individual/leftHook.png b/assets/blocks/individual/leftHook.png new file mode 100644 index 0000000000000000000000000000000000000000..33e5506c5aa9250ac2e3f99747dc48fa35d31e36 GIT binary patch literal 1011 zcmeAS@N?(olHy`uVBq!ia0vp^4M2Q=gAGWYNy}aiq!^2X+?^QKos)S9a~60+7BevL9R^{>-rb#hl_dQ@{IF<-p$kd;iYWn|N>O z{3as?3+4u6EX3!?11HWi*@?OCShuRgeD3UB_xfYl42l@$pF4M`|Ektq-{-#%JO8-W z6H~`>K$2k&BN@a_{e&mAj8BsU^-dYxE!`cXclm1fkA43IUcWWFW3D`%QRd^64aYx! zF8TWC@ZH#5Ry_7h4|o{PF(45!>=utW6+aqu*7L^R`PedHVue%31vE9pa_@*6eA?IW z=u63d%ao37f0^fBe_e9*?e)vSD`rnT&0wSGlETK2&QO3L)-hK&w45N;cuaM@igE&q zMrfgbozX^f%2{EjmNaCm5SBt&b%7 literal 0 HcmV?d00001 diff --git a/assets/blocks/individual/leftZag.png b/assets/blocks/individual/leftZag.png new file mode 100644 index 0000000000000000000000000000000000000000..2e307a3f60716e345d177e66ef5dd247f98558ab GIT binary patch literal 1327 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 S=_#;0XYh3Ob6Mw<&;$Up^`tTY literal 0 HcmV?d00001 diff --git a/assets/blocks/individual/rightZag.png b/assets/blocks/individual/rightZag.png new file mode 100644 index 0000000000000000000000000000000000000000..ed2a00fbc5aa443310e59f2362295af294bae313 GIT binary patch literal 902 zcmeAS@N?(olHy`uVBq!ia0vp^4M2Q=gAGWYNy}aiq!^2X+?^QKos)S9a~60+7BevL9R^{>zH*VfT7`GkC=<*mZshF4oa6izvg;=VcY`s4@|Et zV|J8Ym#$zwI5(j?N$|?442KC#t!cAn{@kBGdCy;ep}2eAV)NtP#PTG5pFdak*ySbB zk0)v{9^q8*V<=?m5O$cu@Q6h~y}<%iNG+a!L-m)m8yLG3I30y*!#qA1YRXid*@VxN9~YYNGT!;{{L%H^Xkwh`A>9_g Xy1y;d^n5KS?=X0}`njxgN@xNA_9;`B literal 0 HcmV?d00001 diff --git a/assets/blocks/individual/square.png b/assets/blocks/individual/square.png new file mode 100644 index 0000000000000000000000000000000000000000..bc9a7236ff328568cf23ca60db973df8abebb697 GIT binary patch literal 2058 zcma)-dpHvcAIB$!9JkY1jF40=rL!Dbxnw5M?AUB3hYnI!5nC>6u8WcyH66LUSR-U) zCd3}5R>EGn%q1HYt4XU3J9Eil#_4_Dzu)t`fBb%*=lTBq{rx@^Kcu&=wuv?X0MLb> z^2B^+&3{H~%lECc{bl+)j1x}&mf%mgkU$EL!vSCsgmX9xcue?390nI2krdmDa|Hl2 znQ%`SHu3H3gO`NSt3Vzi`_P-3`^`2^T_zw{{0q&I6Lm1BDiifc+UnlEvKM+5UdJ47 znLM<}f7}_fGjsMtv-*!wRZ-wZ0nzLS_&WVO^cqytF<_3+2qibXQed zXoKjADTb_&6!^@nb5ov8J(Q1f4H~uzi9#tc4!SCwwFj!^CPUT&RgppDwWV6I`{vBY zS7ofQu+UKY0*V#FxhfOXA4DL+L6+j?WEU>Cg&2u1%X49IFm{+Pd+Ye2On%Jq&RCjP zrJBO{yzJ$TV}iXl4&@xTu8SJlf}F3(rVz+cZs|^s)L^UCo;7E=vw_$F;5*o1?>vAp z5F7DLNa=aR0#b5-*jxYHp`5gFpO$Q*D_{HFVc&;;?9Y0HMZZz~x#YNd@g_Wn;ac1@ zAH7YpUZ-@R`pahLiYl|rXy*>=qCuAFuqo z^ofNz8rnsAFYL zx~aa#jg8*z1KLUNjuux=HVyA6BNgPP{9|E6dnpY#-B&fI>k4sW8fqpD{XgINyhS3=>`3nOv{LFfnXn;>Nr=WHMQ%#VnYdzP>_-0s_(4fP}z>Z2q4g)aLJ`zcr%}U8+vw1{DQKEzKqBFhIaijjWm!BUVAqZ;! zm`9|XQ(o^H?pZBIubeeIV<%q0R2QRcUd=Q#9d~hYadQq+gST{12^2hyHrCN7LZb8H&7T(z z*c#~n&o}vlg}1!0g+~Ck`aH_H3#quP9S$N(m*W=9znW4=rV^@*+^k)5EQ>|)s)Vh% zJU|Ni+V_w%aX~BW*6LZTy92Cw;=TMToV(`yq^?~(jjC6Sw(dPzUpQaP1;|7+YjWC> z%}-{&78`NqM$Nle;h==vp<#p*SX{Xwv|G(^>B}*+Ais1J2-_?JYT_Nc79FH3F0s5$ z<|W%k7m)v~FYyTaSC?${6h)F$ z(MV4%OW(GS6sKvdk#R3EZOr&>9*6#-^tYQ+^V*8qLLl+yjK6du;2i}HJ3`v_gl4i+ zDWH%OA-DNMG4#vB<9K$<=@4mZoMdjUJIrP1wSR1F3sRv-vE|AW5}=ncN~T*J)Y}7j z?NlSHoUj(*Sps5Y))Xz2sWx(Fnw%z^I}ht@CN3YS1j9zPJG)ez
-

Try it yourself!

+

Check out the demo

diff --git a/src/blockrain.jquery.src.js b/src/blockrain.jquery.src.js index fa083b6..cc5fdc7 100644 --- a/src/blockrain.jquery.src.js +++ b/src/blockrain.jquery.src.js @@ -58,6 +58,7 @@ this._board.cur = this._board.nextShape(); this._board.started = true; this._board.gameover = false; + this._board.render(true); this._board.animate(); this._$start.fadeOut(150); @@ -104,6 +105,10 @@ return this._filled.score; }, + freesquares: function() { + return this._filled.getFreeSpaces(); + }, + showStartMessage: function() { this._$start.show(); }, @@ -498,21 +503,25 @@ //TODO - when past limit - auto shift and remember that too! if (!game._checkCollisions(this.x, this.y, this.getBlocks(orientation))) { this.orientation = orientation; + game._board.renderChanged = true; } }, moveRight: function() { if (!game._checkCollisions(this.x + 1, this.y, this.getBlocks())) { this.x++; + game._board.renderChanged = true; } }, moveLeft: function() { if (!game._checkCollisions(this.x - 1, this.y, this.getBlocks())) { this.x--; + game._board.renderChanged = true; } }, drop: function() { if (!game._checkCollisions(this.x, this.y + 1, this.getBlocks())) { this.y++; + game._board.renderChanged = true; } }, getBlocks: function(orientation) { // optional param @@ -671,6 +680,12 @@ this.data[this.asIndex(x, y)] = {blockType: blockType, blockIndex: blockIndex, blockOrientation: blockOrientation}; } }, + getFreeSpaces: function() { + var count = 0; + for( var i=0; i Date: Fri, 19 Jun 2015 20:00:18 -0300 Subject: [PATCH 12/21] Added support for block variations, as well a feature creep. --- src/blockrain.jquery.src.js | 128 +++++++++++++++++++++++---------- src/blockrain.jquery.themes.js | 8 +-- 2 files changed, 94 insertions(+), 42 deletions(-) diff --git a/src/blockrain.jquery.src.js b/src/blockrain.jquery.src.js index cc5fdc7..220cc5d 100644 --- a/src/blockrain.jquery.src.js +++ b/src/blockrain.jquery.src.js @@ -320,7 +320,7 @@ * The blockType is used to draw any block. * The falling attribute is needed to apply different styles for falling and placed blocks. */ - _drawBlock: function(x, y, blockType, blockIndex, blockRotation, falling) { + _drawBlock: function(x, y, blockType, blockVariation, blockIndex, blockRotation, falling) { // convert x and y to pixel x = x * this._block_size; @@ -331,7 +331,7 @@ var borderDistance = Math.round(this._block_size*0.23); var squareDistance = Math.round(this._block_size*0.30); - var color = this._getBlockColor(blockType, blockIndex, falling); + var color = this._getBlockColor(blockType, blockVariation, blockIndex, falling); // Draw the main square this._ctx.globalAlpha = 1.0; @@ -438,7 +438,7 @@ }, - _getBlockColor: function(blockName, blockIndex, falling) { + _getBlockColor: function(blockType, blockVariation, blockIndex, falling) { /** * The theme allows us to do many things: * - Use a specific color for the falling block (primary), regardless of the proper color. @@ -447,22 +447,37 @@ * - With primary and secondary as null, all blocks keep their original colors. */ + var getBlockVariation = function(blockTheme, blockVariation) { + if( $.isArray(blockTheme) ) { + if( blockVariation !== null && typeof blockTheme[blockVariation] !== 'undefined' ) { + return blockTheme[blockVariation]; + } + else if(blockTheme.length > 0) { + return blockTheme[0]; + } else { + return null; + } + } else { + return blockTheme; + } + } + if( typeof falling !== 'boolean' ){ falling = true; } if( falling ) { if( typeof this._theme.primary === 'string' && this._theme.primary !== '' ) { return this._theme.primary; } else if( typeof this._theme.blocks !== 'undefined' && this._theme.blocks !== null ) { - return this._theme.blocks[blockName]; + return getBlockVariation(this._theme.blocks[blockType], blockVariation); } else { - return this._theme.complexBlocks[blockName]; + return getBlockVariation(this._theme.complexBlocks[blockType], blockVariation); } } else { if( typeof this._theme.secondary === 'string' && this._theme.secondary !== '' ) { return this._theme.secondary; } else if( typeof this._theme.blocks !== 'undefined' && this._theme.blocks !== null ) { - return this._theme.blocks[blockName]; + return getBlockVariation(this._theme.blocks[blockType], blockVariation); } else { - return this._theme.complexBlocks[blockName]; + return getBlockVariation(this._theme.complexBlocks[blockType], blockVariation); } } }, @@ -494,9 +509,11 @@ }, blockType: blockType, + blockVariation: null, blocksLen: orientations[0].length, orientations: orientations, orientation: 0, // 4 possible + rotate: function(right) { var orientation = (this.orientation + (right ? -1 : 1) + 4) % 4; @@ -515,12 +532,14 @@ moveLeft: function() { if (!game._checkCollisions(this.x - 1, this.y, this.getBlocks())) { this.x--; + game._board.animate(); game._board.renderChanged = true; } }, drop: function() { if (!game._checkCollisions(this.x, this.y + 1, this.getBlocks())) { this.y++; + game._board.animate(); game._board.renderChanged = true; } }, @@ -535,7 +554,7 @@ index = 0; for (; i= 0 && x < game._BLOCK_WIDTH && y >= 0 && y < game._BLOCK_HEIGHT) { - this.data[this.asIndex(x, y)] = {blockType: blockType, blockIndex: blockIndex, blockOrientation: blockOrientation}; + this.data[this.asIndex(x, y)] = { + blockType: blockType, + blockVariation: blockVariation, + blockIndex: blockIndex, + blockOrientation: blockOrientation + }; } }, getFreeSpaces: function() { @@ -749,7 +773,7 @@ if (this.data[i] !== undefined) { row = this.asY(i); var block = this.data[i]; - game._drawBlock(this.asX(i), row, block.blockType, block.blockIndex, block.blockOrientation); + game._drawBlock(this.asX(i), row, block.blockType, block.blockVariation, block.blockIndex, block.blockOrientation); } } } @@ -857,6 +881,21 @@ result.x = result.best_x; } + if( typeof game._theme.complexBlocks !== 'undefined' ) { + if( $.isArray(game._theme.complexBlocks[result.blockType]) ) { + result.blockVariation = game._randInt(0, game._theme.complexBlocks[result.blockType].length-1); + } else { + result.blockVariation = null; + } + } + else if( typeof game._theme.blocks !== 'undefined' ) { + if( $.isArray(game._theme.blocks[result.blockType]) ) { + result.blockVariation = game._randInt(0, game._theme.blocks[result.blockType].length-1); + } else { + result.blockVariation = null; + } + } + return result; }, @@ -883,7 +922,7 @@ drop = false; var blockIndex = 0; for (var i=0; i 0 ) { + for( var i=0; i Date: Fri, 19 Jun 2015 21:29:32 -0300 Subject: [PATCH 13/21] Touch and keyboard controls are now consistent. --- src/blockrain.jquery.src.js | 196 ++++++++++++++++++++++++++---------- 1 file changed, 145 insertions(+), 51 deletions(-) diff --git a/src/blockrain.jquery.src.js b/src/blockrain.jquery.src.js index 220cc5d..afce300 100644 --- a/src/blockrain.jquery.src.js +++ b/src/blockrain.jquery.src.js @@ -514,8 +514,8 @@ orientations: orientations, orientation: 0, // 4 possible - rotate: function(right) { - var orientation = (this.orientation + (right ? -1 : 1) + 4) % 4; + rotate: function(direction) { + var orientation = (this.orientation + (direction === 'left' ? 1 : -1) + 4) % 4; //TODO - when past limit - auto shift and remember that too! if (!game._checkCollisions(this.x, this.y, this.getBlocks(orientation))) { @@ -523,6 +523,7 @@ game._board.renderChanged = true; } }, + moveRight: function() { if (!game._checkCollisions(this.x + 1, this.y, this.getBlocks())) { this.x++; @@ -532,17 +533,19 @@ moveLeft: function() { if (!game._checkCollisions(this.x - 1, this.y, this.getBlocks())) { this.x--; - game._board.animate(); game._board.renderChanged = true; } }, drop: function() { if (!game._checkCollisions(this.x, this.y + 1, this.getBlocks())) { this.y++; + // Reset the drop count, as we dropped the block sooner + game._board.dropCount = -1; game._board.animate(); game._board.renderChanged = true; } }, + getBlocks: function(orientation) { // optional param return this.orientations[orientation !== undefined ? orientation : this.orientation]; }, @@ -747,7 +750,7 @@ this._popRow(rows[i]); game._board.lines++; if( game._board.lines % 10 == 0 && game._board.dropDelay > 1 ) { - //board.dropDelay -= 2; + board.dropDelay *= 0.9; } } @@ -813,15 +816,22 @@ var info = this._info; this._board = { + // This sets the tick rate for the game animateDelay: 1000 / game.options.speed, + animateTimeoutId: null, cur: null, lines: 0, + // DropCount increments on each animation frame. After n frames, the piece drops 1 square + // By making dropdelay lower (down to 0), the pieces move faster, up to once per tick (animateDelay). dropCount: 0, dropDelay: 5, //5, + holding: {left: null, right: null, drop: null}, + holdingThreshold: 200, // How long do you have to hold a key to make commands repeat (in ms) + started: false, gameover: false, @@ -901,7 +911,9 @@ animate: function() { var drop = false, - gameOver = false; + moved = false, + gameOver = false, + now = Date.now(); if( this.animateTimeoutId ){ clearTimeout(this.animateTimeoutId); } @@ -910,12 +922,29 @@ if( !this.paused && !this.gameover ) { this.dropCount++; - if( this.dropCount >= this.dropDelay || game.options.autoplay ) { + + // Drop by delay or holding + if( (this.dropCount >= this.dropDelay) || + (game.options.autoplay) || + (this.holding.drop && (now - this.holding.drop) >= this.holdingThreshold) ) { drop = true; + moved = true; this.dropCount = 0; } - // test for a collision + // Move Left by holding + if( this.holding.left && (now - this.holding.left) >= this.holdingThreshold ) { + moved = true; + this.cur.moveLeft(); + } + + // Move Right by holding + if( this.holding.right && (now - this.holding.right) >= this.holdingThreshold ) { + moved = true; + this.cur.moveRight(); + } + + // Test for a collision, add the piece to the filled blocks and fetch the next one if (drop) { var cur = this.cur, x = cur.x, y = cur.y, blocks = cur.getBlocks(); if (game._checkCollisions(x, y+1, blocks, true)) { @@ -935,8 +964,13 @@ } } + // Drop if (drop) { + moved = true; this.cur.y++; + } + + if( drop || moved ) { this.renderChanged = true; } @@ -1332,32 +1366,83 @@ var game = this; + var moveLeft = function(start) { + if( ! start ) { game._board.holding.left = null; return; } + if( ! game._board.holding.left ) { + game._board.cur.moveLeft(); + game._board.holding.left = Date.now(); + } + } + var moveRight = function(start) { + if( ! start ) { game._board.holding.right = null; return; } + if( ! game._board.holding.right ) { + game._board.cur.moveRight(); + game._board.holding.right = Date.now(); + } + } + var drop = function(start) { + if( ! start ) { game._board.holding.drop = null; return; } + if( ! game._board.holding.drop ) { + game._board.cur.drop(); + game._board.holding.drop = Date.now(); + } + } + var rotateLeft = function() { + game._board.cur.rotate('left'); + } + var rotateRight = function() { + game._board.cur.rotate('right'); + } + // Handlers: These are used to be able to bind/unbind controls - var handleKeyPress = function(evt) { + var handleKeyDown = function(evt) { + if( ! game._board.cur ) { return true; } var caught = false; - if (game._board.cur) { - caught = true; - if (game.options.asdwKeys) { - switch(evt.keyCode) { - case 65: /*a*/ game._board.cur.moveLeft(); break; - case 87: /*w*/ game._board.cur.rotate(true); break; - case 68: /*d*/ game._board.cur.moveRight(); break; - case 83: /*s*/ game._board.dropCount = game._board.dropDelay; break; - } + + caught = true; + if (game.options.asdwKeys) { + switch(evt.keyCode) { + case 65: /*a*/ moveLeft(true); break; + case 68: /*d*/ moveRight(true); break; + case 83: /*s*/ drop(true); break; + case 87: /*w*/ game._board.cur.rotate('right'); break; } + } + switch(evt.keyCode) { + case 37: /*left*/ moveLeft(true); break; + case 39: /*right*/ moveRight(true); break; + case 40: /*down*/ drop(true); break; + case 38: /*up*/ game._board.cur.rotate('right'); break; + case 88: /*x*/ game._board.cur.rotate('right'); break; + case 90: /*z*/ game._board.cur.rotate('left'); break; + default: caught = false; + } + if (caught) evt.preventDefault(); + return !caught; + }; + + + var handleKeyUp = function(evt) { + if( ! game._board.cur ) { return true; } + var caught = false; + + caught = true; + if (game.options.asdwKeys) { switch(evt.keyCode) { - case 37: /*left*/ game._board.cur.moveLeft(); break; - case 38: /*up*/ game._board.cur.rotate(true); break; - case 39: /*right*/ game._board.cur.moveRight(); break; - case 40: /*down*/ game._board.dropCount = game._board.dropDelay; break; - case 88: /*x*/ game._board.cur.rotate(true); break; - case 90: /*z*/ game._board.cur.rotate(false); break; - default: caught = false; + case 65: /*a*/ moveLeft(false); break; + case 68: /*d*/ moveRight(false); break; + case 83: /*s*/ drop(false); break; } } + switch(evt.keyCode) { + case 37: /*left*/ moveLeft(false); break; + case 39: /*right*/ moveRight(false); break; + case 40: /*down*/ drop(false); break; + default: caught = false; + } if (caught) evt.preventDefault(); return !caught; - } + }; function isStopKey(evt) { var cfg = { @@ -1371,35 +1456,26 @@ function getKey(evt) { return 'safekeypress.' + evt.keyCode; } - function keypress(evt) { - var key = getKey(evt), - val = ($.data(this, key) || 0) + 1; - $.data(this, key, val); - if (val > 0) return handleKeyPress.call(this, evt); - return isStopKey(evt); - } - function keydown(evt) { var key = getKey(evt); $.data(this, key, ($.data(this, key) || 0) - 1); - return handleKeyPress.call(this, evt); + return handleKeyDown.call(this, evt); } function keyup(evt) { $.data(this, getKey(evt), 0); + handleKeyUp.call(this, evt); return isStopKey(evt); } // Unbind everything by default // Use event namespacing so we don't ruin other keypress events - $(document) .unbind('keypress.blockrain') - .unbind('keydown.blockrain') + $(document) .unbind('keydown.blockrain') .unbind('keyup.blockrain'); if( ! game.options.autoplay ) { if( enable ) { - $(document) .bind('keypress.blockrain', keypress) - .bind('keydown.blockrain', keydown) + $(document) .bind('keydown.blockrain', keydown) .bind('keyup.blockrain', keyup); } } @@ -1410,40 +1486,58 @@ var game = this; + // Movements can be held for faster movement var moveLeft = function(event){ event.preventDefault(); game._board.cur.moveLeft(); + game._board.holding.left = Date.now(); }; var moveRight = function(event){ event.preventDefault(); game._board.cur.moveRight(); + game._board.holding.right = Date.now(); }; var drop = function(event){ event.preventDefault(); - game._board.dropCount = game._board.dropDelay; + game._board.cur.drop(); + game._board.holding.drop = Date.now(); + }; + var endMoveLeft = function(event){ + event.preventDefault(); + game._board.holding.left = null; }; + var endMoveRight = function(event){ + event.preventDefault(); + game._board.holding.right = null; + }; + var endDrop = function(event){ + event.preventDefault(); + game._board.holding.drop = null; + }; + + // Rotations can't be held var rotateLeft = function(event){ event.preventDefault(); - game._board.cur.rotate(false); + game._board.cur.rotate('left'); }; var rotateRight = function(event){ event.preventDefault(); - game._board.cur.rotate(true); + game._board.cur.rotate('right'); }; // Unbind everything by default - game._$touchLeft.unbind('touchstart'); - game._$touchRight.unbind('touchstart'); - game._$touchRotateLeft.unbind('touchstart'); - game._$touchRotateRight.unbind('touchstart'); - game._$touchDrop.unbind('touchstart'); + game._$touchLeft.unbind('touchstart touchend click'); + game._$touchRight.unbind('touchstart touchend click'); + game._$touchRotateLeft.unbind('touchstart touchend click'); + game._$touchRotateRight.unbind('touchstart touchend click'); + game._$touchDrop.unbind('touchstart touchend click'); if( ! game.options.autoplay && enable ) { - game._$touchLeft.show().bind('touchstart', moveLeft); - game._$touchRight.show().bind('touchstart', moveRight); - game._$touchRotateLeft.show().bind('touchstart', rotateLeft); - game._$touchRotateRight.show().bind('touchstart', rotateRight); - game._$touchDrop.show().bind('touchstart', drop); + game._$touchLeft.show().bind('touchstart click', moveLeft).bind('touchend', endMoveLeft); + game._$touchRight.show().bind('touchstart click', moveRight).bind('touchend', endMoveRight); + game._$touchDrop.show().bind('touchstart click', drop).bind('touchend', endDrop); + game._$touchRotateLeft.show().bind('touchstart click', rotateLeft); + game._$touchRotateRight.show().bind('touchstart click', rotateRight); } else { game._$touchLeft.hide(); game._$touchRight.hide(); From 5b39e2cdea8c26551df17b715fade67016acc74c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Gonz=C3=A1lez?= Date: Sat, 20 Jun 2015 01:02:06 -0300 Subject: [PATCH 14/21] Reordered stuff slightly. --- demo.html | 5 +- src/blockrain.jquery.src.js | 519 ++++++++++++++++++------------------ 2 files changed, 267 insertions(+), 257 deletions(-) diff --git a/demo.html b/demo.html index 73eb2e4..7c5320f 100644 --- a/demo.html +++ b/demo.html @@ -60,9 +60,9 @@

Check out the demo

diff --git a/src/blockrain.jquery.src.js b/src/blockrain.jquery.src.js index afce300..c6a519f 100644 --- a/src/blockrain.jquery.src.js +++ b/src/blockrain.jquery.src.js @@ -314,180 +314,97 @@ }, - /** - * Draws one block (Each piece is made of 4 blocks) - * The blockType is used to draw any block. - * The falling attribute is needed to apply different styles for falling and placed blocks. + * Shapes */ - _drawBlock: function(x, y, blockType, blockVariation, blockIndex, blockRotation, falling) { - - // convert x and y to pixel - x = x * this._block_size; - y = y * this._block_size; - - falling = typeof falling === 'boolean' ? falling : false; - var borderWidth = this._theme.strokeWidth; - var borderDistance = Math.round(this._block_size*0.23); - var squareDistance = Math.round(this._block_size*0.30); - - var color = this._getBlockColor(blockType, blockVariation, blockIndex, falling); - - // Draw the main square - this._ctx.globalAlpha = 1.0; - - // If it's an image, the block has a specific texture. Use that. - if( color instanceof Image ) { - this._ctx.globalAlpha = 1.0; - - // Not loaded - if( color.width === 0 || color.height === 0 ){ return; } - - // A square is the same style for all blocks - if( typeof this._theme.blocks !== 'undefined' && this._theme.blocks !== null ) { - this._ctx.drawImage(color, 0, 0, color.width, color.height, x, y, this._block_size, this._block_size); - } - // A custom texture - else if( typeof this._theme.complexBlocks !== 'undefined' && this._theme.complexBlocks !== null ) { - if( typeof blockIndex === 'undefined' || blockIndex === null ){ blockIndex = 0; } - - var coords = this._getCustomBlockImageCoordinates(color, blockType, blockIndex); - - this._ctx.save(); - - this._ctx.translate(x, y); - this._ctx.translate(this._block_size/2, this._block_size/2); - this._ctx.rotate(-Math.PI/2 * blockRotation); - this._ctx.drawImage(color, coords.x, coords.y, coords.w, coords.h, - -this._block_size/2, -this._block_size/2, this._block_size, this._block_size); - - this._ctx.restore(); - - } else { - // ERROR - this._ctx.fillStyle = '#ff0000'; - this._ctx.fillRect(x, y, this._block_size, this._block_size); - } - } - else if( typeof color === 'string' ) - { - this._ctx.fillStyle = color; - this._ctx.fillRect(x, y, this._block_size, this._block_size); - - // Inner Shadow - if( typeof this._theme.innerShadow === 'string' ) { - this._ctx.globalAlpha = 1.0; - this._ctx.strokeStyle = this._theme.innerShadow; - this._ctx.lineWidth = 1.0; - - // Draw the borders - this._ctx.strokeRect(x+1, y+1, this._block_size-2, this._block_size-2); - } - - // Decoration (borders) - if( typeof this._theme.stroke === 'string' ) { - this._ctx.globalAlpha = 1.0; - this._ctx.fillStyle = this._theme.stroke; - this._ctx.strokeStyle = this._theme.stroke; - this._ctx.lineWidth = borderWidth; - - // Draw the borders - this._ctx.strokeRect(x, y, this._block_size, this._block_size); - } - if( typeof this._theme.innerStroke === 'string' ) { - // Draw the inner dashes - this._ctx.fillStyle = this._theme.innerStroke; - this._ctx.fillRect(x+borderDistance, y+borderDistance, this._block_size-borderDistance*2, borderWidth); - // The rects shouldn't overlap, to prevent issues with transparency - this._ctx.fillRect(x+borderDistance, y+borderDistance+borderWidth, borderWidth, this._block_size-borderDistance*2-borderWidth); - } - if( typeof this._theme.innerSquare === 'string' ) { - // Draw the inner square - this._ctx.fillStyle = this._theme.innerSquare; - this._ctx.globalAlpha = 0.2; - this._ctx.fillRect(x+squareDistance, y+squareDistance, this._block_size-squareDistance*2, this._block_size-squareDistance*2); - } - } - - // Return the alpha back to 1.0 so we don't create any issues with other drawings. - this._ctx.globalAlpha = 1.0; - }, - - - _getCustomBlockImageCoordinates: function(image, blockType, blockIndex) { - // The image is based on the first ("upright") orientation - var positions = this._shapeFactory[blockType]().orientations[0]; - // Find the number of tiles it should have - var minX = Math.min(positions[0], positions[2], positions[4], positions[6]); - var maxX = Math.max(positions[0], positions[2], positions[4], positions[6]); - var minY = Math.min(positions[1], positions[3], positions[5], positions[7]); - var maxY = Math.max(positions[1], positions[3], positions[5], positions[7]); - var rangeX = maxX - minX + 1; - var rangeY = maxY - minY + 1; - - // X and Y sizes should match. Should. - var tileSizeX = image.width / rangeX; - var tileSizeY = image.height / rangeY; - - return { - x: tileSizeX * (positions[blockIndex*2]-minX), - y: tileSizeY * Math.abs(minY-positions[blockIndex*2+1]), - w: tileSizeX, - h: tileSizeY - }; - }, - + _shapeFactory: null, - _getBlockColor: function(blockType, blockVariation, blockIndex, falling) { + _shapes: { /** - * The theme allows us to do many things: - * - Use a specific color for the falling block (primary), regardless of the proper color. - * - Use another color for the placed blocks (secondary). - * - Default to the "original" block color in any of those cases by setting primary and/or secondary to null. - * - With primary and secondary as null, all blocks keep their original colors. + * The shapes have a reference point (the dot) and always rotate left. + * Keep in mind that the blocks should keep in the same relative position when rotating, + * to allow for custom per-block themes. */ - - var getBlockVariation = function(blockTheme, blockVariation) { - if( $.isArray(blockTheme) ) { - if( blockVariation !== null && typeof blockTheme[blockVariation] !== 'undefined' ) { - return blockTheme[blockVariation]; - } - else if(blockTheme.length > 0) { - return blockTheme[0]; - } else { - return null; - } - } else { - return blockTheme; - } - } - - if( typeof falling !== 'boolean' ){ falling = true; } - if( falling ) { - if( typeof this._theme.primary === 'string' && this._theme.primary !== '' ) { - return this._theme.primary; - } else if( typeof this._theme.blocks !== 'undefined' && this._theme.blocks !== null ) { - return getBlockVariation(this._theme.blocks[blockType], blockVariation); - } else { - return getBlockVariation(this._theme.complexBlocks[blockType], blockVariation); - } - } else { - if( typeof this._theme.secondary === 'string' && this._theme.secondary !== '' ) { - return this._theme.secondary; - } else if( typeof this._theme.blocks !== 'undefined' && this._theme.blocks !== null ) { - return getBlockVariation(this._theme.blocks[blockType], blockVariation); - } else { - return getBlockVariation(this._theme.complexBlocks[blockType], blockVariation); - } - } + /* + * X + * O XOXX + * X + * X + * . . + */ + line: [ + [ 0, -1, 0, -2, 0, -3, 0, -4], + [ 2, -2, 1, -2, 0, -2, -1, -2], + [ 0, -4, 0, -3, 0, -2, 0, -1], + [-1, -2, 0, -2, 1, -2, 2, -2] + ], + /* + * XX + * XX + */ + square: [ + [0, 0, 1, 0, 0, -1, 1, -1], + [1, 0, 1, -1, 0, 0, 0, -1], + [1, -1, 0, -1, 1, 0, 0, 0], + [0, -1, 0, 0, 1, -1, 1, 0] + ], + /* + * X X X + * XOX XO XOX OX + * . .X .X .X + */ + arrow: [ + [0, -1, 1, -1, 2, -1, 1, -2], + [1, 0, 1, -1, 1, -2, 0, -1], + [2, -1, 1, -1, 0, -1, 1, 0], + [1, -2, 1, -1, 1, 0, 2, -1] + ], + /* + * X X XX + * O XOX O XOX + * .XX . .X X + */ + rightHook: [ + [2, 0, 1, 0, 1, -1, 1, -2], + [2, -2, 2, -1, 1, -1, 0, -1], + [0, -2, 1, -2, 1, -1, 1, 0], + [0, 0, 0, -1, 1, -1, 2, -1] + ], + /* + * X XX X + * O XOX O XOX + * XX . X .X . + */ + leftHook: [ + [0, 0, 1, 0, 1, -1, 1, -2], + [2, 0, 2, -1, 1, -1, 0, -1], + [2, -2, 1, -2, 1, -1, 1, 0], + [0, -2, 0, -1, 1, -1, 2, -1] + ], + /* + * X XX + * XO OX + * X . + */ + leftZag: [ + [0, 0, 0, -1, 1, -1, 1, -2], + [2, -1, 1, -1, 1, -2, 0, -2], + [1, -2, 1, -1, 0, -1, 0, 0], + [0, -2, 1, -2, 1, -1, 2, -1] + ], + /* + * X + * XO OX + * .X XX + */ + rightZag: [ + [1, 0, 1, -1, 0, -1, 0, -2], + [2, -1, 1, -1, 1, 0, 0, 0], + [0, -2, 0, -1, 1, -1, 1, 0], + [0, 0, 1, 0, 1, -1, 2, -1] + ] }, - - /** - * Shapes - */ - _shapeFactory: null, - _SetupShapeFactory: function(){ var game = this; if( this._shapeFactory !== null ){ return; } @@ -557,7 +474,7 @@ index = 0; for (; i 1 ) { - board.dropDelay *= 0.9; + game._board.dropDelay *= 0.9; } } @@ -776,7 +617,7 @@ if (this.data[i] !== undefined) { row = this.asY(i); var block = this.data[i]; - game._drawBlock(this.asX(i), row, block.blockType, block.blockVariation, block.blockIndex, block.blockOrientation); + game._board.drawBlock(this.asX(i), row, block.blockType, block.blockVariation, block.blockIndex, block.blockOrientation); } } } @@ -1044,7 +885,175 @@ game._filled.draw(); this.cur.draw(); } + }, + + + /** + * Draws one block (Each piece is made of 4 blocks) + * The blockType is used to draw any block. + * The falling attribute is needed to apply different styles for falling and placed blocks. + */ + drawBlock: function(x, y, blockType, blockVariation, blockIndex, blockRotation, falling) { + + // convert x and y to pixel + x = x * game._block_size; + y = y * game._block_size; + + falling = typeof falling === 'boolean' ? falling : false; + var borderWidth = game._theme.strokeWidth; + var borderDistance = Math.round(game._block_size*0.23); + var squareDistance = Math.round(game._block_size*0.30); + + var color = this.getBlockColor(blockType, blockVariation, blockIndex, falling); + + // Draw the main square + game._ctx.globalAlpha = 1.0; + + // If it's an image, the block has a specific texture. Use that. + if( color instanceof Image ) { + game._ctx.globalAlpha = 1.0; + + // Not loaded + if( color.width === 0 || color.height === 0 ){ return; } + + // A square is the same style for all blocks + if( typeof game._theme.blocks !== 'undefined' && game._theme.blocks !== null ) { + game._ctx.drawImage(color, 0, 0, color.width, color.height, x, y, game._block_size, game._block_size); + } + // A custom texture + else if( typeof game._theme.complexBlocks !== 'undefined' && game._theme.complexBlocks !== null ) { + if( typeof blockIndex === 'undefined' || blockIndex === null ){ blockIndex = 0; } + + var getCustomBlockImageCoordinates = function(image, blockType, blockIndex) { + // The image is based on the first ("upright") orientation + var positions = game._shapes[blockType][0]; + // Find the number of tiles it should have + var minX = Math.min(positions[0], positions[2], positions[4], positions[6]); + var maxX = Math.max(positions[0], positions[2], positions[4], positions[6]); + var minY = Math.min(positions[1], positions[3], positions[5], positions[7]); + var maxY = Math.max(positions[1], positions[3], positions[5], positions[7]); + var rangeX = maxX - minX + 1; + var rangeY = maxY - minY + 1; + + // X and Y sizes should match. Should. + var tileSizeX = image.width / rangeX; + var tileSizeY = image.height / rangeY; + + return { + x: tileSizeX * (positions[blockIndex*2]-minX), + y: tileSizeY * Math.abs(minY-positions[blockIndex*2+1]), + w: tileSizeX, + h: tileSizeY + }; + }; + + var coords = getCustomBlockImageCoordinates(color, blockType, blockIndex); + + game._ctx.save(); + + game._ctx.translate(x, y); + game._ctx.translate(game._block_size/2, game._block_size/2); + game._ctx.rotate(-Math.PI/2 * blockRotation); + game._ctx.drawImage(color, coords.x, coords.y, coords.w, coords.h, + -game._block_size/2, -game._block_size/2, game._block_size, game._block_size); + + game._ctx.restore(); + + } else { + // ERROR + game._ctx.fillStyle = '#ff0000'; + game._ctx.fillRect(x, y, game._block_size, game._block_size); + } + } + else if( typeof color === 'string' ) + { + game._ctx.fillStyle = color; + game._ctx.fillRect(x, y, game._block_size, game._block_size); + + // Inner Shadow + if( typeof game._theme.innerShadow === 'string' ) { + game._ctx.globalAlpha = 1.0; + game._ctx.strokeStyle = game._theme.innerShadow; + game._ctx.lineWidth = 1.0; + + // Draw the borders + game._ctx.strokeRect(x+1, y+1, game._block_size-2, game._block_size-2); + } + + // Decoration (borders) + if( typeof game._theme.stroke === 'string' ) { + game._ctx.globalAlpha = 1.0; + game._ctx.fillStyle = game._theme.stroke; + game._ctx.strokeStyle = game._theme.stroke; + game._ctx.lineWidth = borderWidth; + + // Draw the borders + game._ctx.strokeRect(x, y, game._block_size, game._block_size); + } + if( typeof game._theme.innerStroke === 'string' ) { + // Draw the inner dashes + game._ctx.fillStyle = game._theme.innerStroke; + game._ctx.fillRect(x+borderDistance, y+borderDistance, game._block_size-borderDistance*2, borderWidth); + // The rects shouldn't overlap, to prevent issues with transparency + game._ctx.fillRect(x+borderDistance, y+borderDistance+borderWidth, borderWidth, game._block_size-borderDistance*2-borderWidth); + } + if( typeof game._theme.innerSquare === 'string' ) { + // Draw the inner square + game._ctx.fillStyle = game._theme.innerSquare; + game._ctx.globalAlpha = 0.2; + game._ctx.fillRect(x+squareDistance, y+squareDistance, game._block_size-squareDistance*2, game._block_size-squareDistance*2); + } + } + + // Return the alpha back to 1.0 so we don't create any issues with other drawings. + game._ctx.globalAlpha = 1.0; + }, + + + getBlockColor: function(blockType, blockVariation, blockIndex, falling) { + /** + * The theme allows us to do many things: + * - Use a specific color for the falling block (primary), regardless of the proper color. + * - Use another color for the placed blocks (secondary). + * - Default to the "original" block color in any of those cases by setting primary and/or secondary to null. + * - With primary and secondary as null, all blocks keep their original colors. + */ + + var getBlockVariation = function(blockTheme, blockVariation) { + if( $.isArray(blockTheme) ) { + if( blockVariation !== null && typeof blockTheme[blockVariation] !== 'undefined' ) { + return blockTheme[blockVariation]; + } + else if(blockTheme.length > 0) { + return blockTheme[0]; + } else { + return null; + } + } else { + return blockTheme; + } + } + + if( typeof falling !== 'boolean' ){ falling = true; } + if( falling ) { + if( typeof game._theme.primary === 'string' && game._theme.primary !== '' ) { + return game._theme.primary; + } else if( typeof game._theme.blocks !== 'undefined' && game._theme.blocks !== null ) { + return getBlockVariation(game._theme.blocks[blockType], blockVariation); + } else { + return getBlockVariation(game._theme.complexBlocks[blockType], blockVariation); + } + } else { + if( typeof game._theme.secondary === 'string' && game._theme.secondary !== '' ) { + return game._theme.secondary; + } else if( typeof game._theme.blocks !== 'undefined' && game._theme.blocks !== null ) { + return getBlockVariation(game._theme.blocks[blockType], blockVariation); + } else { + return getBlockVariation(game._theme.complexBlocks[blockType], blockVariation); + } + } } + }; game._niceShapes = game._getNiceShapes(); From 5ec0961480cf0e293a4f870acf5b28a7e2cf5d78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Gonz=C3=A1lez?= Date: Sat, 20 Jun 2015 01:08:00 -0300 Subject: [PATCH 15/21] Fun fact: There was a bug with initialization that led to two games sharing the same theme object. --- demo.html | 24 ++++++++++++------------ src/blockrain.jquery.src.js | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/demo.html b/demo.html index 7c5320f..240e556 100644 --- a/demo.html +++ b/demo.html @@ -50,6 +50,12 @@

Check out the demo

+
+
+
+
+
+ @@ -62,20 +68,14 @@

Check out the demo

var $demo = $('#tetris-demo').blockrain({ speed: 100, theme: 'individual', - autoplay: true, - onStart: function() { - - }, - onLine: function() { - - }, - onGameOver: function(score){ - - } + autoplay: true }); - $demo.blockrain('autoplay', true); - $demo.blockrain('touchControls', true); + var $demo2 = $('#tetris-demo-2').blockrain({ + speed: 100, + theme: 'individual', + autoplay: true + }); diff --git a/src/blockrain.jquery.src.js b/src/blockrain.jquery.src.js index c6a519f..24fb9a5 100644 --- a/src/blockrain.jquery.src.js +++ b/src/blockrain.jquery.src.js @@ -149,7 +149,7 @@ // Setup the theme properly if( typeof newTheme === 'string' ) { this.options.theme = newTheme; - this._theme = BlockrainThemes[newTheme]; + this._theme = $.extend(true, {}, BlockrainThemes[newTheme]); } else { this.options.theme = null; @@ -157,7 +157,7 @@ } if( typeof this._theme === 'undefined' || this._theme === null ) { - this._theme = BlockrainThemes['retro']; + this._theme = $.extend(true, {}, BlockrainThemes['retro']); this.options.theme = 'retro'; } From f0462771f775387ef44c23c779ea3c5df42b969c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Gonz=C3=A1lez?= Date: Sat, 20 Jun 2015 01:09:13 -0300 Subject: [PATCH 16/21] Restore the dropdelay after a restart. --- src/blockrain.jquery.src.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/blockrain.jquery.src.js b/src/blockrain.jquery.src.js index 24fb9a5..fcb2831 100644 --- a/src/blockrain.jquery.src.js +++ b/src/blockrain.jquery.src.js @@ -58,6 +58,7 @@ this._board.cur = this._board.nextShape(); this._board.started = true; this._board.gameover = false; + this._board.dropDelay = 5; this._board.render(true); this._board.animate(); From e958d51619d71d9b1951c1014d4060cb4cb2b54a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Gonz=C3=A1lez?= Date: Sun, 21 Jun 2015 15:33:38 -0300 Subject: [PATCH 17/21] . --- demo.html | 5 ----- 1 file changed, 5 deletions(-) diff --git a/demo.html b/demo.html index 240e556..a426c17 100644 --- a/demo.html +++ b/demo.html @@ -47,11 +47,6 @@

Check out the demo

-
-
- -
-
From 5b124e4df7f14ab3887850d7c33e9621681f4427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Gonz=C3=A1lez?= Date: Sun, 21 Jun 2015 15:42:02 -0300 Subject: [PATCH 18/21] . --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index e4ac8e4..ec99ccb 100644 --- a/index.html +++ b/index.html @@ -210,7 +210,7 @@

Play

}); - var versusSpeed = 500; + var versusSpeed = 100; var $versus1 = $('#tetris-versus-1 .game').blockrain({ autoplay: true, From e2110404765b851ea832d5d22b8ec10a3aa97757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Gonz=C3=A1lez?= Date: Mon, 29 Jun 2015 02:00:19 -0300 Subject: [PATCH 19/21] Added a fix if both the left and right buttons are being held. --- src/blockrain.jquery.src.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/blockrain.jquery.src.js b/src/blockrain.jquery.src.js index fcb2831..5375c33 100644 --- a/src/blockrain.jquery.src.js +++ b/src/blockrain.jquery.src.js @@ -1380,7 +1380,8 @@ if( ! start ) { game._board.holding.left = null; return; } if( ! game._board.holding.left ) { game._board.cur.moveLeft(); - game._board.holding.left = Date.now(); + game._board.holding.left = Date.now(); + game._board.holding.right = null; } } var moveRight = function(start) { @@ -1388,6 +1389,7 @@ if( ! game._board.holding.right ) { game._board.cur.moveRight(); game._board.holding.right = Date.now(); + game._board.holding.left = null; } } var drop = function(start) { @@ -1501,11 +1503,15 @@ event.preventDefault(); game._board.cur.moveLeft(); game._board.holding.left = Date.now(); + game._board.holding.right = null; + game._board.holding.drop = null; }; var moveRight = function(event){ event.preventDefault(); game._board.cur.moveRight(); game._board.holding.right = Date.now(); + game._board.holding.left = null; + game._board.holding.drop = null; }; var drop = function(event){ event.preventDefault(); From 3e859e64046d17684d8fe6bc272394b8dc6221da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Gonz=C3=A1lez?= Date: Sun, 5 Jul 2015 23:16:25 -0300 Subject: [PATCH 20/21] Added a Block Placed event. --- src/blockrain.jquery.src.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/blockrain.jquery.src.js b/src/blockrain.jquery.src.js index 5375c33..7fa74e0 100644 --- a/src/blockrain.jquery.src.js +++ b/src/blockrain.jquery.src.js @@ -28,6 +28,8 @@ onRestart: function(){}, onGameOver: function(score){}, + // When a block is placed + onPlaced: function(){}, // When a line is made. Returns the number of lines, score assigned and total score onLine: function(lines, scoreIncrement, score){} }, @@ -802,6 +804,13 @@ game._filled.checkForClears(); this.cur = this.nextShape(); this.renderChanged = true; + + // Stop holding drop (and any other buttons). Just in case the controls get sticky. + this.holding.left = null; + this.holding.right = null; + this.holding.drop = null; + + game.options.onPlaced.call(game.element); } } } From 8151d3b824dee486b8abbaf1df36903e556adef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Gonz=C3=A1lez?= Date: Tue, 29 Sep 2015 20:16:57 -0300 Subject: [PATCH 21/21] New release. --- README.md | 28 + .../blocks/{individual => custom}/arrow.png | Bin .../{individual => custom}/leftHook.png | Bin .../blocks/{individual => custom}/leftZag.png | Bin assets/blocks/{individual => custom}/line.png | Bin .../{individual => custom}/rightHook.png | Bin .../{individual => custom}/rightZag.png | Bin .../blocks/{individual => custom}/square.png | Bin bower.json | 5 +- dist/README.md | 28 + dist/assets/blocks/custom/arrow.png | Bin 0 -> 1427 bytes dist/assets/blocks/custom/leftHook.png | Bin 0 -> 1011 bytes dist/assets/blocks/custom/leftZag.png | Bin 0 -> 1327 bytes dist/assets/blocks/custom/line.png | Bin 0 -> 2114 bytes dist/assets/blocks/custom/rightHook.png | Bin 0 -> 1583 bytes dist/assets/blocks/custom/rightZag.png | Bin 0 -> 902 bytes dist/assets/blocks/custom/square.png | Bin 0 -> 2058 bytes dist/blockrain.css | 64 ++ dist/blockrain.jquery.js | 908 +++++++++++++----- dist/blockrain.jquery.min.js | 5 +- dist/blockrain.zip | Bin 38164 -> 55927 bytes gulpfile.js | 17 +- package.json | 15 +- src/blockrain.jquery.themes.js | 16 +- 24 files changed, 813 insertions(+), 273 deletions(-) rename assets/blocks/{individual => custom}/arrow.png (100%) rename assets/blocks/{individual => custom}/leftHook.png (100%) rename assets/blocks/{individual => custom}/leftZag.png (100%) rename assets/blocks/{individual => custom}/line.png (100%) rename assets/blocks/{individual => custom}/rightHook.png (100%) rename assets/blocks/{individual => custom}/rightZag.png (100%) rename assets/blocks/{individual => custom}/square.png (100%) create mode 100644 dist/assets/blocks/custom/arrow.png create mode 100644 dist/assets/blocks/custom/leftHook.png create mode 100644 dist/assets/blocks/custom/leftZag.png create mode 100644 dist/assets/blocks/custom/line.png create mode 100644 dist/assets/blocks/custom/rightHook.png create mode 100644 dist/assets/blocks/custom/rightZag.png create mode 100644 dist/assets/blocks/custom/square.png diff --git a/README.md b/README.md index 1f87dd5..4745dc4 100644 --- a/README.md +++ b/README.md @@ -77,8 +77,36 @@ Here's an example of a retro theme (vim) with a **custom texture**: } ``` + +### Creating custom designs + +You can now use **completely custom designs for each block**! You just link to one image for each block when creating your theme and the plugin takes care of the rest. You can even use lists of images if you want BlockRain to pick a random design for each block. + +**Keep in mind that the images need to follow the exact same format (rotation and width/height ratio) as [the blocks that are bundled with the custom theme](https://github.com/Aerolab/blockrain.js/tree/gh-pages/assets/blocks/custom)**. + +Fun fact: Now you can rotate the square! + + +```js +'custom': { + background: '#040304', + backgroundGrid: '#000', + complexBlocks: { + line: ['assets/blocks/custom/line.png', 'assets/blocks/custom/line.png'], + square: 'assets/blocks/custom/square.png', + arrow: 'assets/blocks/custom/arrow.png', + rightHook:'assets/blocks/custom/rightHook.png', + leftHook: 'assets/blocks/custom/leftHook.png', + rightZag: 'assets/blocks/custom/rightZag.png', + leftZag: 'assets/blocks/custom/leftZag.png' + } +} +``` + + ### Available themes: +* custom **NEW!** * candy * modern * retro diff --git a/assets/blocks/individual/arrow.png b/assets/blocks/custom/arrow.png similarity index 100% rename from assets/blocks/individual/arrow.png rename to assets/blocks/custom/arrow.png diff --git a/assets/blocks/individual/leftHook.png b/assets/blocks/custom/leftHook.png similarity index 100% rename from assets/blocks/individual/leftHook.png rename to assets/blocks/custom/leftHook.png diff --git a/assets/blocks/individual/leftZag.png b/assets/blocks/custom/leftZag.png similarity index 100% rename from assets/blocks/individual/leftZag.png rename to assets/blocks/custom/leftZag.png diff --git a/assets/blocks/individual/line.png b/assets/blocks/custom/line.png similarity index 100% rename from assets/blocks/individual/line.png rename to assets/blocks/custom/line.png diff --git a/assets/blocks/individual/rightHook.png b/assets/blocks/custom/rightHook.png similarity index 100% rename from assets/blocks/individual/rightHook.png rename to assets/blocks/custom/rightHook.png diff --git a/assets/blocks/individual/rightZag.png b/assets/blocks/custom/rightZag.png similarity index 100% rename from assets/blocks/individual/rightZag.png rename to assets/blocks/custom/rightZag.png diff --git a/assets/blocks/individual/square.png b/assets/blocks/custom/square.png similarity index 100% rename from assets/blocks/individual/square.png rename to assets/blocks/custom/square.png diff --git a/bower.json b/bower.json index 792acee..da715b6 100644 --- a/bower.json +++ b/bower.json @@ -1,8 +1,11 @@ { "name": "blockrain", - "version": "0.1.0", + "version": "0.2.0", "description": "Add a game of tetris to your site", "main": "dist/blockrain.jquery.min.js", + "dependencies": { + "jquery": "~1.11.3" + }, "repository": { "type": "git", "url": "git://github.com/Aerolab/blockrain.js.git" diff --git a/dist/README.md b/dist/README.md index 1f87dd5..4745dc4 100644 --- a/dist/README.md +++ b/dist/README.md @@ -77,8 +77,36 @@ Here's an example of a retro theme (vim) with a **custom texture**: } ``` + +### Creating custom designs + +You can now use **completely custom designs for each block**! You just link to one image for each block when creating your theme and the plugin takes care of the rest. You can even use lists of images if you want BlockRain to pick a random design for each block. + +**Keep in mind that the images need to follow the exact same format (rotation and width/height ratio) as [the blocks that are bundled with the custom theme](https://github.com/Aerolab/blockrain.js/tree/gh-pages/assets/blocks/custom)**. + +Fun fact: Now you can rotate the square! + + +```js +'custom': { + background: '#040304', + backgroundGrid: '#000', + complexBlocks: { + line: ['assets/blocks/custom/line.png', 'assets/blocks/custom/line.png'], + square: 'assets/blocks/custom/square.png', + arrow: 'assets/blocks/custom/arrow.png', + rightHook:'assets/blocks/custom/rightHook.png', + leftHook: 'assets/blocks/custom/leftHook.png', + rightZag: 'assets/blocks/custom/rightZag.png', + leftZag: 'assets/blocks/custom/leftZag.png' + } +} +``` + + ### Available themes: +* custom **NEW!** * candy * modern * retro diff --git a/dist/assets/blocks/custom/arrow.png b/dist/assets/blocks/custom/arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..6afaad12d1a474ff987dee413ab8a64825ba3b04 GIT binary patch literal 1427 zcmZ`(c~H^`6#l`2A&$wGqU3JU9<<+=)LCLZg0q?z}D37Th~q!e^c86EwF++`wU34Ic@>O^}3q7mDZwJp{*cnjS<`}b% z`_gLY{=jyGc0Ci(bvZmAj{K#hNBX96q8yh?=F$6g9V$+J=SiBgNtsA(SfC2vi6wrfeb=jQ!j!B4h*{h#@dcv+UnsVf3 zld^pb8%|9V`PwTZyHj_bltkz8Csu&LLAy*##wxE|{@$Tral#}!bKvMP`X+k=u8Z=M z+glo^WJg20`L9rj9`?Y8T)F&s-rja4U!nogJ7j%KC}YV2(VL3(eHEypuxEgrFMV5;034nYGjbEk&aLuwE`bW2YBT-ws)NRi4P*&K9D zd@I`l-TCH%0z3Fq8M}@3t-5)5Gbi@+Vs13q7PI@4omgSog9G63dZY7x}`96vrH{C4e3F*kL z&Vkx}6z&$0i@@_-tj2%wF&( z=9O?Wcs_tS3LX?Ky;{18YXIdLt~peK+Qzk8r0xpk1m4guK`JT@Kt>3JLR7KHcWJ$8 zr~SfatjVINDxz)jxDM-<&)+#G7LW}o?|jJDPG#vIs;`Skpl;9RDn&(o40`t_!CpI~ zs;o~WMcF|nes^~udKjW5bFs;36e`x~P-Ekd-*np+W~AY9$NX-c6$&1l326)=y|%Wn z&f*Is$@PU)_Vhd2SVYPNWgpW_YHIt4o?BJcS|B3uN8z9^Ip|+6`2|b$7I7eYfMn?d UT%QKjSFtSMiuZ7Aa0t))6M+MRx&QzG literal 0 HcmV?d00001 diff --git a/dist/assets/blocks/custom/leftHook.png b/dist/assets/blocks/custom/leftHook.png new file mode 100644 index 0000000000000000000000000000000000000000..33e5506c5aa9250ac2e3f99747dc48fa35d31e36 GIT binary patch literal 1011 zcmeAS@N?(olHy`uVBq!ia0vp^4M2Q=gAGWYNy}aiq!^2X+?^QKos)S9a~60+7BevL9R^{>-rb#hl_dQ@{IF<-p$kd;iYWn|N>O z{3as?3+4u6EX3!?11HWi*@?OCShuRgeD3UB_xfYl42l@$pF4M`|Ektq-{-#%JO8-W z6H~`>K$2k&BN@a_{e&mAj8BsU^-dYxE!`cXclm1fkA43IUcWWFW3D`%QRd^64aYx! zF8TWC@ZH#5Ry_7h4|o{PF(45!>=utW6+aqu*7L^R`PedHVue%31vE9pa_@*6eA?IW z=u63d%ao37f0^fBe_e9*?e)vSD`rnT&0wSGlETK2&QO3L)-hK&w45N;cuaM@igE&q zMrfgbozX^f%2{EjmNaCm5SBt&b%7 literal 0 HcmV?d00001 diff --git a/dist/assets/blocks/custom/leftZag.png b/dist/assets/blocks/custom/leftZag.png new file mode 100644 index 0000000000000000000000000000000000000000..2e307a3f60716e345d177e66ef5dd247f98558ab GIT binary patch literal 1327 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 S=_#;0XYh3Ob6Mw<&;$Up^`tTY literal 0 HcmV?d00001 diff --git a/dist/assets/blocks/custom/rightZag.png b/dist/assets/blocks/custom/rightZag.png new file mode 100644 index 0000000000000000000000000000000000000000..ed2a00fbc5aa443310e59f2362295af294bae313 GIT binary patch literal 902 zcmeAS@N?(olHy`uVBq!ia0vp^4M2Q=gAGWYNy}aiq!^2X+?^QKos)S9a~60+7BevL9R^{>zH*VfT7`GkC=<*mZshF4oa6izvg;=VcY`s4@|Et zV|J8Ym#$zwI5(j?N$|?442KC#t!cAn{@kBGdCy;ep}2eAV)NtP#PTG5pFdak*ySbB zk0)v{9^q8*V<=?m5O$cu@Q6h~y}<%iNG+a!L-m)m8yLG3I30y*!#qA1YRXid*@VxN9~YYNGT!;{{L%H^Xkwh`A>9_g Xy1y;d^n5KS?=X0}`njxgN@xNA_9;`B literal 0 HcmV?d00001 diff --git a/dist/assets/blocks/custom/square.png b/dist/assets/blocks/custom/square.png new file mode 100644 index 0000000000000000000000000000000000000000..bc9a7236ff328568cf23ca60db973df8abebb697 GIT binary patch literal 2058 zcma)-dpHvcAIB$!9JkY1jF40=rL!Dbxnw5M?AUB3hYnI!5nC>6u8WcyH66LUSR-U) zCd3}5R>EGn%q1HYt4XU3J9Eil#_4_Dzu)t`fBb%*=lTBq{rx@^Kcu&=wuv?X0MLb> z^2B^+&3{H~%lECc{bl+)j1x}&mf%mgkU$EL!vSCsgmX9xcue?390nI2krdmDa|Hl2 znQ%`SHu3H3gO`NSt3Vzi`_P-3`^`2^T_zw{{0q&I6Lm1BDiifc+UnlEvKM+5UdJ47 znLM<}f7}_fGjsMtv-*!wRZ-wZ0nzLS_&WVO^cqytF<_3+2qibXQed zXoKjADTb_&6!^@nb5ov8J(Q1f4H~uzi9#tc4!SCwwFj!^CPUT&RgppDwWV6I`{vBY zS7ofQu+UKY0*V#FxhfOXA4DL+L6+j?WEU>Cg&2u1%X49IFm{+Pd+Ye2On%Jq&RCjP zrJBO{yzJ$TV}iXl4&@xTu8SJlf}F3(rVz+cZs|^s)L^UCo;7E=vw_$F;5*o1?>vAp z5F7DLNa=aR0#b5-*jxYHp`5gFpO$Q*D_{HFVc&;;?9Y0HMZZz~x#YNd@g_Wn;ac1@ zAH7YpUZ-@R`pahLiYl|rXy*>=qCuAFuqo z^ofNz8rnsAFYL zx~aa#jg8*z1KLUNjuux=HVyA6BNgPP{9|E6dnpY#-B&fI>k4sW8fqpD{XgINyhS3=>`3nOv{LFfnXn;>Nr=WHMQ%#VnYdzP>_-0s_(4fP}z>Z2q4g)aLJ`zcr%}U8+vw1{DQKEzKqBFhIaijjWm!BUVAqZ;! zm`9|XQ(o^H?pZBIubeeIV<%q0R2QRcUd=Q#9d~hYadQq+gST{12^2hyHrCN7LZb8H&7T(z z*c#~n&o}vlg}1!0g+~Ck`aH_H3#quP9S$N(m*W=9znW4=rV^@*+^k)5EQ>|)s)Vh% zJU|Ni+V_w%aX~BW*6LZTy92Cw;=TMToV(`yq^?~(jjC6Sw(dPzUpQaP1;|7+YjWC> z%}-{&78`NqM$Nle;h==vp<#p*SX{Xwv|G(^>B}*+Ais1J2-_?JYT_Nc79FH3F0s5$ z<|W%k7m)v~FYyTaSC?${6h)F$ z(MV4%OW(GS6sKvdk#R3EZOr&>9*6#-^tYQ+^V*8qLLl+yjK6du;2i}HJ3`v_gl4i+ zDWH%OA-DNMG4#vB<9K$<=@4mZoMdjUJIrP1wSR1F3sRv-vE|AW5}=ncN~T*J)Y}7j z?NlSHoUj(*Sps5Y))Xz2sWx(Fnw%z^I}ht@CN3YS1j9zPJG)ez"; +} + +.blockrain-touch-rotate-left { + left: -60px; + bottom: 80px; +} +.blockrain-touch-rotate-left::after { + content: ""; +} + +.blockrain-touch-drop { + left: 50%; + margin-left: -25px; + bottom: -60px; +} +.blockrain-touch-drop::after { + content: "."; +} + /* Buttons */ .blockrain-btn { position: relative; diff --git a/dist/blockrain.jquery.js b/dist/blockrain.jquery.js index 2b06281..f99f288 100644 --- a/dist/blockrain.jquery.js +++ b/dist/blockrain.jquery.js @@ -1,5 +1,5 @@ /*! - * BlockRain.js 0.1.0 + * BlockRain.js 0.2.0 * jQuery plugin that lets you put a playable (and configurable) game of Tetris in your site or just leave it in auto in the background. * http://aerolab.github.io/blockrain.js/ * @@ -40,6 +40,8 @@ onRestart: function(){}, onGameOver: function(score){}, + // When a block is placed + onPlaced: function(){}, // When a line is made. Returns the number of lines, score assigned and total score onLine: function(lines, scoreIncrement, score){} }, @@ -70,6 +72,8 @@ this._board.cur = this._board.nextShape(); this._board.started = true; this._board.gameover = false; + this._board.dropDelay = 5; + this._board.render(true); this._board.animate(); this._$start.fadeOut(150); @@ -95,6 +99,7 @@ this._doStart(); } this._setupControls( ! enable ); + this._setupTouchControls( ! enable ); }, controls: function(enable) { @@ -102,6 +107,11 @@ this._setupControls(enable); }, + touchControls: function(enable) { + if( typeof enable !== 'boolean' ){ enable = true; } + this._setupTouchControls(enable); + }, + score: function(newScore) { if( typeof newScore !== 'undefined' && parseInt(newScore) >= 0 ) { this._filled.score = parseInt(newScore); @@ -110,6 +120,10 @@ return this._filled.score; }, + freesquares: function() { + return this._filled.getFreeSpaces(); + }, + showStartMessage: function() { this._$start.show(); }, @@ -150,7 +164,7 @@ // Setup the theme properly if( typeof newTheme === 'string' ) { this.options.theme = newTheme; - this._theme = BlockrainThemes[newTheme]; + this._theme = $.extend(true, {}, BlockrainThemes[newTheme]); } else { this.options.theme = null; @@ -158,7 +172,7 @@ } if( typeof this._theme === 'undefined' || this._theme === null ) { - this._theme = BlockrainThemes['retro']; + this._theme = $.extend(true, {}, BlockrainThemes['retro']); this.options.theme = 'retro'; } @@ -225,15 +239,22 @@ this._info.init(); this._board.init(); + var renderLoop = function(){ + requestAnimationFrame(renderLoop); + game._board.render(); + }; + renderLoop(); + if( this.options.autoplay ) { this.autoplay(true); + this._setupTouchControls(false); } else { this._setupControls(true); + this._setupTouchControls(false); } }, - _checkCollisions: function(x, y, blocks, checkDownOnly) { // x & y should be aspirational values var i = 0, len = blocks.length, a, b; @@ -277,9 +298,9 @@ var cx = x * this._block_size; var cy = y * this._block_size; - this._ctx.drawImage( this._theme.backgroundGrid, - 0, 0, this._theme.backgroundGrid.width, this._theme.backgroundGrid.height, - cx, cy, this._block_size, this._block_size); + this._ctx.drawImage( this._theme.backgroundGrid, + 0, 0, this._theme.backgroundGrid.width, this._theme.backgroundGrid.height, + cx, cy, this._block_size, this._block_size); } } @@ -308,114 +329,97 @@ }, - /** - * Draws one block (Each piece is made of 4 blocks) - * The blockType is used to draw any block. - * The falling attribute is needed to apply different styles for falling and placed blocks. + * Shapes */ - _drawBlock: function(x, y, blockType, falling) { - - // convert x and y to pixel - x = x * this._block_size; - y = y * this._block_size; - - falling = typeof falling === 'boolean' ? falling : false; - var borderWidth = this._theme.strokeWidth; - var borderDistance = Math.round(this._block_size*0.23); - var squareDistance = Math.round(this._block_size*0.30); - - var color = this._getBlockColor(blockType, falling); - - // Draw the main square - this._ctx.globalAlpha = 1.0; - - // If it's an image, the block has a specific texture. Use that. - if( color instanceof Image ) { - this._ctx.globalAlpha = 1.0; - - // Not loaded - if( color.width === 0 || color.height === 0 ){ return; } - - this._ctx.drawImage(color, 0, 0, color.width, color.height, x, y, this._block_size, this._block_size); - - } - else if( typeof color === 'string' ) - { - this._ctx.fillStyle = color; - this._ctx.fillRect(x, y, this._block_size, this._block_size); - - // Inner Shadow - if( typeof this._theme.innerShadow === 'string' ) { - this._ctx.globalAlpha = 1.0; - this._ctx.strokeStyle = this._theme.innerShadow; - this._ctx.lineWidth = 1.0; - - // Draw the borders - this._ctx.strokeRect(x+1, y+1, this._block_size-2, this._block_size-2); - } - - // Decoration (borders) - if( typeof this._theme.stroke === 'string' ) { - this._ctx.globalAlpha = 1.0; - this._ctx.fillStyle = this._theme.stroke; - this._ctx.strokeStyle = this._theme.stroke; - this._ctx.lineWidth = borderWidth; - - // Draw the borders - this._ctx.strokeRect(x, y, this._block_size, this._block_size); - } - if( typeof this._theme.innerStroke === 'string' ) { - // Draw the inner dashes - this._ctx.fillStyle = this._theme.innerStroke; - this._ctx.fillRect(x+borderDistance, y+borderDistance, this._block_size-borderDistance*2, borderWidth); - // The rects shouldn't overlap, to prevent issues with transparency - this._ctx.fillRect(x+borderDistance, y+borderDistance+borderWidth, borderWidth, this._block_size-borderDistance*2-borderWidth); - } - if( typeof this._theme.innerSquare === 'string' ) { - // Draw the inner square - this._ctx.fillStyle = this._theme.innerSquare; - this._ctx.globalAlpha = 0.2; - this._ctx.fillRect(x+squareDistance, y+squareDistance, this._block_size-squareDistance*2, this._block_size-squareDistance*2); - } - } - - // Return the alpha back to 1.0 so we don't create any issues with other drawings. - this._ctx.globalAlpha = 1.0; - }, - + _shapeFactory: null, - _getBlockColor: function(blockName, falling) { + _shapes: { /** - * The theme allows us to do many things: - * - Use a specific color for the falling block (primary), regardless of the proper color. - * - Use another color for the placed blocks (secondary). - * - Default to the "original" block color in any of those cases by setting primary and/or secondary to null. - * - With primary and secondary as null, all blocks keep their original colors. + * The shapes have a reference point (the dot) and always rotate left. + * Keep in mind that the blocks should keep in the same relative position when rotating, + * to allow for custom per-block themes. */ - - if( typeof falling !== 'boolean' ){ falling = true; } - if( falling ) { - if( typeof this._theme.primary === 'string' && this._theme.primary !== '' ) { - return this._theme.primary; - } else { - return this._theme.blocks[blockName]; - } - } else { - if( typeof this._theme.secondary === 'string' && this._theme.secondary !== '' ) { - return this._theme.secondary; - } else { - return this._theme.blocks[blockName]; - } - } + /* + * X + * O XOXX + * X + * X + * . . + */ + line: [ + [ 0, -1, 0, -2, 0, -3, 0, -4], + [ 2, -2, 1, -2, 0, -2, -1, -2], + [ 0, -4, 0, -3, 0, -2, 0, -1], + [-1, -2, 0, -2, 1, -2, 2, -2] + ], + /* + * XX + * XX + */ + square: [ + [0, 0, 1, 0, 0, -1, 1, -1], + [1, 0, 1, -1, 0, 0, 0, -1], + [1, -1, 0, -1, 1, 0, 0, 0], + [0, -1, 0, 0, 1, -1, 1, 0] + ], + /* + * X X X + * XOX XO XOX OX + * . .X .X .X + */ + arrow: [ + [0, -1, 1, -1, 2, -1, 1, -2], + [1, 0, 1, -1, 1, -2, 0, -1], + [2, -1, 1, -1, 0, -1, 1, 0], + [1, -2, 1, -1, 1, 0, 2, -1] + ], + /* + * X X XX + * O XOX O XOX + * .XX . .X X + */ + rightHook: [ + [2, 0, 1, 0, 1, -1, 1, -2], + [2, -2, 2, -1, 1, -1, 0, -1], + [0, -2, 1, -2, 1, -1, 1, 0], + [0, 0, 0, -1, 1, -1, 2, -1] + ], + /* + * X XX X + * O XOX O XOX + * XX . X .X . + */ + leftHook: [ + [0, 0, 1, 0, 1, -1, 1, -2], + [2, 0, 2, -1, 1, -1, 0, -1], + [2, -2, 1, -2, 1, -1, 1, 0], + [0, -2, 0, -1, 1, -1, 2, -1] + ], + /* + * X XX + * XO OX + * X . + */ + leftZag: [ + [0, 0, 0, -1, 1, -1, 1, -2], + [2, -1, 1, -1, 1, -2, 0, -2], + [1, -2, 1, -1, 0, -1, 0, 0], + [0, -2, 1, -2, 1, -1, 2, -1] + ], + /* + * X + * XO OX + * .X XX + */ + rightZag: [ + [1, 0, 1, -1, 0, -1, 0, -2], + [2, -1, 1, -1, 1, 0, 0, 0], + [0, -2, 0, -1, 1, -1, 1, 0], + [0, 0, 1, 0, 1, -1, 2, -1] + ] }, - - /** - * Shapes - */ - _shapeFactory: null, - _SetupShapeFactory: function(){ var game = this; if( this._shapeFactory !== null ){ return; } @@ -435,46 +439,63 @@ }); return this; }, + blockType: blockType, + blockVariation: null, blocksLen: orientations[0].length, orientations: orientations, orientation: 0, // 4 possible - rotate: function(right) { - var orientation = (this.orientation + (right ? 1 : -1) + 4) % 4; + + rotate: function(direction) { + var orientation = (this.orientation + (direction === 'left' ? 1 : -1) + 4) % 4; //TODO - when past limit - auto shift and remember that too! if (!game._checkCollisions(this.x, this.y, this.getBlocks(orientation))) { this.orientation = orientation; + game._board.renderChanged = true; } }, + moveRight: function() { if (!game._checkCollisions(this.x + 1, this.y, this.getBlocks())) { this.x++; + game._board.renderChanged = true; } }, moveLeft: function() { if (!game._checkCollisions(this.x - 1, this.y, this.getBlocks())) { this.x--; + game._board.renderChanged = true; + } + }, + drop: function() { + if (!game._checkCollisions(this.x, this.y + 1, this.getBlocks())) { + this.y++; + // Reset the drop count, as we dropped the block sooner + game._board.dropCount = -1; + game._board.animate(); + game._board.renderChanged = true; } }, + getBlocks: function(orientation) { // optional param return this.orientations[orientation !== undefined ? orientation : this.orientation]; }, - draw: function(drop, _x, _y, _orientation) { - if (drop) { this.y++; } - + draw: function(_x, _y, _orientation) { var blocks = this.getBlocks(_orientation), - x = _x === undefined ? this.x : _x, - y = _y === undefined ? this.y : _y, - i = 0; + x = _x === undefined ? this.x : _x, + y = _y === undefined ? this.y : _y, + i = 0, + index = 0; for (; i maxx) { maxx = blocks[i]; } @@ -497,82 +518,25 @@ this._shapeFactory = { line: function() { - /* - * X X - * O XOXX O XOXX - * X X - * X X - */ - var ver = [0, -1, 0, -2, 0, -3, 0, -4], - hor = [-1, -2, 0, -2, 1, -2, 2, -2]; - return new Shape(game, [ver, hor, ver, hor], true, 'line'); + return new Shape(game, game._shapes.line, false, 'line'); }, square: function() { - /* - * XX - * XX - */ - var s = [0, 0, 1, 0, 0, -1, 1, -1]; - return new Shape(game, [s, s, s, s], true, 'square'); + return new Shape(game, game._shapes.square, false, 'square'); }, arrow: function() { - /* - * X X X - * XOX OX XOX XO - * X X X - */ - return new Shape(game, [ - [0, -1, 1, -1, 2, -1, 1, -2], - [1, -2, 1, -1, 1, 0, 2, -1], - [0, -1, 1, -1, 2, -1, 1, 0], - [0, -1, 1, -1, 1, -2, 1, 0] - ], false, 'arrow'); - }, - rightHook: function() { - /* - * XX X X - * XOX O XOX O - * X X XX - */ - return new Shape(game, [ - [0, 0, 0, -1, 1, -1, 2, -1], - [0, -2, 1, 0, 1, -1, 1, -2], - [0, -1, 1, -1, 2, -1, 2, -2], - [0, -2, 0, -1, 0, 0, 1, 0] - ], false, 'rightHook'); + return new Shape(game, game._shapes.arrow, false, 'arrow'); }, leftHook: function() { - /* - * X X XX - * XOX O XOX O - * X XX X - */ - return new Shape(game, [ - [2, 0, 0, -1, 1, -1, 2, -1], - [0, 0, 1, 0, 1, -1, 1, -2], - [0, -2, 0, -1, 1, -1, 2, -1], - [0, 0, 0, -1, 0, -2, 1, -2] - ], false, 'leftHook'); + return new Shape(game, game._shapes.leftHook, false, 'leftHook'); + }, + rightHook: function() { + return new Shape(game, game._shapes.rightHook, false, 'rightHook'); }, leftZag: function() { - /* - * X - * XO OX - * XX X - */ - var ver = [0, 0, 0, -1, 1, -1, 1, -2], - hor = [0, -1, 1, -1, 1, 0, 2, 0]; - return new Shape(game, [hor, ver, hor, ver], true, 'leftZag'); + return new Shape(game, game._shapes.leftZag, false, 'leftZag'); }, rightZag: function() { - /* - * X - * OX OX - * XX X - */ - var ver = [0, -2, 0, -1, 1, -1, 1, 0], - hor = [0, 0, 1, 0, 1, -1, 2, -1]; - return new Shape(game, [hor, ver, hor, ver], true, 'rightZag'); + return new Shape(game, game._shapes.rightZag, false, 'rightZag'); } }; }, @@ -589,9 +553,20 @@ check: function(x, y) { return this.data[this.asIndex(x, y)]; }, - add: function(x, y, blockType) { + add: function(x, y, blockType, blockVariation, blockIndex, blockOrientation) { if (x >= 0 && x < game._BLOCK_WIDTH && y >= 0 && y < game._BLOCK_HEIGHT) { - this.data[this.asIndex(x, y)] = blockType; + this.data[this.asIndex(x, y)] = { + blockType: blockType, + blockVariation: blockVariation, + blockIndex: blockIndex, + blockOrientation: blockOrientation + }; + } + }, + getFreeSpaces: function() { + var count = 0; + for( var i=0; i 1 ) { - //board.dropDelay -= 2; + game._board.dropDelay *= 0.9; } } @@ -656,8 +631,8 @@ for (var i=0, len=this.data.length, row, color; i= this.dropDelay || game.options.autoplay ) { + + // Drop by delay or holding + if( (this.dropCount >= this.dropDelay) || + (game.options.autoplay) || + (this.holding.drop && (now - this.holding.drop) >= this.holdingThreshold) ) { drop = true; + moved = true; this.dropCount = 0; } - // test for a collision + // Move Left by holding + if( this.holding.left && (now - this.holding.left) >= this.holdingThreshold ) { + moved = true; + this.cur.moveLeft(); + } + + // Move Right by holding + if( this.holding.right && (now - this.holding.right) >= this.holdingThreshold ) { + moved = true; + this.cur.moveRight(); + } + + // Test for a collision, add the piece to the filled blocks and fetch the next one if (drop) { var cur = this.cur, x = cur.x, y = cur.y, blocks = cur.getBlocks(); if (game._checkCollisions(x, y+1, blocks, true)) { drop = false; + var blockIndex = 0; for (var i=0; i 0) { + return blockTheme[0]; + } else { + return null; + } + } else { + return blockTheme; + } + } + + if( typeof falling !== 'boolean' ){ falling = true; } + if( falling ) { + if( typeof game._theme.primary === 'string' && game._theme.primary !== '' ) { + return game._theme.primary; + } else if( typeof game._theme.blocks !== 'undefined' && game._theme.blocks !== null ) { + return getBlockVariation(game._theme.blocks[blockType], blockVariation); + } else { + return getBlockVariation(game._theme.complexBlocks[blockType], blockVariation); + } + } else { + if( typeof game._theme.secondary === 'string' && game._theme.secondary !== '' ) { + return game._theme.secondary; + } else if( typeof game._theme.blocks !== 'undefined' && game._theme.blocks !== null ) { + return getBlockVariation(game._theme.blocks[blockType], blockVariation); + } else { + return getBlockVariation(game._theme.complexBlocks[blockType], blockVariation); + } + } } + }; game._niceShapes = game._getNiceShapes(); @@ -878,31 +1092,71 @@ */ _preloadThemeAssets: function() { - var base64check = new RegExp('^data:image/(png|gif|jpg);base64,', 'i');; + var game = this; + + var hexColorcheck = new RegExp('^#[A-F0-9+]{3,6}', 'i'); + var base64check = new RegExp('^data:image/(png|gif|jpg);base64,', 'i'); + + var handleAssetLoad = function() { + // Rerender the board as soon as an asset loads + if( game._board ) { + game._board.render(true); + } + }; + + var loadAsset = function(src) { + var plainSrc = src; + if( ! hexColorcheck.test( plainSrc ) ) { + // It's an image + src = new Image(); + src.src = plainSrc; + src.onload = handleAssetLoad; + } else { + // It's a color + src = plainSrc; + } + return src; + }; + + var startAssetLoad = function(block) { + // Assets can be an array of variation so they can change color/design randomly + if( $.isArray(block) && block.length > 0 ) { + for( var i=0; i').appendTo(game._$gameholder); + game._$touchRight = $('
').appendTo(game._$gameholder); + game._$touchRotateRight = $('').appendTo(game._$gameholder); + game._$touchRotateLeft = $('').appendTo(game._$gameholder); + game._$touchDrop = $('').appendTo(game._$gameholder); + }, @@ -1129,32 +1397,85 @@ var game = this; + var moveLeft = function(start) { + if( ! start ) { game._board.holding.left = null; return; } + if( ! game._board.holding.left ) { + game._board.cur.moveLeft(); + game._board.holding.left = Date.now(); + game._board.holding.right = null; + } + } + var moveRight = function(start) { + if( ! start ) { game._board.holding.right = null; return; } + if( ! game._board.holding.right ) { + game._board.cur.moveRight(); + game._board.holding.right = Date.now(); + game._board.holding.left = null; + } + } + var drop = function(start) { + if( ! start ) { game._board.holding.drop = null; return; } + if( ! game._board.holding.drop ) { + game._board.cur.drop(); + game._board.holding.drop = Date.now(); + } + } + var rotateLeft = function() { + game._board.cur.rotate('left'); + } + var rotateRight = function() { + game._board.cur.rotate('right'); + } + // Handlers: These are used to be able to bind/unbind controls - var handleKeyPress = function(evt) { + var handleKeyDown = function(evt) { + if( ! game._board.cur ) { return true; } var caught = false; - if (game._board.cur) { - caught = true; - if (game.options.asdwKeys) { - switch(evt.keyCode) { - case 65: /*a*/ game._board.cur.moveLeft(); break; - case 87: /*w*/ game._board.cur.rotate(true); break; - case 68: /*d*/ game._board.cur.moveRight(); break; - case 83: /*s*/ game._board.dropCount = game._board.dropDelay; break; - } + + caught = true; + if (game.options.asdwKeys) { + switch(evt.keyCode) { + case 65: /*a*/ moveLeft(true); break; + case 68: /*d*/ moveRight(true); break; + case 83: /*s*/ drop(true); break; + case 87: /*w*/ game._board.cur.rotate('right'); break; } + } + switch(evt.keyCode) { + case 37: /*left*/ moveLeft(true); break; + case 39: /*right*/ moveRight(true); break; + case 40: /*down*/ drop(true); break; + case 38: /*up*/ game._board.cur.rotate('right'); break; + case 88: /*x*/ game._board.cur.rotate('right'); break; + case 90: /*z*/ game._board.cur.rotate('left'); break; + default: caught = false; + } + if (caught) evt.preventDefault(); + return !caught; + }; + + + var handleKeyUp = function(evt) { + if( ! game._board.cur ) { return true; } + var caught = false; + + caught = true; + if (game.options.asdwKeys) { switch(evt.keyCode) { - case 37: /*left*/ game._board.cur.moveLeft(); break; - case 38: /*up*/ game._board.cur.rotate(true); break; - case 39: /*right*/ game._board.cur.moveRight(); break; - case 40: /*down*/ game._board.dropCount = game._board.dropDelay; break; - case 88: /*x*/ game._board.cur.rotate(true); break; - case 90: /*z*/ game._board.cur.rotate(false); break; - default: caught = false; + case 65: /*a*/ moveLeft(false); break; + case 68: /*d*/ moveRight(false); break; + case 83: /*s*/ drop(false); break; } } + switch(evt.keyCode) { + case 37: /*left*/ moveLeft(false); break; + case 39: /*right*/ moveRight(false); break; + case 40: /*down*/ drop(false); break; + default: caught = false; + } if (caught) evt.preventDefault(); return !caught; - } + }; function isStopKey(evt) { var cfg = { @@ -1168,34 +1489,100 @@ function getKey(evt) { return 'safekeypress.' + evt.keyCode; } - function keypress(evt) { - var key = getKey(evt), - val = ($.data(this, key) || 0) + 1; - $.data(this, key, val); - if (val > 0) return handleKeyPress.call(this, evt); - return isStopKey(evt); - } - function keydown(evt) { var key = getKey(evt); $.data(this, key, ($.data(this, key) || 0) - 1); - return handleKeyPress.call(this, evt); + return handleKeyDown.call(this, evt); } function keyup(evt) { $.data(this, getKey(evt), 0); + handleKeyUp.call(this, evt); return isStopKey(evt); } // Unbind everything by default // Use event namespacing so we don't ruin other keypress events - $(document).unbind('keypress.blockrain').unbind('keydown.blockrain').unbind('keyup.blockrain'); + $(document) .unbind('keydown.blockrain') + .unbind('keyup.blockrain'); if( ! game.options.autoplay ) { if( enable ) { - $(document).bind('keypress.blockrain', keypress).bind('keydown.blockrain', keydown).bind('keyup.blockrain', keyup); + $(document) .bind('keydown.blockrain', keydown) + .bind('keyup.blockrain', keyup); } } + }, + + + _setupTouchControls: function(enable) { + + var game = this; + + // Movements can be held for faster movement + var moveLeft = function(event){ + event.preventDefault(); + game._board.cur.moveLeft(); + game._board.holding.left = Date.now(); + game._board.holding.right = null; + game._board.holding.drop = null; + }; + var moveRight = function(event){ + event.preventDefault(); + game._board.cur.moveRight(); + game._board.holding.right = Date.now(); + game._board.holding.left = null; + game._board.holding.drop = null; + }; + var drop = function(event){ + event.preventDefault(); + game._board.cur.drop(); + game._board.holding.drop = Date.now(); + }; + var endMoveLeft = function(event){ + event.preventDefault(); + game._board.holding.left = null; + }; + var endMoveRight = function(event){ + event.preventDefault(); + game._board.holding.right = null; + }; + var endDrop = function(event){ + event.preventDefault(); + game._board.holding.drop = null; + }; + + // Rotations can't be held + var rotateLeft = function(event){ + event.preventDefault(); + game._board.cur.rotate('left'); + }; + var rotateRight = function(event){ + event.preventDefault(); + game._board.cur.rotate('right'); + }; + + // Unbind everything by default + game._$touchLeft.unbind('touchstart touchend click'); + game._$touchRight.unbind('touchstart touchend click'); + game._$touchRotateLeft.unbind('touchstart touchend click'); + game._$touchRotateRight.unbind('touchstart touchend click'); + game._$touchDrop.unbind('touchstart touchend click'); + + if( ! game.options.autoplay && enable ) { + game._$touchLeft.show().bind('touchstart click', moveLeft).bind('touchend', endMoveLeft); + game._$touchRight.show().bind('touchstart click', moveRight).bind('touchend', endMoveRight); + game._$touchDrop.show().bind('touchstart click', drop).bind('touchend', endDrop); + game._$touchRotateLeft.show().bind('touchstart click', rotateLeft); + game._$touchRotateRight.show().bind('touchstart click', rotateRight); + } else { + game._$touchLeft.hide(); + game._$touchRight.hide(); + game._$touchRotateLeft.hide(); + game._$touchRotateRight.hide(); + game._$touchDrop.hide(); + } + } }); @@ -1205,6 +1592,19 @@ * Themes. You can add more custom themes to this object. */ window.BlockrainThemes = { + 'custom': { + background: '#040304', + backgroundGrid: 'data:image/png;base64,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', + complexBlocks: { + line: ['assets/blocks/custom/line.png', 'assets/blocks/custom/line.png'], + square: ['assets/blocks/custom/square.png'], + arrow: 'assets/blocks/custom/arrow.png', + rightHook:['assets/blocks/custom/rightHook.png'], + leftHook: 'assets/blocks/custom/leftHook.png', + rightZag: ['assets/blocks/custom/rightZag.png'], + leftZag: 'assets/blocks/custom/leftZag.png' + } + }, 'candy': { background: '#040304', backgroundGrid: 'data:image/png;base64,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', diff --git a/dist/blockrain.jquery.min.js b/dist/blockrain.jquery.min.js index 661cf89..dfd9e9d 100644 --- a/dist/blockrain.jquery.min.js +++ b/dist/blockrain.jquery.min.js @@ -1,5 +1,5 @@ /*! - * BlockRain.js 0.1.0 + * BlockRain.js 0.2.0 * jQuery plugin that lets you put a playable (and configurable) game of Tetris in your site or just leave it in auto in the background. * http://aerolab.github.io/blockrain.js/ * @@ -8,4 +8,5 @@ * Released under the MIT license * http://aerolab.github.io/blockrain.js/LICENSE.txt */ - !function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)}(function(t){var e=0,i=Array.prototype.slice;t.cleanData=function(e){return function(i){var n,o,s;for(s=0;null!=(o=i[s]);s++)try{n=t._data(o,"events"),n&&n.remove&&t(o).triggerHandler("remove")}catch(r){}e(i)}}(t.cleanData),t.widget=function(e,i,n){var o,s,r,a,h={},c=e.split(".")[0];return e=e.split(".")[1],o=c+"-"+e,n||(n=i,i=t.Widget),t.expr[":"][o.toLowerCase()]=function(e){return!!t.data(e,o)},t[c]=t[c]||{},s=t[c][e],r=t[c][e]=function(t,e){return this._createWidget?void(arguments.length&&this._createWidget(t,e)):new r(t,e)},t.extend(r,s,{version:n.version,_proto:t.extend({},n),_childConstructors:[]}),a=new i,a.options=t.widget.extend({},a.options),t.each(n,function(e,n){return t.isFunction(n)?void(h[e]=function(){var t=function(){return i.prototype[e].apply(this,arguments)},o=function(t){return i.prototype[e].apply(this,t)};return function(){var e,i=this._super,s=this._superApply;return this._super=t,this._superApply=o,e=n.apply(this,arguments),this._super=i,this._superApply=s,e}}()):void(h[e]=n)}),r.prototype=t.widget.extend(a,{widgetEventPrefix:s?a.widgetEventPrefix||e:e},h,{constructor:r,namespace:c,widgetName:e,widgetFullName:o}),s?(t.each(s._childConstructors,function(e,i){var n=i.prototype;t.widget(n.namespace+"."+n.widgetName,r,i._proto)}),delete s._childConstructors):i._childConstructors.push(r),t.widget.bridge(e,r),r},t.widget.extend=function(e){for(var n,o,s=i.call(arguments,1),r=0,a=s.length;a>r;r++)for(n in s[r])o=s[r][n],s[r].hasOwnProperty(n)&&void 0!==o&&(e[n]=t.isPlainObject(o)?t.isPlainObject(e[n])?t.widget.extend({},e[n],o):t.widget.extend({},o):o);return e},t.widget.bridge=function(e,n){var o=n.prototype.widgetFullName||e;t.fn[e]=function(s){var r="string"==typeof s,a=i.call(arguments,1),h=this;return s=!r&&a.length?t.widget.extend.apply(null,[s].concat(a)):s,this.each(r?function(){var i,n=t.data(this,o);return"instance"===s?(h=n,!1):n?t.isFunction(n[s])&&"_"!==s.charAt(0)?(i=n[s].apply(n,a),i!==n&&void 0!==i?(h=i&&i.jquery?h.pushStack(i.get()):i,!1):void 0):t.error("no such method '"+s+"' for "+e+" widget instance"):t.error("cannot call methods on "+e+" prior to initialization; attempted to call method '"+s+"'")}:function(){var e=t.data(this,o);e?(e.option(s||{}),e._init&&e._init()):t.data(this,o,new n(s,this))}),h}},t.Widget=function(){},t.Widget._childConstructors=[],t.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
",options:{disabled:!1,create:null},_createWidget:function(i,n){n=t(n||this.defaultElement||this)[0],this.element=t(n),this.uuid=e++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=t(),this.hoverable=t(),this.focusable=t(),n!==this&&(t.data(n,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===n&&this.destroy()}}),this.document=t(n.style?n.ownerDocument:n.document||n),this.window=t(this.document[0].defaultView||this.document[0].parentWindow)),this.options=t.widget.extend({},this.options,this._getCreateOptions(),i),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:t.noop,_getCreateEventData:t.noop,_create:t.noop,_init:t.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetFullName).removeData(t.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:t.noop,widget:function(){return this.element},option:function(e,i){var n,o,s,r=e;if(0===arguments.length)return t.widget.extend({},this.options);if("string"==typeof e)if(r={},n=e.split("."),e=n.shift(),n.length){for(o=r[e]=t.widget.extend({},this.options[e]),s=0;n.length-1>s;s++)o[n[s]]=o[n[s]]||{},o=o[n[s]];if(e=n.pop(),1===arguments.length)return void 0===o[e]?null:o[e];o[e]=i}else{if(1===arguments.length)return void 0===this.options[e]?null:this.options[e];r[e]=i}return this._setOptions(r),this},_setOptions:function(t){var e;for(e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return this.options[t]=e,"disabled"===t&&(this.widget().toggleClass(this.widgetFullName+"-disabled",!!e),e&&(this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus"))),this},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_on:function(e,i,n){var o,s=this;"boolean"!=typeof e&&(n=i,i=e,e=!1),n?(i=o=t(i),this.bindings=this.bindings.add(i)):(n=i,i=this.element,o=this.widget()),t.each(n,function(n,r){function a(){return e||s.options.disabled!==!0&&!t(this).hasClass("ui-state-disabled")?("string"==typeof r?s[r]:r).apply(s,arguments):void 0}"string"!=typeof r&&(a.guid=r.guid=r.guid||a.guid||t.guid++);var h=n.match(/^([\w:-]*)\s*(.*)$/),c=h[1]+s.eventNamespace,l=h[2];l?o.delegate(l,c,a):i.bind(c,a)})},_off:function(e,i){i=(i||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.unbind(i).undelegate(i),this.bindings=t(this.bindings.not(e).get()),this.focusable=t(this.focusable.not(e).get()),this.hoverable=t(this.hoverable.not(e).get())},_delay:function(t,e){function i(){return("string"==typeof t?n[t]:t).apply(n,arguments)}var n=this;return setTimeout(i,e||0)},_hoverable:function(e){this.hoverable=this.hoverable.add(e),this._on(e,{mouseenter:function(e){t(e.currentTarget).addClass("ui-state-hover")},mouseleave:function(e){t(e.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(e){this.focusable=this.focusable.add(e),this._on(e,{focusin:function(e){t(e.currentTarget).addClass("ui-state-focus")},focusout:function(e){t(e.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(e,i,n){var o,s,r=this.options[e];if(n=n||{},i=t.Event(i),i.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase(),i.target=this.element[0],s=i.originalEvent)for(o in s)o in i||(i[o]=s[o]);return this.element.trigger(i,n),!(t.isFunction(r)&&r.apply(this.element[0],[i].concat(n))===!1||i.isDefaultPrevented())}},t.each({show:"fadeIn",hide:"fadeOut"},function(e,i){t.Widget.prototype["_"+e]=function(n,o,s){"string"==typeof o&&(o={effect:o});var r,a=o?o===!0||"number"==typeof o?i:o.effect||i:e;o=o||{},"number"==typeof o&&(o={duration:o}),r=!t.isEmptyObject(o),o.complete=s,o.delay&&n.delay(o.delay),r&&t.effects&&t.effects.effect[a]?n[e](o):a!==e&&n[a]?n[a](o.duration,o.easing,s):n.queue(function(i){t(this)[e](),s&&s.call(n[0]),i()})}}),t.widget}),function(t){"use strict";t.widget("aerolab.blockrain",{options:{autoplay:!1,autoplayRestart:!0,showFieldOnStart:!0,theme:null,blockWidth:10,autoBlockWidth:!1,autoBlockSize:24,difficulty:"normal",speed:20,asdwKeys:!0,playText:"Let's play some Tetris",playButtonText:"Play",gameOverText:"Game Over",restartButtonText:"Play Again",scoreText:"Score",onStart:function(){},onRestart:function(){},onGameOver:function(){},onLine:function(){}},start:function(){this._doStart(),this.options.onStart.call(this.element)},restart:function(){this._doStart(),this.options.onRestart.call(this.element)},gameover:function(){this.showGameOverMessage(),this._board.gameover=!0,this.options.onGameOver.call(this.element,this._filled.score)},_doStart:function(){this._filled.clearAll(),this._filled._resetScore(),this._board.cur=this._board.nextShape(),this._board.started=!0,this._board.gameover=!1,this._board.animate(),this._$start.fadeOut(150),this._$gameover.fadeOut(150),this._$score.fadeIn(150)},pause:function(){this._board.paused=!0},resume:function(){this._board.paused=!1},autoplay:function(t){"boolean"!=typeof t&&(t=!0),this.options.autoplay=t,t&&!this._board.started&&this._doStart(),this._setupControls(!t)},controls:function(t){"boolean"!=typeof t&&(t=!0),this._setupControls(t)},score:function(t){return"undefined"!=typeof t&&parseInt(t)>=0&&(this._filled.score=parseInt(t),this._$scoreText.text(this._filled_score)),this._filled.score},showStartMessage:function(){this._$start.show()},showGameOverMessage:function(){this._$gameover.show()},updateSizes:function(){this._PIXEL_WIDTH=this.element.innerWidth(),this._PIXEL_HEIGHT=this.element.innerHeight(),this._BLOCK_WIDTH=this.options.blockWidth,this._BLOCK_HEIGHT=Math.floor(this.element.innerHeight()/this.element.innerWidth()*this._BLOCK_WIDTH),this._block_size=Math.floor(this._PIXEL_WIDTH/this._BLOCK_WIDTH),this._border_width=2,this._PIXEL_WIDTH=this._block_size*this._BLOCK_WIDTH,this._PIXEL_HEIGHT=this._block_size*this._BLOCK_HEIGHT,this._$canvas.attr("width",this._PIXEL_WIDTH).attr("height",this._PIXEL_HEIGHT)},theme:function(t){return"undefined"==typeof t?this.options.theme||this._theme:("string"==typeof t?(this.options.theme=t,this._theme=BlockrainThemes[t]):(this.options.theme=null,this._theme=t),("undefined"==typeof this._theme||null===this._theme)&&(this._theme=BlockrainThemes.retro,this.options.theme="retro"),(isNaN(parseInt(this._theme.strokeWidth))||"number"!=typeof parseInt(this._theme.strokeWidth))&&(this._theme.strokeWidth=2),this._preloadThemeAssets(),void(null!==this._board&&("string"==typeof this._theme.background&&this._$canvas.css("background-color",this._theme.background),this._board.render())))},_theme:{},_$game:null,_$canvas:null,_$gameholder:null,_$start:null,_$gameover:null,_$score:null,_$scoreText:null,_canvas:null,_ctx:null,_create:function(){this.theme(this.options.theme),this._createHolder(),this._createUI(),this._refreshBlockSizes(),this.updateSizes(),t(window).resize(function(){}),this._SetupShapeFactory(),this._SetupFilled(),this._SetupInfo(),this._SetupBoard(),this._info.init(),this._board.init(),this.options.autoplay?this.autoplay(!0):this._setupControls(!0)},_checkCollisions:function(t,e,i,n){for(var o,s,r=0,a=i.length;a>r;r+=2){if(o=t+i[r],s=e+i[r+1],s>=this._BLOCK_HEIGHT||this._filled.check(o,s))return!0;if(!n&&0>o||o>=this._BLOCK_WIDTH)return!0}return!1},_board:null,_info:null,_filled:null,_drawBackground:function(){if("string"==typeof this._theme.background){if(this._theme.backgroundGrid instanceof Image){if(0===this._theme.backgroundGrid.width||0===this._theme.backgroundGrid.height)return;this._ctx.globalAlpha=1;for(var t=0;tn;n+=2)i[n]r&&(r=i[n]),i[n+1]h&&(h=i[n+1]);return{left:s,right:r,top:a,bottom:h,width:r-s,height:h-a}}}),this.init()}var i=this;null===this._shapeFactory&&(this._shapeFactory={line:function(){var t=[0,-1,0,-2,0,-3,0,-4],n=[-1,-2,0,-2,1,-2,2,-2];return new e(i,[t,n,t,n],!0,"line")},square:function(){var t=[0,0,1,0,0,-1,1,-1];return new e(i,[t,t,t,t],!0,"square")},arrow:function(){return new e(i,[[0,-1,1,-1,2,-1,1,-2],[1,-2,1,-1,1,0,2,-1],[0,-1,1,-1,2,-1,1,0],[0,-1,1,-1,1,-2,1,0]],!1,"arrow")},rightHook:function(){return new e(i,[[0,0,0,-1,1,-1,2,-1],[0,-2,1,0,1,-1,1,-2],[0,-1,1,-1,2,-1,2,-2],[0,-2,0,-1,0,0,1,0]],!1,"rightHook")},leftHook:function(){return new e(i,[[2,0,0,-1,1,-1,2,-1],[0,0,1,0,1,-1,1,-2],[0,-2,0,-1,1,-1,2,-1],[0,0,0,-1,0,-2,1,-2]],!1,"leftHook")},leftZag:function(){var t=[0,0,0,-1,1,-1,1,-2],n=[0,-1,1,-1,1,0,2,0];return new e(i,[n,t,n,t],!0,"leftZag")},rightZag:function(){var t=[0,-2,0,-1,1,-1,1,0],n=[0,0,1,0,1,-1,2,-1];return new e(i,[n,t,n,t],!0,"rightZag")}})},_SetupFilled:function(){var t=this;null===this._filled&&(this._filled={data:new Array(t._BLOCK_WIDTH*t._BLOCK_HEIGHT),score:0,toClear:{},check:function(t,e){return this.data[this.asIndex(t,e)]},add:function(e,i,n){e>=0&&e=0&&i=0;i--)this.data[i]=i>=t._BLOCK_WIDTH?this.data[i-t._BLOCK_WIDTH]:void 0},checkForClears:function(){var e,i,n,o,s=t._board.lines,r=[];for(e=0,i=this.data.length;i>e;e++)o=this.asX(e),0==o&&(n=0),this.data[e]&&"string"==typeof this.data[e]&&(n+=1),o==t._BLOCK_WIDTH-1&&n==t._BLOCK_WIDTH&&r.push(this.asY(e));for(e=0,i=r.length;i>e;e++)this._popRow(r[e]),t._board.lines++,t._board.lines%10==0&&t._board.dropDelay>1;var a=t._board.lines-s;this._updateScore(a)},_updateScore:function(e){if(!(0>=e)){var i=[0,400,1e3,3e3,12e3];e>=i.length&&(e=i.length-1),this.score+=i[e],t._$scoreText.text(this.score),t.options.onLine.call(t.element,e,i[e],this.score)}},_resetScore:function(){this.score=0,t._$scoreText.text(this.score)},draw:function(){for(var e,i=0,n=this.data.length;n>i;i++)if(void 0!==this.data[i]){e=this.asY(i);var o=this.data[i];t._drawBlock(this.asX(i),e,o)}}})},_SetupInfo:function(){var t=this;this._info={mode:t.options.difficulty,modes:["normal","nice","evil"],modesY:170,autopilotY:null,init:function(){this.mode=t.options.difficulty},setMode:function(e){this.mode=e,t._board.nextShape(!0)}}},_SetupBoard:function(){var t=this,e=this._info;this._board={animateDelay:1e3/t.options.speed,cur:null,lines:0,dropCount:0,dropDelay:5,started:!1,gameover:!1,init:function(){this.cur=this.nextShape(),t.options.showFieldOnStart&&(t._drawBackground(),t._board.createRandomBoard(),t._board.render()),this.showStartMessage()},showStartMessage:function(){t._$start.show()},showGameOverMessage:function(){t._$gameover.show()},nextShape:function(i){var n,o,s,r=this.next;if(n="nice"==e.mode||"evil"==e.mode?t._niceShapes:t._randomShapes(),t.options.no_preview){if(this.next=null,i)return null;if(o=n(t._filled,t._checkCollisions,t._BLOCK_WIDTH,t._BLOCK_HEIGHT,e.mode),!o)throw new Error("No shape returned from shape function!",n);o.init(),s=o}else{if(o=n(t._filled,t._checkCollisions,t._BLOCK_WIDTH,t._BLOCK_HEIGHT,e.mode),!o)throw new Error("No shape returned from shape function!",n);if(o.init(),this.next=o,i)return null;s=r||this.nextShape()}return t.options.autoplay&&(t._niceShapes(t._filled,t._checkCollisions,t._BLOCK_WIDTH,t._BLOCK_HEIGHT,"normal",s),s.orientation=s.best_orientation,s.x=s.best_x),s},animate:function(){var e=!1,i=!1;if(!this.paused&&!this.gameover){if(this.dropCount++,(this.dropCount>=this.dropDelay||t.options.autoplay)&&(e=!0,this.dropCount=0),e){var n=this.cur,o=n.x,s=n.y,r=n.getBlocks();if(t._checkCollisions(o,s+1,r,!0)){e=!1;for(var a=0;ae;e++)for(n=0,o=t._randChoice([t._randInt(0,8),t._randInt(5,9)]);o>n;n++)s&&t._randInt(0,3)||(s=t._randChoice(r)),t._filled.add(e,t._BLOCK_HEIGHT-n,s)},render:function(){t._ctx.clearRect(0,0,t._PIXEL_WIDTH,t._PIXEL_HEIGHT),t._drawBackground(),t._filled.draw(),this.cur.draw(!1)}},t._niceShapes=t._getNiceShapes()},_randInt:function(t,e){return t+Math.floor(Math.random()*(1+e-t))},_randSign:function(){return 2*this._randInt(0,1)-1},_randChoice:function(t){return t[this._randInt(0,t.length-1)]},_preloadThemeAssets:function(){var t=new RegExp("^data:image/(png|gif|jpg);base64,","i");if("undefined"!=typeof this._theme.blocks)for(var e=Object.keys(this._theme.blocks),i=0;i
'),this._$gameholder.css("position","relative").css("width","100%").css("height","100%"),this.element.html("").append(this._$gameholder),this._$canvas=t(''),"string"==typeof this._theme.background&&this._$canvas.css("background-color",this._theme.background),this._$gameholder.append(this._$canvas),this._canvas=this._$canvas.get(0),this._ctx=this._canvas.getContext("2d")},_createUI:function(){var e=this;e._$score=t('
'+this.options.scoreText+'
0
').hide(),e._$scoreText=e._$score.find(".blockrain-score-num"),e._$gameholder.append(e._$score),e._$start=t('
").hide(),e._$gameholder.append(e._$start),e._$start.find(".blockrain-start-btn").click(function(t){t.preventDefault(),e.start()}),e._$gameover=t('
'+this.options.gameOverText+'
'+this.options.restartButtonText+"
").hide(),e._$gameover.find(".blockrain-game-over-btn").click(function(t){t.preventDefault(),e.restart()}),e._$gameholder.append(e._$gameover)},_refreshBlockSizes:function(){this.options.autoBlockWidth&&(this.options.blockWidth=Math.ceil(this.element.width()/this.options.autoBlockSize))},_getNiceShapes:function(){function t(t,e,i,o,s,r,a){var h,c,l,d,u=e.length,A=0,g={};for(h=0;u>h;h+=2)A+=t[n._filled.asIndex(i+e[h],o+e[h+1])]||0;for(h=0;u>h;h+=2)c=e[h],l=e[h+1],(void 0===g[c]||g[c]o+l;l++,h++)if(!n._filled.check(i+c,o+l)){d+=0==h?2:1;break}return A-=d}function e(){for(var t in o)o[t].x=0,o[t].y=-1}var i,n=this,o={};for(var i in this._shapeFactory)o[i]=this._shapeFactory[i]();var s=function(i,s,r,a,h,c){c||e();var l,d,u,A,g,f,m,p,b,_,k,I,v,y,C,w=new Array(r*a),G="evil"==h,B=999*(G?1:-1);for(l=0;r>l;l++)for(d=0;a>=d;d++)if(d==a||i.check(l,d)){for(u=d-4;d>u;u++)w[i.asIndex(l,u)]=u;break}var E=void 0===c?o:{cur:c};for(A in E){for(g=E[A],v=-999,f=0;f<(g.symmetrical?2:4);f++)for(m=g.getBlocks(f),p=g.getBounds(m),l=-p.left;lv&&(v=b,y=f,C=l);break}(G&&B>v||!G&&v>B)&&(_=g,B=v,k=y,I=C)}return _.best_orientation=k,_.best_x=I,_};return s.no_preview=!0,s},_randomShapes:function(){var e=[];return t.each(this._shapeFactory,function(t,i){e.push(i)}),this._randChoice(e)},_setupControls:function(e){function i(t){var e={stopKeys:{37:1,38:1,39:1,40:1}},i=e.stopKeys[t.keyCode]||e.moreStopKeys&&e.moreStopKeys[t.keyCode];return i&&t.preventDefault(),i}function n(t){return"safekeypress."+t.keyCode}function o(e){var o=n(e),s=(t.data(this,o)||0)+1;return t.data(this,o,s),s>0?h.call(this,e):i(e)}function s(e){var i=n(e);return t.data(this,i,(t.data(this,i)||0)-1),h.call(this,e)}function r(e){return t.data(this,n(e),0),i(e)}var a=this,h=function(t){var e=!1;if(a._board.cur){if(e=!0,a.options.asdwKeys)switch(t.keyCode){case 65:a._board.cur.moveLeft();break;case 87:a._board.cur.rotate(!0);break;case 68:a._board.cur.moveRight();break;case 83:a._board.dropCount=a._board.dropDelay}switch(t.keyCode){case 37:a._board.cur.moveLeft();break;case 38:a._board.cur.rotate(!0);break;case 39:a._board.cur.moveRight();break;case 40:a._board.dropCount=a._board.dropDelay;break;case 88:a._board.cur.rotate(!0);break;case 90:a._board.cur.rotate(!1);break;default:e=!1}}return e&&t.preventDefault(),!e};t(document).unbind("keypress.blockrain").unbind("keydown.blockrain").unbind("keyup.blockrain"),a.options.autoplay||e&&t(document).bind("keypress.blockrain",o).bind("keydown.blockrain",s).bind("keyup.blockrain",r)}})}(jQuery),window.BlockrainThemes={candy:{background:"#040304",backgroundGrid:"data:image/png;base64,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",blocks:{line:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAIAAADZrBkAAAACuklEQVR4Xi2MzW4cRRSFz/2p6p4eT2zjjE2MHBQWvAALNjwDS8SOFc/FIyCxQgh2LFHkBQgJyQo/wXKCEZ7x9E9VV93LBPNJ516dxXfo/U8+HTZ9uzrZympTjLo4DbtDiBpXSBGMocI5lkaMhKv0fz+LVX9P6ZuvvxqBby+3L3eJu6Zt27DL4qgIWW0KsxPC3Kjxz5fPT3z48csvtHSHd0C/1374RddPX/9xK6JdcjEutNfqFJMBsQat3By+i/7VxqJ6c/zd5avvn1+N7dl2V9Ad92M2ViI2ksyWSJ2QXQXc5/H25jYcHHKl1YYebcJqw/rW03OOzfr89NHbR8vH3Wq9Olofrddni+XhycXJhBSkKFLxWeHBZFFDVyD343Rzc/0XeYSXeXZIJaam2V9pLsBOtRIKYAorXqvAg8giaKsCKw1zJAGFbKhwtxrdG9E3BQxAIW1xyYUKUIwNxMAwDEwuSgA5iAw2l5ITOeE/GLRMihIOsnQZnKqOlWXRUWidyYkFpCxtCF1s8D+seBggYVYRhChkqqjmld3NKhhu1XKuKUf4g6egEitkvqc5ewo+3ZOVZJO4Q4OSEDGRRyAQkYH8QfMUCR07KS8DIsO8xhjcnUXnSv4GMRYShSUG2MFCeby/awOJFyvF3TU22ckk3E3FQjci+mJVggwz12rKVEvWOk3dwWpIr7ezrU4XZ+9ciBAxWCVlhDb2o5cZTgBR17R3w45hgg8/fu+Dj643adZVXzCmebsbp5T6fhr2L9W8z5xLNsyDpl2btrsXPynS9NvVVc28xzMLPDCUYbVUMy+TMgdinupCEapdvPv0lqGwjW9fHsXjF39eIzRpnFbLdiy918qCWmclnq3mcWhVnzw5v+83XYz0+LPP/8lL704NB3BBdbCDKlChAq8QgRvmGSFouyo3vz7Lr/8FMHqie3VCpNQAAAAASUVORK5CYII=",square:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAIAAADZrBkAAAACfUlEQVR4Xh3LvY5cRRBA4VNV3ffe+fEaZARgWfBExEhEZEg8A69AgkC8AzEiICMgJCdAxggsGRuW3Z3dmenbXVWskT6d7MiXnz3qclu87esm1qW3NteRuqaCIAmQABwPvPU2NyeaUa6P159/9QV3l/HqlWqN41El0PaadEJAoZBKqS9+eybL/tvvvi8PrHA4ku33pz9v5rafKmc0I7QhbiGaJSikyeCh1T7OG6fMluOvP/5+8csb+/RxhUtlEXA5KUMpiEpWwZKU3D799Zl1CtpEjsoh++HRxUMBVhgry4yUXLvstnE8qWi/HZndTEwpppj5XLIg7fZ4+fJlb91jzSlGhjc2O7RMj995nApRIRW0BHRl9UXLona6PYiGGKpaa50qPtQ96/5BCgkpBKghpI7VJZK5bmYju5IxQkZONqtbu+txd5ZEQFI0KaRRJxEZY0wjh/dqKqbZ/z9tqmJIqpQSnaD8T9sYkGqWmuTIZHgoWYupKh4SqSQimqrJfeV1gTECF4NKmUHwDFRqNSuJjMTxFQANNKGUyTBxYqSX6J6USdc1BquYFhEMFEQCUvSeC5rheL/Y74kAvX/OPXRZojIkqHkaLpMwWdYJm1fHlZIJotdXN7tFtczvvfuB5MIyRZwQ11pora2BTKOvva3zPKtStpsKLNNmmcr53xtFMtLaGLSR61IKKaPHenO1L2+qThqrn5FvPuGjjz8s4x+NI6Ptdvtxckywo0cjstZZZfZhNhSWNuoPP/5Udhebc8+tbp4//zPd6dcaGtJtWtUiVkhTWSJkTn3y5P15M19ervL1p9UZFzX9zHYmO1Ph3KFQK+rkIBMScbY7DicOzn+QRoW5iamqhgAAAABJRU5ErkJggg==",arrow:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAIAAADZrBkAAAACsklEQVR4XhWPu25bVxREZz/OuQ9RVKhXjBSu8gX5h+QD0udD8ilByjRpUqZxa6RxY8DuYlhwHhAc2qRIieK9vOfsvUMNBoPVrGLoh6+++7y7mbFfTNIVdShCxCGuAgE8tSilhOVWU6lrtPjPK33ffvvb6xd4KG9/+f1kenIYoAgOIc+AF9u5Rdteuvubty9LU168fqW9z7AFanr36uPZSOIgWHB1IJABKE0keSr3QdLolXitjw1n717++sfPP/7Ula6pfbYmeU7eaBybnzg6ewwpT8DW/vth2acFkzf9Pi0OOU1+/eVlM2/m14vZ+Rfz88t+Np+fnZ8tns1OL66vLss0FIughgppDumLzIpmYBrHz+uVsZVSsraorJoMQU5dOs3K3jaiSXGciNYoG3cQcbJjwiKC3Ny9ljhEEUlGBnh4IJwR+qQ6q7FbuMPBLEQCVjaYA0mYwcyIY6p5qYFQQqOexRMhHOqg6sV8mtiqQki51gSHV6YAMYMMxgIC2IOcBcIsQipBBCIjNqEQBWARjjAOHAtSh1eqk9bqLpBKQUSZE4ccIqpJFnWQiRSKypjUA1DgEDw5janNkgA4zKmGQtpgsNqhMoRCmRni4AgKJh6DB842TffENWWqU+m448eYje186GZT31nXo5EqPhUGIqoGwd1gtWFtRBeLxcXF1TydYh+td1E5lMdpOOxGr9bPOzdrtFGWk2lAg84e9/fYbGmsync0xD7mfkITgUMbJaKc26GOVn2sB61Gf958OE992wsoQjSSjBHUwEmlISTsxjEsOIsxP3v+/M3tey3wrRVh29wuA2Vo3Xoe3KP6Endhzh3v92NjKefcXZzETKxR+Sa+vt2s3/3z127YrYfN+mGz2m4+rT+tNuu77d3yfvn3+vbh8eH4bb3dLrer97c3q7L6H15gvODKB5u4AAAAAElFTkSuQmCC",rightHook:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAIAAADZrBkAAAACqElEQVR4Xh3PO2tlZRSH8f9a73XvPTkTExl1dLAIKFpNY2Fl4UcT7G3FwmIaO3sbEfQjWAxDAkIORDHJyXFf3stayzC/9qke+ubrF0u7zqwfsJNFXEKtCAJriBGBoB0gNAZ5WIekcC0f+br8++3Pr1AP5Y/f6Xgfx4RqoB2kI27QgkYQw5BA2L95M+vTn379y0c2HI+Y5Ob6z3B/M/ZmlTieV7ISj9rXZ2n338NciEMedGshJacbZ9X16vK3H76vh/1paCOWiWvos5M1U9llLIebKeqz0zG4PmZ/dfl6XWc/9p4Ox/fMwnIcXrwL6ohPg54OZhYTUUc+w1YQ83z3kMadEKdp8EmE54cnKifTBLOr17cqtwIf4gAuKhUd8Lh4+TKPowjyOK1l8cxAm9nK2nWnsQeAyNtgldnClCLntkrRrTBcFyPjYRg8AEAY4JDhkhp7uOBIRbyqrmK+KcBm1qU30UbSxHcGnIGpKYk63dQxnC2sPcWo2slZUCCGYXPkkBnUqjcCSAGFsaOUQk5koqUqPFV5G2sDai+tG3vv6ZF3BojBzFrvpeij4KtDZTjPXTWGBA91uWJTo1WkqTAZoAbpT3ejd0YOBW1zoAHE/tG8FThm52KOLnDv1dA8DACTwbRU6TxSaX1WZII/1qBgwLvWtgN6ieQc2hC9hwLGTFS35eTJ7uOL5xxTkZI44l7BDGpwBke8FFCA9Pj2EAipHbd8Qre3fxOMDWykGryyM2Vv67JwmCJ7cQRRM6JXX+CrLz97/uHJ4bgHFUdKBi8B5gECLLAys4grAkr5Vt758ZdLTwhuPNvfHP7ZPzjrBAHYLBlChwPQ+jrtpq2UJv3i0/clni/Y03efYzxPvZdBkAzeAKATukENAoTA86ynZ3GrVQl3Eu/yJ/8D33mmeKR3Cz8AAAAASUVORK5CYII=",leftHook:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAIAAADZrBkAAAACq0lEQVR4Xg3HO24mVRBH8X/Vrfv4ut02BjS8GSBAQuyCmE0gwSLICFgCBLASAhLiiQjQICFBMAMSFn63v+77qCp89EsO5U+/rus/0zQPPW8thXRQABLAjtHAAZ2gzGk2HRCG1YMPwgdf/fnXj1fX+O7732s/A0kzbwEUCW5Fgh8HGVdFTOn5H79NiZ/98rPATBVS8OzX5xTehYsxd3KFwXcGEljVOGVJ8a7W4Q4YT8sb33z70xdf/oB8HufzhjI0m2a3JLykuAyV4RGxrLVN5+f/3dxSKXJc59qfUk77djhdXhGx0/mMAg/rpm30bXq97Fp3su1mrMe19e46BLLw9Nb1w0WaZoO+fPmCNbTW3D1Fcjci77Cnn3wMhCBpWU7vuwqo3evgaar6QHRqfRXKhQiELFG1O6H3MZUyLpTIx24UMkNASbqZwZiN3AQsgKhZ6/VYR9OcDw/blg5xmKqPnIRBLQUZw4iIWQKydRcEcvLOOZ2A80Nv8SRv1iiHQWPXewbztm3MbObMYgpGCMwiwgwAIhJCAGBmjMD+KDJJThJzTI8TKZm5E9S7U3c0s6PrkVujvYbm0Qr1iceJ+GZ9772OMawNDNAgVm8cADcAQSgzCSiChZj8MRLwXCTPufQEC8SlVKPWNTJJ4BTDcds58tCaMsVoIQ8Nq2AgS97uVg2h7v29Dz86W86MGqB922F+djjsdbWE0eu233fbwF0opd57KYU43l5ewQ43N7d17CwUHJnlsl4QmUwkJJKZ5uXaLdBrnzl6EGbTbV2nVIiMuMU44EMwMjn76GMHeWAKhKuLvyXoC+F3IvXrfy9zmO/WKyUM6c1riWUY7btKiA+9UkyvPnk7KFMPtLz/uS9vrjVFLNqTUSEJNLN5hQL7gIXpsGytO0ekCduR/fg/hV+olVqSm3YAAAAASUVORK5CYII=",rightZag:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAIAAADZrBkAAAACt0lEQVR4Xg3LOW6eVRQG4PcM937DP9hYlkgUQ6RQsAiEWAC7YCWUtGyAFqhpEHRI0CCBIjpHJBSxEhzkxP6H+93pHPz0D3358IsbuyY/XlCs7/YU5zjFZgdGp07BEDq4KXwA0PvuqIfDGbT0u69/+hZvr/DrH1gc1WENwUAGM3RDcXQGRbA9/e3nJPX3F5dqdY/ja8ztx++/+YhX5S6P47REODW2Pra+qsbOR5VFWwjHVPKJJF1FevPn019++O7jeYo3h5VG8Ua5OLnCh25T7+RwYfZavVz993q5OehccfImnV3nqdLjD54gTiDAF3cnEJrBAbZNSS//vTKP1FcTk0ppsfYzkpEt58Pls8vb29vTabDWYZJzjsqnJ+vHjx9tVvf3qG3QVpXJ0Y5L2xWmYbPt7W5WeK7RKUqICic7poQY6q4Fw2AUDSykUGUlQ0cUy3XUqCxm8Obe4SypVoRwOC7kLE5szIoBHsmlO6NJO3Qv5GEozI3IiE25K2EeLAiYADiBOwi51NLdCRrGcQ5xTLVUcg1BVeFszXtaWinkIAcALigQDwISby0Vq3dpR8IA2r1cKNfZRTq9F2c1iLuYqQcHg2Dmvbam08QUG1V07zASqDCLouSSE0tojCbGablFoMgkpMxht9QukvICASIXtNLy7rDDakVDeGepzpIUup1mlIZs5Dbo9OknnwEELGgZJgBhHHDYIx/v8/r98+d/P2cVVSOkitRPN9uXfz0j2rRSh1CZDKRmFomgnns62Wyvrq+ncTy2JJ/rRXv76vx04ymr83pci9gYRYISS4N3cgRKvYb15EHOHzy8fPaPgtMe8zHG5y8uH6y3wa7LPbNOIIkQRpCOZt7KzatHFx+Ww0Ki9NX8ZHWy7Sltchtz2aj32nicjZkpLr1m760vp5tN2e8jtHX0Yf4f3da+1L4oEEQAAAAASUVORK5CYII=",leftZag:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAIAAADZrBkAAAACtElEQVR4Xg2Lu25cZRhF93f5L3OOPeOQmJuDhEIHDa/CC/B4SHSICqS0CERDE2MJAYKEmITEcewZz/nvH7O0taq16eTL++P66nhCDegOAEhghFYhDDM0hSgowQkKkDIwJi0pP/72G9j24vIi8S7nN34lYG1VyOKg0uVKFFIiY/XL+R8s977+6nvttBMkovTDz9/Np3G3fTlvYkoFJswzaxtya2haQ0nUdGa2PLY6GD/9+vjJ+Y+bD+K2vFxtrLS3cQq9t1rLwUZ7IpuOAmQQ8u9/PgFDWbG5708/jK/Ti9OzExErhYVU1TMrCZqV7fY2Or2+uQ5H7zgPMNQF5HL7+upZeFeHLU//etrraM2YedQBAXsnoPXHn8yrcHVzE0LICWoECTQf+SG19dRqK3tMUxSRZtkIZtqbsblW+vF8/Pzy1XoNvdthjDas7He7swdno+JkM21v997r6A1MIKNBwiCiXssqhNsbcAwQosPTeek1MzBa947NmnewYcGR8Oh1sZG8s5LvQoACaK0Yegi+965MNWXnxIAx0AdyWnqDMjuh1KoIkYGNUPqh0zHaYcpwoin1ZiBFjFBVEWLm1ppzTkQAsAQYQdwhTap+dBCRXzkW6g2lIpdqRkYE1v1+AZgEuiRo8G2YaCBo75ZylSCdiMnoYPVefO1k8AYm7rlAjUDi7/ZN18HIffbp5zFO22Vf0bzXfsBQUu4DIJ6P1/t/XowB9RGl4Xj94M62zy+vou2sDUySyhJjTDXpAeL9YFKXaxYnuoL2BRfnzxghj7YKm4liHkszGkOUjtxIYjKM9ncpTnPr4+HDj8j+U5/B5R5k/vfv344m6rfXHb3NSqKvdrs5xKUWeN95nUd69Oi9vpQI0PtfTAn7eE/eLF0Y92eUjrcDISBmrBjbgkrIDPFYCfoCLPgflXOjuIEFgMYAAAAASUVORK5CYII="}},modern:{background:"#000000",backgroundGrid:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAIAAAC0Ujn1AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpjZTg0NzU4MC00ODk3LTRkNjAtOWNhYi1mZTk1NzQ5NzhiNjkiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTEzOEQwMDc5MDQyMTFFNDlBMzlFNzY4RjBCNkNENzMiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MTEzOEQwMDY5MDQyMTFFNDlBMzlFNzY4RjBCNkNENzMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDplNDRjOWZiNC0yNzE5LTQ3NDYtYmRmMi0wMmY2ZTA4ZjAxMmUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MzMwNTNEOTk5MDM1MTFFNDlBMzlFNzY4RjBCNkNENzMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7Y01+zAAAAMklEQVR42mJgGAWjYBSMgkEJGIlUd+j/WjjbjjGYGC1MtHP10DR6FIyCUTAKBikACDAA0NoDCLGGjH8AAAAASUVORK5CYII=",primary:null,secondary:null,stroke:null,blocks:{line:"#fa1e1e",square:"#f1fa1e",arrow:"#d838cb",rightHook:"#f5821f",leftHook:"#42c6f0",rightZag:"#4bd838",leftZag:"#fa1e1e"}},retro:{background:"#000000",backgroundGrid:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAIAAAC0Ujn1AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpjZTg0NzU4MC00ODk3LTRkNjAtOWNhYi1mZTk1NzQ5NzhiNjkiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTEzOEQwMDc5MDQyMTFFNDlBMzlFNzY4RjBCNkNENzMiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MTEzOEQwMDY5MDQyMTFFNDlBMzlFNzY4RjBCNkNENzMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDplNDRjOWZiNC0yNzE5LTQ3NDYtYmRmMi0wMmY2ZTA4ZjAxMmUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MzMwNTNEOTk5MDM1MTFFNDlBMzlFNzY4RjBCNkNENzMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7Y01+zAAAAMklEQVR42mJgGAWjYBSMgkEJGIlUd+j/WjjbjjGYGC1MtHP10DR6FIyCUTAKBikACDAA0NoDCLGGjH8AAAAASUVORK5CYII=",primary:null,secondary:null,stroke:"#000000",innerStroke:"#000000",blocks:{line:"#fa1e1e",square:"#f1fa1e",arrow:"#d838cb",rightHook:"#f5821f",leftHook:"#42c6f0",rightZag:"#4bd838",leftZag:"#fa1e1e"}},monochrome:{background:"#000000",backgroundGrid:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAIAAAC0Ujn1AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpjZTg0NzU4MC00ODk3LTRkNjAtOWNhYi1mZTk1NzQ5NzhiNjkiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTEzOEQwMDc5MDQyMTFFNDlBMzlFNzY4RjBCNkNENzMiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MTEzOEQwMDY5MDQyMTFFNDlBMzlFNzY4RjBCNkNENzMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDplNDRjOWZiNC0yNzE5LTQ3NDYtYmRmMi0wMmY2ZTA4ZjAxMmUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MzMwNTNEOTk5MDM1MTFFNDlBMzlFNzY4RjBCNkNENzMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7Y01+zAAAAMklEQVR42mJgGAWjYBSMgkEJGIlUd+j/WjjbjjGYGC1MtHP10DR6FIyCUTAKBikACDAA0NoDCLGGjH8AAAAASUVORK5CYII=",primary:"#ffffff",secondary:"#ffffff",stroke:"#000000",innerStroke:"#000000"},aerolab:{background:"#ffffff",primary:"#ff7b00",secondary:"#000000"},gameboy:{background:"#C4CFA1",primary:null,secondary:null,stroke:"#414141",innerStroke:"#414141",innerSquare:"#000000",blocks:{line:"#88926A",square:"#585E44",arrow:"#A4AC8C",rightHook:"#6B7353",leftHook:"#6B7353",rightZag:"#595F45",leftZag:"#595F45"}},vim:{background:"#000000",backgroundGrid:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAIAAAC0Ujn1AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpjZTg0NzU4MC00ODk3LTRkNjAtOWNhYi1mZTk1NzQ5NzhiNjkiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTEzOEQwMDc5MDQyMTFFNDlBMzlFNzY4RjBCNkNENzMiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MTEzOEQwMDY5MDQyMTFFNDlBMzlFNzY4RjBCNkNENzMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDplNDRjOWZiNC0yNzE5LTQ3NDYtYmRmMi0wMmY2ZTA4ZjAxMmUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MzMwNTNEOTk5MDM1MTFFNDlBMzlFNzY4RjBCNkNENzMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7Y01+zAAAAMklEQVR42mJgGAWjYBSMgkEJGIlUd+j/WjjbjjGYGC1MtHP10DR6FIyCUTAKBikACDAA0NoDCLGGjH8AAAAASUVORK5CYII=",primary:"#C2FFAE",secondary:"#C2FFAE",stroke:"#000000",strokeWidth:3,innerStroke:null}}; + !function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)}(function(t){var e=0,i=Array.prototype.slice;t.cleanData=function(e){return function(i){var o,n,s;for(s=0;null!=(n=i[s]);s++)try{o=t._data(n,"events"),o&&o.remove&&t(n).triggerHandler("remove")}catch(r){}e(i)}}(t.cleanData),t.widget=function(e,i,o){var n,s,r,a,h={},l=e.split(".")[0];return e=e.split(".")[1],n=l+"-"+e,o||(o=i,i=t.Widget),t.expr[":"][n.toLowerCase()]=function(e){return!!t.data(e,n)},t[l]=t[l]||{},s=t[l][e],r=t[l][e]=function(t,e){return this._createWidget?void(arguments.length&&this._createWidget(t,e)):new r(t,e)},t.extend(r,s,{version:o.version,_proto:t.extend({},o),_childConstructors:[]}),a=new i,a.options=t.widget.extend({},a.options),t.each(o,function(e,o){return t.isFunction(o)?void(h[e]=function(){var t=function(){return i.prototype[e].apply(this,arguments)},n=function(t){return i.prototype[e].apply(this,t)};return function(){var e,i=this._super,s=this._superApply;return this._super=t,this._superApply=n,e=o.apply(this,arguments),this._super=i,this._superApply=s,e}}()):void(h[e]=o)}),r.prototype=t.widget.extend(a,{widgetEventPrefix:s?a.widgetEventPrefix||e:e},h,{constructor:r,namespace:l,widgetName:e,widgetFullName:n}),s?(t.each(s._childConstructors,function(e,i){var o=i.prototype;t.widget(o.namespace+"."+o.widgetName,r,i._proto)}),delete s._childConstructors):i._childConstructors.push(r),t.widget.bridge(e,r),r},t.widget.extend=function(e){for(var o,n,s=i.call(arguments,1),r=0,a=s.length;a>r;r++)for(o in s[r])n=s[r][o],s[r].hasOwnProperty(o)&&void 0!==n&&(e[o]=t.isPlainObject(n)?t.isPlainObject(e[o])?t.widget.extend({},e[o],n):t.widget.extend({},n):n);return e},t.widget.bridge=function(e,o){var n=o.prototype.widgetFullName||e;t.fn[e]=function(s){var r="string"==typeof s,a=i.call(arguments,1),h=this;return s=!r&&a.length?t.widget.extend.apply(null,[s].concat(a)):s,this.each(r?function(){var i,o=t.data(this,n);return"instance"===s?(h=o,!1):o?t.isFunction(o[s])&&"_"!==s.charAt(0)?(i=o[s].apply(o,a),i!==o&&void 0!==i?(h=i&&i.jquery?h.pushStack(i.get()):i,!1):void 0):t.error("no such method '"+s+"' for "+e+" widget instance"):t.error("cannot call methods on "+e+" prior to initialization; attempted to call method '"+s+"'")}:function(){var e=t.data(this,n);e?(e.option(s||{}),e._init&&e._init()):t.data(this,n,new o(s,this))}),h}},t.Widget=function(){},t.Widget._childConstructors=[],t.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
",options:{disabled:!1,create:null},_createWidget:function(i,o){o=t(o||this.defaultElement||this)[0],this.element=t(o),this.uuid=e++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=t(),this.hoverable=t(),this.focusable=t(),o!==this&&(t.data(o,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===o&&this.destroy()}}),this.document=t(o.style?o.ownerDocument:o.document||o),this.window=t(this.document[0].defaultView||this.document[0].parentWindow)),this.options=t.widget.extend({},this.options,this._getCreateOptions(),i),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:t.noop,_getCreateEventData:t.noop,_create:t.noop,_init:t.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetFullName).removeData(t.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:t.noop,widget:function(){return this.element},option:function(e,i){var o,n,s,r=e;if(0===arguments.length)return t.widget.extend({},this.options);if("string"==typeof e)if(r={},o=e.split("."),e=o.shift(),o.length){for(n=r[e]=t.widget.extend({},this.options[e]),s=0;o.length-1>s;s++)n[o[s]]=n[o[s]]||{},n=n[o[s]];if(e=o.pop(),1===arguments.length)return void 0===n[e]?null:n[e];n[e]=i}else{if(1===arguments.length)return void 0===this.options[e]?null:this.options[e];r[e]=i}return this._setOptions(r),this},_setOptions:function(t){var e;for(e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return this.options[t]=e,"disabled"===t&&(this.widget().toggleClass(this.widgetFullName+"-disabled",!!e),e&&(this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus"))),this},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_on:function(e,i,o){var n,s=this;"boolean"!=typeof e&&(o=i,i=e,e=!1),o?(i=n=t(i),this.bindings=this.bindings.add(i)):(o=i,i=this.element,n=this.widget()),t.each(o,function(o,r){function a(){return e||s.options.disabled!==!0&&!t(this).hasClass("ui-state-disabled")?("string"==typeof r?s[r]:r).apply(s,arguments):void 0}"string"!=typeof r&&(a.guid=r.guid=r.guid||a.guid||t.guid++);var h=o.match(/^([\w:-]*)\s*(.*)$/),l=h[1]+s.eventNamespace,c=h[2];c?n.delegate(c,l,a):i.bind(l,a)})},_off:function(e,i){i=(i||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.unbind(i).undelegate(i),this.bindings=t(this.bindings.not(e).get()),this.focusable=t(this.focusable.not(e).get()),this.hoverable=t(this.hoverable.not(e).get())},_delay:function(t,e){function i(){return("string"==typeof t?o[t]:t).apply(o,arguments)}var o=this;return setTimeout(i,e||0)},_hoverable:function(e){this.hoverable=this.hoverable.add(e),this._on(e,{mouseenter:function(e){t(e.currentTarget).addClass("ui-state-hover")},mouseleave:function(e){t(e.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(e){this.focusable=this.focusable.add(e),this._on(e,{focusin:function(e){t(e.currentTarget).addClass("ui-state-focus")},focusout:function(e){t(e.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(e,i,o){var n,s,r=this.options[e];if(o=o||{},i=t.Event(i),i.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase(),i.target=this.element[0],s=i.originalEvent)for(n in s)n in i||(i[n]=s[n]);return this.element.trigger(i,o),!(t.isFunction(r)&&r.apply(this.element[0],[i].concat(o))===!1||i.isDefaultPrevented())}},t.each({show:"fadeIn",hide:"fadeOut"},function(e,i){t.Widget.prototype["_"+e]=function(o,n,s){"string"==typeof n&&(n={effect:n});var r,a=n?n===!0||"number"==typeof n?i:n.effect||i:e;n=n||{},"number"==typeof n&&(n={duration:n}),r=!t.isEmptyObject(n),n.complete=s,n.delay&&o.delay(n.delay),r&&t.effects&&t.effects.effect[a]?o[e](n):a!==e&&o[a]?o[a](n.duration,n.easing,s):o.queue(function(i){t(this)[e](),s&&s.call(o[0]),i()})}}),t.widget}),function(t){"use strict";t.widget("aerolab.blockrain",{options:{autoplay:!1,autoplayRestart:!0,showFieldOnStart:!0,theme:null,blockWidth:10,autoBlockWidth:!1,autoBlockSize:24,difficulty:"normal",speed:20,asdwKeys:!0,playText:"Let's play some Tetris",playButtonText:"Play",gameOverText:"Game Over",restartButtonText:"Play Again",scoreText:"Score",onStart:function(){},onRestart:function(){},onGameOver:function(t){},onPlaced:function(){},onLine:function(t,e,i){}},start:function(){this._doStart(),this.options.onStart.call(this.element)},restart:function(){this._doStart(),this.options.onRestart.call(this.element)},gameover:function(){this.showGameOverMessage(),this._board.gameover=!0,this.options.onGameOver.call(this.element,this._filled.score)},_doStart:function(){this._filled.clearAll(),this._filled._resetScore(),this._board.cur=this._board.nextShape(),this._board.started=!0,this._board.gameover=!1,this._board.dropDelay=5,this._board.render(!0),this._board.animate(),this._$start.fadeOut(150),this._$gameover.fadeOut(150),this._$score.fadeIn(150)},pause:function(){this._board.paused=!0},resume:function(){this._board.paused=!1},autoplay:function(t){"boolean"!=typeof t&&(t=!0),this.options.autoplay=t,t&&!this._board.started&&this._doStart(),this._setupControls(!t),this._setupTouchControls(!t)},controls:function(t){"boolean"!=typeof t&&(t=!0),this._setupControls(t)},touchControls:function(t){"boolean"!=typeof t&&(t=!0),this._setupTouchControls(t)},score:function(t){return"undefined"!=typeof t&&parseInt(t)>=0&&(this._filled.score=parseInt(t),this._$scoreText.text(this._filled_score)),this._filled.score},freesquares:function(){return this._filled.getFreeSpaces()},showStartMessage:function(){this._$start.show()},showGameOverMessage:function(){this._$gameover.show()},updateSizes:function(){this._PIXEL_WIDTH=this.element.innerWidth(),this._PIXEL_HEIGHT=this.element.innerHeight(),this._BLOCK_WIDTH=this.options.blockWidth,this._BLOCK_HEIGHT=Math.floor(this.element.innerHeight()/this.element.innerWidth()*this._BLOCK_WIDTH),this._block_size=Math.floor(this._PIXEL_WIDTH/this._BLOCK_WIDTH),this._border_width=2,this._PIXEL_WIDTH=this._block_size*this._BLOCK_WIDTH,this._PIXEL_HEIGHT=this._block_size*this._BLOCK_HEIGHT,this._$canvas.attr("width",this._PIXEL_WIDTH).attr("height",this._PIXEL_HEIGHT)},theme:function(e){return"undefined"==typeof e?this.options.theme||this._theme:("string"==typeof e?(this.options.theme=e,this._theme=t.extend(!0,{},BlockrainThemes[e])):(this.options.theme=null,this._theme=e),("undefined"==typeof this._theme||null===this._theme)&&(this._theme=t.extend(!0,{},BlockrainThemes.retro),this.options.theme="retro"),(isNaN(parseInt(this._theme.strokeWidth))||"number"!=typeof parseInt(this._theme.strokeWidth))&&(this._theme.strokeWidth=2),this._preloadThemeAssets(),void(null!==this._board&&("string"==typeof this._theme.background&&this._$canvas.css("background-color",this._theme.background),this._board.render())))},_theme:{},_$game:null,_$canvas:null,_$gameholder:null,_$start:null,_$gameover:null,_$score:null,_$scoreText:null,_canvas:null,_ctx:null,_create:function(){var e=this;this.theme(this.options.theme),this._createHolder(),this._createUI(),this._refreshBlockSizes(),this.updateSizes(),t(window).resize(function(){}),this._SetupShapeFactory(),this._SetupFilled(),this._SetupInfo(),this._SetupBoard(),this._info.init(),this._board.init();var i=function(){requestAnimationFrame(i),e._board.render()};i(),this.options.autoplay?(this.autoplay(!0),this._setupTouchControls(!1)):(this._setupControls(!0),this._setupTouchControls(!1))},_checkCollisions:function(t,e,i,o){for(var n,s,r=0,a=i.length;a>r;r+=2){if(n=t+i[r],s=e+i[r+1],s>=this._BLOCK_HEIGHT||this._filled.check(n,s))return!0;if(!o&&0>n||n>=this._BLOCK_WIDTH)return!0}return!1},_board:null,_info:null,_filled:null,_drawBackground:function(){if("string"==typeof this._theme.background){if(this._theme.backgroundGrid instanceof Image){if(0===this._theme.backgroundGrid.width||0===this._theme.backgroundGrid.height)return;this._ctx.globalAlpha=1;for(var t=0;to;o+=2)i[o]r&&(r=i[o]),i[o+1]h&&(h=i[o+1]);return{left:s,right:r,top:a,bottom:h,width:r-s,height:h-a}}}),this.init()}var i=this;null===this._shapeFactory&&(this._shapeFactory={line:function(){return new e(i,i._shapes.line,!1,"line")},square:function(){return new e(i,i._shapes.square,!1,"square")},arrow:function(){return new e(i,i._shapes.arrow,!1,"arrow")},leftHook:function(){return new e(i,i._shapes.leftHook,!1,"leftHook")},rightHook:function(){return new e(i,i._shapes.rightHook,!1,"rightHook")},leftZag:function(){return new e(i,i._shapes.leftZag,!1,"leftZag")},rightZag:function(){return new e(i,i._shapes.rightZag,!1,"rightZag")}})},_SetupFilled:function(){var t=this;null===this._filled&&(this._filled={data:new Array(t._BLOCK_WIDTH*t._BLOCK_HEIGHT),score:0,toClear:{},check:function(t,e){return this.data[this.asIndex(t,e)]},add:function(e,i,o,n,s,r){e>=0&&e=0&&i=0;i--)this.data[i]=i>=t._BLOCK_WIDTH?this.data[i-t._BLOCK_WIDTH]:void 0},checkForClears:function(){var e,i,o,n,s=t._board.lines,r=[];for(e=0,i=this.data.length;i>e;e++)n=this.asX(e),0==n&&(o=0),this.data[e]&&"undefined"!=typeof this.data[e]&&"string"==typeof this.data[e].blockType&&(o+=1),n==t._BLOCK_WIDTH-1&&o==t._BLOCK_WIDTH&&r.push(this.asY(e));for(e=0,i=r.length;i>e;e++)this._popRow(r[e]),t._board.lines++,t._board.lines%10==0&&t._board.dropDelay>1&&(t._board.dropDelay*=.9);var a=t._board.lines-s;this._updateScore(a)},_updateScore:function(e){if(!(0>=e)){var i=[0,400,1e3,3e3,12e3];e>=i.length&&(e=i.length-1),this.score+=i[e],t._$scoreText.text(this.score),t.options.onLine.call(t.element,e,i[e],this.score)}},_resetScore:function(){this.score=0,t._$scoreText.text(this.score)},draw:function(){for(var e,i=0,o=this.data.length;o>i;i++)if(void 0!==this.data[i]){e=this.asY(i);var n=this.data[i];t._board.drawBlock(this.asX(i),e,n.blockType,n.blockVariation,n.blockIndex,n.blockOrientation)}}})},_SetupInfo:function(){var t=this;this._info={mode:t.options.difficulty,modes:["normal","nice","evil"],modesY:170,autopilotY:null,init:function(){this.mode=t.options.difficulty},setMode:function(e){this.mode=e,t._board.nextShape(!0)}}},_SetupBoard:function(){var e=this,i=this._info;this._board={animateDelay:1e3/e.options.speed,animateTimeoutId:null,cur:null,lines:0,dropCount:0,dropDelay:5,holding:{left:null,right:null,drop:null},holdingThreshold:200,started:!1,gameover:!1,renderChanged:!0,init:function(){this.cur=this.nextShape(),e.options.showFieldOnStart&&(e._drawBackground(),e._board.createRandomBoard(),e._board.render()),this.showStartMessage()},showStartMessage:function(){e._$start.show()},showGameOverMessage:function(){e._$gameover.show()},nextShape:function(o){var n,s,r,a=this.next;if(n="nice"==i.mode||"evil"==i.mode?e._niceShapes:e._randomShapes(),e.options.no_preview){if(this.next=null,o)return null;if(s=n(e._filled,e._checkCollisions,e._BLOCK_WIDTH,e._BLOCK_HEIGHT,i.mode),!s)throw new Error("No shape returned from shape function!",n);s.init(),r=s}else{if(s=n(e._filled,e._checkCollisions,e._BLOCK_WIDTH,e._BLOCK_HEIGHT,i.mode),!s)throw new Error("No shape returned from shape function!",n);if(s.init(),this.next=s,o)return null;r=a||this.nextShape()}return e.options.autoplay&&(e._niceShapes(e._filled,e._checkCollisions,e._BLOCK_WIDTH,e._BLOCK_HEIGHT,"normal",r),r.orientation=r.best_orientation,r.x=r.best_x),"undefined"!=typeof e._theme.complexBlocks?r.blockVariation=t.isArray(e._theme.complexBlocks[r.blockType])?e._randInt(0,e._theme.complexBlocks[r.blockType].length-1):null:"undefined"!=typeof e._theme.blocks&&(r.blockVariation=t.isArray(e._theme.blocks[r.blockType])?e._randInt(0,e._theme.blocks[r.blockType].length-1):null),r},animate:function(){var t=!1,i=!1,o=!1,n=Date.now();if(this.animateTimeoutId&&clearTimeout(this.animateTimeoutId),!this.paused&&!this.gameover&&(this.dropCount++,(this.dropCount>=this.dropDelay||e.options.autoplay||this.holding.drop&&n-this.holding.drop>=this.holdingThreshold)&&(t=!0,i=!0,this.dropCount=0),this.holding.left&&n-this.holding.left>=this.holdingThreshold&&(i=!0,this.cur.moveLeft()),this.holding.right&&n-this.holding.right>=this.holdingThreshold&&(i=!0,this.cur.moveRight()),t)){var s=this.cur,r=s.x,a=s.y,h=s.getBlocks();if(e._checkCollisions(r,a+1,h,!0)){t=!1;for(var l=0,c=0;ct;t++)for(o=0,n=e._randChoice([e._randInt(0,8),e._randInt(5,9)]);n>o;o++)s&&e._randInt(0,3)||(s=e._randChoice(r)),e._filled.add(t,e._BLOCK_HEIGHT-o,s,e._randInt(0,3),null,e._randInt(0,3));e._board.render(!0)},render:function(t){(this.renderChanged||t)&&(this.renderChanged=!1,e._ctx.clearRect(0,0,e._PIXEL_WIDTH,e._PIXEL_HEIGHT),e._drawBackground(),e._filled.draw(),this.cur.draw())},drawBlock:function(t,i,o,n,s,r,a){t*=e._block_size,i*=e._block_size,a="boolean"==typeof a?a:!1;var h=e._theme.strokeWidth,l=Math.round(.23*e._block_size),c=Math.round(.3*e._block_size),d=this.getBlockColor(o,n,s,a);if(e._ctx.globalAlpha=1,d instanceof Image){if(e._ctx.globalAlpha=1,0===d.width||0===d.height)return;if("undefined"!=typeof e._theme.blocks&&null!==e._theme.blocks)e._ctx.drawImage(d,0,0,d.width,d.height,t,i,e._block_size,e._block_size);else if("undefined"!=typeof e._theme.complexBlocks&&null!==e._theme.complexBlocks){("undefined"==typeof s||null===s)&&(s=0);var u=function(t,i,o){var n=e._shapes[i][0],s=Math.min(n[0],n[2],n[4],n[6]),r=Math.max(n[0],n[2],n[4],n[6]),a=Math.min(n[1],n[3],n[5],n[7]),h=Math.max(n[1],n[3],n[5],n[7]),l=r-s+1,c=h-a+1,d=t.width/l,u=t.height/c;return{x:d*(n[2*o]-s),y:u*Math.abs(a-n[2*o+1]),w:d,h:u}},g=u(d,o,s);e._ctx.save(),e._ctx.translate(t,i),e._ctx.translate(e._block_size/2,e._block_size/2),e._ctx.rotate(-Math.PI/2*r),e._ctx.drawImage(d,g.x,g.y,g.w,g.h,-e._block_size/2,-e._block_size/2,e._block_size,e._block_size),e._ctx.restore()}else e._ctx.fillStyle="#ff0000",e._ctx.fillRect(t,i,e._block_size,e._block_size)}else"string"==typeof d&&(e._ctx.fillStyle=d,e._ctx.fillRect(t,i,e._block_size,e._block_size),"string"==typeof e._theme.innerShadow&&(e._ctx.globalAlpha=1,e._ctx.strokeStyle=e._theme.innerShadow,e._ctx.lineWidth=1,e._ctx.strokeRect(t+1,i+1,e._block_size-2,e._block_size-2)),"string"==typeof e._theme.stroke&&(e._ctx.globalAlpha=1,e._ctx.fillStyle=e._theme.stroke,e._ctx.strokeStyle=e._theme.stroke,e._ctx.lineWidth=h,e._ctx.strokeRect(t,i,e._block_size,e._block_size)),"string"==typeof e._theme.innerStroke&&(e._ctx.fillStyle=e._theme.innerStroke,e._ctx.fillRect(t+l,i+l,e._block_size-2*l,h),e._ctx.fillRect(t+l,i+l+h,h,e._block_size-2*l-h)),"string"==typeof e._theme.innerSquare&&(e._ctx.fillStyle=e._theme.innerSquare,e._ctx.globalAlpha=.2,e._ctx.fillRect(t+c,i+c,e._block_size-2*c,e._block_size-2*c)));e._ctx.globalAlpha=1},getBlockColor:function(i,o,n,s){var r=function(e,i){return t.isArray(e)?null!==i&&"undefined"!=typeof e[i]?e[i]:e.length>0?e[0]:null:e};return"boolean"!=typeof s&&(s=!0),s?"string"==typeof e._theme.primary&&""!==e._theme.primary?e._theme.primary:"undefined"!=typeof e._theme.blocks&&null!==e._theme.blocks?r(e._theme.blocks[i],o):r(e._theme.complexBlocks[i],o):"string"==typeof e._theme.secondary&&""!==e._theme.secondary?e._theme.secondary:"undefined"!=typeof e._theme.blocks&&null!==e._theme.blocks?r(e._theme.blocks[i],o):r(e._theme.complexBlocks[i],o)}},e._niceShapes=e._getNiceShapes()},_randInt:function(t,e){return t+Math.floor(Math.random()*(1+e-t))},_randSign:function(){return 2*this._randInt(0,1)-1},_randChoice:function(t){return t[this._randInt(0,t.length-1)]},_preloadThemeAssets:function(){var e=this,i=new RegExp("^#[A-F0-9+]{3,6}","i"),o=(new RegExp("^data:image/(png|gif|jpg);base64,","i"),function(){e._board&&e._board.render(!0)}),n=function(t){var e=t;return i.test(e)?t=e:(t=new Image,t.src=e,t.onload=o),t},s=function(e){if(t.isArray(e)&&e.length>0)for(var i=0;i
'),this._$gameholder.css("position","relative").css("width","100%").css("height","100%"),this.element.html("").append(this._$gameholder),this._$canvas=t(''),"string"==typeof this._theme.background&&this._$canvas.css("background-color",this._theme.background),this._$gameholder.append(this._$canvas),this._canvas=this._$canvas.get(0),this._ctx=this._canvas.getContext("2d")},_createUI:function(){var e=this;e._$score=t('
'+this.options.scoreText+'
0
').hide(),e._$scoreText=e._$score.find(".blockrain-score-num"),e._$gameholder.append(e._$score),e._$start=t('
'+this.options.playText+'
'+this.options.playButtonText+"
").hide(),e._$gameholder.append(e._$start),e._$start.find(".blockrain-start-btn").click(function(t){t.preventDefault(),e.start()}),e._$gameover=t('
'+this.options.gameOverText+'
'+this.options.restartButtonText+"
").hide(),e._$gameover.find(".blockrain-game-over-btn").click(function(t){t.preventDefault(),e.restart()}),e._$gameholder.append(e._$gameover),this._createControls()},_createControls:function(){var e=this;e._$touchLeft=t('').appendTo(e._$gameholder),e._$touchRight=t('').appendTo(e._$gameholder),e._$touchRotateRight=t('').appendTo(e._$gameholder),e._$touchRotateLeft=t('').appendTo(e._$gameholder),e._$touchDrop=t('').appendTo(e._$gameholder)},_refreshBlockSizes:function(){this.options.autoBlockWidth&&(this.options.blockWidth=Math.ceil(this.element.width()/this.options.autoBlockSize))},_getNiceShapes:function(){function t(t,e,i,n,s,r,a){var h,l,c,d,u=e.length,g=0,A={};for(h=0;u>h;h+=2)g+=t[o._filled.asIndex(i+e[h],n+e[h+1])]||0;for(h=0;u>h;h+=2)l=e[h],c=e[h+1],(void 0===A[l]||A[l]n+c;c++,h++)if(!o._filled.check(i+l,n+c)){d+=0==h?2:1;break}return g-=d}function e(){for(var t in n)n[t].x=0,n[t].y=-1}var i,o=this,n={};for(var i in this._shapeFactory)n[i]=this._shapeFactory[i]();var s=function(i,s,r,a,h,l){l||e();var c,d,u,g,A,f,p,b,m,k,_,I,v,y,C,w=new Array(r*a),B="evil"==h,G=999*(B?1:-1);for(c=0;r>c;c++)for(d=0;a>=d;d++)if(d==a||i.check(c,d)){for(u=d-4;d>u;u++)w[i.asIndex(c,u)]=u;break}var D=void 0===l?n:{cur:l};for(g in D){for(A=D[g],v=-999,f=0;f<(A.symmetrical?2:4);f++)for(p=A.getBlocks(f),b=A.getBounds(p),c=-b.left;cv&&(v=m,y=f,C=c);break}(B&&G>v||!B&&v>G)&&(k=A,G=v,_=y,I=C)}return k.best_orientation=_,k.best_x=I,k};return s.no_preview=!0,s},_randomShapes:function(){var e=[];return t.each(this._shapeFactory,function(t,i){e.push(i)}),this._randChoice(e)},_setupControls:function(e){function i(t){var e={stopKeys:{37:1,38:1,39:1,40:1}},i=e.stopKeys[t.keyCode]||e.moreStopKeys&&e.moreStopKeys[t.keyCode];return i&&t.preventDefault(),i}function o(t){return"safekeypress."+t.keyCode}function n(e){var i=o(e);return t.data(this,i,(t.data(this,i)||0)-1),c.call(this,e)}function s(e){return t.data(this,o(e),0),d.call(this,e),i(e)}var r=this,a=function(t){return t?void(r._board.holding.left||(r._board.cur.moveLeft(),r._board.holding.left=Date.now(),r._board.holding.right=null)):void(r._board.holding.left=null)},h=function(t){return t?void(r._board.holding.right||(r._board.cur.moveRight(),r._board.holding.right=Date.now(),r._board.holding.left=null)):void(r._board.holding.right=null)},l=function(t){return t?void(r._board.holding.drop||(r._board.cur.drop(),r._board.holding.drop=Date.now())):void(r._board.holding.drop=null)},c=function(t){if(!r._board.cur)return!0;var e=!1;if(e=!0,r.options.asdwKeys)switch(t.keyCode){case 65:a(!0);break;case 68:h(!0);break;case 83:l(!0);break;case 87:r._board.cur.rotate("right")}switch(t.keyCode){case 37:a(!0);break;case 39:h(!0);break;case 40:l(!0);break;case 38:r._board.cur.rotate("right");break;case 88:r._board.cur.rotate("right");break;case 90:r._board.cur.rotate("left");break;default:e=!1}return e&&t.preventDefault(),!e},d=function(t){if(!r._board.cur)return!0;var e=!1;if(e=!0,r.options.asdwKeys)switch(t.keyCode){case 65:a(!1);break;case 68:h(!1);break;case 83:l(!1)}switch(t.keyCode){case 37:a(!1);break;case 39:h(!1);break;case 40:l(!1);break;default:e=!1}return e&&t.preventDefault(),!e};t(document).unbind("keydown.blockrain").unbind("keyup.blockrain"),r.options.autoplay||e&&t(document).bind("keydown.blockrain",n).bind("keyup.blockrain",s)},_setupTouchControls:function(t){var e=this,i=function(t){t.preventDefault(),e._board.cur.moveLeft(),e._board.holding.left=Date.now(),e._board.holding.right=null,e._board.holding.drop=null},o=function(t){t.preventDefault(),e._board.cur.moveRight(),e._board.holding.right=Date.now(),e._board.holding.left=null,e._board.holding.drop=null},n=function(t){t.preventDefault(),e._board.cur.drop(),e._board.holding.drop=Date.now()},s=function(t){t.preventDefault(),e._board.holding.left=null},r=function(t){t.preventDefault(),e._board.holding.right=null},a=function(t){t.preventDefault(),e._board.holding.drop=null},h=function(t){t.preventDefault(),e._board.cur.rotate("left")},l=function(t){t.preventDefault(),e._board.cur.rotate("right")};e._$touchLeft.unbind("touchstart touchend click"),e._$touchRight.unbind("touchstart touchend click"),e._$touchRotateLeft.unbind("touchstart touchend click"),e._$touchRotateRight.unbind("touchstart touchend click"),e._$touchDrop.unbind("touchstart touchend click"),!e.options.autoplay&&t?(e._$touchLeft.show().bind("touchstart click",i).bind("touchend",s),e._$touchRight.show().bind("touchstart click",o).bind("touchend",r),e._$touchDrop.show().bind("touchstart click",n).bind("touchend",a),e._$touchRotateLeft.show().bind("touchstart click",h),e._$touchRotateRight.show().bind("touchstart click",l)):(e._$touchLeft.hide(),e._$touchRight.hide(),e._$touchRotateLeft.hide(),e._$touchRotateRight.hide(),e._$touchDrop.hide())}})}(jQuery),window.BlockrainThemes={custom:{background:"#040304",backgroundGrid:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAAlC+aJAAAHHElEQVR4XsVZgZbkqgqkTO77//+dbuvtgQ7QcGwnO3PPZTPG1dhWASIxwP8OEcqTYhJ3ypsAuLqsB7KSNrQ14uMoXAXsnwNihoUDInKKbCdDf2YjPuL+KDRSyOpE1Q5k6JBJV7IJSfnvJUzf8RhyAOh9ADqN3vtz+am+zIXWHIK9l1D5ISuSTbv3aUAJZKfvmMYYBn3O6Y3W/lt2IFmmIHmbQDcCgOM4DCjJqeKsNgQAIe9ag13I4NNHoUWhomMn4BoiubXAqn27qAoNm9HLwhMAfQ10lgYxc5gqvgxcfuw8sdhMHKtD99IrGfCpkXZjBG9x9r8SizJ/JHF8Yww3hYszNDnz5uawDH3WsTESIZBcs6O5r36SVn4gmcFYJVmgSYZOMqmEdjf8vxV8riA4tG0Zo51qeeDQtQxhuP6hUmgYY/U/yu8JKYBVmGdZGznWhqBZoAefTTi7GYOY/jKHEPL57loObBU8zhL4z/P8UxbdN02sUzOSqKmlymZnCLckt2tdq41AOI8KyU4AQGfCrNEOkr0DPjxD767VBUls3qHNEfjdhdpWxa7++zkzVmMB+0PXcndy9yMogcwsd5fJAFzotccfgKBfArmukPKQQ8dCOvrGAXkNxBPekvMahyNbMZbfFFcDLcVPfgV8MoJOcgo2QcWDQZiNNh3lJ9IdaNRskCk0FMUZFJJhgTnpspxF3l5S/3UhuXgpq1EopxxQyX7V3pdB8ndxXo4aukmapDQaJAlSGGZzAu8bIdIDr/Lb6BnXTtgk/wLJnoCUbLSPR+PNTbAMmt3HCDPonnN/c0BrMU7MawAAmAQggOIweu9oGEUmiHLQBPxS+v2WSgDIwTgmjwrblgk1kBbtVId1p/453BAPR+5fJyKuQGQ49KLDWvnLSNQJse8e+SiunI/UcAQ5aTBo6ncj+HMLmGBH04WOqVkm+qPnQkwYBKR1GEpXcXOfpNVAOnSQmJS8euloqxd1fWLZUi2I4JCkvySWN/psMd8HDJhzyD/DdW5fBAFvIzvqKLsErOwcRkKUXT8D5CJdpkCvEG7Szz0r6qVFE6q0faCSxuV05kO8/GUBdOlNkL0wStgd/reRSgCE0FWPhoXfiS5Eg47P6CH8TBlSc+RSP31RCgjwytR5J0riVjsyh60AH3uVgKFPipkiQ/CBAyoUNsVvhE1HkL+SM6Gc6kW0QJrnSHENDa8J9jiYal07ND3uc75GAEkl4GWBkufc8hmsHYQeoUs3vb26TYfeoxBE6NBHxctbKwFV2eFvsdcU/2FdGsv/USX3nd01IfweWHx7i+qm6VmQ4ULBTAo+JrKjgHLXv386gveoiPIo1pEN5d4zyLVHnYYZYVkyjBAgmLUZzV3XPSHo6IMoe4p0U8Z6d/R7VRIoSwsINl5VzVSEXfdcL8P+gYPJD/CuEuAqus/FaQW70Vld/47EOiCawZRAiSBrZ+yooFy7+VG0yHcX4l8eTXLpQn0oIADxIUMBeoDtrsHW87EdsvtvbxgQSResFIHjRFZtj6KEX+ucgZ0D9+iL89avBCLvBMQ5RCUU3pOwvmVSwKwPMNWFoHvSTrXoCenqi8FwZMN7rYEOEN4bJnFBRcK4gi21nClKFOYZ7ZJLYxKwDRYEeXJs1tl92fv9tq/nQkguSVgF9FPonquwBi1ssdbxApQcgkvIAHbpdADKHsLw/C430332xJ8JYSJ6Z2emUHg6ehBCwB0JsQU1ENgmKz2WouXmWCUjKN4CYGOBqn4IWLlmxPTZuYUOh/Kqg6hnY/clDrbsh0jTsMe/lf0oflbRjYAlIiTXYRy3ImfbEN76xG+QT8c5KZPEVBKjKRgFY9vf4KTpkL2F1Ia6fK+2xTrvX5bmnO1Lvd6nkno8nxp6jkEBkOMNwi1GnS5MopWs7c6f9mMoKmlM4sDctT5VHo/Hi4DKgTF8LnLqPQbHLMNahn859fKCESuoLqtoBZC2zfj5LtHsun8+n19fX3/KOVXhyQLkyzknJylTcBw4j6GoHYCBLi/lNRKGC61fQZHA8yJe7AafzV3/oZJei5GjEC8ak4Q8XsobHFrJ2x9IYXtzjQAFpibC+kmUE3f6tJ4P0LGWU/c/Wi/ofYrzdR9G4eIqU54PhXoA42oXRi49BCNY2VCUPIgxiB47AYCC7HB8vgzBpAwgEVChSn2hiayfcZF8zikPOUXGIaBMDQBzUtEfA0Yg1Mp+YqU+eVVIRW8GiO8pIlNCGPfwnwg7RWiL+J+BEY3FK3wVTc7Hw9YPXaGkkDKZxAO0VTn1ojDaqaU1+lOqHuoVffkDducA9e4Th1sApnswouIEByhD5iRBe0TAMSzj85P8IAW3Rjp/prYL7E4CQu0IA033s1C/lUIO5QMBEQQOlHOhnogxciC+12k3l3DffqyXx01JP8p8CemsQ/9yGcwBFfk/Wqz6T1UU/3cAAAAASUVORK5CYII=", +complexBlocks:{line:["assets/blocks/custom/line.png","assets/blocks/custom/line.png"],square:["assets/blocks/custom/square.png"],arrow:"assets/blocks/custom/arrow.png",rightHook:["assets/blocks/custom/rightHook.png"],leftHook:"assets/blocks/custom/leftHook.png",rightZag:["assets/blocks/custom/rightZag.png"],leftZag:"assets/blocks/custom/leftZag.png"}},candy:{background:"#040304",backgroundGrid:"data:image/png;base64,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",blocks:{line:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAIAAADZrBkAAAACuklEQVR4Xi2MzW4cRRSFz/2p6p4eT2zjjE2MHBQWvAALNjwDS8SOFc/FIyCxQgh2LFHkBQgJyQo/wXKCEZ7x9E9VV93LBPNJ516dxXfo/U8+HTZ9uzrZympTjLo4DbtDiBpXSBGMocI5lkaMhKv0fz+LVX9P6ZuvvxqBby+3L3eJu6Zt27DL4qgIWW0KsxPC3Kjxz5fPT3z48csvtHSHd0C/1374RddPX/9xK6JdcjEutNfqFJMBsQat3By+i/7VxqJ6c/zd5avvn1+N7dl2V9Ad92M2ViI2ksyWSJ2QXQXc5/H25jYcHHKl1YYebcJqw/rW03OOzfr89NHbR8vH3Wq9Olofrddni+XhycXJhBSkKFLxWeHBZFFDVyD343Rzc/0XeYSXeXZIJaam2V9pLsBOtRIKYAorXqvAg8giaKsCKw1zJAGFbKhwtxrdG9E3BQxAIW1xyYUKUIwNxMAwDEwuSgA5iAw2l5ITOeE/GLRMihIOsnQZnKqOlWXRUWidyYkFpCxtCF1s8D+seBggYVYRhChkqqjmld3NKhhu1XKuKUf4g6egEitkvqc5ewo+3ZOVZJO4Q4OSEDGRRyAQkYH8QfMUCR07KS8DIsO8xhjcnUXnSv4GMRYShSUG2MFCeby/awOJFyvF3TU22ckk3E3FQjci+mJVggwz12rKVEvWOk3dwWpIr7ezrU4XZ+9ciBAxWCVlhDb2o5cZTgBR17R3w45hgg8/fu+Dj643adZVXzCmebsbp5T6fhr2L9W8z5xLNsyDpl2btrsXPynS9NvVVc28xzMLPDCUYbVUMy+TMgdinupCEapdvPv0lqGwjW9fHsXjF39eIzRpnFbLdiy918qCWmclnq3mcWhVnzw5v+83XYz0+LPP/8lL704NB3BBdbCDKlChAq8QgRvmGSFouyo3vz7Lr/8FMHqie3VCpNQAAAAASUVORK5CYII=",square:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAIAAADZrBkAAAACfUlEQVR4Xh3LvY5cRRBA4VNV3ffe+fEaZARgWfBExEhEZEg8A69AgkC8AzEiICMgJCdAxggsGRuW3Z3dmenbXVWskT6d7MiXnz3qclu87esm1qW3NteRuqaCIAmQABwPvPU2NyeaUa6P159/9QV3l/HqlWqN41El0PaadEJAoZBKqS9+eybL/tvvvi8PrHA4ku33pz9v5rafKmc0I7QhbiGaJSikyeCh1T7OG6fMluOvP/5+8csb+/RxhUtlEXA5KUMpiEpWwZKU3D799Zl1CtpEjsoh++HRxUMBVhgry4yUXLvstnE8qWi/HZndTEwpppj5XLIg7fZ4+fJlb91jzSlGhjc2O7RMj995nApRIRW0BHRl9UXLona6PYiGGKpaa50qPtQ96/5BCgkpBKghpI7VJZK5bmYju5IxQkZONqtbu+txd5ZEQFI0KaRRJxEZY0wjh/dqKqbZ/z9tqmJIqpQSnaD8T9sYkGqWmuTIZHgoWYupKh4SqSQimqrJfeV1gTECF4NKmUHwDFRqNSuJjMTxFQANNKGUyTBxYqSX6J6USdc1BquYFhEMFEQCUvSeC5rheL/Y74kAvX/OPXRZojIkqHkaLpMwWdYJm1fHlZIJotdXN7tFtczvvfuB5MIyRZwQ11pora2BTKOvva3zPKtStpsKLNNmmcr53xtFMtLaGLSR61IKKaPHenO1L2+qThqrn5FvPuGjjz8s4x+NI6Ptdvtxckywo0cjstZZZfZhNhSWNuoPP/5Udhebc8+tbp4//zPd6dcaGtJtWtUiVkhTWSJkTn3y5P15M19ervL1p9UZFzX9zHYmO1Ph3KFQK+rkIBMScbY7DicOzn+QRoW5iamqhgAAAABJRU5ErkJggg==",arrow:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAIAAADZrBkAAAACsklEQVR4XhWPu25bVxREZz/OuQ9RVKhXjBSu8gX5h+QD0udD8ilByjRpUqZxa6RxY8DuYlhwHhAc2qRIieK9vOfsvUMNBoPVrGLoh6+++7y7mbFfTNIVdShCxCGuAgE8tSilhOVWU6lrtPjPK33ffvvb6xd4KG9/+f1kenIYoAgOIc+AF9u5Rdteuvubty9LU168fqW9z7AFanr36uPZSOIgWHB1IJABKE0keSr3QdLolXitjw1n717++sfPP/7Ula6pfbYmeU7eaBybnzg6ewwpT8DW/vth2acFkzf9Pi0OOU1+/eVlM2/m14vZ+Rfz88t+Np+fnZ8tns1OL66vLss0FIughgppDumLzIpmYBrHz+uVsZVSsraorJoMQU5dOs3K3jaiSXGciNYoG3cQcbJjwiKC3Ny9ljhEEUlGBnh4IJwR+qQ6q7FbuMPBLEQCVjaYA0mYwcyIY6p5qYFQQqOexRMhHOqg6sV8mtiqQki51gSHV6YAMYMMxgIC2IOcBcIsQipBBCIjNqEQBWARjjAOHAtSh1eqk9bqLpBKQUSZE4ccIqpJFnWQiRSKypjUA1DgEDw5janNkgA4zKmGQtpgsNqhMoRCmRni4AgKJh6DB842TffENWWqU+m448eYje186GZT31nXo5EqPhUGIqoGwd1gtWFtRBeLxcXF1TydYh+td1E5lMdpOOxGr9bPOzdrtFGWk2lAg84e9/fYbGmsync0xD7mfkITgUMbJaKc26GOVn2sB61Gf958OE992wsoQjSSjBHUwEmlISTsxjEsOIsxP3v+/M3tey3wrRVh29wuA2Vo3Xoe3KP6Endhzh3v92NjKefcXZzETKxR+Sa+vt2s3/3z127YrYfN+mGz2m4+rT+tNuu77d3yfvn3+vbh8eH4bb3dLrer97c3q7L6H15gvODKB5u4AAAAAElFTkSuQmCC",rightHook:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAIAAADZrBkAAAACqElEQVR4Xh3PO2tlZRSH8f9a73XvPTkTExl1dLAIKFpNY2Fl4UcT7G3FwmIaO3sbEfQjWAxDAkIORDHJyXFf3stayzC/9qke+ubrF0u7zqwfsJNFXEKtCAJriBGBoB0gNAZ5WIekcC0f+br8++3Pr1AP5Y/f6Xgfx4RqoB2kI27QgkYQw5BA2L95M+vTn379y0c2HI+Y5Ob6z3B/M/ZmlTieV7ISj9rXZ2n338NciEMedGshJacbZ9X16vK3H76vh/1paCOWiWvos5M1U9llLIebKeqz0zG4PmZ/dfl6XWc/9p4Ox/fMwnIcXrwL6ohPg54OZhYTUUc+w1YQ83z3kMadEKdp8EmE54cnKifTBLOr17cqtwIf4gAuKhUd8Lh4+TKPowjyOK1l8cxAm9nK2nWnsQeAyNtgldnClCLntkrRrTBcFyPjYRg8AEAY4JDhkhp7uOBIRbyqrmK+KcBm1qU30UbSxHcGnIGpKYk63dQxnC2sPcWo2slZUCCGYXPkkBnUqjcCSAGFsaOUQk5koqUqPFV5G2sDai+tG3vv6ZF3BojBzFrvpeij4KtDZTjPXTWGBA91uWJTo1WkqTAZoAbpT3ejd0YOBW1zoAHE/tG8FThm52KOLnDv1dA8DACTwbRU6TxSaX1WZII/1qBgwLvWtgN6ieQc2hC9hwLGTFS35eTJ7uOL5xxTkZI44l7BDGpwBke8FFCA9Pj2EAipHbd8Qre3fxOMDWykGryyM2Vv67JwmCJ7cQRRM6JXX+CrLz97/uHJ4bgHFUdKBi8B5gECLLAys4grAkr5Vt758ZdLTwhuPNvfHP7ZPzjrBAHYLBlChwPQ+jrtpq2UJv3i0/clni/Y03efYzxPvZdBkAzeAKATukENAoTA86ynZ3GrVQl3Eu/yJ/8D33mmeKR3Cz8AAAAASUVORK5CYII=",leftHook:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAIAAADZrBkAAAACq0lEQVR4Xg3HO24mVRBH8X/Vrfv4ut02BjS8GSBAQuyCmE0gwSLICFgCBLASAhLiiQjQICFBMAMSFn63v+77qCp89EsO5U+/rus/0zQPPW8thXRQABLAjtHAAZ2gzGk2HRCG1YMPwgdf/fnXj1fX+O7732s/A0kzbwEUCW5Fgh8HGVdFTOn5H79NiZ/98rPATBVS8OzX5xTehYsxd3KFwXcGEljVOGVJ8a7W4Q4YT8sb33z70xdf/oB8HufzhjI0m2a3JLykuAyV4RGxrLVN5+f/3dxSKXJc59qfUk77djhdXhGx0/mMAg/rpm30bXq97Fp3su1mrMe19e46BLLw9Nb1w0WaZoO+fPmCNbTW3D1Fcjci77Cnn3wMhCBpWU7vuwqo3evgaar6QHRqfRXKhQiELFG1O6H3MZUyLpTIx24UMkNASbqZwZiN3AQsgKhZ6/VYR9OcDw/blg5xmKqPnIRBLQUZw4iIWQKydRcEcvLOOZ2A80Nv8SRv1iiHQWPXewbztm3MbObMYgpGCMwiwgwAIhJCAGBmjMD+KDJJThJzTI8TKZm5E9S7U3c0s6PrkVujvYbm0Qr1iceJ+GZ9772OMawNDNAgVm8cADcAQSgzCSiChZj8MRLwXCTPufQEC8SlVKPWNTJJ4BTDcds58tCaMsVoIQ8Nq2AgS97uVg2h7v29Dz86W86MGqB922F+djjsdbWE0eu233fbwF0opd57KYU43l5ewQ43N7d17CwUHJnlsl4QmUwkJJKZ5uXaLdBrnzl6EGbTbV2nVIiMuMU44EMwMjn76GMHeWAKhKuLvyXoC+F3IvXrfy9zmO/WKyUM6c1riWUY7btKiA+9UkyvPnk7KFMPtLz/uS9vrjVFLNqTUSEJNLN5hQL7gIXpsGytO0ekCduR/fg/hV+olVqSm3YAAAAASUVORK5CYII=",rightZag:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAIAAADZrBkAAAACt0lEQVR4Xg3LOW6eVRQG4PcM937DP9hYlkgUQ6RQsAiEWAC7YCWUtGyAFqhpEHRI0CCBIjpHJBSxEhzkxP6H+93pHPz0D3358IsbuyY/XlCs7/YU5zjFZgdGp07BEDq4KXwA0PvuqIfDGbT0u69/+hZvr/DrH1gc1WENwUAGM3RDcXQGRbA9/e3nJPX3F5dqdY/ja8ztx++/+YhX5S6P47REODW2Pra+qsbOR5VFWwjHVPKJJF1FevPn019++O7jeYo3h5VG8Ua5OLnCh25T7+RwYfZavVz993q5OehccfImnV3nqdLjD54gTiDAF3cnEJrBAbZNSS//vTKP1FcTk0ppsfYzkpEt58Pls8vb29vTabDWYZJzjsqnJ+vHjx9tVvf3qG3QVpXJ0Y5L2xWmYbPt7W5WeK7RKUqICic7poQY6q4Fw2AUDSykUGUlQ0cUy3XUqCxm8Obe4SypVoRwOC7kLE5szIoBHsmlO6NJO3Qv5GEozI3IiE25K2EeLAiYADiBOwi51NLdCRrGcQ5xTLVUcg1BVeFszXtaWinkIAcALigQDwISby0Vq3dpR8IA2r1cKNfZRTq9F2c1iLuYqQcHg2Dmvbam08QUG1V07zASqDCLouSSE0tojCbGablFoMgkpMxht9QukvICASIXtNLy7rDDakVDeGepzpIUup1mlIZs5Dbo9OknnwEELGgZJgBhHHDYIx/v8/r98+d/P2cVVSOkitRPN9uXfz0j2rRSh1CZDKRmFomgnns62Wyvrq+ncTy2JJ/rRXv76vx04ymr83pci9gYRYISS4N3cgRKvYb15EHOHzy8fPaPgtMe8zHG5y8uH6y3wa7LPbNOIIkQRpCOZt7KzatHFx+Ww0Ki9NX8ZHWy7Sltchtz2aj32nicjZkpLr1m760vp5tN2e8jtHX0Yf4f3da+1L4oEEQAAAAASUVORK5CYII=",leftZag:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAIAAADZrBkAAAACtElEQVR4Xg2Lu25cZRhF93f5L3OOPeOQmJuDhEIHDa/CC/B4SHSICqS0CERDE2MJAYKEmITEcewZz/nvH7O0taq16eTL++P66nhCDegOAEhghFYhDDM0hSgowQkKkDIwJi0pP/72G9j24vIi8S7nN34lYG1VyOKg0uVKFFIiY/XL+R8s977+6nvttBMkovTDz9/Np3G3fTlvYkoFJswzaxtya2haQ0nUdGa2PLY6GD/9+vjJ+Y+bD+K2vFxtrLS3cQq9t1rLwUZ7IpuOAmQQ8u9/PgFDWbG5708/jK/Ti9OzExErhYVU1TMrCZqV7fY2Or2+uQ5H7zgPMNQF5HL7+upZeFeHLU//etrraM2YedQBAXsnoPXHn8yrcHVzE0LICWoECTQf+SG19dRqK3tMUxSRZtkIZtqbsblW+vF8/Pzy1XoNvdthjDas7He7swdno+JkM21v997r6A1MIKNBwiCiXssqhNsbcAwQosPTeek1MzBa947NmnewYcGR8Oh1sZG8s5LvQoACaK0Yegi+965MNWXnxIAx0AdyWnqDMjuh1KoIkYGNUPqh0zHaYcpwoin1ZiBFjFBVEWLm1ppzTkQAsAQYQdwhTap+dBCRXzkW6g2lIpdqRkYE1v1+AZgEuiRo8G2YaCBo75ZylSCdiMnoYPVefO1k8AYm7rlAjUDi7/ZN18HIffbp5zFO22Vf0bzXfsBQUu4DIJ6P1/t/XowB9RGl4Xj94M62zy+vou2sDUySyhJjTDXpAeL9YFKXaxYnuoL2BRfnzxghj7YKm4liHkszGkOUjtxIYjKM9ncpTnPr4+HDj8j+U5/B5R5k/vfv344m6rfXHb3NSqKvdrs5xKUWeN95nUd69Oi9vpQI0PtfTAn7eE/eLF0Y92eUjrcDISBmrBjbgkrIDPFYCfoCLPgflXOjuIEFgMYAAAAASUVORK5CYII="}},modern:{background:"#000000",backgroundGrid:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAIAAAC0Ujn1AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpjZTg0NzU4MC00ODk3LTRkNjAtOWNhYi1mZTk1NzQ5NzhiNjkiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTEzOEQwMDc5MDQyMTFFNDlBMzlFNzY4RjBCNkNENzMiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MTEzOEQwMDY5MDQyMTFFNDlBMzlFNzY4RjBCNkNENzMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDplNDRjOWZiNC0yNzE5LTQ3NDYtYmRmMi0wMmY2ZTA4ZjAxMmUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MzMwNTNEOTk5MDM1MTFFNDlBMzlFNzY4RjBCNkNENzMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7Y01+zAAAAMklEQVR42mJgGAWjYBSMgkEJGIlUd+j/WjjbjjGYGC1MtHP10DR6FIyCUTAKBikACDAA0NoDCLGGjH8AAAAASUVORK5CYII=",primary:null,secondary:null,stroke:null,blocks:{line:"#fa1e1e",square:"#f1fa1e",arrow:"#d838cb",rightHook:"#f5821f",leftHook:"#42c6f0",rightZag:"#4bd838",leftZag:"#fa1e1e"}},retro:{background:"#000000",backgroundGrid:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAIAAAC0Ujn1AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpjZTg0NzU4MC00ODk3LTRkNjAtOWNhYi1mZTk1NzQ5NzhiNjkiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTEzOEQwMDc5MDQyMTFFNDlBMzlFNzY4RjBCNkNENzMiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MTEzOEQwMDY5MDQyMTFFNDlBMzlFNzY4RjBCNkNENzMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDplNDRjOWZiNC0yNzE5LTQ3NDYtYmRmMi0wMmY2ZTA4ZjAxMmUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MzMwNTNEOTk5MDM1MTFFNDlBMzlFNzY4RjBCNkNENzMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7Y01+zAAAAMklEQVR42mJgGAWjYBSMgkEJGIlUd+j/WjjbjjGYGC1MtHP10DR6FIyCUTAKBikACDAA0NoDCLGGjH8AAAAASUVORK5CYII=",primary:null,secondary:null,stroke:"#000000",innerStroke:"#000000",blocks:{line:"#fa1e1e",square:"#f1fa1e",arrow:"#d838cb",rightHook:"#f5821f",leftHook:"#42c6f0",rightZag:"#4bd838",leftZag:"#fa1e1e"}},monochrome:{background:"#000000",backgroundGrid:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAIAAAC0Ujn1AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpjZTg0NzU4MC00ODk3LTRkNjAtOWNhYi1mZTk1NzQ5NzhiNjkiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTEzOEQwMDc5MDQyMTFFNDlBMzlFNzY4RjBCNkNENzMiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MTEzOEQwMDY5MDQyMTFFNDlBMzlFNzY4RjBCNkNENzMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDplNDRjOWZiNC0yNzE5LTQ3NDYtYmRmMi0wMmY2ZTA4ZjAxMmUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MzMwNTNEOTk5MDM1MTFFNDlBMzlFNzY4RjBCNkNENzMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7Y01+zAAAAMklEQVR42mJgGAWjYBSMgkEJGIlUd+j/WjjbjjGYGC1MtHP10DR6FIyCUTAKBikACDAA0NoDCLGGjH8AAAAASUVORK5CYII=",primary:"#ffffff",secondary:"#ffffff",stroke:"#000000",innerStroke:"#000000"},aerolab:{background:"#ffffff",primary:"#ff7b00",secondary:"#000000"},gameboy:{background:"#C4CFA1",primary:null,secondary:null,stroke:"#414141",innerStroke:"#414141",innerSquare:"#000000",blocks:{line:"#88926A",square:"#585E44",arrow:"#A4AC8C",rightHook:"#6B7353",leftHook:"#6B7353",rightZag:"#595F45",leftZag:"#595F45"}},vim:{background:"#000000",backgroundGrid:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAIAAAC0Ujn1AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpjZTg0NzU4MC00ODk3LTRkNjAtOWNhYi1mZTk1NzQ5NzhiNjkiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTEzOEQwMDc5MDQyMTFFNDlBMzlFNzY4RjBCNkNENzMiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MTEzOEQwMDY5MDQyMTFFNDlBMzlFNzY4RjBCNkNENzMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDplNDRjOWZiNC0yNzE5LTQ3NDYtYmRmMi0wMmY2ZTA4ZjAxMmUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MzMwNTNEOTk5MDM1MTFFNDlBMzlFNzY4RjBCNkNENzMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7Y01+zAAAAMklEQVR42mJgGAWjYBSMgkEJGIlUd+j/WjjbjjGYGC1MtHP10DR6FIyCUTAKBikACDAA0NoDCLGGjH8AAAAASUVORK5CYII=",primary:"#C2FFAE",secondary:"#C2FFAE",stroke:"#000000",strokeWidth:3,innerStroke:null}}; \ No newline at end of file diff --git a/dist/blockrain.zip b/dist/blockrain.zip index 2262d628c82b6a4545344ab28e32726d1957fdeb..4c794ec32014254c2a05f4513e5094e512034f48 100644 GIT binary patch literal 55927 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 k;#&MCF0l6(xSuO?O%16awD+W-In literal 38164 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%0D|~ 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 diff --git a/gulpfile.js b/gulpfile.js index 00e7e65..467855f 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,5 +1,6 @@ var gulp = require('gulp'), fs = require('fs'), +clean = require("gulp-clean"), uglify = require("gulp-uglify"), concat = require("gulp-concat"), header = require("gulp-header"), @@ -32,22 +33,34 @@ gulp.task('css', function () { .pipe(gulp.dest('./dist')); }); +gulp.task('blocks', function () { + // CSS + return gulp.src(['./assets/blocks/custom/*.*']) + .pipe(gulp.dest('./dist/assets/blocks/custom')); +}); + gulp.task('readme', function () { // Readme return gulp.src(['./README.md']) .pipe(gulp.dest('./dist')); }); +gulp.task('clean', function () { + return gulp.src('./dist', {read: false}) + .pipe(clean()); +}); + gulp.task('dist', function () { // Create a ZIP File - return gulp.src(['./dist/blockrain.jquery.js', './dist/blockrain.jquery.min.js', './dist/blockrain.css']) + return gulp.src(['./dist/**/*.*']) .pipe(zip('blockrain.zip')) .pipe(gulp.dest('./dist')); }); gulp.task('build', function(callback){ - runSequence('js', 'css', 'readme', 'dist', + runSequence('clean', + 'js', 'css', 'blocks', 'readme', 'dist', callback); }); diff --git a/package.json b/package.json index 0414b76..7758de4 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,19 @@ { - "name": "Blockrain.JS", - "version": "0.1.0", + "name": "blockrain", + "version": "0.2.0", "description": "Add a game of tetris to your site", + "main": "dist/blockrain.jquery.min.js", + "dependencies": { + "jquery": "~1.11.3" + }, "devDependencies": { "gulp": "^3.8.8", + "gulp-clean": "^0.3.1", "gulp-concat": "^2.4.1", "gulp-header": "^1.1.1", "gulp-uglify": "^1.0.1", - "gulp-zip": "~2.0.2" + "gulp-zip": "~2.0.2", + "run-sequence": "~1.0.2" }, "repository": { "type": "git", @@ -17,8 +23,5 @@ "license": "MIT", "bugs": { "url": "https://github.com/Aerolab/blockrain.js/issues" - }, - "dependencies": { - "run-sequence": "~1.0.2" } } diff --git a/src/blockrain.jquery.themes.js b/src/blockrain.jquery.themes.js index bcda64c..9124c37 100644 --- a/src/blockrain.jquery.themes.js +++ b/src/blockrain.jquery.themes.js @@ -2,17 +2,17 @@ * Themes. You can add more custom themes to this object. */ window.BlockrainThemes = { - 'individual': { + 'custom': { background: '#040304', backgroundGrid: 'data:image/png;base64,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', complexBlocks: { - line: ['assets/blocks/individual/line.png', 'assets/blocks/individual/line.png'], - square: ['assets/blocks/individual/square.png'], - arrow: 'assets/blocks/individual/arrow.png', - rightHook:['assets/blocks/individual/rightHook.png'], - leftHook: 'assets/blocks/individual/leftHook.png', - rightZag: ['assets/blocks/individual/rightZag.png'], - leftZag: 'assets/blocks/individual/leftZag.png' + line: ['assets/blocks/custom/line.png', 'assets/blocks/custom/line.png'], + square: ['assets/blocks/custom/square.png'], + arrow: 'assets/blocks/custom/arrow.png', + rightHook:['assets/blocks/custom/rightHook.png'], + leftHook: 'assets/blocks/custom/leftHook.png', + rightZag: ['assets/blocks/custom/rightZag.png'], + leftZag: 'assets/blocks/custom/leftZag.png' } }, 'candy': {